mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 11:23:18 +00:00
- 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>
92 lines
4.3 KiB
SQL
92 lines
4.3 KiB
SQL
--liquibase formatted sql
|
|
-- PANELS · panels_product.iam (Postgres) · baseline
|
|
--
|
|
-- Identidad y RBAC DE CADA TENANT (ej. empleados de ARCTEC que usan
|
|
-- web-panel). No confundir con panels_platform.platform_users (identidad
|
|
-- de PANELS como operador SaaS) -- son dos sistemas de identidad distintos
|
|
-- que no comparten tabla ni base de datos.
|
|
--
|
|
-- Este esquema NO tiene FK hacia `core` (ver reglas del monolito modular
|
|
-- en el plan): documents.uploaded_by/badge_jobs.created_by pasan a
|
|
-- snapshot desnormalizado en `core`, y users.company_id es una referencia
|
|
-- lógica a core.companies(id) sin FK real.
|
|
|
|
--changeset panel:iam-001a-roles endDelimiter:; splitStatements:true
|
|
--preconditions onFail:MARK_RAN
|
|
--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='iam' AND table_name='roles'
|
|
CREATE TABLE iam.roles (
|
|
code TEXT PRIMARY KEY,
|
|
label TEXT NOT NULL
|
|
);
|
|
|
|
INSERT INTO iam.roles (code, label) VALUES
|
|
('tenant_admin', 'Administrador del tenant'),
|
|
('user', 'Usuario operativo');
|
|
|
|
--changeset panel:iam-001b-permissions endDelimiter:; splitStatements:true
|
|
--preconditions onFail:MARK_RAN
|
|
--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='iam' AND table_name='permissions'
|
|
--comment: Catálogo base de permisos. El código de la app hoy sigue gateando
|
|
-- por role_code (igual que el string "role" anterior); esta tabla es la
|
|
-- base para pasar a chequeos granulares por permiso de forma incremental,
|
|
-- sin bloquear la migración a Postgres en ese rediseño más grande.
|
|
CREATE TABLE iam.permissions (
|
|
code TEXT PRIMARY KEY,
|
|
label TEXT NOT NULL
|
|
);
|
|
|
|
INSERT INTO iam.permissions (code, label) VALUES
|
|
('manage_workers', 'Alta, edición y expediente de personal'),
|
|
('manage_projects', 'Alta y edición de obras'),
|
|
('manage_companies', 'Alta y edición de empresas'),
|
|
('manage_budget', 'Presupuesto de obra'),
|
|
('manage_payroll', 'Nómina y préstamos'),
|
|
('manage_documents', 'Documentos de personal/obra/empresa'),
|
|
('manage_users', 'Alta y edición de usuarios del tenant'),
|
|
('manage_settings', 'Configuración del tenant (zona horaria, etc.)'),
|
|
('view_reports', 'Reportes y tableros');
|
|
|
|
--changeset panel:iam-001c-role-permissions endDelimiter:; splitStatements:true
|
|
--preconditions onFail:MARK_RAN
|
|
--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='iam' AND table_name='role_permissions'
|
|
CREATE TABLE iam.role_permissions (
|
|
role_code TEXT NOT NULL REFERENCES iam.roles(code) ON DELETE CASCADE,
|
|
permission_code TEXT NOT NULL REFERENCES iam.permissions(code) ON DELETE CASCADE,
|
|
PRIMARY KEY (role_code, permission_code)
|
|
);
|
|
|
|
INSERT INTO iam.role_permissions (role_code, permission_code)
|
|
SELECT 'tenant_admin', code FROM iam.permissions;
|
|
|
|
INSERT INTO iam.role_permissions (role_code, permission_code) VALUES
|
|
('user', 'manage_workers'),
|
|
('user', 'manage_documents'),
|
|
('user', 'view_reports');
|
|
|
|
--changeset panel:iam-001d-users endDelimiter:; splitStatements:true
|
|
--preconditions onFail:MARK_RAN
|
|
--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='iam' AND table_name='users'
|
|
CREATE TABLE iam.users (
|
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
username TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
display_name TEXT NOT NULL,
|
|
-- Referencia lógica a core.companies(id) -- SIN FK real (iam y core están
|
|
-- aislados a propósito; ver reglas del monolito modular).
|
|
company_id INTEGER,
|
|
-- Referencia lógica a panels_platform.tenants(id) -- SIN FK real (bases
|
|
-- de datos distintas, Postgres no permite FK entre databases).
|
|
tenant_id INTEGER,
|
|
role_code TEXT NOT NULL DEFAULT 'user' REFERENCES iam.roles(code),
|
|
must_change_password BOOLEAN NOT NULL DEFAULT false,
|
|
email TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX idx_iam_users_tenant ON iam.users(tenant_id);
|
|
|
|
-- Nota: el primer usuario (platform_admin y el tenant_admin de cada tenant
|
|
-- nuevo) NO se siembra aquí. Un password_hash real requiere PBKDF2 (mismo
|
|
-- algoritmo que api/crypto.ts), que Liquibase/SQL no puede calcular. Ese
|
|
-- bootstrap es un comando explícito y one-shot: scripts/bootstrap-admin.ts
|
|
-- (Fase 4), no lógica de seed en el arranque de la app ni en un changeset.
|