Saltar a contenido

Schema Municipio

Cada organizacion tiene su propio schema PostgreSQL con 33 tablas organizadas en 9 grupos funcionales. El nombre del schema sigue la convencion {numero}_{acronimo}, por ejemplo: 200_muni, 201_otra.

Resumen por Grupo

Grupo Tablas Descripcion
A - Estructura Organizacional 2 departments, sectors
B - Usuarios 5 users, user_roles, user_seals, user_sector_permissions, estado_users
C - Rangos y Sellos 2 ranks, city_seals
D - Documentos 7 document_types, dtabr, edts, document_draft, document_signers, document_rejections, official_documents
E - Expedientes 6 case_templates, ctad, cases, case_movements, case_official_documents, case_proposed_documents
F - Configuracion 1 settings
G - Agente IA 1 document_chunks
H - Notas 2 notes_recipients, notes_openings
I - Registros 7 registry_families, registry_family_permissions, records, record_history, record_relations, record_case_links, record_document_links

Diagrama ER Simplificado

erDiagram
    departments ||--o{ sectors : "contiene"
    departments ||--o{ departments : "parent_id"
    departments }o--|| ranks : "rank_id"

    sectors ||--o{ users : "sector_id"
    users ||--o{ user_roles : "user_id"
    users ||--|| user_seals : "user_id"

    ranks ||--o{ city_seals : "rank_id"
    city_seals ||--o{ user_seals : "city_seal_id"

    document_types ||--o{ document_draft : "document_type_id"
    users ||--o{ document_draft : "created_by"
    document_draft ||--o{ document_signers : "document_id"
    document_types ||--o{ official_documents : "document_type_id"

    case_templates ||--o{ cases : "case_template_id"
    cases ||--o{ case_movements : "case_id"
    cases ||--o{ case_official_documents : "case_id"
    official_documents ||--o{ case_official_documents : "official_document_id"

    document_draft ||--o{ notes_recipients : "document_id"
    document_draft ||--o{ notes_openings : "document_id"

    registry_families ||--o{ records : "registry_family_id"
    records ||--o{ record_history : "record_id"

Grupo A: Estructura Organizacional

TABLA 1: departments

Departamentos de la organizacion. Soporta jerarquia via parent_id (self-referencing).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
name VARCHAR(100) NO - Nombre del departamento
acronym VARCHAR(20) SI - Acronimo (ej: INTE, LEGAL)
parent_id UUID SI - FK self-ref para jerarquia
rank_id UUID SI - FK a ranks (rango jerarquico del depto)
head_user_id UUID SI - Jefe del departamento
primary_color VARCHAR(7) SI - Color hex (ej: #2C3E50)
is_active BOOLEAN NO true Si esta activo
start_date TIMESTAMPTZ NO NOW() Inicio de vigencia
end_date TIMESTAMPTZ SI - Fin de vigencia
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, FK parent_id -> self, FK rank_id -> ranks(id) (diferida)

TABLA 2: sectors

Sectores dentro de cada departamento. Cada departamento tiene al menos un sector PRIV (privado).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
department_id UUID NO - FK a departments
acronym VARCHAR(10) NO - Tipo: PRIV, MESA, ADMIN
primary_color VARCHAR(7) SI - Color hex
is_active BOOLEAN NO true Si esta activo
start_date TIMESTAMPTZ NO NOW() Inicio de vigencia
end_date TIMESTAMPTZ SI - Fin de vigencia
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, FK department_id -> departments(id), UNIQUE (department_id, acronym)


Grupo B: Usuarios

TABLA 3: users

Usuarios de la organizacion. Cada usuario pertenece a un sector.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
auth_id TEXT SI - ID de Auth0
email TEXT NO - Email (unique)
full_name VARCHAR(150) NO - Nombre completo
profile_picture_url TEXT SI - URL foto de perfil (Auth0)
CountryID VARCHAR(20) SI - Documento de identidad
sector_id UUID SI - FK a sectors
estado INT NO 1 Estado del usuario (FK implicita a estado_users)
last_access TIMESTAMPTZ SI - Ultimo acceso
can_global_search_documents BOOLEAN NO true Permiso de busqueda global de docs
can_global_search_cases BOOLEAN NO true Permiso de busqueda global de expedientes
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, UNIQUE email, FK sector_id -> sectors(id)

Indices: idx_{schema}_users_email, idx_{schema}_users_sector

Trigger de sincronizacion

Al insertar, actualizar o eliminar un usuario, el trigger trg_sync_user_registry sincroniza automaticamente public.user_registry.

TABLA 4: user_roles

Asignacion de roles a usuarios. Un usuario puede tener un rol (tipicamente Funcionario o Administrador).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
user_id UUID NO - FK a users
role_id UUID NO - FK a public.roles
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, UNIQUE (user_id, role_id), FK a users y public.roles

TABLA 5: user_seals

Asigna exactamente un sello de firma por usuario. Relacion 1:1 (UNIQUE en user_id).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
user_id UUID NO - FK a users (UNIQUE)
city_seal_id INT NO - FK a city_seals
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, UNIQUE user_id, FK a users y city_seals (diferida)

TABLA 6: user_sector_permissions

Permisos adicionales de un usuario sobre sectores que no son el suyo.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
user_id UUID NO - FK a users
sector_id UUID NO - FK a sectors
can_view BOOLEAN NO true Permiso de lectura
can_edit BOOLEAN NO false Permiso de escritura
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, UNIQUE (user_id, sector_id)

TABLA 7: estado_users

Tabla lookup para estados de usuario.

Columna Tipo Nullable Default Descripcion
id SERIAL NO auto PK
estado VARCHAR(50) NO - Nombre del estado

Datos seed: 1=Activo, 2=Inactivo, 3=Suspendido, 4=Pendiente


Grupo C: Rangos y Sellos

Per-tenant

Desde v4.0.0, rangos y sellos son per-tenant. Cada organizacion define sus propias jerarquias y sellos.

TABLA 8: ranks

Jerarquias de la organizacion. El campo level determina el orden (1 = mas alto).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
name VARCHAR(50) NO - Nombre del rango (unique)
level INT NO - Nivel jerarquico (1 = mas alto, unique)
head_signature VARCHAR(100) SI - Texto en firma de documentos
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, UNIQUE name, UNIQUE level

Ejemplo (200_muni): Intendente (level=1), Secretario (level=2), Director (level=3)

TABLA 9: city_seals

Sellos de firma de la organizacion. Pueden estar vinculados a un rango o ser genericos.

Columna Tipo Nullable Default Descripcion
id SERIAL NO auto PK
name TEXT NO - Nombre del sello (unique)
description TEXT SI - Descripcion
rank_id UUID SI - FK a ranks. NULL = sello generico
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: PK id, UNIQUE name, FK rank_id -> ranks(id)

Ejemplo (200_muni): Innovador (generico, rank_id=NULL), Intendente Municipal (rank_id=Intendente), Secretario, Director


Grupo D: Documentos

TABLA 10: document_types

Tipos de documento habilitados en la organizacion. Copiados del catalogo global.

Columna Tipo Nullable Default Descripcion
id SERIAL NO auto PK
global_document_type_id UUID NO - FK a public.global_document_types
name VARCHAR(100) NO - Nombre local
acronym VARCHAR(6) NO - Acronimo (unique en el schema)
description TEXT SI - Descripcion
required_signature VARCHAR(50) SI - Tipo de firma requerida
is_active BOOLEAN NO true Si esta activo
type document_type_source NO 'HTML' Fuente: HTML, Importado, NOTA
trust BOOLEAN NO true Documento confiable (gobierno) vs externo
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

TABLA 11: document_types_allowed_by_rank

Define que rango minimo se necesita para numerar un tipo de documento.

Columna Tipo Nullable Default Descripcion
id SERIAL NO auto PK
document_type_id INT NO - FK a document_types
rank_id UUID NO - FK a ranks
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: UNIQUE (document_type_id, rank_id)

TABLA 12: enabled_document_types_by_sector

Tipos de documento habilitados por sector. Controla que tipos puede crear cada sector.

Columna Tipo Nullable Default Descripcion
id SERIAL NO auto PK
document_type_id INT NO - FK a document_types
sector_id UUID NO - FK a sectors
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: UNIQUE (document_type_id, sector_id)

TABLA 13: document_draft

Borradores de documentos. Tabla principal del flujo documental.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
created_by UUID NO - FK a users
document_type_id INT SI - FK a document_types
reference VARCHAR(100) NO - Asunto/referencia del documento
content JSONB SI - Contenido HTML como JSON
status document_status NO 'draft' Estado del ciclo de vida
sent_to_sign_at TIMESTAMPTZ SI - Cuando se envio a firmar
sent_by UUID SI - Quien lo envio a firmar
document_number TEXT SI - Numero oficial (al firmar)
numbered_at TIMESTAMPTZ SI - Cuando fue numerado
numbered_by UUID SI - Quien lo numero
is_deleted BOOLEAN NO false Soft delete
resume TEXT SI - Resumen del documento (texto libre)
last_modified_at TIMESTAMPTZ NO NOW() Ultima modificacion
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Indices:

Indice Columnas Proposito
idx_document_draft_status status Filtrar por estado
idx_document_draft_created_by created_by "Mis documentos"
idx_document_draft_type document_type_id Filtrar por tipo
idx_document_draft_created_by_date (created_by, created_at DESC) "Mis documentos" ordenados
idx_doc_draft_last_modified last_modified_at DESC Listado ordenado por modificacion

TABLA 14: document_signers

Firmantes asignados a un documento borrador.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
document_id UUID NO - FK a document_draft
user_id UUID NO - FK a users
is_numerator BOOLEAN NO false Si es el firmante numerador
signing_order INT SI - Orden de firma
status document_signer_status NO 'pending' Estado de firma
signed_at TIMESTAMPTZ SI - Cuando firmo
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Indices: document_id, user_id, status, (document_id, user_id) compuesto

TABLA 15: document_rejections

Registro de rechazos de documentos con motivo.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
document_id UUID NO - FK a document_draft
rejected_by UUID NO - FK a users
reason TEXT SI - Motivo del rechazo
rejected_at TIMESTAMPTZ NO NOW() Fecha del rechazo

TABLA 16: official_documents

Documentos oficiales firmados y numerados. Inmutables despues de la firma.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
document_type_id INT NO - FK a document_types
reference VARCHAR(100) NO - Asunto/referencia
content JSONB NO - Contenido HTML completo
official_number VARCHAR(50) NO - Numero oficial unico
year SMALLINT NO - Anio de emision
department_id UUID NO - FK a departments (del numerador)
numerator_id UUID NO - FK a users (quien numero)
signed_at TIMESTAMPTZ NO - Cuando fue firmado
signers JSONB SI - Datos de firmantes snapshot
global_sequence INT SI - Secuencia global del anio
signer_sector_ids UUID[] SI - Array pre-calculado de sector_ids
resume TEXT SI - Resumen (copiado del draft)
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Indices:

Indice Columnas Tipo Proposito
idx_official_docs_signer_sectors signer_sector_ids GIN Busqueda por sector firmante
idx_official_docs_number official_number B-tree Busqueda por numero
idx_official_docs_signed_at signed_at DESC B-tree Listado cronologico
idx_official_docs_department department_id B-tree Filtro por departamento

Grupo E: Expedientes

TABLA 17: case_templates

Plantillas de expediente habilitadas en la organizacion. Copiadas del catalogo global.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
global_case_template_id UUID NO - FK a public.global_case_templates
type_name VARCHAR(100) NO - Nombre local
acronym VARCHAR(6) NO - Acronimo (unique)
description TEXT SI - Descripcion
creation_channel case_creation_channel NO 'web' Canal de creacion
filing_department_id UUID NO - Departamento que caratula
is_active BOOLEAN NO true Si esta activo
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

TABLA 18: case_template_allowed_departments

Departamentos autorizados para crear expedientes de cada tipo.

Columna Tipo Nullable Default Descripcion
case_template_id UUID NO - FK a case_templates (PK compuesta)
department_id UUID NO - FK a departments (PK compuesta)

TABLA 19: cases

Expedientes de la organizacion.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
case_number VARCHAR(50) NO - Numero unico (formato: EE-YYYY-NNNNNN-MUNI-DEPT)
reference VARCHAR(250) NO - Asunto del expediente
status status_case NO 'inactive' Estado del ciclo de vida
case_template_id UUID NO - FK a case_templates
created_by_user_id UUID NO - FK a users
owner_department_id UUID NO - Departamento actual propietario
owner_sector_id UUID SI - Sector actual propietario
created_at TIMESTAMPTZ NO NOW() Fecha de creacion
ai_summary TEXT SI - Resumen generado por IA
ai_summary_updated_at TIMESTAMPTZ SI - Fecha del resumen IA

Indices: status, owner_department_id, created_at DESC, parcial en activos

TABLA 20: case_movements

Historial de movimientos del expediente. Cada transferencia, asignacion o cambio queda registrado.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
case_id UUID NO - FK a cases
type movement_type NO - Tipo de movimiento
user_id UUID SI - Usuario que ejecuto
creator_sector_id UUID NO - Sector que creo el movimiento
admin_sector_id UUID NO - Sector administrador
assigned_sector_id UUID SI - Sector asignado (para assignments)
assigned_user_id UUID SI - Usuario asignado (para assignments)
reason VARCHAR(200) NO - Motivo del movimiento
is_active BOOLEAN NO true Si esta activo
closed_at TIMESTAMPTZ SI - Cuando se cerro
closing_reason VARCHAR(200) SI - Motivo de cierre
closed_by UUID SI - Quien cerro
supporting_document_id UUID SI - Documento de soporte (ej: PV)
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Indices especiales de performance:

Indice Tipo Proposito
idx_case_mov_admin_lookup Compuesto parcial (creation/transfer) Lookup de admin_sector
idx_case_mov_transfers Parcial WHERE type='transfer' Verificar si tiene transfers
idx_case_mov_assigned_active Parcial WHERE is_active=true Sectores asignados activos

TABLA 21: case_official_documents

Vinculacion de documentos oficiales a expedientes.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
case_id UUID NO - FK a cases
official_document_id UUID NO - FK a official_documents
linking_user_id UUID NO - FK a users
order_number INT NO - Orden de foliatura
linking_date TIMESTAMPTZ NO NOW() Fecha de vinculacion
is_active BOOLEAN NO true Si esta activo
deactivated_at TIMESTAMPTZ SI - Fecha de desvinculacion
deactivated_by_user_id UUID SI - Quien desvinculo

TABLA 22: case_proposed_documents

Propuestas de vinculacion de borradores a expedientes (pendientes de aprobacion).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
case_id UUID NO - FK a cases
document_draft_id UUID NO - FK a document_draft
proposing_user_id UUID NO - FK a users
proposing_date TIMESTAMPTZ NO NOW() Fecha de propuesta
is_active BOOLEAN NO true Si esta activa

Grupo F: Configuracion

TABLA 23: settings

Configuracion de la organizacion. Una unica fila por organizacion.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
timezone TEXT NO 'America/Argentina/Buenos_Aires' Zona horaria
bucket_oficial TEXT NO - Nombre del bucket R2 para docs oficiales
bucket_tosign TEXT NO - Nombre del bucket R2 para docs a firmar
city VARCHAR(100) SI 'LATAM' Ciudad (aparece en sellos de firma)
address VARCHAR(150) SI - Direccion de la organizacion
contact_email VARCHAR(100) SI - Email de contacto
website_url VARCHAR(150) SI - Sitio web
annual_slogan VARCHAR(255) SI - Slogan anual
logo_url TEXT SI - URL del logo
isologo_url TEXT SI - URL del isologo
cover_url TEXT SI - URL de la imagen de portada
primary_color VARCHAR(6) SI '16158C' Color primario hex sin #
created_at TIMESTAMPTZ NO NOW() Fecha de creacion
updated_at TIMESTAMPTZ NO NOW() Ultima modificacion

Grupo G: Agente IA

TABLA 24: document_chunks

Chunks de documentos oficiales con embeddings para busqueda semantica (RAG). Usado por GDI-AgenteLANG.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
official_document_id UUID NO - FK a official_documents
chunk_index INTEGER NO - Indice del chunk dentro del documento
chunk_text TEXT NO - Texto del chunk
embedding vector(1536) SI - Embedding del modelo text-embedding-3-small
embedding_model VARCHAR(100) NO 'text-embedding-3-small' Modelo usado
indexed_at TIMESTAMPTZ NO NOW() Fecha de indexacion

Constraints: UNIQUE (official_document_id, chunk_index)

Indices:

Indice Tipo Proposito
idx_chunks_doc B-tree Buscar chunks por documento
idx_chunks_embedding HNSW (vector_cosine_ops) Busqueda semantica por similitud

Grupo H: Notas

TABLA 25: notes_recipients

Destinatarios de notas oficiales con soporte TO, CC, BCC y archivado.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
document_id UUID NO - FK a document_draft
sector_id UUID NO - FK a sectors (sector destinatario)
recipient_type VARCHAR(3) NO - Tipo: TO, CC, BCC
sender_sector_id UUID NO - FK a sectors (sector remitente)
is_archived BOOLEAN NO false Si el destinatario archivo la nota
archived_at TIMESTAMPTZ SI - Fecha de archivado

Constraints: UNIQUE (document_id, sector_id), CHECK recipient_type IN ('TO','CC','BCC')

Indices parciales:

  • idx_notes_recipients_not_archived: sector_id WHERE is_archived = false (bandeja de entrada)
  • idx_notes_recipients_archived: sector_id WHERE is_archived = true (archivadas)

TABLA 26: notes_openings

Tracking de apertura de notas. Registra si un usuario leyo la nota.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
document_id UUID NO - FK a document_draft
sector_id UUID NO - FK a sectors
user_id UUID NO - FK a users
opened_at TIMESTAMPTZ NO NOW() Fecha de apertura

Constraints: UNIQUE (document_id, user_id)


Grupo I: Registros

TABLA 27: registry_families

Familias de registros de la organizacion. Copiadas y personalizadas desde public.global_registry_families.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
global_family_id UUID SI - FK a public.global_registry_families
code VARCHAR(10) NO - Codigo unico (ej: ARQ, LUM)
name VARCHAR(200) NO - Nombre
description TEXT SI - Descripcion
data_schema JSONB SI '{}' Schema de campos del registro
states JSONB SI '["Activo","Inactivo","Suspendido","Archivado"]' Estados posibles
is_active BOOLEAN NO true Si esta activa
created_at TIMESTAMPTZ NO NOW() Fecha de creacion
updated_at TIMESTAMPTZ NO NOW() Ultima modificacion

TABLA 28: registry_family_permissions

Permisos de sectores sobre familias de registros.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
registry_family_id UUID NO - FK a registry_families
sector_id UUID NO - FK a sectors
can_create BOOLEAN NO false Puede crear registros
can_edit BOOLEAN NO false Puede editar registros
can_view BOOLEAN NO true Puede ver registros
can_verify BOOLEAN NO false Puede verificar/validar campos
created_at TIMESTAMPTZ NO NOW() Fecha de creacion

Constraints: UNIQUE (registry_family_id, sector_id)

TABLA 29: records

Registros individuales con datos JSONB segun el schema de la familia.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
record_number VARCHAR(50) NO - Numero unico del registro
registry_family_id UUID NO - FK a registry_families
data JSONB SI '{}' Datos del registro (segun data_schema)
state VARCHAR(50) SI 'Activo' Estado actual
next_expiration DATE SI - Proxima fecha de vencimiento
created_by_user_id UUID NO - FK a users
created_by_sector_id UUID NO - FK a sectors
created_at TIMESTAMPTZ NO NOW() Fecha de creacion
updated_at TIMESTAMPTZ NO NOW() Ultima modificacion

Indices: registry_family_id, state, created_by_user_id, GIN en data, parcial en next_expiration (NOT NULL)

TABLA 30: record_history

Historial de cambios en registros.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
record_id UUID NO - FK a records
action VARCHAR(50) NO - Tipo de accion
field_name VARCHAR(100) SI - Campo modificado
before_value JSONB SI - Valor anterior
after_value JSONB SI - Valor nuevo
user_id UUID NO - FK a users
sector_id UUID NO - FK a sectors
created_at TIMESTAMPTZ NO NOW() Fecha del cambio

TABLA 31: record_relations

Relaciones entre registros (ej: obra relacionada con luminaria).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
source_record_id UUID NO - FK a records
target_record_id UUID NO - FK a records
relation_type VARCHAR(50) SI 'related' Tipo de relacion
notes TEXT SI - Notas
created_by_user_id UUID NO - FK a users
created_at TIMESTAMPTZ NO NOW() Fecha

Constraints: UNIQUE (source_record_id, target_record_id)

Vinculos entre registros y expedientes.

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
record_id UUID NO - FK a records
case_id UUID NO - FK a cases
notes TEXT SI - Notas
linked_by_user_id UUID NO - FK a users
linked_at TIMESTAMPTZ NO NOW() Fecha

Constraints: UNIQUE (record_id, case_id)

Vinculos entre registros y documentos (draft u oficial).

Columna Tipo Nullable Default Descripcion
id UUID NO gen_random_uuid() PK
record_id UUID NO - FK a records
document_id UUID NO - UUID del draft o documento oficial
field_name VARCHAR(100) SI - Campo del registro asociado
notes TEXT SI - Notas
linked_by_user_id UUID NO - FK a users
linked_at TIMESTAMPTZ NO NOW() Fecha

Constraints: UNIQUE (record_id, document_id)


Trigger: fn_sync_user_registry

Sincroniza automaticamente public.user_registry cuando se crea, actualiza o elimina un usuario.

CREATE OR REPLACE FUNCTION "{SCHEMA_NAME}"."fn_sync_user_registry"()
RETURNS TRIGGER AS $$
DECLARE
    v_schema_name TEXT := TG_TABLE_SCHEMA;
BEGIN
    IF TG_OP = 'INSERT' THEN
        INSERT INTO public.user_registry (email, schema_name, is_default)
        VALUES (NEW.email, v_schema_name, false)
        ON CONFLICT (email, schema_name) DO NOTHING;
        RETURN NEW;
    ELSIF TG_OP = 'UPDATE' THEN
        IF OLD.email IS DISTINCT FROM NEW.email THEN
            UPDATE public.user_registry
            SET email = NEW.email
            WHERE email = OLD.email AND schema_name = v_schema_name;
        END IF;
        RETURN NEW;
    ELSIF TG_OP = 'DELETE' THEN
        DELETE FROM public.user_registry
        WHERE email = OLD.email AND schema_name = v_schema_name;
        RETURN OLD;
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

Trigger: AFTER INSERT OR UPDATE OR DELETE ON {SCHEMA_NAME}.users FOR EACH ROW