Appearance
Modelo de datos
SIVA persiste en SQLite (driver sql.js) mediante TypeORM. Las 31 entidades se declaran en backend/src/entities/ y el esquema se crea con la migración 1718300001000-CreateTables.ts (synchronize:false, migrationsRun:true). Los valores booleanos se almacenan como 0/1 y las fechas como date/datetime de SQLite.
⚠️ Nota: algunas restricciones (uniques compuestos,
CHECK,ON DELETE) existen solo en la migración y no están decoradas en las entidades. Se indican en cada tabla.
Diagrama Entidad-Relación
Entidades
Usuarios
User → tabla users
| Campo (TS) | Columna | Tipo | Nulo | Default | Constraints |
|---|---|---|---|---|---|
id | id | uuid | No | generado | PK |
name | name | varchar(100) | No | — | — |
email | email | varchar(255) | No | — | unique |
password | password | varchar | No | — | oculto (select:false) |
role | role | text | No | SUPERVISOR | — |
is_active | is_active | boolean | No | true | — |
is_email_verified | is_email_verified | boolean | No | false | — |
email_verification_token | email_verification_token | varchar(255) | Sí | — | select:false |
refresh_token | refresh_token | text | Sí | — | select:false |
password_reset_token | password_reset_token | varchar(255) | Sí | — | select:false |
password_reset_expires | password_reset_expires | datetime | Sí | — | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP | — |
searchNormalized | search_normalized | text | Sí | — | índice de búsqueda |
profile | — | 1:1 | Sí | — | cascade, eager |
UserProfile → tabla user_profiles
| Campo | Columna | Tipo | Nulo | Constraints |
|---|---|---|---|---|
id | id | uuid | No | PK |
avatar_key | avatar_key | varchar(512) | Sí | — |
dni | dni | varchar(9) | Sí | — |
phone | phone | varchar(12) | Sí | — |
company | company | varchar(255) | Sí | — |
notes | notes | text | Sí | — |
user | user_id | uuid | No | unique (UQ_user_profiles_user_id), FK ON DELETE CASCADE |
Catálogos
Vigilante → tabla vigilantes
| Campo | Columna | Tipo | Nulo | Default | Constraints |
|---|---|---|---|---|---|
id | id | uuid | No | generado | PK |
dni | dni | varchar(9) | No | — | unique (UQ_vigilantes_dni) |
nombre | nombre | varchar(100) | No | — | — |
primer_apellido | primer_apellido | varchar(100) | No | — | — |
segundo_apellido | segundo_apellido | varchar(100) | No | — | (vacío si no se informa) |
correo_electronico_corporativo | idem | varchar(255) | Sí | — | — |
correo_electronico_personal | idem | varchar(255) | Sí | — | — |
telefono | telefono | varchar(20) | Sí | — | — |
bloqueado | bloqueado | boolean | No | false | — |
motivo_bloqueo / fecha_bloqueo | idem | text/datetime | Sí | — | — |
motivo_desbloqueo / fecha_desbloqueo | idem | text/datetime | Sí | — | — |
comentarios | comentarios | text | Sí | — | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP | — |
searchNormalized | search_normalized | text | Sí | — | — |
Relaciones: N:M tags (vigilante_tags), 1:N vigilanteEjercicios, 1:N asignaciones.
Tag → tabla tags
| Campo | Columna | Tipo | Nulo | Default | Constraints |
|---|---|---|---|---|---|
id | id | uuid | No | generado | PK |
nombre | nombre | varchar(100) | No | — | — |
system_key | system_key | varchar(20) | Sí | — | unique (UQ_tags_system_key) |
color | color | varchar(9) | No | #6c757d | — |
scope | scope | varchar(20) | No | general | — |
created_at | created_at | datetime | No | CURRENT_TIMESTAMP | — |
TipoEjercicio → tabla tipos_ejercicio
| Campo | Columna | Tipo | Nulo | Constraints |
|---|---|---|---|---|
id | id | uuid | No | PK |
nombre | nombre | varchar(100) | No | unique |
created_at | created_at | datetime | No | — |
Ubicaciones: Sede → Edificio → Planta → Aula
Sede → tabla sedes
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
nombre | nombre | varchar(150) | No | — |
direccion | direccion | varchar(255) | No | — |
municipio | municipio | varchar(100) | Sí | — |
codigoPostal | codigo_postal | varchar(10) | Sí | — |
provincia | provincia | varchar(100) | Sí | — |
responsable | responsable | varchar(150) | Sí | — |
telefono | telefono | varchar(20) | Sí | — |
correoContacto | correo_contacto | varchar(255) | Sí | — |
isActive | is_active | boolean | No | true |
observaciones / comollegar | observaciones / como_llegar | text | Sí | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Relaciones: 1:N edificios, 1:N ejercicioSedes.
Edificio → tabla edificios
| Campo | Columna | Tipo | Nulo | Default | Índice |
|---|---|---|---|---|---|
id | id | uuid | No | PK | — |
nombre | nombre | varchar(100) | No | — | — |
sede_id | sede_id | uuid | No | — | IDX_edificios_sede_id |
direccion | direccion | varchar(255) | Sí | — | — |
estado | estado | varchar(20) | No | activo | — |
observaciones | observaciones | text | Sí | — | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP | — |
Relaciones: N:1 sede, 1:N aulas.
Planta → tabla plantas
| Campo | Columna | Tipo | Nulo | Default | Constraints |
|---|---|---|---|---|---|
id | id | uuid | No | PK | — |
nombre | nombre | varchar(50) | No | — | unique |
orden | orden | integer | No | 0 | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP | — |
Relaciones: 1:N edificioPlantas, 1:N aulas.
EdificioPlanta → tabla edificio_plantas (puente N:M)
| Campo | Columna | Tipo | Nulo | FK |
|---|---|---|---|---|
id | id | uuid | No | PK |
edificio | edificio_id | uuid | No | ON DELETE CASCADE |
planta | planta_id | uuid | No | ON DELETE CASCADE |
⚠️ No tiene unique compuesto: se permiten pares repetidos.
Aula → tabla aulas
| Campo | Columna | Tipo | Nulo | Default | Índice |
|---|---|---|---|---|---|
id | id | uuid | No | PK | — |
nombre | nombre | varchar(100) | No | — | — |
planta_id | planta_id | uuid | Sí | — | FK ON DELETE SET NULL |
capacidad | capacidad | integer | No | — | — |
tipo | tipo | varchar(20) | No | general | — |
equipamiento | equipamiento | text | Sí | — | — |
estado | estado | varchar(20) | No | disponible | — |
observaciones | observaciones | text | Sí | — | — |
edificio_id | edificio_id | uuid | No | — | IDX_aulas_edificio_id |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP | — |
Relaciones: N:1 planta, N:1 edificio, N:M tags (aula_tags), 1:N ejercicioSedeAulas.
Convocatoria y ejercicio
Convocatoria → tabla convocatorias
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
nombre | nombre | varchar(200) | No | — |
anio | anio | integer | No | 2025 |
observaciones | observaciones | text | Sí | — |
estado | estado | text | No | ABIERTA |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Relaciones: 1:N ejercicios, 1:N miembros.
TribunalMiembro → tabla tribunal_miembros
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
convocatoria_id | idem | uuid | No | — |
tipo | tipo | text | No | TITULAR |
nombre | nombre | varchar(200) | No | — |
cargo | cargo | text | No | VOCAL |
correo_electronico | idem | varchar(255) | Sí | — |
telefono | telefono | varchar(20) | Sí | — |
renuncia | renuncia | boolean | No | false |
motivo_renuncia / fecha_renuncia | idem | text/datetime | Sí | — |
motivo_reincorporacion / fecha_reincorporacion | idem | text/datetime | Sí | — |
comentarios | comentarios | text | Sí | — |
searchNormalized | search_normalized | text | Sí | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Relación: N:1 convocatoria.
Ejercicio → tabla ejercicios
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
nombre | nombre | varchar(200) | No | — |
fecha | fecha | date | Sí | — |
hora_vigilantes_aula_tribunal | idem | text | Sí | — |
hora_comienzo_ejercicio | idem | text | Sí | — |
duracion_acceso_libre | idem | integer | Sí | — |
duracion_promocion_interna | idem | integer | Sí | — |
observaciones | observaciones | text | Sí | — |
tipo | tipo | text | No | — |
convocatoria_id | idem | uuid | No | — |
estado | estado | text | No | ABIERTA |
fecha_cierre | idem | datetime | Sí | — |
cerrado_por | idem | uuid | Sí | — (sin FK) |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Relaciones: N:1 convocatoria, 1:N ejercicioSedes, 1:N vigilanteEjercicios, 1:N llamamientos.
EjercicioGrupo → tabla ejercicio_grupos
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
ejercicio_id | idem | uuid | No | FK ON DELETE CASCADE |
nombre | nombre | varchar(200) | No | — |
orden | orden | integer | No | 0 |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
VigilanteEjercicio → tabla vigilante_ejercicios (puente N:M con datos)
| Campo | Columna | Tipo | Nulo | Constraints |
|---|---|---|---|---|
id | id | uuid | No | PK |
vigilante_id | idem | uuid | No | IDX_vigilante_ejercicios_vigilante_id |
ejercicio_id | idem | uuid | No | IDX_vigilante_ejercicios_ejercicio_id |
grupo_id | idem | uuid | Sí | FK ON DELETE SET NULL |
orden | orden | integer | Sí | — |
fecha_seleccion | idem | datetime | No | — |
created_at/updated_at | idem | datetime | No | — |
Constraints: unique (vigilante_id, ejercicio_id).
EjercicioSede → tabla ejercicio_sedes
| Campo | Columna | Tipo | Nulo |
|---|---|---|---|
id | id | uuid | No |
ejercicio_id | idem | uuid | No |
sede_id | idem | uuid | No |
Constraints: unique (ejercicio_id, sede_id). Relación 1:N ejercicioSedeEdificios.
EjercicioSedeEdificio → tabla ejercicio_sede_edificios
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
ejercicio_sede_id | idem | uuid | No | FK ON DELETE CASCADE |
edificio_id | idem | uuid | No | — |
modo | modo | varchar(20) | No | calcular_aulas |
vigilantes_manual | idem | integer | Sí | — |
Constraints: unique (ejercicio_sede_id, edificio_id).
EjercicioSedeAula → tabla ejercicio_sede_aulas
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
ejercicio_sede_edificio_id | idem | uuid | No | FK ON DELETE CASCADE |
aula_id | aula_id | uuid | No | — |
modo_asignacion | idem | text | No | ratio |
ratio_denominador | idem | integer | Sí | — |
vigilantes_fijos | idem | integer | Sí | — |
Constraints: unique (ejercicio_sede_edificio_id, aula_id).
Llamamientos
Llamamiento → tabla llamamientos
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
ejercicio_id | idem | uuid | No | FK ON DELETE CASCADE |
numero | numero | integer | No | — |
fecha_exportacion | idem | datetime | No | — |
fecha_limite_respuesta | idem | datetime | Sí | — |
estado | estado | text | No | activo |
fecha_anulacion / motivo_anulacion | idem | datetime/text | Sí | — |
created_by | idem | uuid | Sí | FK ON DELETE SET NULL |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Constraints: unique (ejercicio_id, numero) (solo en migración).
VigilanteLlamamiento → tabla vigilante_llamamientos (puente N:M con datos)
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
llamamiento_id | idem | uuid | No | FK ON DELETE CASCADE |
vigilante_id | idem | uuid | No | IDX_vigilante_llamamientos_vigilante_id |
grupo_nombre | idem | text | Sí | — |
fecha_envio | idem | datetime | No | — |
estado_respuesta | idem | text | No | pendiente |
sede_id | sede_id | uuid | Sí | FK ON DELETE SET NULL |
fecha_respuesta | idem | datetime | Sí | — |
origen_confirmacion | idem | text | Sí | — |
correo_enviado | idem | boolean | No | false |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Constraints: unique (llamamiento_id, vigilante_id).
Asignaciones
Asignacion → tabla asignaciones
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
ejercicio_sede_aula_id | idem | uuid | Sí | FK ON DELETE CASCADE |
ejercicio_sede_edificio_id | idem | uuid | Sí | FK ON DELETE CASCADE |
vigilante_id | idem | uuid | No | IDX_asignaciones_vigilante_id |
es_responsable_aula | idem | boolean | No | false |
estado_asistencia | idem | text | No | pendiente |
anulado | anulado | boolean | No | false |
motivo_anulacion | idem | text | Sí | — |
fecha_anulacion_asistencia | idem | datetime | Sí | — |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Constraints:
- unique
(ejercicio_sede_aula_id, vigilante_id). - unique
(ejercicio_sede_edificio_id, vigilante_id). - CHECK
CHK_asignaciones_destino: exactamente uno de los dos destinos no nulo. - CHECK
CHK_asignaciones_estado_asistencia:pendiente | asistio | no_asistio.
Notificaciones y documentos
Notificacion → tabla notificaciones
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
ejercicio_id | idem | uuid | No | FK ON DELETE CASCADE |
numero | numero | integer | No | — |
tipo | tipo | text | No | llamamiento |
asunto | asunto | text | No | — |
cuerpo | cuerpo | text | No | — |
fecha_envio | idem | datetime | No | — |
estado | estado | text | No | activo |
fecha_anulacion / motivo_anulacion | idem | datetime/text | Sí | — |
created_by | idem | uuid | Sí | FK ON DELETE SET NULL |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Constraints: unique (ejercicio_id, tipo, numero) (solo en migración). Relaciones 1:N notificacionVigilantes, 1:N documentos.
NotificacionVigilante → tabla notificacion_vigilantes
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
notificacion_id | idem | uuid | No | FK ON DELETE CASCADE |
vigilante_id | idem | uuid | No | IDX_notificacion_vigilantes_vigilante_id |
asignacion_id | idem | uuid | Sí | FK ON DELETE SET NULL |
fecha_envio | idem | datetime | No | — |
snapshot | snapshot | text | Sí | — |
correo_enviado | idem | boolean | No | false |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Constraints: unique (notificacion_id, vigilante_id).
NotificacionDocumento → tabla notificacion_documentos
| Campo | Columna | Tipo | Nulo |
|---|---|---|---|
id | id | uuid | No |
notificacion_id | idem | uuid | No (FK ON DELETE CASCADE) |
nombre_original | idem | text | No |
nombre_almacenado | idem | text | No |
mime_type | idem | text | No |
tamaño | tamano | integer | No |
created_at | created_at | datetime | No |
EjercicioDocumento → tabla ejercicio_documentos
Misma estructura que NotificacionDocumento, con ejercicio_id en lugar de notificacion_id (FK ON DELETE CASCADE).
Penalizaciones
Penalizacion → tabla penalizaciones
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
vigilante_id | idem | uuid | No | IDX_penalizaciones_vigilante_id |
asignacion_id | idem | uuid | Sí | FK ON DELETE SET NULL |
ejercicio_id | idem | uuid | Sí | FK ON DELETE SET NULL |
motivo | motivo | text | Sí | — |
duracion_dias | idem | integer | No | — |
fecha_inicio | idem | datetime | No | — |
fecha_fin | idem | datetime | No | — |
estado | estado | text | No | activa |
fecha_levantada / motivo_levantamiento | idem | datetime/text | Sí | — |
created_by | idem | uuid | Sí | FK ON DELETE SET NULL (solo migración) |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
Plantillas y configuración
EmailTemplate → tabla email_templates
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
nombre | nombre | varchar(150) | No | — |
description | description | text | Sí | — |
tipo | tipo | text | No | — |
asunto | asunto | varchar(300) | No | — |
cuerpo | cuerpo | text | No | — |
is_active | is_active | boolean | No | false |
is_system | is_system | boolean | No | false |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
La migración añade
search_normalized, no declarada en la entidad.
DocumentTemplate → tabla document_templates
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
nombre | nombre | varchar(150) | No | — |
descripcion | idem | text | Sí | — |
tipo | tipo | text | No | — |
html | html | text | Sí | — |
is_active | is_active | boolean | No | false |
is_system | is_system | boolean | No | false |
created_at/updated_at | idem | datetime | No | CURRENT_TIMESTAMP |
ParametroSistema → tabla parametros_sistema
| Campo | Columna | Tipo | Nulo | Constraints |
|---|---|---|---|---|
id | id | uuid | No | PK |
clave | clave | varchar(100) | No | unique |
valor | valor | text | No | — |
descripcion | descripcion | text | Sí | — |
created_at/updated_at | idem | datetime | No | — |
Importación masiva
ImportBatch → tabla import_batches
| Campo | Columna | Tipo | Nulo | Default |
|---|---|---|---|---|
id | id | uuid | No | PK |
user_id | user_id | uuid | No | FK ON DELETE CASCADE |
archivo_nombre | idem | varchar(255) | Sí | — |
etiquetas_aplicadas | idem | text | Sí | — |
total_nuevos | idem | integer | No | 0 |
total_actualizados | idem | integer | No | 0 |
total_solo_etiqueta | idem | integer | No | 0 |
total_sin_cambios | idem | integer | No | 0 |
total_omitidos | idem | integer | No | 0 |
total_errores | idem | integer | No | 0 |
created_at | created_at | datetime | No | CURRENT_TIMESTAMP |
ImportBatchRow → tabla import_batch_rows
| Campo | Columna | Tipo | Nulo | Índice |
|---|---|---|---|---|
id | id | uuid | No | PK |
import_batch_id | idem | uuid | No | IDX_import_batch_rows_import_batch_id, FK ON DELETE CASCADE |
dni | dni | varchar(20) | Sí | — |
resultado | resultado | varchar(20) | No | — |
detalle | detalle | text | Sí | — |
created_at | created_at | datetime | No | — |
Enumerados
| Enum | Valores |
|---|---|
UserRole | SUPERADMIN, ADMIN, SUPERVISOR |
ConvocatoriaEstado | ABIERTA, CERRADA |
EjercicioEstado | ABIERTA, CERRADA |
EstadoAsistencia | pendiente, asistio, no_asistio |
LlamamientoEstado | activo, anulado, cerrado |
RespuestaEstado | pendiente, confirmado, rechazado, sin_respuesta |
OrigenConfirmacion | manual, excel |
NotificacionEstado | activo, anulado |
NotificacionTipo | citacion, llamamiento, anulacion, restauracion |
PenalizacionEstado | activa, finalizada, levantada |
EmailTemplateTipo | PASSWORD_RESET, VERIFICATION_EMAIL, CONVOCATORIA_LLAMAMIENTO, NOTIFICACION_ASIGNACION, NOTIFICACION_REASIGNACION, NOTIFICACION_CANCELACION, ANULACION_ASISTENCIA, NOTIFICACION_RESTAURACION |
DocumentTemplateTipo | CONTROL_ASISTENCIA |
TribunalTipo | TITULAR, SUPLENTE |
TribunalMiembroCargo | PRESIDENTE, VOCAL, SECRETARIO |
EjercicioSedeEdificio.modo | calcular_aulas, manual |
EjercicioSedeAula.modo_asignacion | ratio, fijo |
Índices y constraints destacados
users.emailúnico;users.search_normalizedpara búsquedas sin acentos.vigilantes.dniúnico.user_profiles.user_idúnico (1:1 conusers).tags.system_keyúnico.plantas.nombreúnico;tipos_ejercicio.nombreúnico;parametros_sistema.claveúnico.- Claves foráneas con
ON DELETE CASCADE:user_profiles,ejercicio_grupos,ejercicio_sede_edificios,ejercicio_sede_aulas,asignaciones(ambos destinos),llamamientos,vigilante_llamamientos,notificaciones,notificacion_vigilantes,notificacion_documentos,ejercicio_documentos,import_batches,import_batch_rows,edificio_plantasy los puentesvigilante_tags/aula_tags(lado etiqueta). - Claves foráneas con
ON DELETE SET NULL:aulas.planta_id,vigilante_ejercicios.grupo_id,vigilante_llamamientos.sede_id,notificacion_vigilantes.asignacion_id,penalizaciones.ejercicio_id,penalizaciones.asignacion_id,penalizaciones.created_by,llamamientos.created_by,notificaciones.created_by.
Datos iniciales
Las migraciones de datos crean:
- Usuarios: superadministrador (
SUPERADMIN) siempre, y dos cuentas de desarrollo (ADMINLaura ySUPERVISOR) — verDEUDA_TECNICA.mdpara la salvedad de que se crean también en producción. - Plantillas de email por defecto, etiquetas por defecto, tipos de ejercicio, plantas, parámetros de configuración y datos de demo (vigilantes, sedes, edificios, aulas, convocatorias, tribunales y ejercicios).