Features incluidas
AI Pipelines
Motor de flujos de IA configurables sin codigo para agencias
Team Workspaces
Espacios aislados por equipo con roles y permisos granulares
Usage Analytics
Dashboard de uso: ejecuciones, creditos, tendencias por pipeline
API Access
Tokens de API por workspace con rate limiting y audit logs
Webhook Triggers
Disparadores externos para integrar con cualquier herramienta
CSV Export
Exportacion de resultados y reportes en CSV, JSON o PDF
Codigo generado — fragmentos clave
🔐
lib/auth.ts
TypeScript
// NextAuth + DrizzleAdapter + Google OAuth
import { NextAuthOptions } from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { DrizzleAdapter } from "@auth/drizzle-adapter"
import { db } from "./db"
export const authOptions: NextAuthOptions = {
adapter: DrizzleAdapter(db),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
],
callbacks: {
session: async ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id,
subscriptionStatus: user.subscriptionStatus,
},
}),
},
pages: { signIn: "/login" },
}
🗄
db/schema.ts
TypeScript
// Drizzle ORM schema — NeonDB PostgreSQL
import { pgTable, text, timestamp, integer }
from "drizzle-orm/pg-core"
export const users = pgTable("users", {
id: text("id").primaryKey()
.$defaultFn(() => crypto.randomUUID()),
name: text("name"),
email: text("email").notNull().unique(),
stripeCustomerId: text("stripe_customer_id").unique(),
stripeSubscriptionId: text("stripe_subscription_id"),
stripePriceId: text("stripe_price_id"),
stripeCurrentPeriodEnd: timestamp("stripe_current_period_end"),
createdAt: timestamp("created_at").defaultNow().notNull(),
})
// + accounts, sessions, pipelines, workspaces
💳
api/billing/checkout/route.ts
TypeScript
export async function POST(req: Request) {
const session = await getServerSession(authOptions)
if (!session?.user)
return NextResponse.json(
{ error: "Unauthorized" }, { status: 401 })
const { priceId } = await req.json()
// Reutiliza customer existente o crea uno nuevo
let customerId = user.stripeCustomerId
if (!customerId) {
const customer = await stripe.customers.create(
{ email: session.user.email! })
customerId = customer.id
await db.update(users)
.set({ stripeCustomerId: customerId })
.where(eq(users.id, user.id))
}
const checkout = await stripe.checkout.sessions.create({
customer: customerId, mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
subscription_data: { trial_period_days: 14 },
success_url: `${APP_URL}/dashboard?upgraded=true`,
})
return NextResponse.json({ url: checkout.url })
}
🛡
middleware.ts
TypeScript
// Protege rutas autenticadas con NextAuth
import { withAuth } from "next-auth/middleware"
import { NextResponse } from "next/server"
export default withAuth(
function middleware(req) {
const token = req.nextauth.token
if (req.nextUrl.pathname.startsWith("/dashboard")
&& !token) {
return NextResponse.redirect(
new URL("/login", req.url))
}
},
{ callbacks: { authorized: ({ token }) => !!token } }
)
export const config = {
matcher: [
"/dashboard/:path*",
"/settings/:path*",
"/billing/:path*",
],
}
Checklist de implementacion — 5 fases
1
Foundation
- Next.js inicializado con TypeScript + App Router
- Tailwind CSS con tokens de tema custom
- shadcn/ui instalado y configurado
- ESLint + Prettier configurados
- .env.example con todas las variables
✓ Validar:
npm run build sin errores TS/lint2
Database
- Drizzle ORM instalado y configurado
- Schema: users, accounts, sessions, verification_tokens
- Migracion inicial generada y aplicada
- Singleton db exportado desde lib/db.ts
- Conexion DB probada en local
✓ Validar:
db.select().from(users) retorna []3
Authentication
- NextAuth instalado con DrizzleAdapter
- Google OAuth configurado
- Ruta API auth creada
- Callback session con id + subscriptionStatus
- Middleware protege /dashboard, /settings, /billing
- Login y register con estados de error
✓ Validar: OAuth login → session.user.id existe; sin sesion → redirect a /login
4
Payments
- Stripe inicializado con tipos TypeScript
- Ruta checkout session creada
- Ruta customer portal creada
- Webhook handler con verificacion de firma
- Webhook actualiza subscriptionStatus en DB (idempotente)
✓ Validar: checkout con 4242 4242... → stripeSubscriptionId en DB
5
UI — Landing + Dashboard + Billing + Settings
- Landing: hero, features, pricing
- Dashboard layout con sidebar y header responsive
- Billing page: plan actual + upgrade
- Settings: formulario de perfil con success states
✓ Validar:
npm run build produccion — sin broken layouts, sin hydration errorsVariables de entorno — .env.example
Variable
Valor por defecto / formato
Estado
NEXT_PUBLIC_APP_URL
http://localhost:3000
REQUIRED
DATABASE_URL
postgresql://...neon.tech/neondb?sslmode=require
REQUIRED
NEXTAUTH_SECRET
openssl rand -base64 32
REQUIRED
NEXTAUTH_URL
http://localhost:3000
REQUIRED
GOOGLE_CLIENT_ID
console.cloud.google.com
REQUIRED
GOOGLE_CLIENT_SECRET
— desde Google Console
REQUIRED
STRIPE_SECRET_KEY
sk_test_...
REQUIRED
STRIPE_WEBHOOK_SECRET
whsec_... (stripe listen output)
REQUIRED
NEXT_PUBLIC_STRIPE_PK
pk_test_...
REQUIRED
STRIPE_PRO_PRICE_ID
price_... (Pro 79€/mes)
REQUIRED
APP_NAME
fluxy
OPTIONAL
SMTP_HOST / SMTP_PORT
smtp.example.com / 587
OPTIONAL
S3_BUCKET / AWS_ACCESS_KEY_ID
— para storage de archivos
OPTIONAL
REDIS_URL
redis://localhost:6379 (rate limiting)
OPTIONAL
Planes de precios — Stripe Price IDs
Free
0€
para siempre
- ✓ 3 pipelines
- ✓ 500 ejecuciones/mes
- ✓ 1 workspace
- ✗ Sin API access
POPULAR
Pro
79€
por mes · 14 dias gratis
- ✓ Pipelines ilimitados
- ✓ 10.000 ejecuciones/mes
- ✓ 5 workspaces
- ✓ API access + webhooks
- ✓ Soporte prioritario
Enterprise
Custom
precio a medida
- ✓ Todo de Pro
- ✓ SSO / SAML
- ✓ SLA garantizado
- ✓ Onboarding dedicado
- ✓ Audit logs avanzados