0016. Ciclo de vida de empresa y aprovisionamiento del tenant¶
Estado: Propuesto
Fecha: 2026-09-08
Autor: Duval Alcivar
Módulo(s) afectado(s): svc-identidad (core_sigfa), svc-erp, svc-crm
Contexto¶
El ADR 0008 define el alta transaccional de una empresa y la propagación
por outbox (empresa.creada). Pero la empresa tiene un ciclo de vida:
luego se edita, se le agregan/quitan aplicaciones, sucursales y finalmente se
deshabilita o elimina. Además, el alta (ADR 0008) no detalla cómo queda
aprovisionado el tenant: su árbol de navegación (plantilla ADR 0013), su
catálogo de permisos vigente y el acceso inicial del usuario administrador.
Este ADR define: (1) el aprovisionamiento completo del tenant dentro del alta, (2) los endpoints del ciclo de vida (editar, sucursales, aplicaciones, soft-delete), y (3) las reglas de aislamiento RLS al operar sobre empresas.
Decisión¶
1. Aprovisionamiento del tenant (dentro del alta, misma transacción)¶
El POST /api/v1/empresas (ADR 0008) ejecuta, en un solo flush, la
empresa y todo lo que su tenant necesita:
| Paso | Qué | ADR |
|---|---|---|
| 1 | mae_empresas (ID BIGINT de secuencia) |
0004 |
| 2 | sucursales iniciales (si las dio) | 0004 |
| 3 | rel_empresa_aplicacion: core siempre + erp/crm contratadas |
0006 |
| 4 | clonar plantilla → cfg_modulos, cfg_menu, cfg_menu_acciones por empresa_id |
0013 |
| 5 | permisos base globales ya existen en cat_permisos (empresa_id NULL) |
0014 |
| 6 | usuario inicial: mae_usuarios (tipo usuario), rel_usuario_empresa |
0005 |
| 7 | acceso del usuario inicial: páginas de permisos (rel_usuario_menu) + sus acciones (rel_usuario_menu_accion) |
0007, 0012, 0015 |
| 8 | mensaje empresa.creada en la outbox |
0008 |
Usuario inicial = usuario con privilegio mínimo: administra la propia
tenencia (módulo permisos: usuarios, asignaciones) y nada más por
defecto; el resto de módulos operativos se otorga después (ADR 0014/0015).
Nunca se crea un root de plataforma como "usuario inicial" (el root es
interno, ADR 0001/0007). Si el alta lo pide, puede asignársele permisos.*
para que gestione sin listar acciones.
Para habilitar "toda la navegación" al administrador inicial, el alta asegura
rel_usuario_menu de las páginas del módulo permisos (clonado en el paso 4)
con sus acciones (paso 7); los códigos resultantes viajan en el JWT (ADR
0011/0015).
2. Endpoints del ciclo de vida (todos bajo /api/v1)¶
| Endpoint | Método | Qué hace | Evento |
|---|---|---|---|
/api/v1/empresas |
POST | alta transaccional + aprovisionamiento (§1) | empresa.creada (ADR 0008) |
/api/v1/empresas |
GET | listar empresas (plataforma, paginado, sin eliminadas) | — |
/api/v1/empresas/{id} |
GET | ver empresa + conteo de sucursales/usuario | — |
/api/v1/empresas/{id} |
PATCH | editar datos generales (nombre, contacto, país…); en ningún caso identificacion |
empresa.actualizada |
/api/v1/empresas/{id} |
DELETE | soft-delete: deleted_at + is_activo=false (§3) |
empresa.eliminada |
/api/v1/empresas/{id}/aplicaciones |
PUT | reemplazar apps contratadas; clonar plantilla de las apps nuevas (§4) | empresa.aplicaciones_actualizadas |
/api/v1/empresas/{id}/sucursales |
POST / GET | crear / listar sucursales | sucursal.creada |
/api/v1/empresas/{id}/sucursales/{suc} |
PUT / DELETE | editar / eliminar sucursal | sucursal.actualizada / sucursal.eliminada |
identificacion(RUC) es inmutable: es la clave natural de la empresa; si se corrigió, se audita el cambio de forma manual (script con bitácora), nunca por PATCH.- El alta y el PATCH de aplicaciones recalculan la plantilla; los demás pasos no tocan la plantilla clonada.
3. Soft-delete y apagado de la empresa¶
DELETE /api/v1/empresas/{id} no borra filas:
mae_empresas.deleted_at = now()+is_activo = false.- Se revocan los refresh tokens de los usuarios de esa empresa
(
trx_refresh_tokens, ADR 0005/0011): el próximo refresh falla. - Los access tokens vivos expiran solos (≤ 30 min, ADR 0011): el login
y el panel ya no la ofrecen (
mae_empresas.is_activo = falsese valida en el paso 1 del login, ADR 0011). - Se emite
empresa.eliminada(payload ={empresa_id}, soft) para que los demás servicios deshabiliten la empresa sin borrar historial. - Los datos históricos se conservan (auditoría): el tenant queda
congelado, no borrado. Reactivar =
is_activo=true+ nuevoempresa.creada? No: se emiteempresa.actualizada(o unempresa.reactivadaexplícito) — se decide al implementar la reactivación (no se incluye en el alcance inicial).
Regla heredada del ADR 0008: solo
svc-identidadcrea/deshabilita empresas; ningún servicio inventa unempresa_id.
4. Contratar una aplicación nueva¶
PUT /api/v1/empresas/{id}/aplicaciones recibe la lista completa (declarativo,
ADR 0009). Al añadir una app (p. ej. crm):
- se inserta
rel_empresa_aplicacion; - se clona la plantilla de esa app al
empresa_id(módulos/páginas/ acciones, ADR 0013) — misma lógica que el alta; - se emiten los códigos base de
cat_permisos(ADR 0014) si algún permiso global de la app no existía.
Quitar una app no borra el árbol clonado: queda is_visible=false en sus
módulos/páginas (reversible) y se emite empresa.aplicaciones_actualizadas.
5. Aislamiento (RLS) al operar empresas¶
- El RLS de la plataforma es una sola policy por
app.current_empresa_id(ADR transversal 0012), no roles por tenant: aprovisionar el tenant = crear sus filas base en las tablas conempresa_id; no hay esquemas ni roles DB por empresa. mae_empresasno tiene RLS (es el catálogo de tenencias): el PATCH de otra empresa y elDELETEquedan restringidos por lógica de negocio arootde plataforma y se auditan (ADR transversal 0008/0009).- Las tablas del tenant (
cfg_modulos,cfg_menu,cfg_menu_acciones,rel_usuario_menu_accion,mae_sucursales…) sí tienen RLS porempresa_id(ADR 0004/0006/0013/0015): la operación interna del alta las escribe con el contexto privilegiado del servicio, y los admin de empresa solo ven su empresa.
Alternativas descartadas¶
- Borrado físico de la empresa — destruye historial y rompe auditoría; solo soft-delete.
- Nuevo esquema/BD por empresa (aprovisionamiento físico de tenant) —
contrapeso innecesario con RLS por
empresa_id(ADR transversal 0012). - Usuario inicial como
rootde plataforma — rompe el modelo (elrootes interno, ADR 0001) y regala permisos fuera de la empresa. - Crear la empresa sin clonar la plantilla — el tenant día 1 no tendría navegación (ADR 0013).
Consecuencias¶
- Alta operativa al minuto 1: empresa + apps + árbol + permiso base + usuario inicial en una sola transacción.
- Menor superficie de permisos: el usuario inicial administra la tenencia y no más; el resto se otorga explícito (ADR 0015).
- El ciclo de vida completo emite eventos versionados por outbox, con soft-delete reversible y conservando el historial.
- Contratar apps nuevas aprovisiona su plantilla; quitarlas solo oculta.
- Resuelve el pendiente 0016 del README (edición/ciclo de vida + aprovisionamiento).
El alta conceptual y el formato empresa.creada están en el ADR 0008; el DDL
de la empresa en el 0004; la plantilla y el clon en el 0013; el catálogo de
permisos en el 0014; las acciones finas en el 0015; el versionado de eventos
al adoptar Kafka queda pendiente (0019).