203 lines
10 KiB
Markdown
203 lines
10 KiB
Markdown
# Base de datos local y migraciones
|
|
|
|
## Entornos
|
|
|
|
[Resultados y límites de validación](./validacion-docker-y-migraciones-bd.md).
|
|
|
|
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
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
1. 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.
|
|
2. Actualizar el contrato vigente en `schema-contract.ts`, conservando el snapshot
|
|
inicial. Los cambios del esquema y los datos deben respetar tenants y referencias.
|
|
3. Comprobar precondiciones y prever ejecución parcial. Una segunda invocación del
|
|
ejecutor debe dejar aplicadas las migraciones sin repetirlas.
|
|
4. 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.
|
|
5. 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.
|
|
|
|
1. Obtener un backup y comprobar su restauración en una instancia aislada.
|
|
2. Usar `status` para ver tablas ausentes o diferentes. Comparar sus definiciones
|
|
con el SQL inicial y revisar los datos antes de cualquier reconciliación.
|
|
3. Preparar cambios específicos para las diferencias reales. La herramienta no
|
|
elimina columnas, tablas legacy ni datos automáticamente.
|
|
4. Cuando el esquema activo coincida, ejecutar `adopt` con el ejecutable de esta
|
|
versión inicial. Solo registra el baseline; no recrea tablas ni modifica sus datos.
|
|
5. Ejecutar `verify` y 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
|
|
|
|
```bash
|
|
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](../tests/e2e/README.md).
|
|
|
|
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
|
|
|
|
```bash
|
|
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.
|