UDT-005: Gestión de Permisos (RBAC) — catálogo + asignación rol↔permisos #9

Merged
dmolinari merged 8 commits from feature/UDT-005 into main 2026-04-15 19:02:03 +00:00
Owner

Summary

Implementa el modelo RBAC granular de SIG-CM 2.0: catálogo de 18 permisos, asignación M:N Rol ↔ Permiso, CRUD admin para editar permisos por rol. Sin enforcement (UDT-006) ni override por usuario (UDT-008).

Decisiones clave

  • Modelo plano (sin heredaDe entre roles, sin wildcard). El rol admin tiene los 18 permisos EXPLÍCITOS en RolPermiso.
  • Convención obligatoria: cada permiso nuevo (en cualquier UDT futura) DEBE asignarse explícitamente a admin en la migración. Registrado en engram como architecture/rbac-admin-convention.
  • Override por usuario (Usuario.PermisosJson) diferido a UDT-008.
  • Enforcement ([RequirePermission]) diferido a UDT-006.

Cambios

  • BD: V005__create_permiso.sql (tabla + seed 18), V006__create_rol_permiso.sql (tabla M:N + seed 36 rows).
  • Domain: Permissions/Permiso.cs (18 const string), Entities/Permiso.cs, PermisoNotFoundException.
  • Application: IPermisoRepository, IRolPermisoRepository, 3 handlers (ListPermisos, GetRolPermisos, AssignPermisosToRol) + validators FluentValidation.
  • Infrastructure: PermisoRepository, RolPermisoRepository con ReplaceForRolAsync en transacción explícita.
  • Api: PermisosController con 3 endpoints [Authorize(Roles="admin")]. ExceptionFilter extendido.
  • Frontend: features/permisos/ con grid checkbox agrupado por módulo, ruta /admin/permisos, link en sidebar.
  • Tests: 257 tests totales (210 Application + 47 Api), TDD RED→GREEN en batches críticos.
  • Doc: 2.4.2 Autorización (RBAC).md actualizado (modelo plano, override diferido, convención admin).

Endpoints

  • GET /api/v1/permisos → 200 PermisoDto[]
  • GET /api/v1/roles/{codigo}/permisos → 200 | 400 (codigo inválido) | 404
  • PUT /api/v1/roles/{codigo}/permisos body { codigos: string[] } → 200 | 400 (admin vacío / codigo inválido) | 404 (rol o permiso inexistente)

Test plan

  • Migraciones V005/V006 aplicadas a SIGCM2_Test (18 permisos, 36 asignaciones)
  • dotnet test SIGCM2.Application.Tests → 220/220
  • dotnet test SIGCM2.Api.Tests → 47/47
  • Verify SDD → PASS (sin CRITICAL, sin WARNING pendiente tras fix W1)
  • Admin explícito con 18 permisos en RolPermiso verificado en BD
  • TablesToIgnore protege seed en todos los fixtures de integración
  • PUT admin con {codigos:[]} → 400
  • PUT idempotente verificado

Follow-ups

Ninguno abierto en esta UDT. Issue #5 (ProtectedRoute granular) reasignado a UDT-006 por decisión D4.

Trazabilidad engram

  • Proposal: sdd/udt-005-gestion-permisos/proposal
  • Spec: sdd/udt-005-gestion-permisos/spec
  • Design: sdd/udt-005-gestion-permisos/design
  • Tasks: sdd/udt-005-gestion-permisos/tasks
  • Apply: sdd/udt-005-gestion-permisos/apply-progress
  • Verify: sdd/udt-005-gestion-permisos/verify-report
  • Convención global: architecture/rbac-admin-convention
