10 KiB
US-MGN-001-002-002: Asignar Permisos CRUD a Roles por Modelo
RF Asociado: RF-MGN-001-002 Módulo: MGN-001 - Fundamentos Epic: Autenticación y Seguridad Prioridad: P0 (MVP) Story Points: 5 Sprint: Sprint 1 Estado: Ready for Development Fecha: 2025-11-24
User Story
Como administrador del sistema, Quiero asignar permisos CRUD (create, read, update, delete) a roles por modelo del sistema, Para controlar granularmente qué acciones puede realizar cada rol sobre cada entidad.
Descripción Detallada
Esta user story implementa la asignación granular de permisos a roles. El sistema debe:
- Listar todos los modelos disponibles (sale.order, account.invoice, etc.)
- Permitir seleccionar un rol y un modelo
- Permitir marcar/desmarcar permisos individuales: create, read, update, delete
- Guardar permisos en auth.permissions (role_id, model_id, can_create, can_read, can_update, can_delete)
- Aplicar cambios inmediatamente (sin logout requerido)
Los modelos se registran automáticamente en auth.models al iniciar el sistema (decorador/metadata).
Criterios de Aceptación
Escenario 1: Asignar permisos completos (CRUD)
Dado que existe un rol "Contador", Cuando asigno permisos CRUD completos sobre modelo "account.invoice", Entonces el sistema crea registro en auth.permissions con can_create=true, can_read=true, can_update=true, can_delete=true.
Escenario 2: Asignar permisos parciales (solo lectura)
Dado que existe un rol "Auditor", Cuando asigno solo permiso de lectura (read) sobre modelo "sale.order", Entonces usuarios con rol Auditor pueden ver órdenes de venta pero no crearlas, editarlas ni eliminarlas.
Escenario 3: Modificar permisos existentes
Dado que un rol "Vendedor" tiene permisos read/create sobre "sale.order", Cuando agrego permiso update, Entonces el sistema actualiza el registro de auth.permissions y los vendedores pueden ahora editar órdenes.
Escenario 4: Revocar todos los permisos de un modelo
Dado que un rol tiene permisos sobre "account.payment", Cuando desmarco todos los checkboxes de permisos, Entonces el sistema elimina el registro de auth.permissions para ese rol+modelo.
Escenario 5: Listar permisos actuales de un rol
Dado que selecciono un rol "Contador", Cuando veo la matriz de permisos, Entonces veo todos los modelos del sistema con checkboxes indicando qué permisos tiene (marcados/desmarcados).
Escenario 6: Herencia de permisos visualizada
Dado que rol "Vendedor Senior" hereda de rol "Vendedor", Cuando veo la matriz de permisos, Entonces veo permisos heredados en gris (read-only) y permisos propios editables.
Reglas de Negocio
- RN-1: Un rol puede tener 0 o más permisos sobre múltiples modelos.
- RN-2: Permisos son granulares: cada CRUD (create, read, update, delete) es independiente.
- RN-3: Permisos heredados del rol padre no pueden editarse en el hijo (solo agregar, no quitar).
- RN-4: Rol Administrator tiene is_admin=true y bypass de validación de permisos.
- RN-5: Cambios de permisos se aplican inmediatamente sin logout.
- RN-6: Modelos se registran automáticamente en auth.models al inicio del sistema.
- RN-7: No se puede asignar permisos sobre modelos inexistentes.
Tareas Técnicas (Checklist de Implementación)
Backend
- Crear endpoint:
POST /api/v1/auth/roles/:roleId/permissions- Asignar permisos - Crear endpoint:
GET /api/v1/auth/roles/:roleId/permissions- Listar permisos del rol - Crear endpoint:
PATCH /api/v1/auth/roles/:roleId/permissions/:modelId- Actualizar permisos - Crear endpoint:
DELETE /api/v1/auth/roles/:roleId/permissions/:modelId- Revocar permisos - Crear endpoint:
GET /api/v1/auth/models- Listar modelos disponibles - Implementar método:
PermissionsService.assignPermissions(roleId, modelId, permissions) - Implementar método:
PermissionsService.getRolePermissions(roleId)con herencia - Implementar método:
PermissionsService.updatePermissions(roleId, modelId, permissions) - Implementar método:
ModelsService.registerModel(modelName, description)(decorador) - Crear DTO:
AssignPermissionsDtocon validaciones - Crear DTO:
PermissionsMatrixDtopara respuesta con matriz completa - Implementar caché de permisos en Redis (invalidar al cambiar)
- Agregar unit tests (10 test cases)
- Agregar integration tests (8 test cases)
- Documentar endpoints en Swagger
- Seed data: registrar modelos del sistema en auth.models
Frontend
- Crear página:
RolePermissionsPage.tsxcon matriz de permisos - Crear componente:
PermissionsMatrix.tsx(tabla modelo x CRUD) - Crear componente:
ModelSelector.tsx(dropdown de modelos) - Implementar checkboxes interactivos para CRUD
- Mostrar permisos heredados en gris (disabled)
- Crear API client:
permissionsApi.assign/get/update/revoke - Implementar búsqueda/filtrado de modelos por nombre/módulo
- Agregar feedback visual al guardar (toast notification)
- Implementar "bulk actions": asignar mismo permiso a múltiples modelos
- Agregar component tests (6 test cases)
- Agregar e2e test: "should assign and revoke permissions"
Database
- Verificar tabla:
auth.permissions(role_id, model_id, can_create, can_read, can_update, can_delete) - Verificar tabla:
auth.models(name, description, module, category) - Crear índice:
idx_permissions_role_model(UNIQUE on role_id + model_id) - Crear índice:
idx_models_name(UNIQUE) - Validar foreign keys: role_id → auth.roles, model_id → auth.models
- Crear seed data: registrar modelos del sistema (sale.order, account.invoice, etc.)
Mockups / Wireframes
Página de Permisos de Rol:
- Header: "Permisos del Rol: [Nombre Rol]"
- Selector: "Seleccione un rol" (dropdown)
- Filtros: búsqueda de modelos, agrupar por módulo (Sales, Accounting, Inventory)
- Matriz de permisos (tabla):
- Columnas: Modelo | Create | Read | Update | Delete
- Filas: un row por modelo (ej: sale.order, account.invoice)
- Checkboxes interactivos (disabled si es permiso heredado)
- Icono de info: tooltip explicando qué hace cada modelo
- Permisos heredados: texto "(Heredado de [Rol Padre])" en gris
- Botón "Guardar Cambios" (sticky al hacer scroll)
- Botón "Restablecer" (descartar cambios)
Estados:
- Loading: Skeleton de tabla con shimmer effect
- Success: Toast "Permisos actualizados correctamente"
- Error: Alert rojo con mensaje de error
Casos de Prueba (Test Scenarios)
Pruebas Funcionales
-
TC-001: Asignar permisos completos
- Input: roleId=Contador, modelId=account.invoice, CRUD all true
- Expected: Registro creado en permissions
-
TC-002: Asignar permisos parciales
- Input: roleId=Auditor, modelId=sale.order, solo read=true
- Expected: can_read=true, resto false
-
TC-003: Actualizar permisos
- Input: agregar update=true a permiso existente
- Expected: Registro actualizado
-
TC-004: Revocar permisos
- Input: desmarcar todos los checkboxes
- Expected: Registro eliminado de permissions
-
TC-005: Herencia de permisos
- Input: Rol hijo con parent_role_id
- Expected: getRolePermissions retorna permisos propios + heredados
-
TC-006: Modelo inexistente
- Input: modelId=99999 (no existe)
- Expected: Error 404 "Model not found"
-
TC-007: Permisos de Administrator
- Input: roleId=Administrator
- Expected: Bypass (no necesita permisos explícitos)
-
TC-008: Caché de permisos
- Input: actualizar permisos de rol
- Expected: Caché invalidado, próxima request trae permisos actualizados
Pruebas No Funcionales
- Performance:
- Lista de 50 modelos x 10 roles en < 300ms
- Validación de permisos en middleware < 10ms (usando caché)
- Usabilidad:
- Checkboxes responden < 100ms
- Búsqueda de modelos en tiempo real
- Seguridad:
- Solo usuarios con 'auth.permissions.manage' pueden acceder
Dependencias
- User Stories bloqueantes:
- US-MGN-001-002-001 (Crear y Gestionar Roles)
- Módulos requeridos: Sistema de modelos registrado
- Datos maestros necesarios: Modelos del sistema registrados en auth.models
Notas de Implementación
- Implementar decorador
@RegisterModel('sale.order', 'Sales Order')en entidades - En startup, escanear entidades decoradas y registrar en auth.models
- Caché de permisos en Redis:
- Key:
permissions:user:{userId} - Value: JSON con permisos resueltos (incluyendo herencia)
- TTL: 1 hora
- Key:
- Invalidar caché al actualizar permisos de un rol
- Middleware de permisos:
@UseGuards(PermissionsGuard) @RequirePermission('sale.order.create') async createOrder() {}
Estimación Detallada
| Tarea | Estimación |
|---|---|
| Backend Development | 3 horas |
| Frontend Development | 4 horas |
| Testing (Unit + Integration + E2E) | 2 horas |
| Code Review | 1 hora |
| TOTAL | 10 horas |
Equivalente: 5 Story Points
Definition of Done (DoD)
- Código backend implementado según ET-BACKEND-MGN-001-002
- Código frontend implementado según ET-FRONTEND-MGN-001-002
- Unit tests escritos y pasando (cobertura > 80%)
- Integration tests escritos y pasando
- E2E test "should assign and revoke permissions" pasando
- Code review completado y aprobado
- Documentación Swagger actualizada
- Caché de permisos implementado y testeado
- Seed data de modelos creado
- Merge a branch
developcompletado - QA manual completado