UDT-004: Gestión de Roles (tabla maestra + CRUD admin + validator dinámico + UI) #8
Reference in New Issue
Block a user
Delete Branch "feature/UDT-004"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
dbo.Rolcon 8 roles canónicos del RBAC doc (§2.4.2) + FKUsuario.Rol → Rol.Codigoreemplazando el CHECK constraint hardcodeado./api/v1/roles(list / get / create / update / soft-delete con guard 409 por usuarios activos).CreateUsuarioCommandValidatorde whitelist hardcoded a lookup async víaIRolRepository.ExistsActiveByCodigoAsync./admin/roles(list + create + edit + deactivate) yUserFormmigrado a dropdown dinámico con loading/error states.Capabilities
role-management— 6 requirements, 13 scenarios (todos compliant).user-registration— Request Validation ahora consulta la tabla Rol en tiempo real (5 scenarios cubiertos).Tests
SIGCM2.Application.TestsSIGCM2.Api.Testsvitest(8 files)dotnet buildtsc -bMigraciones aplicadas
V003__create_rol.sql— creadbo.Rol+ CK formato codigo + MERGE idempotente con 8 seeds (admin,cajero,operador_ctacte,picadora,jefe_publicidad,productor,diagramacion,reportes).V004__alter_usuario_rol_fk.sql— DROPCK_Usuario_Rol+ ADDFK_Usuario_Rol.SIGCM2ySIGCM2_Test.UPDATE Usuario SET Rol='cajero' WHERE Username='dmolinari'(mapeo canónico del legacy placeholdervendedor).Decisiones arquitecturales
Codigocomo FK vs surrogateRolId INT— mantiene JWT claim string,[Authorize(Roles=...)]nativo, contrato HTTP legible.SELECT 1 FROM Rol WHERE Codigo=@c AND Activo=1.HasActiveUsuariosAsyncbloquea desactivación si hay usuarios referenciando.[Authorize(Roles="admin")]nativo — paridad conUsuariosController;RequirePermissiongranular llega en UDT-006.Infra testing (deviations documentadas)
IClassFixture<TestWebAppFactory>→ICollectionFixture<TestWebAppFactory>(shared factory) — resuelveObjectDisposedException: RSABCryptcross-class.tests/tests.runsettingsconMaxCpuCount=1— evita race entre assemblies sobreSIGCM2_Test.SeedRolCanonicalAsyncpost-Respawn en 4 fixtures — RespawnTablesToIgnoreno respetado en 6.2.1.Test plan
/admin/roles— ver los 8 seeds con badges Activo/Inactivo.cajero_senior) — validar regex codigo^[a-z][a-z0-9_]*$.admin→ 409 (tiene el usuario admin asociado)./usuarios/nuevo— confirmar que el dropdown de Rol se puebla async con los activos y NO incluye inactivos.errors.Rol.Out of Scope (diferidos)
RolPermisos→ UDT-005.RequirePermissionmiddleware → UDT-006.heredaDe) → UDT-005.Artifacts SDD (engram)
Audit trail completo en engram (topic_keys):
sdd/udt-004-gestion-roles/{explore,proposal,spec,design,tasks,apply-progress,verify-report,archive-report}- RolesController /api/v1/roles CRUD admin-only: GET list, GET {codigo}, POST, PUT, DELETE (soft-delete con guard 409) - ExceptionFilter: mapea RolNotFound (404), RolAlreadyExists (409), RolInUse (409) - DI: registra 5 handlers de Roles (Application) y IRolRepository/RolRepository (Infrastructure) - CreateUsuarioCommandValidator: reemplaza whitelist hardcoded por IRolRepository.ExistsActiveByCodigoAsync via MustAsync; constructor recibe (AuthOptions, IRolRepository) - Tests: 202 verdes (173 application + 29 api). Nuevas: RolesEndpointTests (13 integration), CreateUsuarioCommandValidatorTests reescrito con NSubstitute mock, CreateUsuario_WithInactiveRol_Returns400 en Api.Tests - Fix: ApiIntegration pasa de IClassFixture (N factories) a ICollectionFixture (1 factory shared) — evitaba ObjectDisposedException sobre RSABCrypt al compartir coleccion con multiples test classes - tests/tests.runsettings: MaxCpuCount=1 para evitar race entre assemblies sobre SIGCM2_Test