ADR-028 · Modelo de identidad CIS — Personas/Empresas/Vínculos · bridge Authentik ↔ cis_admin¶
Fecha: 2026-04-29 Source:
/srv/projects/cis/cis-plan/DECISIONS.md(do not edit here — re-split desde la fuente)
Contexto
Hallazgo del 2026-04-29: el modelo legal Personas/Empresas/Vínculos NO necesita ADR de diseño. Ya existe construido en cis_admin Postgres, hereado del cds-admin original migrado a CIS. El plan inicialmente lo trataba como gap a diseñar; el audit lo encontró ya implementado en 14 tablas con relaciones bien definidas.
Este ADR no diseña — documenta el schema existente, formaliza el bridge con Authentik, declara las reglas anti-alucinación de RUT, y especifica el flow de onboarding de empleados con FES.
La distinción es importante: cualquier cambio al schema requiere migration Alembic + ADR nuevo. El schema actual es canon hasta que un ADR explícito lo modifique.
Alternativas consideradas
- (a) Diseñar modelo nuevo cleanroom
- Pro: schema teóricamente óptimo.
-
Contra: ignora 2 años de iteración en cis_admin con datos reales (estatutos firmados, actas, contratos). Migration costosa. Riesgo de re-introducir bugs ya resueltos.
-
(b) Documentar schema existente + bridge Authentik explícito ← propuesta
- Pro: cero migration de datos. Captura conocimiento operativo en ADR. Permite a agentes nuevos razonar sobre el modelo sin abrir psql.
-
Contra: el schema heredado tiene decisiones legacy (column names en castellano + JSONB metadata) que no son las que se elegirían cleanroom. Aceptable como costo.
-
(c) Ignorar el modelo y hacer todo en JSON metadata
- Pro: flexibilidad.
- Contra: pierde queryability. Constraints SQL no aplican. Reportes contables imposibles.
Decisión
Schema canónico (existente en cis_admin DB, 14 tablas verificadas 2026-04-29):
empresas ← persona jurídica · RUT canon SII
- id, rut (UNIQUE), razon_social, nombre_fantasia, tipo, giro,
direccion, comuna, fecha_constitucion, regimen_tributario,
estado, parent_id (FK self · grupo holding),
capital_pagado, capital_suscrito, total_acciones,
valor_nominal_accion, mutual_code, tasa_mutual, zona_extrema,
actividad_economica, metadata (JSONB)
accionistas ← FK empresa_id · persona × % participación
actas ← FK empresa_id · sesiones de directorio
contratos ← FK empresa_id · contratos generales
contratos_comerciales ← FK empresa_id · acuerdos cliente/proveedor
cuentas_bancarias ← FK empresa_id · banco + N° cuenta
declaraciones ← FK empresa_id · F29, F22 SII
documentos ← FK empresa_id · estatutos, poderes
firmas ← receipts FES de firmasydocumentos
obligaciones_tributarias ← deadlines + status SII por empresa
sesiones_directorio ← actas formales registradas
usuarios ← persona física (interno cis-admin)
usuario_empresa_acceso ← M:N user × empresa con permisos
asientos ← entradas contables doble partida (FK empresa_id)
Hechos consumados:
empresas.parent_id(self-FK) ya soporta multi-tenant:parent = CIS,children = clientes externoscuando se active marketplace whitelabel (LH long-horizon).- CIS SpA es
empresas.id = 968, RUT 78.384.591-1. - Sopapo tiene Authentik attribute
empresas_acceso=[968]mapeando a CIS.
Bridge Authentik ↔ cis_admin.usuarios (formalización ADR-028)¶
- Authentik User UUID = canónico (heredado de ADR-014). Es la
subdel JWT. cis_admin.usuarios.authentik_uuid UUID UNIQUE NULL(NULL durante transición; backfill flujo F.0).- Authentik User attributes mirror en
cis_admin.usuarios: rut TEXT(validado contra SII, ver reglas abajo)cargo TEXT(Gerente General, Director, Empleado, Contador, etc.)telefono TEXTdomicilio TEXTprofesion TEXTrol_empresa TEXT(mapa al catalog §7.2 de CONSTITUTION)email_corporativo TEXT(puede diferir de Authentik primary email)usuario_empresa_accesomapea: User × Empresa →
Reglas anti-alucinación de RUT (canónicas)¶
Identificadores legales no se pueden alucinar. La constitución impone:
-
RUT empresa → validado contra
cis-sii-gateway /sii/contribuyente/datos. Lo que SII reconoce es canon. Si SII responde con razón social diferente a la que el user ingresó, prevalece SII y se actualizacis_admin.empresas.razon_social. -
RUT persona → validado contra el mismo endpoint. Cualquier RUT chileno (números 1.000.000-K hasta 99.999.999-9 con dígito verificador correcto). Si el RUT no calcula DV correcto → rechazo en validación frontend.
-
Sin coincidencia SII → el RUT queda como
unverified. El vínculo enusuario_empresa_accesono activa permisos privilegiados hasta que un FES víafirmasydocumentos.cllo confirme. Estado intermedio Authentik attribute:rut: "PENDING_FES_VERIFICATION". -
RUT inventado por agente Claude → prohibido. Si Claudia genera un RUT en una conversación o doc, debe ser explícitamente prefijado
RUT-PROPUESTO-NO-VERIFICADOy validado por humano antes de persistirse en DB. La DB tiene check constraint que rechaza inserts con RUTs no validados sin flag_unverified=trueexplícito.
Flow de onboarding agente empleado (canónico)¶
- Datos básicos: email + nombre + RUT.
- RUT validado contra
cis-sii-gateway /sii/contribuyente/datos(paso obligatorio antes de continuar). - Email único en Authentik (validation OIDC).
-
Rol asignado según catalog §7.2 CONSTITUTION (Socio | Director | Representante legal | Empleado interno | Contador externo | Abogado externo | Periodista | Colaborador externo | Cliente | Proveedor).
-
Documento generado:
cis-admin/documentos/contratos/<año>-<id>.pdfcon plantilla apropiada al rol (contrato laboral, mandato profesional, contrato proyecto, términos servicio). -
Firma FES: empleado firma vía
firmasydocumentos.clcon factor segundo (OTP / SMS / TOTP / WebAuthn). Receipt (JWT firmado RS256) queda en tablafirmascon FK adocumentos.id. -
Activación:
- Backend valida receipt (signature, expiry, audience).
- Crea Authentik User si no existe.
- Asigna group correspondiente al rol (
cis-staff,cis-readonly-contable,cis-collab, etc.). - Inserta row en
cis_admin.usuariosconauthentik_uuidset. -
Inserta row en
usuario_empresa_accesocon{rol, permisos[], fecha_inicio, fecha_fin?, documento_id}. -
Notificación:
cis-mailerenvía recovery link al empleado con flowcis-primary-auth(Google primary + email OTP fallback, ADR-014). -
Audit log:
- Entry en
cis_claudia.chat_tool_auditscontool=user_onboard,params={user, rol, empresa_id, documento_id}. -
Log en
CHANNEL.mdcon tag[onboarding] <persona> · rol <rol> · receipt <fes_id>. -
Primera operación: la persona entra al panel correspondiente (
admin.innovacionsantiago.clpara staff;indieweb.cl/billingpara cliente/proveedor) con SSO transparente.
Permisos privilegiados activos solo post-FES: ningún row en usuario_empresa_acceso con permisos privilegiados (sudo, vault_set, db_write en cis-admin) se considera activo si no hay receipt FES asociado vía documento_id → firmas.documento_id. Verificación on-the-fly en cada autorización.
Consecuencias
- Positivo: agentes nuevos entienden el modelo legal sin abrir psql. El flow de onboarding queda documentado y reproducible. Reglas anti-alucinación protegen contra agentes que inventan RUTs en docs. Receipt FES = evidencia legal de activación de cualquier rol privilegiado.
- Negativo: el schema heredado tiene castellano + JSONB metadata. Queries cross-DB requieren conocer column names en castellano. Aceptable como costo histórico.
- Riesgo: bug en
cis-sii-gatewayque produce false positive de validación RUT (acepta RUT inválido) propaga al modelo. Mitigación: el gateway está en T2 con monitoring; cualquier divergencia respecto a SII oficial dispara alerta acis-inbox(ya implementado). - Migración:
- Backfill
cis_admin.usuarios.authentik_uuidpara usuarios pre-Authentik vía email lower (flujo F.0). - Usuarios actuales (martin, sopapo) ya tienen
authentik_uuiddesde ADR-014. Sopapo ya tieneempresas_acceso=[968](CIS). - Empresas actuales (CIS, CDS, LIBRO si aplica) presentes con RUT validado.
- Compatibilidad: cualquier endpoint actual que consume
cis_admin.usuariossigue funcionando. Lo nuevo es la disciplina formal del flow + el bridgeauthentik_uuid. - Dependencia de ADR-008 + ADR-026: el flow requires
firmasydocumentos.clcon sign endpoint productivo (T1 roadmap). Mientras esté en construcción, onboarding manual para superadmin (caso actual martin + sopapo) sigue válido como excepción documentada. - Dependencia de ADR-020: este ADR provee el modelo legal; ADR-020 provee el bridge técnico cross-service (JIT provisioning + cross-DB GRANT). Son complementarios.
- Schema evolution: cualquier cambio a las 14 tablas (rename column, add constraint, drop column) requires migration Alembic en
cis-admin/alembic/versions/+ ADR explícito que cite este ADR-028 como base. - Multi-tenant futuro: cuando active marketplace whitelabel (LH),
parent_id = CIS, children = clientespermite isolation por scope. RBAC sobreusuario_empresa_accesofiltra por empresa.