Skip to content

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.

CapacidadSUPERADMINADMINSUPERVISOR
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 (requireRole por ruta). SUPERADMIN hace bypass en requireRole. Tras este cambio, todas las rutas operativas admiten ADMIN y SUPERVISOR; solo Usuarios y Plantillas quedan para ADMIN.
  • La UI (frontend/src/auth/role-permissions.ts) refleja la misma matriz: el SUPERVISOR recibe todos los permisos operativos (VIGILANTES_*, SEDES_*, EDIFICIOS_*, AULAS_*, TRIBUNAL_MIEMBROS_*, CONVOCATORIAS_*, EJERCICIOS_*, ASIGNACIONES_READ, CONFIGURACION_READ) y no recibe TEMPLATES_* ni USERS_*.
  • Configuración reservada a ADMIN (CLAVES_CONFIGURACION_SOLO_ADMIN en backend/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_default y url_pagina_ayuda. configuracion.controller responde 403 si un SUPERVISOR intenta modificarlas, y ConfiguracionPage deshabilita su edición.

Al cambiar permisos hay que alinear tres sitios: roles de las rutas backend, role-permissions.ts y las comprobaciones de la UI.

2. Correcciones del flujo de ejercicios

2.1 Asignación rápida (simulation.service.ts)

  • applySimulation ahora valida el destino (pertenece al ejercicio), la capacidad (ratio/fijo en aulas; vigilantes_manual en 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.update y remove rechazan la operación si la convocatoria está CERRADA (antes solo lo hacía create y la reapertura). La UI ya mostraba el aviso de "solo lectura"; ahora el backend lo impone.

2.3 Notificación activa y asignaciones anuladas

  • getAsignacionesConNotificacionActiva ya 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 con bloqueado=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 citacion en NotificacionTipo. notificacionService.create guarda las citaciones como citacion (antes usaban el valor heredado llamamiento); la numeración considera ambos. La columna notificaciones.tipo se crea directamente con default 'citacion' (CreateTables y notificacion.entity), por lo que no se necesita migración de reclasificación: llamamiento sigue siendo un valor válido para los registros históricos.

2.6 Otros

  • created_by de las notificaciones ya se rellena con el usuario autenticado (req.currentUser).
  • Corregido el parámetro de DELETE /ejercicios/:ejercicioId/sedes/:id y .../aulas/:id (leían un req.params inexistente).
  • El componente ConfirmarExportacionLlamamientoDialog declara la prop modalId (elimina el Vue 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.create ya la comprobaba con getAsignacionActiva.
  • asignacion.service.autoAsignar ahora excluye del reparto a los vigilantes que ya tienen una asignación activa en el ejercicio (rellena solo huecos; con reasignar=true se borran antes).
  • asignacion.service.restaurarAsistencia ahora 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.applySimulation ya validaba duplicados del payload y la reactivación de anuladas.
  • La semilla InsertTestExpediente ya 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 compartido frontend/src/utils/asignacion.ts para calcular los vigilantes disponibles, excluyendo asignados, anulados y bloqueados.

3. Pruebas

  • Backend: src/__tests__/fixes-regresion.test.ts y src/__tests__/simulation-capacidad.test.ts cubren el bloqueo de vigilantes, la lista de claves reservadas y la validación de capacidad.
  • Backend: src/__tests__/asignacion.service.test.ts cubre la invariante en create, restaurarAsistencia y autoAsignar; src/__tests__/seed-asignaciones-integridad.test.ts valida que la semilla no duplica asignaciones activas por ejercicio.
  • Frontend: src/utils/__tests__/asignacion.test.ts y src/stores/__tests__/ejercicioStore.test.ts cubren la disponibilidad de vigilantes y el rechazo al restaurar.
  • E2E (Playwright, carpeta e2e/): tests/asignaciones-invariante.spec.ts comprueba 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.ts abre el modal de asignaciones del ejercicio semilla.
  • Frontend: src/auth/__tests__/role-permissions.test.ts refleja la nueva matriz del SUPERVISOR.

SIVA — Sistema Integral de Vigilantes de Aulas