## Summary Implementa el modelo RBAC granular de SIG-CM 2.0: catálogo de 18 permisos, asignación M:N `Rol ↔ Permiso`, CRUD admin para editar permisos por rol. Sin enforcement (UDT-006) ni override por usuario (UDT-008). ## Decisiones clave - **Modelo plano** (sin `heredaDe` entre roles, sin wildcard). El rol `admin` tiene los 18 permisos EXPLÍCITOS en `RolPermiso`. - **Convención obligatoria**: cada permiso nuevo (en cualquier UDT futura) DEBE asignarse explícitamente a `admin` en la migración. Registrado en engram como `architecture/rbac-admin-convention`. - **Override por usuario** (`Usuario.PermisosJson`) diferido a UDT-008. - **Enforcement** (`[RequirePermission]`) diferido a UDT-006. ## Cambios - **BD**: `V005__create_permiso.sql` (tabla + seed 18), `V006__create_rol_permiso.sql` (tabla M:N + seed 36 rows). - **Domain**: `Permissions/Permiso.cs` (18 `const string`), `Entities/Permiso.cs`, `PermisoNotFoundException`. - **Application**: `IPermisoRepository`, `IRolPermisoRepository`, 3 handlers (`ListPermisos`, `GetRolPermisos`, `AssignPermisosToRol`) + validators FluentValidation. - **Infrastructure**: `PermisoRepository`, `RolPermisoRepository` con `ReplaceForRolAsync` en transacción explícita. - **Api**: `PermisosController` con 3 endpoints `[Authorize(Roles="admin")]`. `ExceptionFilter` extendido. - **Frontend**: `features/permisos/` con grid checkbox agrupado por módulo, ruta `/admin/permisos`, link en sidebar. - **Tests**: 257 tests totales (210 Application + 47 Api), TDD RED→GREEN en batches críticos. - **Doc**: `2.4.2 Autorización (RBAC).md` actualizado (modelo plano, override diferido, convención admin). ## Endpoints - `GET /api/v1/permisos` → 200 `PermisoDto[]` - `GET /api/v1/roles/{codigo}/permisos` → 200 | 400 (codigo inválido) | 404 - `PUT /api/v1/roles/{codigo}/permisos` body `{ codigos: string[] }` → 200 | 400 (admin vacío / codigo inválido) | 404 (rol o permiso inexistente) ## Test plan - [x] Migraciones V005/V006 aplicadas a `SIGCM2_Test` (18 permisos, 36 asignaciones) - [x] `dotnet test SIGCM2.Application.Tests` → 220/220 ✅ - [x] `dotnet test SIGCM2.Api.Tests` → 47/47 ✅ - [x] Verify SDD → PASS (sin CRITICAL, sin WARNING pendiente tras fix W1) - [x] Admin explícito con 18 permisos en `RolPermiso` verificado en BD - [x] `TablesToIgnore` protege seed en todos los fixtures de integración - [x] PUT admin con `{codigos:[]}` → 400 - [x] PUT idempotente verificado ## Follow-ups Ninguno abierto en esta UDT. Issue #5 (`ProtectedRoute` granular) reasignado a UDT-006 por decisión D4. ## Trazabilidad engram - Proposal: `sdd/udt-005-gestion-permisos/proposal` - Spec: `sdd/udt-005-gestion-permisos/spec` - Design: `sdd/udt-005-gestion-permisos/design` - Tasks: `sdd/udt-005-gestion-permisos/tasks` - Apply: `sdd/udt-005-gestion-permisos/apply-progress` - Verify: `sdd/udt-005-gestion-permisos/verify-report` - Convención global: `architecture/rbac-admin-convention`
dmolinari added 8 commits 2026-04-15 18:58:35 +00:00
- api/types.ts: PermisoDto, AssignPermisosRequest
- api/listPermisos, getRolPermisos, assignPermisos
- hooks: usePermisos, useRolPermisos, useAssignPermisos (TanStack Query)
- components/RolPermisosEditor: checkbox-grid agrupado por modulo (codigo.split(':')[0])
- pages/RolPermisosPage: selector rol activo + guard admin + RolPermisosEditor
- router.tsx: ruta /admin/permisos
- AppSidebar.tsx: link Permisos (KeyRound icon) en seccion admin
- tests: 5 smoke tests RolPermisosEditor (render, prefill, toggle, save, 400)
Agrega GetRolPermisosQueryValidator con regex ^[a-z][a-z0-9_]*$ para
rechazar codigos invalidos con 400 en GET /api/v1/roles/{codigo}/permisos.
dmolinari merged commit 2afac53fca into main 2026-04-15 19:02:03 +00:00
dmolinari deleted branch feature/UDT-005 2026-04-15 19:02:03 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dmolinari/SIG-CM2.0#9