panels-origin/db/README.md
Cursor Agent b87b0205a8
db: migrar infraestructura de BD a Postgres (fase 0-1)
- Fase 0: scripts de aprovisionamiento (db/provision/) para roles, dos
  bases de datos separadas (panels_platform / panels_product con
  esquemas iam+core) y ACLs de Redis por modulo, con verificacion
  automatizada de aislamiento (verify-isolation.sh) y setup local
  reproducible (dev-local.sh).
- Fase 1: changelogs de Liquibase reescritos para Postgres
  (db/platform, db/iam, db/core reemplazan db/app + los changesets
  SQLite de platform). Baseline como estado final (no replay literal),
  tipos traducidos (IDENTITY, TIMESTAMPTZ/DATE, NUMERIC, BOOLEAN,
  CITEXT), contexts dev vs. schema/catalogos, RLS por tenant_id como
  defensa en profundidad, uploaded_by/created_by como snapshot
  desnormalizado (sin FK hacia iam).
- Migraciones ya no corren en el arranque de la API: paso explicito de
  deploy via db/update.sh con credenciales _owner.

Verificado end-to-end contra Postgres 16 + Redis local.

Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
2026-09-02 20:00:49 +00:00

73 lines
3.4 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 # staging/producción: solo esquema + catálogos
# Un solo módulo
./db/update.sh core
./db/update.sh iam
./db/update.sh platform
```
`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.