Schema Public¶
El schema public contiene 9 tablas globales compartidas por todas las organizaciones, mas dos tablas de auditoria/workflow (firma_audit_log, catalog_proposals) y tablas automaticas creadas por GDI-AgenteLANG.
Diagrama ER¶
erDiagram
roles {
UUID role_id PK
VARCHAR role_name UK
TEXT description
TIMESTAMPTZ created_at
}
global_document_types {
UUID id PK
VARCHAR name
VARCHAR acronym UK
TEXT description
VARCHAR signature_type
BOOLEAN is_visible
BOOLEAN is_active
document_type_source type
BOOLEAN trust
TIMESTAMPTZ created_at
}
global_case_templates {
UUID id PK
VARCHAR type_name
VARCHAR acronym UK
TEXT description
BOOLEAN is_active
TIMESTAMPTZ created_at
}
municipalities {
UUID id PK
TEXT name
VARCHAR acronym UK
country_enum country
VARCHAR primary_color
INT schema_number UK
TEXT schema_name UK
BOOLEAN is_active
TIMESTAMPTZ created_at
UUID created_by
}
document_display_states {
SERIAL id PK
VARCHAR display_state_code UK
VARCHAR display_state_name
TEXT description
TIMESTAMPTZ created_at
}
user_registry {
UUID id PK
TEXT email
TEXT schema_name
BOOLEAN is_default
TIMESTAMPTZ created_at
}
api_keys {
UUID id PK
VARCHAR api_key UK
UUID municipality_id FK
VARCHAR name
TEXT description
BOOLEAN is_active
TIMESTAMPTZ expires_at
TIMESTAMPTZ last_used_at
INT rate_limit_per_minute
VARCHAR created_by
}
api_key_users {
UUID id PK
UUID api_key_id FK
UUID user_id
VARCHAR schema_name
TIMESTAMPTZ created_at
}
global_registry_families {
UUID id PK
VARCHAR code UK
VARCHAR name
TEXT description
JSONB default_data_schema
JSONB default_states
BOOLEAN is_active
TIMESTAMPTZ created_at
TIMESTAMPTZ updated_at
}
municipalities ||--o{ api_keys : "tiene"
api_keys ||--o{ api_key_users : "autoriza"
TABLA 1: roles¶
Roles globales del sistema. Compartidos por todas las organizaciones.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
role_id |
UUID | NO | gen_random_uuid() |
Identificador unico |
role_name |
VARCHAR(50) | NO | - | Nombre del rol (unique) |
description |
TEXT | SI | - | Descripcion del rol |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
Constraints: PK role_id, UNIQUE role_name
Datos seed (3 roles):
| role_name | Descripcion |
|---|---|
| Usuario General | Usuario basico del sistema |
| Funcionario | Funcionario con permisos operativos |
| Administrador | Administrador con todos los permisos |
TABLA 2: global_document_types¶
Catalogo maestro de tipos de documento. Cada organizacion copia los que necesita a su tabla local document_types.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
name |
VARCHAR(100) | NO | - | Nombre completo |
acronym |
VARCHAR(6) | NO | - | Acronimo (max 6 chars, unique) |
description |
TEXT | SI | - | Descripcion del tipo |
signature_type |
VARCHAR(50) | SI | 'required' |
Tipo de firma requerida |
is_visible |
BOOLEAN | NO | true |
false para tipos internos (PV, CAEX) |
is_active |
BOOLEAN | NO | true |
Si esta activo para uso |
type |
document_type_source |
NO | 'HTML' |
Fuente: HTML, Importado, NOTA |
trust |
BOOLEAN | NO | true |
true = documento gobierno, false = externo |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
Constraints: PK id, UNIQUE acronym, CHECK char_length(acronym) <= 6
Datos seed: 61 tipos (58 publicos + PV + CAEX internos). Ejemplos:
| Acronimo | Nombre | Tipo | Trust | Visible |
|---|---|---|---|---|
| IF | Informe | HTML | true | true |
| NOTA | Nota | NOTA | true | true |
| PROV | Providencia | HTML | true | true |
| IFGRA | Informe Grafico Importado | Importado | true | true |
| OFJUD | Oficio Judicial | Importado | false | true |
| PV | Pase | HTML | true | false |
| CAEX | Caratula | HTML | true | false |
Tipos internos
PV (Pase) y CAEX (Caratula) tienen is_visible = false y is_active = false. Son de uso exclusivo del modulo de Expedientes Electronicos y se generan automaticamente.
TABLA 3: global_case_templates¶
Catalogo maestro de plantillas de expediente. Cada organizacion copia las que necesita.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
type_name |
VARCHAR(100) | NO | - | Nombre de la plantilla |
acronym |
VARCHAR(6) | NO | - | Acronimo (unique) |
description |
TEXT | SI | - | Descripcion detallada |
is_active |
BOOLEAN | NO | true |
Si esta activa |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
Constraints: PK id, UNIQUE acronym
Datos seed: 30 plantillas. Ejemplos:
| Acronimo | Nombre |
|---|---|
| EEVAR | Varios |
| LICPUB | Licitacion Publica |
| HABI | Habilitacion Comercial |
| COMP | Compras y Contrataciones |
| DEM | Demanda Judicial |
| RRHH | Recursos Humanos |
| OBPUB | Obra Publica |
| MAMBI | Medio Ambiente |
TABLA 4: municipalities¶
Registro de organizaciones activas. Cada fila representa un tenant con su propio schema.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
name |
TEXT | NO | - | Nombre completo de la organizacion |
acronym |
VARCHAR(4) | NO | - | Acronimo auto-generado (WXYZ) |
country |
country_enum |
NO | - | Codigo de pais (AR, BR, UY...) |
primary_color |
VARCHAR(6) | NO | '16158C' |
Color hex sin # |
schema_number |
INT | NO | - | Numero auto-incremental (100, 101...) |
schema_name |
TEXT | NO | - | Nombre del schema (ej: 200_muni) |
is_active |
BOOLEAN | NO | true |
Si esta activo |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
created_by |
UUID | SI | - | Usuario que creo el registro |
Constraints: PK id, UNIQUE acronym, UNIQUE schema_number, UNIQUE schema_name
Convencion de nombres
El schema_name sigue el formato {schema_number}_{acronym_lower}, por ejemplo: 200_muni, 201_otra. El acronimo se genera automaticamente con WXYZ y puede cambiar cuando la organizacion formaliza el contrato.
TABLA 5: document_display_states¶
Estados de visualizacion para el frontend. Mapeo de estados internos a nombres amigables.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
SERIAL | NO | auto | Identificador secuencial |
display_state_code |
VARCHAR(50) | NO | - | Codigo (unique) |
display_state_name |
VARCHAR(100) | NO | - | Nombre para mostrar |
description |
TEXT | SI | - | Descripcion |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
Constraints: PK id, UNIQUE display_state_code
Datos seed (6 estados):
| ID | Codigo | Nombre |
|---|---|---|
| 1 | DRAFT | Borrador |
| 2 | PENDING_SIGN | Pendiente de Firma |
| 3 | SIGNED | Firmado |
| 4 | REJECTED | Rechazado |
| 5 | CANCELLED | Cancelado |
| 6 | NUMBERED | Numerado |
TABLA 6: user_registry¶
Mapeo multi-tenant: asocia un email a los schemas donde tiene acceso. Un usuario puede pertenecer a multiples organizaciones.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
email |
TEXT | NO | - | Email del usuario |
schema_name |
TEXT | NO | - | Schema de la organizacion |
is_default |
BOOLEAN | NO | false |
Organizacion por defecto |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
Constraints: PK id, UNIQUE (email, schema_name)
Indices: idx_user_registry_email en email
Sincronizacion automatica
Esta tabla se mantiene sincronizada automaticamente via trigger fn_sync_user_registry en cada schema de organizacion. Cuando se crea, actualiza o elimina un usuario en {schema}.users, el trigger refleja el cambio en public.user_registry.
TABLA 7: api_keys¶
API Keys para acceso REST a GDI-MCP Server. Cada organizacion puede tener multiples API Keys.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
api_key |
VARCHAR(64) | NO | - | Key unica (formato: sk_live_xxx o sk_test_xxx) |
municipality_id |
UUID | NO | - | FK a municipalities |
name |
VARCHAR(100) | NO | - | Nombre descriptivo del cliente |
description |
TEXT | SI | - | Descripcion de la integracion |
is_active |
BOOLEAN | NO | true |
Si esta activa |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
expires_at |
TIMESTAMPTZ | SI | - | NULL = no expira |
last_used_at |
TIMESTAMPTZ | SI | - | Ultimo uso (se actualiza en cada request) |
rate_limit_per_minute |
INT | SI | 60 |
Limite de requests/minuto |
created_by |
VARCHAR(100) | SI | - | Quien creo la key |
Constraints: PK id, UNIQUE api_key, FK municipality_id -> municipalities(id)
Indices:
idx_api_keys_key: parcial enapi_keyWHEREis_active = trueidx_api_keys_municipality: enmunicipality_id
TABLA 8: api_key_users¶
Asocia usuarios a API Keys para trazabilidad. El cliente REST debe enviar X-User-ID en cada request.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
api_key_id |
UUID | NO | - | FK a api_keys (CASCADE on delete) |
user_id |
UUID | NO | - | UUID del usuario en el schema del tenant |
schema_name |
VARCHAR(100) | NO | - | Schema donde existe el usuario |
created_at |
TIMESTAMPTZ | NO | NOW() |
Fecha de creacion |
Constraints: PK id, UNIQUE (api_key_id, user_id, schema_name), FK api_key_id -> api_keys(id) ON DELETE CASCADE
Indices:
idx_api_key_users_key: enapi_key_ididx_api_key_users_user: en (user_id,schema_name)
TABLA 9: global_registry_families¶
Familias de registros globales con esquema de datos y estados por defecto. Cada organizacion puede copiar y personalizar estas familias.
| Columna | Tipo | Nullable | Default | Descripcion |
|---|---|---|---|---|
id |
UUID | NO | gen_random_uuid() |
Identificador unico |
code |
VARCHAR(10) | NO | - | Codigo unico (ej: ARQ, LUM, ORD) |
name |
VARCHAR(200) | NO | - | Nombre de la familia |
description |
TEXT | SI | - | Descripcion |
default_data_schema |
JSONB | SI | '{}' |
Schema JSONB que define los campos del registro |
default_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 |
Constraints: PK id, UNIQUE code
Datos seed (3 familias):
| Codigo | Nombre | Estados |
|---|---|---|
| ARQ | Registro de Arquitectura y Obras Particulares | Activo, En Inspeccion, Aprobado, Rechazado, Suspendido, Archivado |
| LUM | Registro de Luminarias y Alumbrado Publico | Activo, En Reparacion, Fuera de Servicio, Reemplazado, Archivado |
| ORD | Registro de Ordenanzas y Normativa | Vigente, Derogada, Modificada, En Revision, Archivada |
TABLA: firma_audit_log¶
Tabla de auditoria de firma digital conforme a la Ley 25.506 (Ley de Firma Digital Argentina). INSERT-only; no se permiten UPDATE ni DELETE.
Schema: public (global, no por tenant). El tenant se identifica por la columna schema_name.
Migracion: 045 (045_create_firma_audit_log.sql). Parche 052: columna session_id cambiada de uuid a varchar(50) para soportar el formato de session_id de FirmadorGDI ("SES" + token_hex(6), ej: SESCE461141ADC1).
Retencion: 10 anos.
| Columna | Tipo | Nullable | Descripcion |
|---|---|---|---|
id |
UUID | NO | PK, gen_random_uuid() |
created_at |
TIMESTAMPTZ | NO | Timestamp de insercion |
schema_name |
TEXT | NO | Tenant (schema de la municipalidad) |
session_id |
VARCHAR(50) | SI | ID de sesion de firma digital (NULL para firma electronica) |
signature_method |
TEXT | NO | electronic, digital_token o digital_cloud |
user_id |
UUID | NO | Usuario firmante |
user_cuit |
TEXT | SI | CUIT del firmante (extraido del certificado) |
document_id |
UUID | NO | Documento firmado |
official_number |
TEXT | SI | Numero oficial del documento (ej: IF-2026-00001234) |
document_hash_pre |
BYTEA | SI | Hash SHA del PDF antes de firmar |
document_hash_post |
BYTEA | SI | Hash SHA del PDF firmado |
cert_serial |
TEXT | SI | Numero de serie del certificado |
cert_issuer_dn |
TEXT | SI | DN del emisor del certificado |
cert_subject_dn |
TEXT | SI | DN del sujeto del certificado |
cert_subject_cuit |
TEXT | SI | CUIT del sujeto del certificado |
cert_not_after |
TIMESTAMPTZ | SI | Fecha de vencimiento del certificado |
cert_policy_oids |
TEXT[] | SI | OIDs de politica del certificado |
signature_algorithm |
TEXT | SI | Algoritmo de firma (ej: SHA256withRSA) |
signature_level |
TEXT | SI | Nivel AdES: B-B, B-T, B-LT, B-LTA |
tsa_url |
TEXT | SI | URL del servidor de sello de tiempo (TSA) |
tsa_serial |
TEXT | SI | Serial del sello de tiempo |
tsa_time |
TIMESTAMPTZ | SI | Tiempo del sello TSA |
server_time |
TIMESTAMPTZ | NO | Hora del servidor al registrar (DEFAULT NOW()) |
time_skew_seconds |
INT | SI | Diferencia entre hora cliente y servidor |
ip_address |
INET | SI | IP del cliente firmante |
user_agent |
TEXT | SI | User-Agent del cliente (FirmadorGDI version) |
revocation_method |
TEXT | SI | Metodo de verificacion de revocacion (OCSP, CRL) |
revocation_status |
TEXT | SI | good, revoked o unknown |
revocation_check_time |
TIMESTAMPTZ | SI | Cuando se verifico la revocacion |
result |
TEXT | NO | Resultado de la firma: success, failure, etc. |
failure_reason |
TEXT | SI | Detalle del error si result != success |
r2_object_key |
TEXT | SI | Key del objeto en R2 donde quedo el PDF firmado |
Constraints:
- CHECK
signature_method IN ('electronic', 'digital_token', 'digital_cloud') - CHECK
signature_level IS NULL OR signature_level IN ('B-B', 'B-T', 'B-LT', 'B-LTA') - CHECK
revocation_status IS NULL OR revocation_status IN ('good', 'revoked', 'unknown')
Indices:
| Indice | Columnas | Proposito |
|---|---|---|
idx_firma_audit_log_created_schema |
(created_at, schema_name) |
Consultas por tenant y periodo |
idx_firma_audit_log_session |
session_id |
Buscar por sesion de firma digital |
idx_firma_audit_log_user |
user_id |
Historial por usuario |
idx_firma_audit_log_document |
document_id |
Historial por documento |
idx_firma_audit_log_result |
result |
Filtrar por exito/fallo |
Anti-tampering (permisos SQL):
REVOKE UPDATE, DELETE, TRUNCATE ON public.firma_audit_log FROM PUBLIC;
GRANT INSERT, SELECT ON public.firma_audit_log TO authenticated;
El rol authenticated (usado por GDI-Backend) solo puede INSERT y SELECT. Ningun UPDATE ni DELETE es posible desde la aplicacion.
INSERT-only
Esta tabla nunca se modifica. Cada evento de firma genera una nueva fila. Los sistemas de auditoria deben consultar por document_id o session_id para reconstruir el historial.
TABLA: catalog_proposals¶
Tabla global para el sistema de propuestas al catalogo. Permite que admins de municipios sugieran nuevos tipos de documento, plantillas de expediente o familias de registro para que sean incorporados al catalogo global.
Schema: public (global).
Migracion: 056 (056_create_global_catalog_proposals.sql).
Tablas destino soportadas: global_document_types, global_case_templates, global_registry_families.
Flujo: Admin de municipio propone un item → GDI-AgenteLANG lo analiza con LLM (POST /api/v1/ai/analyze-catalog-proposal en GDI-AgenteLANG, auth: X-API-Key interna) → la IA decide auto_approve o review con justificacion → si es review, queda en cola para revisor humano (BackOffice) → al aprobar, se crea el item en la tabla global destino y se llena global_item_id.
| Columna | Tipo | Nullable | Descripcion |
|---|---|---|---|
id |
UUID | NO | PK, gen_random_uuid() |
catalog_table |
TEXT | NO | Tabla destino: global_document_types, global_case_templates o global_registry_families |
proposed_data |
JSONB | NO | Datos propuestos (estructura libre segun tabla destino) |
proposed_by_user_id |
TEXT | NO | ID del admin que propone |
proposed_by_schema |
TEXT | NO | Schema del tenant que origina la propuesta |
ai_decision |
TEXT | NO | Decision IA: auto_approve o review |
ai_reason |
TEXT | SI | Justificacion textual de la decision IA |
status |
TEXT | NO | Estado del workflow: pending, approved, rejected, auto_approved (default pending) |
global_item_id |
UUID | SI | UUID del item creado en la tabla global (se llena al aprobar) |
review_notes |
TEXT | SI | Notas del revisor humano |
created_at |
TIMESTAMPTZ | NO | Fecha de creacion |
reviewed_at |
TIMESTAMPTZ | SI | Fecha de revision humana |
reviewed_by |
TEXT | SI | ID del revisor humano |
Constraints: CHECK catalog_table IN (...), CHECK ai_decision IN (...), CHECK status IN (...)
Indices:
| Indice | Columnas | Proposito |
|---|---|---|
idx_catalog_proposals_status_created |
(status, created_at DESC) |
Cola de revision ordenada por fecha |
idx_catalog_proposals_proposed_by |
(proposed_by_user_id, created_at DESC) |
Historial por admin |
idx_catalog_proposals_table |
catalog_table |
Filtrar por tabla destino |
Endpoint de analisis IA (GDI-AgenteLANG):
Request:
{
"catalog_table": "global_document_types",
"proposed_data": {"name": "Informe Ambiental", "acronym": "IAMB"},
"existing_items": [{"name": "Informe", "acronym": "IF"}, ...]
}
Response:
{
"decision": "auto_approve",
"reason": "Acronimo unico y categoricamente distinto a los existentes."
}
Feature en consolidacion
La tabla catalog_proposals y el endpoint de analisis IA existen en codigo y BD (migracion 056 aplicada). La interfaz de gestion en BackOffice para que los admins propongan y revisen items esta en desarrollo. La tabla no es visible desde el Frontend principal.
Tablas Automaticas (LangGraph)¶
Las siguientes tablas son creadas automaticamente por GDI-AgenteLANG durante el startup. No deben crearse manualmente.
| Tabla | Proposito |
|---|---|
checkpoints |
Estado del grafo LangGraph por thread_id |
checkpoint_blobs |
Datos binarios grandes (mensajes, estado) |
checkpoint_writes |
Escrituras pendientes (concurrencia) |
checkpoint_migrations |
Control de version del schema de checkpoints |
chat_messages |
Historial de chat relacional y consultable |
No crear manualmente
Estas tablas las administra LangGraph. El thread_id tiene formato {municipality_id}:{conversation_id} para aislamiento multi-tenant.