Apariencia
0052. Operator pasa de solo-lectura a operador de soporte
Estado
Aceptada
Contexto
El rol de sistema de plataforma Operator era, desde su creación (ADR-0048), solo-lectura en los 6 módulos del catálogo de plataforma (ver uniforme). En la práctica, un operador de soporte necesita poder actuar sobre un tenant (corregir datos de una organización, dar de alta o editar usuarios de esa organización) sin tener que pedirle ese trabajo a un Owner. Decisión de producto tomada el 2026-07-23.
Decisión
Matriz explícita por módulo en vez del ['ver'] uniforme (PLATFORM_DEFAULT_ROLE_PERMISSIONS.Operator, platform-rbac.constants.ts):
| Módulo | Acciones | Por qué |
|---|---|---|
organizaciones | ver, editar | corregir/activar-desactivar datos de una org |
usuarios-tenant | ver, crear, editar | altas/ediciones de usuarios de un tenant |
roles-tenant | ver | solo lectura de roles de tenant |
usuarios-plataforma | ver | sin escritura — no crea superadmins |
roles-plataforma | ver | sin escritura — no amplía roles de plataforma, ni el propio |
metricas | ver | dashboard |
(a) usuarios-plataforma/roles-plataforma quedan en solo ver — cierre explícito del vector de escalada
Es la parte no negociable de la decisión: si Operator pudiera crear usuarios de plataforma o editar la matriz de cualquier rol de plataforma (incluido el suyo propio), podría fabricarse permisos de Owner. Cubierto por test/platform-operator-role.e2e-spec.ts (403 en las 5 combinaciones de escritura sobre esos dos módulos).
(b) Backfill por migración explícita, no por el onModuleInit existente
PlatformPermissionsService.backfillDefaultPermissions() (el mecanismo que ya otorga defaults a los roles de sistema al agregar un módulo nuevo) es conservador a propósito: solo agrega los defaults de un módulo a un rol si ese rol no tiene aún ningún permiso de ese módulo — para no re-otorgar algo que un Owner haya quitado deliberadamente en un módulo ya conocido. Como los Operator ya sembrados tienen ver en organizaciones y usuarios-tenant desde que esos módulos existen, ese backfill de arranque saltearía por completo las acciones nuevas (editar, crear) — no las agregaría nunca.
Por eso el backfill de las bases ya sembradas va por una migración SQL dedicada (prisma/migrations/20260723180000_operator_soporte_permisos_backfill/), no por generalizar el mecanismo de arranque: es explícita, corre una sola vez, es idempotente (ON CONFLICT DO NOTHING sobre el índice único (roleId, moduleId, actionId)), solo agrega filas nuevas (no borra nada, no toca Owner ni roles custom) y no cambia el comportamiento conservador existente del onModuleInit para el resto de los módulos. Verificada con un test que baja manualmente un Operator a su perfil viejo (solo ver), corre el SQL de la migración dos veces (idempotencia) y confirma que converge al perfil nuevo.
Consecuencias
platform-rbac.constants.ts:PLATFORM_DEFAULT_ROLE_PERMISSIONS.Operatorpasa dePLATFORM_MODULES.map(() => ['ver'])a la lista explícita por módulo de la tabla arriba.- Migración nueva
20260723180000_operator_soporte_permisos_backfill— solo INSERT condicional, sin cambios de schema. - Tests e2e nuevos:
test/platform-operator-role.e2e-spec.ts(perfil exacto, invariante anti-escalada, idempotencia de la migración). Se ajustaron además dos tests preexistentes que usabanOperatorcomo stand-in genérico de "rol sin el permiso X" (platform-organizations.e2e-spec.ts, dos casos deorganizaciones:editar) — ya no es válido usarOperatorpara esos casos porque ahora sí tiene ese permiso; se reemplazó por un rol custom sin permisos. Y un test enplatform-tenant-admin.e2e-spec.tsque documentaba el perfil viejo deOperatorse actualizó al perfil nuevo. camaroneras_platform/camaroneras_admin/camaroneras_mobile: sin cambios — la UI de plataforma renderiza el catálogo/matriz que devuelve el backend, no hardcodea el perfil deOperator.
Referencias
- Tarea
operator-permisos-soporte(2026-07-23). - ADR-0048 — RBAC de plataforma, define el mecanismo de backfill de
onModuleInitcuyo límite motiva esta decisión. - ADR-0051 — introdujo los módulos
usuarios-tenant/roles-tenantsobre los que ahoraOperatorgana escritura acotada. camaroneras_backend/src/modules/platform/platform-rbac.constants.ts,platform-permissions.service.ts.camaroneras_backend/prisma/migrations/20260723180000_operator_soporte_permisos_backfill/.camaroneras_backend/test/platform-operator-role.e2e-spec.ts.camaroneras_docs/plataforma/superadmin-flow.md(matriz documentada en la sección RBAC de plataforma).