10 KiB
Base de datos local y migraciones
Entornos
Resultados y límites de validación.
Desarrollo, integración HTTP y E2E utilizan la imagen oficial MariaDB 11.8.3
basada en Ubuntu 24.04, fijada por digest en
infrastructure/database/compose.yaml. Cambiar esa referencia requiere comprobar
compatibilidad con producción y ejecutar las suites de BD.
El código de la aplicación sigue ejecutándose en WSL Ubuntu-24.04, con Node.js 24
y PNPM 11.25.0. El checkout de esta adaptación está en
/home/david/dev/factuges/factuges-erp; la ruta anterior documentada en AGENTS.md
no existe en este entorno. Ejecutar los comandos desde la raíz Linux real.
Desarrollo
pnpm db:dev:up
pnpm db:migrate
pnpm db:status
pnpm db:verify
pnpm dev:server:local
La primera orden genera infrastructure/database/.env si falta, con contraseñas
aleatorias y permisos 0600. No sobrescribe ficheros existentes. El archivo está
excluido de Git; no compartirlo ni copiar sus valores en documentación o logs.
Compose publica MariaDB en 127.0.0.1:3307, usa la base
factuges_erp_development y conserva los datos en un volumen nombrado. El puerto
se puede cambiar en ese .env. Las órdenes de desarrollo leen exclusivamente
ese fichero y rechazan otros nombres de base u hosts.
Los comandos dev del servidor y dev:server:local leen el .env habitual
de apps/server (si existe) y superponen únicamente
la conexión Docker local, sin pasarle al proceso la contraseña administrativa ni reescribir
archivos existentes. Para arrancar el servidor con otras herramientas, configurar
la conexión local con DB_HOST, DB_PORT, DB_NAME,
DB_USER y DB_PASS del archivo generado, y DB_SYNC_MODE=none. El .env de la
aplicación necesita también su configuración habitual de HTTP, JWT y servicios.
No se reescriben los .env locales existentes automáticamente.
El usuario de aplicación tiene lectura del esquema y del historial, y DML por
tabla activa. No puede escribir en database_migrations. Las órdenes locales de migración
usan la contraseña administrativa en una conexión separada. La inicialización del volumen concede lectura; db:migrate, db:adopt y
db:recover ajustan los permisos del usuario local después de verificar el
esquema. Modificar las credenciales de un .env no cambia cuentas ya persistidas.
pnpm db:dev:logs
pnpm db:dev:down
Detener Compose conserva el volumen. Para eliminar exclusivamente los datos de este proyecto local existe una orden distinta:
pnpm db:dev:reset --confirm-reset
El reset no forma parte del arranque ni de las migraciones. Después hay que volver
a levantar la base y ejecutar db:migrate. No se cargan empresas ni cuentas de
demostración automáticamente; se conserva el flujo funcional de bootstrap/onboarding.
Migraciones
El catálogo y el motor están en
modules/core/src/api/infrastructure/database, compartidos por servidor y worker.
Esta ubicación evita dependencias entre aplicaciones. La CLI está en
apps/server/src/infrastructure/database y no necesita HTTP, JWT ni certificados.
Se utiliza Umzug sobre una conexión SQL dedicada de mysql2. Se mantiene la misma
sesión desde GET_LOCK hasta RELEASE_LOCK, incluidos los commits implícitos del
DDL. La aplicación continúa utilizando Sequelize v6.
La migración 202610170001-initial-schema crea las 30 tablas del runtime activo.
Es SQL congelado, ordenado por dependencias y sin imports de modelos. Las longitudes,
fechas, índices, claves externas y colaciones reflejan los modelos registrados al
preparar esta versión; no se han cambiado contratos de dominio para acomodar SQL antiguo.
database_migrations registra nombre, checksum SHA-256, estado, fechas y si se
adoptó un esquema existente. La aplicación no tiene permisos para modificar ese
historial en desarrollo. Un checksum distinto, una versión desconocida, un hueco
o una migración incompleta impiden continuar.
Servidor y worker verifican historial y definiciones de tablas antes de arrancar.
La comparación es deliberadamente estricta: usa SHOW CREATE TABLE, ignora el
contador AUTO_INCREMENT y el formato de líneas, pero no diferencias en columnas,
índices, restricciones, orden o nombres. Tablas adicionales ajenas al contrato,
por ejemplo legacy, se conservan y no impiden adoptar una base compatible.
DB_SYNC_MODE solo admite none. No se ejecuta sequelize.sync() al arrancar,
preparar HTTP ni preparar E2E.
Incorporar un cambio nuevo
- Añadir un fichero de migración con SQL explícito y un identificador ordenable único al catálogo. No modificar migraciones ya aplicadas ni importar modelos.
- Actualizar el contrato vigente en
schema-contract.ts, conservando el snapshot inicial. Los cambios del esquema y los datos deben respetar tenants y referencias. - Comprobar precondiciones y prever ejecución parcial. Una segunda invocación del ejecutor debe dejar aplicadas las migraciones sin repetirlas.
- Añadir una prueba de actualización desde la versión anterior con datos representativos, además de la instalación vacía y las verificaciones de contrato.
- Ejecutar las suites dirigidas, build y comprobaciones del área afectada.
Los seeds de escenarios pertenecen a los tests; los datos opcionales de desarrollo no son migraciones. No reutilizar UUIDs de empresas de los antiguos SQL de ejemplo.
Bases existentes
No ejecutar la migración inicial sobre una base que ya contiene tablas. El comando
migrate lo rechaza antes de aplicar DDL.
- Obtener un backup y comprobar su restauración en una instancia aislada.
- Usar
statuspara ver tablas ausentes o diferentes. Comparar sus definiciones con el SQL inicial y revisar los datos antes de cualquier reconciliación. - Preparar cambios específicos para las diferencias reales. La herramienta no elimina columnas, tablas legacy ni datos automáticamente.
- Cuando el esquema activo coincida, ejecutar
adoptcon el ejecutable de esta versión inicial. Solo registra el baseline; no recrea tablas ni modifica sus datos. - Ejecutar
verifyy ensayar los flujos funcionales antes del cambio real.
La adopción inicial se limita a esta versión de baseline. Si ya existen migraciones posteriores, usar las herramientas del baseline para adoptar y después actualizar con el ejecutor de la versión destino. No marcar todas las versiones como aplicadas.
La herramienta verifica estructura, no garantiza por sí sola la validez de todos los datos históricos. Deben auditarse huérfanos, contadores y contratos fiscales en la copia del entorno concreto. No se ha inspeccionado ni adoptado producción.
Fallos y recuperación
MariaDB hace commits implícitos con DDL: una migración de varios pasos puede quedar
parcialmente aplicada. El ejecutor registra running antes del SQL, failed si
puede registrar el fallo, y applied únicamente tras completarla. Un proceso
interrumpido puede dejar running; nunca se reintenta automáticamente ese SQL.
status es de lectura y muestra estados incompletos y diferencias. Corregir o
restaurar la base mediante un procedimiento revisado. recover solo permite
registrar como aplicada una migración final incompleta cuando el esquema completo
coincide con el contrato y no hay migraciones posteriores pendientes. No ejecuta
SQL correctivo ni comprueba backfills de datos: estos deben comprobarse por separado
antes de recuperar. No se ofrece rollback destructivo automático.
Tests y CI
pnpm test:unit
pnpm test:db
pnpm test:http
pnpm test:e2e
Cada launcher crea su propio proyecto Compose con nombre aleatorio, puerto local
dinámico y credenciales generadas. No utiliza la MariaDB de desarrollo ni la de
producción. El contenedor y sus volúmenes se eliminan al terminar, también ante
fallos. test:unit excluye las suites HTTP y los ficheros *.integration.test.ts;
no necesita Docker. El paralelismo se limita a cuatro procesos para evitar
crear cientos de workers simultáneos.
La suite HTTP usa una base con nombre único por runtime sobre su instancia
exclusiva. La contraseña administrativa se transmite solo al runtime de test para
crear esas bases y conceder acceso al usuario temporal. No toma su destino de
.env.test: el launcher lo sustituye y el runtime verifica su prefijo de ejecución.
La configuración no relacionada con BD puede proceder de .env.test o, si falta,
de .env.test.example.
Los E2E conservan sus ficheros locales de configuración de aplicación y sus fixtures; la preparación del esquema ahora ejecuta las mismas migraciones que desarrollo. Ver infraestructura E2E.
La suite de migraciones comprueba instalación vacía, reejecución conservando datos,
adopción compatible/incompatible, checksum, diferencias de esquema, bloqueo y
recuperación. También comprueba la CLI compilada. pnpm test:database:ci agrupa
las validaciones de base de datos; requiere Docker y los .env.e2e configurados.
Puede integrarse en el proveedor de CI existente sin imponer uno nuevo.
Ejecución desde el artefacto desplegable
pnpm --filter @erp/factuges-server build
node --env-file=/ruta/segura/migraciones.env apps/server/dist/database-cli.js status
node --env-file=/ruta/segura/migraciones.env apps/server/dist/database-cli.js migrate
node --env-file=/ruta/segura/migraciones.env apps/server/dist/database-cli.js verify
En un contenedor de aplicación se ejecuta la misma CLI incluida en dist como
proceso independiente. Su configuración mínima es DB_HOST, DB_PORT, DB_NAME,
DB_USER, DB_PASS y, si corresponde, DB_SSL=true. Para producción, suministrar
credenciales de migración separadas y verificar el backup y la compatibilidad de
aplicación antes del despliegue. El usuario ordinario requiere DML y lectura de
metadatos/historial; revisar cualquier permiso adicional que necesite la instalación.
Las órdenes PNPM de la raíz db:* están restringidas a desarrollo. Para otros
destinos usar la CLI compilada con un archivo de configuración explícito.
Los antiguos SQL en docs/*/sql y modules/identity/sql quedan como referencia
histórica, diagnóstico o procedimiento específico. No se ejecutan automáticamente
ni constituyen una segunda fuente del esquema vigente.