Agregar un permiso al catálogo
Agregar un código al catálogo de permisos no es suficiente para que llegue a los tenants existentes — hay que sembrarlo y limpiar caché.
El error común
Agregar un @CheckPermission('accion', 'modulo') nuevo en un controller, junto con su
entrada en permission-catalog.ts, no alcanza automáticamente a los tenants ya
existentes. Es fácil asumir que sí, porque DEFAULT_ROLE_PERMISSIONS vive en código —
pero ese camino solo se usa como legacy fallback para usuarios sin roleId dinámico. La
mayoría de usuarios reales (incluido cualquier Admin de un tenant en producción) usan el
camino DB-backed, que ignora por completo esas constantes en tiempo de ejecución — solo
las lee un script de seed puntual.
Ver el sistema completo en Autenticación → CaslAbilityFactory.
Cómo aplicarlo correctamente
Cada vez que agregues un código nuevo a PERMISSION_CATALOG/DEFAULT_ROLE_PERMISSIONS y
lo despliegues:
- Verifica si afecta a tenants ya existentes — casi siempre sí, si el permiso debe estar disponible para roles que ya tienen usuarios activos.
- Corre la lógica de seed contra todos los tenants —
RolesService.seedPermissions()seedDefaultRoles(tenantId)es lo que alimenta la tablaRolePermission. El endpointPOST /roles/seedsolo cubre un tenant a la vez y requiere serSUPER_ADMINde ese tenant específico — no sirve para aplicar el cambio a todos de una vez.
- Limpia la caché de Redis, o el cambio no se sentirá hasta que expire el TTL de 5
minutos:
docker exec valwisp-redis redis-cli KEYS 'ability:*' | xargs redis-cli DEL
Por qué importa
Esto no es hipotético: en julio de 2026 se agregó time-entries:record y dio 403 real
en producción para el Admin de un tenant, a pesar de que ADMIN debería tener todos los
permisos — porque el nuevo código nunca se sembró contra ese tenant. Al revisar, otras
adiciones recientes de esa misma sesión (templates:read/update, branches:create)
tampoco habían llegado a ningún tenant real.
Pendiente conocido
No existe todavía un endpoint "seed all tenants" (a nivel de plataforma, no por tenant) — hoy se resuelve con un script one-off contra el contenedor de producción. Construir ese endpoint evitaría repetir el proceso manual cada vez.