Práctico

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 con credits_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.tspnpm drizzle-kit generatepnpm drizzle-kit migratesrc/models/<dominio>.ts → uso en src/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.

EscenarioRecomendación
Solo desarrollo localEjecuta 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 entornoUsa .env para desarrollo local y configura los secretos de producción directamente en tu hosting.
Base de datos existente con otras tablasDrizzle 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.

.env
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 en users.

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). Elimina usePlural si lo copiaste de ejemplos antiguos.
  • Falta una columna al iniciar sesión – Cambiaste schema.ts pero olvidaste ejecutar generate + 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 y migrate.

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.