mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 13:23:17 +00:00
Fase 5 (migracion de datos): - api/scripts/migrate-sqlite-to-postgres.ts: ETL unico SQLite -> Postgres. Pre-flight (CURP/RFC duplicados case-insensitive, FKs huerfanas, tenant_id invalido, fechas mal formateadas) -> carga por base/esquema con credenciales _owner (setval de secuencias, OVERRIDING SYSTEM VALUE, ON CONFLICT DO NOTHING idempotente) -> verificacion de conteos y sumas de dinero con tolerancia. Probado end-to-end contra un dataset SQLite legacy sintetico y un Postgres limpio (solo schema+catalogos, sin contexto dev): 100% de las filas migradas, sumas de dinero exactas, snapshot de uploaded_by/created_by resuelto correctamente. - db/RUNBOOK-corte.md: checklist go/no-go para el corte por ambiente. - Fix de bug real encontrado al probar: sin --context-filter explicito, Liquibase corre TAMBIEN los changesets context=dev (comportamiento por defecto, no "modo seguro") -- documentado en db/README.md con el ejemplo correcto (--context-filter='!dev' para staging/produccion). Fase 5b: patron de compensacion para createTenant ya resuelto en el rewrite de saas.ts (fase 3/4). Fase 6 (backups): db/backups/ con plantillas pgBackRest por base, politica de retencion, nota de persistencia minima de Redis (RDB, sin retencion de negocio), checklist de simulacro de restauracion mensual, y la validacion pendiente de si Coolify permite WAL archiving antes de comprometerse a PITR real. Fase 7 (limpieza y CI): - Dockerfile.api simplificado (sin JRE/Liquibase/FFI). Dockerfile.migrate y Dockerfile.provision nuevos, de un solo uso, para el paso explicito de deploy (nunca sirven trafico). - docker-compose.yml: postgres+redis+provision+migrate para dev local end-to-end; api ya no arranca hasta que migrate termina bien. - docs/coolify.md y .env.example actualizados al modelo de 2 bases + Redis + Contabo. - api/schema.sql eliminado (desincronizado, competia con Liquibase como fuente de verdad). - .github/workflows/ci.yml: Postgres+Redis de servicio, aprovisiona roles/ACLs, dry-run de Liquibase (updateSQL) antes de aplicar, verify-isolation.sh, deno check + deno test, build de los dos frontends. Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
79 lines
3.8 KiB
Markdown
79 lines
3.8 KiB
Markdown
# Base de datos (Postgres + Liquibase)
|
|
|
|
PANELS usa **Postgres** organizado como monolito modular: dos bases de datos
|
|
físicamente separadas en el mismo servidor/instancia por ambiente.
|
|
|
|
| Base de datos | Esquema(s) | Changelog | Qué vive ahí |
|
|
|---|---|---|---|
|
|
| `panels_platform` | `public` | `db/platform/` | Control plane SaaS: `tenants`, `platform_users` (identidad de PANELS como operador), `smtp_settings`. Solo lo tocan las rutas `/v1/saas/*`. |
|
|
| `panels_product` | `iam` | `db/iam/` | Identidad/roles/permisos **de cada tenant** (ej. usuarios de ARCTEC). Aislado de `core` -- sin JOIN/FK cruzado. |
|
|
| `panels_product` | `core` | `db/core/` | Negocio: empresas, personal, obras, expedientes, presupuesto, nómina, gafetes. |
|
|
|
|
No hay FK real entre `panels_platform` y `panels_product` (bases distintas),
|
|
ni entre los esquemas `iam` y `core` (aislamiento a propósito). `tenant_id`
|
|
es una referencia lógica validada en la capa de aplicación. Ver el plan de
|
|
migración para el detalle de la arquitectura y las reglas del monolito
|
|
modular.
|
|
|
|
## Aprovisionamiento (una vez por ambiente, antes de Liquibase)
|
|
|
|
Ver [`db/provision/README.md`](provision/README.md): crea los 6 roles de
|
|
Postgres (`panels_{platform,iam,core}_{owner,app}`), las 2 bases de datos,
|
|
los esquemas `iam`/`core`, la extensión `citext`, y los usuarios ACL de
|
|
Redis. Incluye `dev-local.sh` para reproducir todo esto en una máquina de
|
|
desarrollo sin depender de Coolify, y `verify-isolation.sh` para confirmar
|
|
que el aislamiento realmente se cumple.
|
|
|
|
## Aplicar migraciones
|
|
|
|
Requiere Java 17+ y las credenciales del rol `_owner` de cada módulo (nunca
|
|
`_app`, que es solo runtime):
|
|
|
|
```bash
|
|
# Local, después de correr db/provision/dev-local.sh:
|
|
set -a && source .env.dev-local && set +a
|
|
./db/update.sh all --context-filter=dev # dev: incluye datos de demo
|
|
./db/update.sh all --context-filter='!dev' # staging/producción: solo esquema + catálogos
|
|
|
|
# Un solo módulo
|
|
./db/update.sh core --context-filter='!dev'
|
|
./db/update.sh iam --context-filter='!dev'
|
|
./db/update.sh platform --context-filter='!dev'
|
|
```
|
|
|
|
**Importante**: Liquibase, si NO se le pasa `--context-filter`, corre TODOS
|
|
los changesets sin importar su `context` -- incluidos los de `context="dev"`.
|
|
No pasar el filtro en staging/producción NO es "modo seguro por defecto",
|
|
es lo contrario: cargaría el tenant/empresas/proyecto de demostración. Por
|
|
eso `--context-filter` es obligatorio siempre, nunca opcional.
|
|
|
|
`npm run db:migrate` corre `./db/update.sh all`. **Las migraciones ya NO
|
|
corren automáticamente al arrancar la API** -- son un paso explícito de
|
|
deploy (a diferencia del `runLiquibase()` que existía con SQLite).
|
|
|
|
Contexts de Liquibase:
|
|
- Sin `context`: changesets de esquema y catálogos requeridos (`risk_levels`,
|
|
`document_types`, etc.) -- corren en **todos** los ambientes.
|
|
- `context="dev"`: datos de demostración (tenant/empresas/proyecto ARCTEC) --
|
|
**nunca** en staging/producción. Siempre pasar `--context-filter`
|
|
explícito; no confiar en el default de Liquibase.
|
|
|
|
## Nuevos cambios de schema
|
|
|
|
Un changeset nuevo en `db/{platform,iam,core}/changesets/`, referenciado en
|
|
el `changelog-master.xml` correspondiente. Reglas:
|
|
|
|
- Nunca editar un changeset ya aplicado en un ambiente compartido -- crear
|
|
uno nuevo.
|
|
- Usar `dbms:postgresql` en vez de `context` para lógica específica de motor.
|
|
- No añadir migraciones directamente en `api/*.ts`.
|
|
- Las herramientas (Liquibase + driver JDBC de Postgres) viven en
|
|
`db/tools/` (gitignored); `bootstrap-tools.sh` las descarga.
|
|
|
|
## Bootstrap del primer usuario administrador
|
|
|
|
El `password_hash` (PBKDF2) no lo puede generar un changeset SQL. El primer
|
|
`platform_admin` y el primer `tenant_admin` de un tenant nuevo se crean con
|
|
`scripts/bootstrap-admin.ts` (ver Fase 4 del plan de migración), no con
|
|
lógica de seed en el arranque de la API ni con datos hardcodeados en
|
|
Liquibase.
|