Appearance
Roles, permisos y correcciones recientes del flujo de ejercicios
Documento de apoyo que consolida, en un solo sitio, el modelo de roles/permisos vigente y las correcciones aplicadas al flujo de ejercicios (ubicaciones, vigilantes/llamamiento, asignaciones, notificación y asistencia).
Última revisión: 2026-09-20.
1. Roles y permisos
Roles reales (backend/src/enums/user-role.enum.ts): SUPERADMIN, ADMIN, SUPERVISOR.
| Capacidad | SUPERADMIN | ADMIN | SUPERVISOR |
|---|---|---|---|
Acceso total ("*" en frontend) | ✅ | ✅ | — |
| Catálogos: Sedes / Edificios / Aulas / Plantas / Vigilantes / Etiquetas | ✅ | ✅ | ✅ (CRUD) |
| Tribunal, Convocatorias, Ejercicios (CRUD y cambio de estado) | ✅ | ✅ | ✅ |
| Ubicaciones, Selección de vigilantes, Llamamiento, Confirmación | ✅ | ✅ | ✅ |
| Asignaciones y Asignación rápida | ✅ | ✅ | ✅ |
| Notificación y Asistencia (incluida anulación) | ✅ | ✅ | ✅ |
| Configuración (consulta y edición habitual) | ✅ | ✅ | ✅ |
| Configuración: claves reservadas a ADMIN | ✅ | ✅ | ❌ |
Plantillas (templates:*) | ✅ | ✅ | ❌ |
Usuarios (users:*) | ✅ | ✅ | ❌ |
- La autorización real vive en el backend (
requireRolepor ruta).SUPERADMINhace bypass enrequireRole. Tras este cambio, todas las rutas operativas admitenADMINySUPERVISOR; solo Usuarios y Plantillas quedan paraADMIN. - La UI (
frontend/src/auth/role-permissions.ts) refleja la misma matriz: elSUPERVISORrecibe todos los permisos operativos (VIGILANTES_*,SEDES_*,EDIFICIOS_*,AULAS_*,TRIBUNAL_MIEMBROS_*,CONVOCATORIAS_*,EJERCICIOS_*,ASIGNACIONES_READ,CONFIGURACION_READ) y no recibeTEMPLATES_*niUSERS_*. - Configuración reservada a ADMIN (
CLAVES_CONFIGURACION_SOLO_ADMINenbackend/src/services/configuracion.service.ts):colores_miembros_tribunal,colores_roles_usuarios,envio_correos_vigilantes,etiqueta_colores_predefinidos,export_field_labels,penalizacion_duracion_dias,penalizacion_habilitada,modo_asignacion_aulas_defaultyurl_pagina_ayuda.configuracion.controllerresponde403si unSUPERVISORintenta modificarlas, yConfiguracionPagedeshabilita su edición.
Al cambiar permisos hay que alinear tres sitios: roles de las rutas backend,
role-permissions.tsy las comprobaciones de la UI.
2. Correcciones del flujo de ejercicios
2.1 Asignación rápida (simulation.service.ts)
applySimulationahora valida el destino (pertenece al ejercicio), la capacidad (ratio/fijo en aulas;vigilantes_manualen edificios manuales) y que el vigilante no esté bloqueado ni penalizado. Antes podía sobreasignar un aula o crear asignaciones a ubicaciones de otro ejercicio por API.- Al reactivar una asignación anulada se comprueba antes que el vigilante no tenga ya otra asignación activa, evitando dos asignaciones activas simultáneas.
2.2 Convocatoria cerrada = solo lectura efectiva
ejercicio.service.updateyremoverechazan la operación si la convocatoria estáCERRADA(antes solo lo hacíacreatey la reapertura). La UI ya mostraba el aviso de "solo lectura"; ahora el backend lo impone.
2.3 Notificación activa y asignaciones anuladas
getAsignacionesConNotificacionActivaya no ignora las asignaciones anuladas: una notificación activa protege siempre su asignación, evitando que se borre y deje la notificación huérfana (asignacion_id = NULL).- Las asignaciones anuladas sin notificación activa dejan de bloquear quitar su sede/edificio/aula (
validarUbicaciones,removeSede,removeAula) o al vigilante del ejercicio (removeVigilante). - La pestaña Asistencia incluye ahora las asignaciones anuladas y ofrece un botón Eliminar (habilitado solo sin notificación activa). Flujo resultante: anular asistencia → anular notificación (si la hubiera) → eliminar asignación → quitar la ubicación.
2.4 Bloqueo de vigilantes
vigilante.service.toggleBloqueado(y la edición conbloqueado=true) impide bloquear a un vigilante con asignaciones activas o notificaciones activas. Debe resolverse primero (anular/eliminar la asignación o anular la notificación).
2.5 Tipo de notificación
- Nuevo valor
citacionenNotificacionTipo.notificacionService.createguarda las citaciones comocitacion(antes usaban el valor heredadollamamiento); la numeración considera ambos. La columnanotificaciones.tipose crea directamente condefault 'citacion'(CreateTablesynotificacion.entity), por lo que no se necesita migración de reclasificación:llamamientosigue siendo un valor válido para los registros históricos.
2.6 Otros
created_byde las notificaciones ya se rellena con el usuario autenticado (req.currentUser).- Corregido el parámetro de
DELETE /ejercicios/:ejercicioId/sedes/:idy.../aulas/:id(leían unreq.paramsinexistente). - El componente
ConfirmarExportacionLlamamientoDialogdeclara la propmodalId(elimina elVue warn).
2.7 Un vigilante, una sola ubicación activa por ejercicio
Un vigilante no puede estar asignado a dos aulas/edificios a la vez dentro del mismo ejercicio. La invariante se garantiza en la capa de servicio (no en BD) y se aplica en todos los caminos:
asignacion.service.createya la comprobaba congetAsignacionActiva.asignacion.service.autoAsignarahora excluye del reparto a los vigilantes que ya tienen una asignación activa en el ejercicio (rellena solo huecos; conreasignar=truese borran antes).asignacion.service.restaurarAsistenciaahora rechaza reactivar una asignación anulada si el vigilante ya tiene otra activa en el ejercicio (409). Antes podía quedar activo en dos destinos a la vez.simulation.service.applySimulationya validaba duplicados del payload y la reactivación de anuladas.- La semilla
InsertTestExpedienteya no crea dos asignaciones activas del mismo ejercicio para el vigilante de prueba (cada ejercicio tiene una activa y una anulada). - El frontend (
GestionarAsignacionesModal) usa el util compartidofrontend/src/utils/asignacion.tspara calcular los vigilantes disponibles, excluyendo asignados, anulados y bloqueados.
3. Pruebas
- Backend:
src/__tests__/fixes-regresion.test.tsysrc/__tests__/simulation-capacidad.test.tscubren el bloqueo de vigilantes, la lista de claves reservadas y la validación de capacidad. - Backend:
src/__tests__/asignacion.service.test.tscubre la invariante encreate,restaurarAsistenciayautoAsignar;src/__tests__/seed-asignaciones-integridad.test.tsvalida que la semilla no duplica asignaciones activas por ejercicio. - Frontend:
src/utils/__tests__/asignacion.test.tsysrc/stores/__tests__/ejercicioStore.test.tscubren la disponibilidad de vigilantes y el rechazo al restaurar. - E2E (Playwright, carpeta
e2e/):tests/asignaciones-invariante.spec.tscomprueba contra la app real que ningún ejercicio duplica vigilantes activos y que no se puede restaurar una asistencia con otra activa;tests/asignaciones-ui.spec.tsabre el modal de asignaciones del ejercicio semilla. - Frontend:
src/auth/__tests__/role-permissions.test.tsrefleja la nueva matriz delSUPERVISOR.