218 lines
12 KiB
Markdown
218 lines
12 KiB
Markdown
# Plan de Docker y migraciones de base de datos
|
|
|
|
Estado: implementación local disponible; adopción de producción pendiente de inventario y ensayo.
|
|
Fecha: 17 de octubre de 2026.
|
|
|
|
Operación vigente: [Base de datos local y migraciones](./desarrollo-y-migraciones-bd.md).
|
|
Este documento conserva la planificación y sus criterios de aceptación.
|
|
|
|
## Objetivo y alcance
|
|
|
|
Levantar MariaDB local para desarrollo y tests, y evolucionar el esquema mediante
|
|
migraciones versionadas. La referencia facilitada para producción es
|
|
`11.8.3-MariaDB-ubu2404`.
|
|
|
|
El backend y el frontend seguirán ejecutándose en WSL con Node.js 24 y PNPM
|
|
11.25.0. Esta adaptación no requiere contenerizar toda la aplicación ni cambiar
|
|
la base de producción. Su incorporación al historial se preparará y ensayará
|
|
antes de ejecutarse en ese entorno.
|
|
|
|
## Situación de partida
|
|
|
|
- Los E2E ya provisionan una MariaDB efímera con Compose, puerto dinámico,
|
|
credenciales generadas y limpieza al finalizar.
|
|
- Los E2E preparan el esquema mediante `sequelize.sync()`.
|
|
- Los tests HTTP crean bases con nombres únicos sobre un servidor configurado
|
|
y fuerzan `DB_SYNC_MODE=alter`; su cierre no elimina esas bases.
|
|
- El runtime permite `none`, `alter` y `force`, sin restricción por entorno.
|
|
- Los scripts SQL están repartidos entre `docs` y `modules/identity/sql`;
|
|
mezclan DDL, cambios de datos, seeds, diagnósticos y procedimientos históricos.
|
|
- No existe un historial versionado de migraciones.
|
|
- El build del servidor tiene un único punto de entrada. Las migraciones deben
|
|
formar parte del artefacto desplegable.
|
|
- El Dockerfile raíz declara PNPM 10.20.0, mientras `packageManager` exige
|
|
11.25.0. Habrá que alinear el build afectado sin modificar `packageManager`.
|
|
|
|
## Decisiones propuestas
|
|
|
|
- Usar la imagen oficial `mariadb:11.8.3`, verificar el servidor resultante y
|
|
registrar su digest para fijar el artefacto utilizado.
|
|
- Centralizar la referencia de imagen utilizada en desarrollo, HTTP, E2E y CI.
|
|
- Usar Compose para el ciclo de vida de MariaDB. Reutilizar la infraestructura
|
|
E2E existente donde encaje, sin crear un framework nuevo.
|
|
- Usar Umzug con Sequelize v6 para ejecutar migraciones TypeScript mediante un
|
|
catálogo explícito y ordenado. No depender de descubrir archivos TS en producción.
|
|
- Ubicar el ejecutor y el catálogo en `modules/core/src/api/infrastructure/database`
|
|
para compartir contrato entre servidor y worker. La CLI reside en
|
|
`apps/server/src/infrastructure/database`. No entran en Domain/Application.
|
|
- Mantener migraciones aplicadas inmutables. Los cambios posteriores se harán
|
|
mediante nuevas migraciones, sin importar modelos ORM que puedan evolucionar.
|
|
- Separar migraciones, datos de demostración y fixtures de tests. Los datos
|
|
funcionales indispensables se clasificarán expresamente antes de incorporarlos.
|
|
- Ejecutar migraciones con una orden explícita, separada del arranque del backend.
|
|
El backend comprobará compatibilidad sin modificar el esquema.
|
|
|
|
## Fase 0. Inventario y contrato inicial
|
|
|
|
1. Confirmar Docker/Compose disponibles desde WSL. Resolver la discrepancia entre
|
|
la ruta real del checkout y la indicada en `AGENTS.md` antes de modificar código.
|
|
2. Inventariar modelos registrados realmente por la composición del servidor,
|
|
asociaciones, índices, restricciones y tablas de auditoría.
|
|
3. Clasificar todos los SQL: vigente, histórico, seed, diagnóstico o limpieza.
|
|
Registrar dependencias y precondiciones, sin ejecutarlos en lote.
|
|
4. Comparar el esquema esperado con un inventario autorizado de desarrollo y,
|
|
cuando se disponga de él, de producción. No asumir que coinciden con los modelos.
|
|
5. Determinar `charset`, `collation`, `sql_mode`, zona horaria y configuración
|
|
relevante de producción. Mantener explícitamente cualquier diferencia necesaria.
|
|
6. Resolver diferencias detectadas entre SQL y modelos, por ejemplo `archived_at`
|
|
y la longitud de `proforma_number`, sin escoger un contrato arbitrariamente.
|
|
|
|
Salida: inventario y contrato de esquema revisables; lista de diferencias por
|
|
entorno y clasificación de tablas legacy. No se eliminan datos ni tablas.
|
|
|
|
## Fase 1. MariaDB de desarrollo
|
|
|
|
1. Añadir un Compose local dedicado a la base de datos, independiente de los
|
|
stacks de despliegue por empresa.
|
|
2. Usar un volumen nombrado persistente y publicar el puerto solo en `127.0.0.1`.
|
|
3. Incorporar `healthcheck.sh --connect --innodb_initialized` y comprobación SQL
|
|
antes de preparar el esquema.
|
|
4. Definir configuración de ejemplo sin secretos reales. Usar credenciales
|
|
distintas para administrar/migrar y para ejecutar la aplicación.
|
|
5. Añadir órdenes PNPM para levantar, detener y consultar logs. El reset de datos
|
|
será una orden separada, explícita y limitada al proyecto local correspondiente.
|
|
6. Documentar conexión desde WSL, persistencia y recuperación de un backup local.
|
|
|
|
Aceptación: detener y levantar conserva los datos; el reset solo afecta al
|
|
volumen local previsto; la imagen y la versión SQL son las esperadas.
|
|
|
|
## Fase 2. Ejecutor de migraciones
|
|
|
|
1. Incorporar Umzug como dependencia del servidor y un punto de entrada CLI
|
|
independiente, con configuración mínima de conexión y sin inicializar HTTP,
|
|
módulos, warmups, certificados ni servicios externos.
|
|
2. Definir identificadores ordenables, por ejemplo
|
|
`202610170001-initial-schema`, y un catálogo sin duplicados.
|
|
3. Persistir el historial de migraciones aplicadas y sus checksums. El historial
|
|
permitirá distinguir pendientes, aplicadas y cambios indebidos de archivos.
|
|
Usar el almacenamiento de Umzug como base y ampliar solo los datos necesarios.
|
|
4. Detectar historiales incompatibles: migraciones desconocidas, huecos y
|
|
checksums diferentes. Registrar inicio, resultado y fallos sin credenciales.
|
|
5. Impedir ejecuciones concurrentes mediante bloqueo de MariaDB mantenido en una
|
|
conexión dedicada durante toda la operación. Probar liberación y timeout.
|
|
6. Registrar una migración como aplicada únicamente después de completarla.
|
|
Los cambios con varios pasos tendrán precondiciones y recuperación documentada
|
|
ante ejecución parcial; no se reintentará a ciegas tras un fallo.
|
|
7. Incorporar órdenes propuestas `db:migrate`, `db:status` y `db:verify`.
|
|
`db:verify` comprobará historial y contrato de esquema; `db:status` será de lectura.
|
|
8. Compilar y empaquetar el ejecutor y todas las migraciones con el servidor;
|
|
comprobar su funcionamiento desde el artefacto final sin `tsx` ni fuentes TS.
|
|
|
|
MariaDB realiza commits implícitos en operaciones DDL. No se ofrecerá un rollback
|
|
transaccional general ni una orden destructiva de reversión de producción.
|
|
Se usarán transacciones para cambios de datos cuando proceda; para DDL, pasos
|
|
recuperables, migraciones correctivas y restauración verificada cuando sea necesaria.
|
|
|
|
Aceptación: una base vacía se prepara; una segunda ejecución no cambia nada;
|
|
un fallo no aparece como éxito; se detectan modificaciones del historial y se
|
|
impiden dos ejecutores simultáneos.
|
|
|
|
## Fase 3. Migración inicial y adopción de bases existentes
|
|
|
|
### Bases nuevas
|
|
|
|
Crear una migración inicial explícita con el esquema activo completo, validado
|
|
contra el inventario: identity, companies, catalogs, customers, suppliers,
|
|
customer-invoices, recurring-proformas, onboarding, factuges y auditoría, según
|
|
su registro real. No copiar automáticamente todos los modelos ni encadenar SQL legacy.
|
|
|
|
La migración inicial no incluirá empresas concretas, usuarios reales ni datos de
|
|
demostración. Los seeds de desarrollo serán opcionales e idempotentes.
|
|
|
|
### Bases existentes
|
|
|
|
1. Obtener backup verificable y ensayar el procedimiento en una copia aislada.
|
|
2. Ejecutar un diagnóstico de tablas, columnas, tipos, índices, restricciones y
|
|
datos relevantes para los cambios pendientes.
|
|
3. Preparar reconciliaciones explícitas para las diferencias demostradas.
|
|
Conservar tablas legacy y datos ajenos al esquema activo.
|
|
4. Permitir registrar la migración inicial como ya existente solo después de
|
|
verificar el contrato. Rechazar bases incompatibles; no marcar todas las
|
|
migraciones como aplicadas ni ejecutar el DDL inicial sobre ellas.
|
|
5. Registrar la evidencia de adopción y ejecutar después las migraciones pendientes.
|
|
|
|
Aceptación: una instalación nueva y una base existente reconciliada alcanzan el
|
|
mismo contrato activo. Los datos existentes y las tablas legacy se conservan.
|
|
|
|
## Fase 4. Tests sobre migraciones reales
|
|
|
|
1. Mantener el ciclo de vida Compose de los E2E y fijar la imagen de MariaDB.
|
|
2. Sustituir `sequelize.sync()` en la preparación E2E por el mismo ejecutor de
|
|
migraciones. Mantener separados bootstrap y datos de escenario.
|
|
3. Añadir un launcher de integración HTTP que provisione MariaDB temporal con
|
|
credenciales generadas. Mantener una base única por runtime cuando lo requiera
|
|
el aislamiento actual y eliminar todas al terminar el contenedor.
|
|
4. Sustituir `DB_SYNC_MODE=alter` del runtime HTTP por migraciones y `none`.
|
|
5. Limitar creación/eliminación de bases a la instancia temporal aprovisionada.
|
|
No aceptar automáticamente servidores externos desde `.env.test`.
|
|
6. Mantener los tests unitarios independientes de Docker cuando no necesiten BD.
|
|
7. Añadir pruebas de instalación vacía, reejecución, fallo parcial recuperable,
|
|
concurrencia, checksums y adopción de esquema compatible/incompatible.
|
|
8. Probar actualizaciones desde versiones anteriores con datos representativos,
|
|
incluyendo aislamiento por empresa, referencias, contadores e integridad fiscal.
|
|
|
|
Aceptación: HTTP y E2E pasan con el esquema creado por migraciones; dos ejecuciones
|
|
concurrentes no comparten datos; éxito, fallo y cancelación limpian sus recursos.
|
|
|
|
## Fase 5. Retirada de sincronización y despliegue
|
|
|
|
1. Tras convertir los consumidores, retirar `alter` y `force` del arranque normal
|
|
y actualizar configuración, tests y ejemplos. Rechazar explícitamente esas opciones.
|
|
2. Hacer que el arranque falle con un diagnóstico claro si el historial no es
|
|
compatible o quedan migraciones pendientes. No aplicar DDL automáticamente.
|
|
3. Añadir a CI instalación vacía, actualización desde versión anterior, verificación
|
|
del esquema y pruebas desde el artefacto compilado.
|
|
4. Preparar el procedimiento de despliegue: backup, control de escrituras cuando
|
|
proceda, ejecución única de migraciones, verificación y arranque de procesos.
|
|
5. Separar privilegios del usuario migrador y de la aplicación. Revisar los permisos
|
|
que requieran los warmups existentes antes de reducirlos.
|
|
6. Documentar compatibilidad entre versiones de aplicación/esquema y recuperación.
|
|
Ejecutar cambios destructivos solo tras auditoría y una migración posterior.
|
|
7. Marcar los SQL antiguos como referencia histórica o procedimiento específico,
|
|
enlazando la migración que los sustituye. Conservar los necesarios para auditoría.
|
|
|
|
## Entregas y validación
|
|
|
|
Entregas incrementales propuestas:
|
|
|
|
1. Inventario, contrato y Compose de desarrollo.
|
|
2. Ejecutor, historial, migración inicial y artefacto compilado.
|
|
3. Diagnóstico y adopción de bases existentes, ensayados en copias.
|
|
4. Integración HTTP y E2E mediante Docker y migraciones.
|
|
5. Retirada de sincronización, CI y procedimiento operativo.
|
|
|
|
No retirar la preparación anterior hasta que su sustitución funcione en la misma
|
|
entrega. Cada entrega tendrá sus comprobaciones dirigidas; al modificar contratos
|
|
compartidos se ejecutarán `pnpm typecheck` y `pnpm lint` globales, las suites
|
|
unitarias pertinentes, `pnpm --filter @erp/factuges-server test`, `pnpm test:e2e`
|
|
y `pnpm --filter @erp/factuges-server build`, según alcance. El ejecutor compilado
|
|
se verificará contra una MariaDB temporal. Se informarán fallos y comprobaciones
|
|
no ejecutadas; este documento no implica que hayan pasado.
|
|
|
|
## Datos pendientes para cerrar la implementación
|
|
|
|
- Configuración efectiva de producción y esquema activo real.
|
|
- Disponibilidad de una copia anonimizada o fixtures equivalentes para ensayar adopción.
|
|
- Cómo se ejecutan actualmente los despliegues y qué CI se utiliza.
|
|
- Recursos Docker disponibles para ajustar el paralelismo de tests.
|
|
|
|
Estas comprobaciones no impiden preparar la infraestructura local y el ejecutor,
|
|
pero sí condicionan el contrato final y la adopción de producción.
|
|
|
|
## Referencias
|
|
|
|
- [Imagen MariaDB 11.8.3 basada en Ubuntu Noble](https://hub.docker.com/layers/library/mariadb/11.8.3/).
|
|
- [Umzug: ejecución e historial con Sequelize](https://github.com/sequelize/umzug).
|
|
- [MariaDB: sentencias con commit implícito](https://mariadb.com/docs/server/reference/sql-statements/transactions/sql-statements-that-cause-an-implicit-commit).
|
|
- [Infraestructura E2E existente](../tests/e2e/README.md).
|