Configuración de la base de datos
Configura Postgres y Drizzle ORM — la columna vertebral para auth, cobros, almacenamiento, tareas y tablas de la app.
La base de datos es el centro de un SaaS moderno. Casi todo —autenticación, cobros, créditos, almacenamiento, seguimiento de uso e incluso módulos de demo— pasa por la BD. A veces decimos en broma que somos “ingenieros CRUD”: crear, leer, actualizar, borrar es el trabajo diario. A medida que el esquema crece, tratar la BD como la base mantiene la app predecible.
Esta guía pone la BD primero: mapea el esquema a funcionalidades, explica el CRUD tipado con Drizzle y luego cómo conectar, migrar y validar.
Por qué la base va primero
- Sistema de registro: auth, cobros, archivos y tareas se persisten aquí y se cruzan en servicios/APIs.
- Esquema → Tipos → UI: los modelos de Drizzle en
src/db/schema.tsgeneran tipos seguros que se comparten por modelos y rutas. - CRUD como superficie de producto: la mayoría de pantallas son listas/detalles de lectura/escritura. Un buen diseño de tablas acelera la UI.
Dominios clave (tablas → funcionalidades)
- Auth:
users,sessions,accounts,verificationspara Better Auth. - Cobros y créditos:
orders,creditsregistran compras y movimientos de crédito. - Almacenamiento:
filesguarda metadatos S3/R2 y ciclo de vida (uploading → active → deleted). - Uso y tareas (IA):
tasksregistra queued/running/completed concredits_trans_noenlazado al libro mayor. - Contenido:
postspara snapshots de contenido. - Crecimiento y feedback:
affiliates,feedbacks. - Demo:
reservation_services,reservationsmuestran patrones de agenda/pagos.
Patrones centrados en CRUD en el código
- Modelos en
src/models/*con helpers tipados:src/models/file.ts:insertFile,findFileByUuid,updateFileByUuid,listFilesByUser,softDeleteFile.src/models/task.ts:insertTask,findTaskByUuid,getTasksByUserUuid,updateTaskStatus.
- Servicios y rutas API llaman estos helpers; centraliza el acceso a la BD.
- Para añadir una feature: tablas en
src/db/schema.ts→pnpm drizzle-kit generate→pnpm drizzle-kit migrate→src/models/<dominio>.ts→ uso ensrc/services/*y rutas.
1. ¿Qué es Drizzle ORM?
Usamos Drizzle ORM como capa tipada entre
TypeScript y Postgres. El esquema en src/db/schema.ts es la única fuente de
verdad. Desde ese archivo podemos:
- Generar migraciones SQL con
drizzle-kit - Ejecutar migraciones contra Postgres
- Compartir tipos en toda la app (por ejemplo
users.$inferSelect)
No edites SQL a mano; modifica el esquema y deja que Drizzle cree y aplique las migraciones.
2. Elige tu escenario de base de datos
No existe una configuración única. Escoge el escenario que mejor encaje y
actualiza .env.
| Escenario | Recomendación |
|---|---|
| Solo desarrollo local | Ejecuta Postgres con Docker (por ejemplo docker run ... postgres:16) y apunta DATABASE_URL a postgres://postgres:postgres@localhost:5432/postgres. |
| Postgres gestionado (Neon, Supabase, Railway, Render...) | Copia la cadena de conexión del proveedor y asegúrate de permitir la IP desde la que ejecutas migraciones. |
| BD diferente por entorno | Usa .env para desarrollo local y configura los secretos de producción directamente en tu hosting. |
| Base de datos existente con otras tablas | Drizzle solo modificará las tablas declaradas en src/db/schema.ts. Comprueba que no haya conflictos de nombres o crea un schema distinto. |
Consejo: Drizzle no crea la base de datos. Crea la BD vacía antes de lanzar las migraciones.
3. Configura las variables de entorno
Define la cadena de conexión y los secretos de Better Auth. Leemos .env,
.env.local y .env.development por defecto.
DATABASE_URL="postgresql://user:password@host:5432/db?sslmode=require"
BETTER_AUTH_SECRET="$(openssl rand -base64 32)"
BETTER_AUTH_URL="http://localhost:3000"Reinicia pnpm dev después de cambiar cualquier valor para que el proceso los
recargue.
4. Conoce los archivos del esquema
src/db/schema.ts– modelos Drizzle para Better Auth (users,sessions,accounts,verifications) y tablas propias:orders,credits,files,tasks,posts,affiliates,feedbacks,reservation_services,reservations.src/db/config.ts– configuración de drizzle-kit que apunta al esquema y a la URL de Postgres.src/lib/auth.ts– mapea los campos de Better Auth hacia las columnas Drizzle. Actualiza este archivo si renombras columnas enusers.
Cuando necesites nuevas columnas o tablas, modifica schema.ts y, si aplica, el mapeo correspondiente en auth.ts. Añade índices en schema.ts (uniqueIndex/index) para mantener lecturas rápidas cuando crezca el volumen.
5. Genera migraciones tras cambiar código
Cada vez que cambie schema.ts, ejecuta:
pnpm drizzle-kit generate --config src/db/config.tsSalida esperada (ejemplo):
Reading config file 'src/db/config.ts'
...
[✓] Your SQL migration file ➜ src/db/migrations/0002_add_user_flag.sql 🚀El comando crea dos archivos:
src/db/migrations/<timestamp>_*.sql– el SQL que se ejecutarásrc/db/migrations/meta/_journal.json– el registro de migraciones
Acuérdate de añadir ambos archivos al control de versiones.
6. Aplica las migraciones a Postgres
Ejecuta el SQL generado sobre la base de datos:
pnpm drizzle-kit migrate --config src/db/config.tsEjemplo de éxito:
Applying migrations from src/db/migrations
Migration 0002_add_user_flag.sql executed in 380 ms
All migrations applied!Si ves errores de autenticación, revisa DATABASE_URL. Si el comando se queda
colgado o caduca, verifica permisos de red o que el contenedor esté encendido.
7. Valida el resultado
Usa cualquier cliente Postgres para inspeccionar las tablas/columnas. Con psql:
\dt
SELECT * FROM sessions LIMIT 1;
SELECT email_verified FROM users LIMIT 1;Deberías ver las tablas de Better Auth y las tablas núcleo de la app. Como smoke test de CRUD, inserta y lee una fila con un helper del modelo (p. ej., crea un files mínimo vía POST /api/storage/uploads, luego SELECT * FROM files LIMIT 1;).
8. Prueba el flujo de autenticación
Después de aplicar las migraciones, reinicia pnpm dev, abre /es/signup (o la
ruta con tu locale) y crea un usuario. Deberías volver a la home y ver registros
nuevos en users y sessions.
9. Solución de problemas
- Error: model "userss" not found – Comprueba que
src/lib/auth.tsreferencia la tabla correcta (users). EliminausePluralsi lo copiaste de ejemplos antiguos. - Falta una columna al iniciar sesión – Cambiaste
schema.tspero olvidaste ejecutargenerate+migrate. Vuelve a generarlas. - No se puede conectar a la base de datos – Confirma que la BD existe, las credenciales son correctas y que la red permite conexiones.
- Necesito borrar todo – Elimina las tablas manualmente o usa el SQL de
drizzle-kit para revertirlas antes de volver a ejecutar
generateymigrate.
Sigue siempre esta secuencia: modifica el código, genera migraciones, aplícalas y valida. Así evitarás errores 500 en los flujos de autenticación.
Servicio de Email (Resend)
Integra email transaccional con Resend. Verifica tu dominio, crea claves API, renderiza plantillas de bienvenida y pago en el servidor y envíalas a través de Resend con configuración por entorno.
Cuentas, pedidos y créditos
Comprende cómo se relacionan los usuarios, los pedidos y el libro mayor de créditos en el template Sushi SaaS. Aprende la fórmula del saldo, el manejo de caducidad y las APIs/servicios para otorgar, consumir y consultar créditos.