Visión general y stack
Next.js 16 + Supabase, multi-tenant real (aislamiento en base de datos, no en código de aplicación), pensado para servir a 20 sociedades distintas sin tocar código.
Stack
| Framework | Next.js 16 (App Router, Server Components, Server Actions), TypeScript estricto |
| UI | Tailwind CSS v4, shadcn/ui, lucide-react, sonner |
| Formularios | react-hook-form + zod |
| Tablas | TanStack Table v8 (paginación/orden/filtro en servidor) |
| BBDD / Auth / Storage | Supabase (PostgreSQL, región Frankfurt/UE) |
| Migraciones |
Supabase CLI, todo versionado en
supabase/migrations/*.sql
|
| Hosting | Vercel |
| SMTP propio o Resend, configurable en caliente (ver Envío de email) | |
| @react-pdf/renderer | |
| Excel | exceljs (nunca SheetJS, por licencia) |
| Jobs / colas |
Vercel Cron + tabla job_queue (patrón outbox),
sin Redis
|
El núcleo: aislamiento por sociedad
Base de datos única, esquema único. Toda tabla de negocio lleva
society_id y Row Level Security con
ENABLE + FORCE. El aislamiento
no se implementa con un
WHERE society_id = ... en el código de la aplicación —
eso es una optimización, no la barrera de seguridad. La barrera real
vive en las políticas RLS de Postgres. Detalle completo en
Seguridad, cifrado y RLS y
Roles, RLS y superadmin.
service_role key en
código que atienda peticiones de usuario — solo en
src/lib/server/admin/, con un comentario justificando
cada uso, reforzado por una regla de ESLint
(no-restricted-syntax/no-restricted-imports)
que impide usarla fuera de esas rutas.
Routing
-
/(app)/[societySlug]/...— área de gestión y de socio de una sociedad concreta. -
/admin/...— área de superadmin, sin slug de sociedad. -
/loginvs/admin/login— dos puertas separadas, nunca cruzadas (ver Roles, RLS y superadmin).
Sistema de módulos
Buena parte de lo construido más allá del núcleo (certificados, 2FA, correos personalizados, importación, login de marca, SSO WordPress, formularios de alta, tickets) es un módulo activable, con interruptor global y por sociedad. Detalle en Sistema de módulos activables.
Entornos
Hoy no hay separación real de entornos Supabase (local Docker /
staging / producción) — supabase/config.toml es la
configuración compartida de todos los proyectos vinculados, con
site_url apuntando a localhost a propósito
(el código siempre pasa un redirectTo explícito) y la
URL de producción añadida a la lista de redirecciones permitidas.
[auth] en
config.toml) no se sincroniza sola con el
proyecto en la nube — hace falta
supabase config push explícitamente. Ver
Incidencias resueltas, fue
la causa real de un bug de producción el 19/09/2026.