panels-origin/db/provision
Cursor Agent d36c287a82
db/infra: ETL de datos, backups y limpieza de despliegue (fase 5-7)
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>
2026-09-02 21:05:07 +00:00
..
01-roles.sql db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
02-databases.sql db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
03-platform-database.sql db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
04-product-database.sql db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
05-redis-acl.sh db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
dev-local.sh db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
docker-provision.sh db/infra: ETL de datos, backups y limpieza de despliegue (fase 5-7) 2026-09-02 21:05:07 +00:00
README.md db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00
verify-isolation.sh db: migrar infraestructura de BD a Postgres (fase 0-1) 2026-09-02 20:00:49 +00:00

Aprovisionamiento de infraestructura (Fase 0)

Scripts para dejar Postgres y Redis listos, en cualquier ambiente (dev local, staging o producción en Coolify), antes de correr Liquibase o levantar la API. Ver el plan de migración para el diseño completo: dos bases de datos (panels_platform, panels_product) y, dentro de panels_product, dos esquemas (iam, core).

Orden de ejecución (Postgres)

Contra el servidor Postgres del ambiente (uno por dev/staging/producción), como usuario superusuario/admin:

SUPERUSER_URL="postgresql://postgres:adminpass@HOST:5432/postgres"

# 1. Roles cluster-wide (genera una clave distinta por rol y por ambiente:
#    openssl rand -hex 24). Pasar los valores SIN comillas propias -- el
#    script usa :'var' internamente para escaparlos como literal SQL.
psql "$SUPERUSER_URL" \
  -v platform_owner_pw="..." -v platform_app_pw="..." \
  -v iam_owner_pw="..."      -v iam_app_pw="..." \
  -v core_owner_pw="..."     -v core_app_pw="..." \
  -f 01-roles.sql

# 2. Bases de datos (panels_platform, panels_product)
psql "$SUPERUSER_URL" -f 02-databases.sql

# 3. Privilegios dentro de panels_platform
psql "${SUPERUSER_URL%/postgres}/panels_platform" -f 03-platform-database.sql

# 4. Esquemas + privilegios dentro de panels_product
psql "${SUPERUSER_URL%/postgres}/panels_product" -f 04-product-database.sql

Las conexiones que usará la API (secrets por ambiente):

Secret Apunta a Usuario
DATABASE_URL_PLATFORM panels_platform panels_platform_app
DATABASE_URL_IAM panels_product (search_path=iam) panels_iam_app
DATABASE_URL_CORE panels_product (search_path=core) panels_core_app

Liquibase (paso de deploy, no en runtime) usa los roles _owner: DATABASE_URL_PLATFORM_OWNER, DATABASE_URL_IAM_OWNER, DATABASE_URL_CORE_OWNER.

Redis

REDIS_ADMIN_URL="redis://:adminpass@HOST:6379" \
IAM_REDIS_PASSWORD="$(openssl rand -base64 32)" \
CORE_REDIS_PASSWORD="$(openssl rand -base64 32)" \
./05-redis-acl.sh

Secrets resultantes: REDIS_URL_IAM (redis://panels_iam_redis:<pw>@HOST:6379), REDIS_URL_CORE (redis://panels_core_redis:<pw>@HOST:6379).

El script verifica automáticamente que cruzar de módulo devuelva NOPERM (ver "Riesgos y mitigaciones" del plan: un prefijo de llave sin ACL detrás no aísla nada).

Qué falta hacer manualmente en Coolify (staging/producción)

Estos scripts asumen que ya existe un servidor Postgres y un servidor Redis accesibles (el recurso gestionado de Coolify por ambiente). El agente no tiene acceso a la cuenta de Coolify del usuario, así que:

  1. Crear el recurso Postgres gestionado en Coolify para el ambiente.
  2. Crear el recurso Redis gestionado en Coolify para el ambiente.
  3. Correr estos scripts contra ambos usando las credenciales admin que da Coolify.
  4. Cargar los secrets resultantes (DATABASE_URL_*, REDIS_URL_*) en la configuración del servicio api de ese ambiente.

Desarrollo local

db/provision/dev-local.sh reproduce estos mismos pasos contra un Postgres y Redis instalados en la máquina de desarrollo (sin Coolify), generando .env.dev-local con las URLs resultantes — útil para correr la API y los tests sin depender de infraestructura externa.