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.ts
generan 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
,verifications
para Better Auth. - Cobros y créditos:
orders
,credits
registran compras y movimientos de crédito. - Almacenamiento:
files
guarda metadatos S3/R2 y ciclo de vida (uploading → active → deleted). - Uso y tareas (IA):
tasks
registra queued/running/completed concredits_trans_no
enlazado al libro mayor. - Contenido:
posts
para snapshots de contenido. - Crecimiento y feedback:
affiliates
,feedbacks
. - Demo:
reservation_services
,reservations
muestran 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.ts
Salida 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.ts
Ejemplo 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.ts
referencia la tabla correcta (users
). EliminausePlural
si lo copiaste de ejemplos antiguos. - Falta una columna al iniciar sesión – Cambiaste
schema.ts
pero 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
generate
ymigrate
.
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.