Construimos un SaaS completo de gastos corporativos en 17 sesiones de desarrollo
24.400 líneas de código. 231 commits. 14 tablas. 52 tests. 19 API endpoints. 28 páginas. Un producto listo para su primer cliente de 50 usuarios. Y lo hicimos en 17 sesiones, no en 17 meses.
Un cliente nos planteó un reto que nos encantó:
"Quiero competir con las grandes herramientas de gastos corporativos del mercado español. Tengo un primer cliente de 50 usuarios esperando. ¿En cuánto tiempo podéis tener algo funcional?"
La respuesta honesta era: depende de lo que entiendas por "funcional". Un MVP con captura de gastos, 3 semanas. Un producto completo con OCR, workflow de aprobación, exportación multi-formato, fiscalidad española, Stripe, dark mode, y RGPD — eso es otra historia.
Lo hicimos en 17 sesiones de desarrollo. No 17 meses. No 17 sprints. 17 sesiones de trabajo enfocado, con las herramientas adecuadas y las decisiones correctas desde el día 1.
De la idea al producto completo con primer cliente.
24.400 líneas · 231 commits · 0 deploy failures.
Lo que entregamos
No era un prototipo. Era un producto completo, listo para facturar. Esto es lo que incluía el día que el primer cliente empezó a usarlo:
Además: 4 roles de usuario (owner, admin, approver, employee), 15+ permisos granulares, 4 planes de pricing con Stripe live, 3 tipos de gasto (estándar, kilometraje, dietas), exportación en XLSX/PDF/CSV con desglose fiscal, dark mode, notificaciones push nativas, cumplimiento RGPD con endpoint ARCO, y cero dependencias con vulnerabilidades.
Las decisiones que hicieron posible la velocidad
17 sesiones no es magia. Es el resultado de tomar las decisiones de arquitectura correctas al principio — cuando son baratas — y no cambiarlas después.
Decisión 1: Server Components por defecto
Cada página sigue el mismo patrón: page.tsx es un Server Component que hace el fetch de datos, y pasa los resultados como props a un Client Component que maneja la interactividad.
// 💚 Patrón consistente en 28 páginas
// page.tsx → Server Component (fetch datos)
// page-client.tsx → Client Component (interactividad)
// 📊 Resultado: menos JS en el cliente, más rápido, más seguro
// 🔒 Las queries a BD nunca se exponen al navegador
Esto no es solo rendimiento — es seguridad. Las queries a Supabase con service role nunca llegan al bundle del cliente. Y el patrón se repite idéntico en todas las páginas, lo que hace el desarrollo predecible.
Decisión 2: RLS como red de seguridad
En un SaaS multi-tenant, un bug que filtre datos entre empresas es el fin. Nuestra solución: Row Level Security de PostgreSQL en todas las tablas.
// 💚 Incluso si el código tiene un bug y olvida WHERE tenant_id = X
// La base de datos RECHAZA el acceso
// Es una red de seguridad a nivel de infraestructura
// 📊 14 tablas × 23+ políticas RLS
// 🔒 Funciones SECURITY DEFINER con search_path = public
Con RLS, no dependes de que cada query tenga el filtro correcto. La base de datos lo aplica siempre. Es la diferencia entre "confío en que el código es correcto" y "es imposible acceder a datos de otro tenant".
Decisión 3: Billing como contexto transversal
Cuando la suscripción de un tenant expira, el usuario puede ver sus datos pero no modificarlos. Esto tiene que funcionar en todas las páginas, todos los endpoints, sin excepción.
Lo resolvimos con un React Context (BillingProvider) que expone isReadOnly a toda la app. En el servidor, una función checkBillingWriteAccess() devuelve 403 o nada. Los superadmins bypasean todo.
Un cron diario purga datos 90 días después de la expiración, respetando el orden de foreign keys. Simple, predecible, imposible de olvidar.
Decisión 4: Stripe desde el día 1
No "añadimos pagos después". Stripe estuvo desde la primera sesión con el modelo de pricing definido:
El dato que más nos enorgullece
Deploy failures en producción.
231 commits, 17 sesiones, cada push directo a main.
Esto no es suerte. Es el resultado de Server Components que se verifican en build, TypeScript strict sin any, 52 tests que cubren la lógica más crítica, y un stack que elimina categorías enteras de errores (RLS en vez de filtros manuales, Stripe webhooks en vez de polling).
La evolución sesión a sesión
Para que se vea que no es un MVP disfrazado — esta es la progresión real del producto:
Cosas que haríamos igual
- Supabase en vez de un backend custom. Auth, RLS, Storage, Realtime — todo incluido. Nos ahorró semanas de infraestructura.
- Vercel Pro con deploy desde main. Cada push es un deploy. Si falla el build, no llega a producción. Simple.
- shadcn/ui como base de componentes. Componentes de calidad que se copian en tu proyecto (no dependencia npm). Se customiza todo.
- Stripe desde el día 1. El billing no es algo que "añades después". Es la columna vertebral del negocio.
- 52 tests en la lógica fiscal. La fiscalidad española tiene demasiados edge cases para confiar en "funciona en mi máquina".
No es rápido por ser simple — es rápido por ser disciplinado
17 sesiones con 24.400 líneas de código no es "programar rápido y que salga lo que salga". Es elegir un stack que elimina categorías de problemas (RLS, Server Components, TypeScript strict), un patrón que se repite en todas las páginas (server fetch + client render), y no perder tiempo en decisiones que ya están tomadas.
Los datos finales
🛠️ Stack completo del proyecto
¿Tienes una idea de producto SaaS y necesitas velocidad sin sacrificar calidad? En Nexus Code construimos productos SaaS B2B completos con Next.js, Supabase, Stripe y despliegue continuo. Del concepto al primer cliente en semanas. Cuéntanos tu proyecto.