Saltar a contenido

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:

  1. mae_empresas.deleted_at = now() + is_activo = false.
  2. Se revocan los refresh tokens de los usuarios de esa empresa (trx_refresh_tokens, ADR 0005/0011): el próximo refresh falla.
  3. Los access tokens vivos expiran solos (≤ 30 min, ADR 0011): el login y el panel ya no la ofrecen (mae_empresas.is_activo = false se valida en el paso 1 del login, ADR 0011).
  4. Se emite empresa.eliminada (payload = {empresa_id}, soft) para que los demás servicios deshabiliten la empresa sin borrar historial.
  5. Los datos históricos se conservan (auditoría): el tenant queda congelado, no borrado. Reactivar = is_activo=true + nuevo empresa.creada? No: se emite empresa.actualizada (o un empresa.reactivada explícito) — se decide al implementar la reactivación (no se incluye en el alcance inicial).

Regla heredada del ADR 0008: solo svc-identidad crea/deshabilita empresas; ningún servicio inventa un empresa_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):

  1. se inserta rel_empresa_aplicacion;
  2. se clona la plantilla de esa app al empresa_id (módulos/páginas/ acciones, ADR 0013) — misma lógica que el alta;
  3. 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 con empresa_id; no hay esquemas ni roles DB por empresa.
  • mae_empresas no tiene RLS (es el catálogo de tenencias): el PATCH de otra empresa y el DELETE quedan restringidos por lógica de negocio a root de 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 por empresa_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 root de plataforma — rompe el modelo (el root es 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).