Saltar a contenido

Modelo de datos — diagrama ER completo

Esta página presenta el esquema relacional completo de Custodiam: las dieciocho tablas de la base de datos de negocio, agrupadas por módulo, más un mapa de las relaciones que cruzan los límites de un módulo a otro.

Es el complemento del Modelo de datos, que explica el patrón de diseño (catálogo + instancias + JSONB + enum discriminador, ADR-025); aquí el foco es el mapa entidad-relación de todo el esquema.

Alcance del diagrama

El esquema corresponde a la base de datos de negocio (custodiam), gestionada con SQLModel y migrada con Alembic. La base de datos de Keycloak (custodiam_kc, ~70 tablas internas del servidor de identidad) es independiente y queda fuera de este diagrama, coherente con la separación de ADR-009.

Convenciones del diagrama

  • Clave primaria (primary_key): id de tipo uuid, generado en la capa de aplicación (no en la base de datos).
  • Clave foránea (foreign_key): referencia a la clave primaria de otra tabla.
  • unique: columna con restricción de unicidad.
  • Las relaciones se dibujan en notación crow's foot desde el lado "uno" (clave primaria) hacia el lado "muchos" (clave foránea).
  • Por legibilidad, los índices compuestos, los valores por defecto y las cláusulas ON DELETE no se representan en el diagrama; se describen en las notas de modelado.

Módulo Voluntarios

El núcleo del dominio de personas. La tabla voluntarios es la raíz; a su alrededor cuelgan los roles (con vigencia temporal), las disponibilidades por día, las acreditaciones y tallas (patrón catálogo + instancias de ADR-025), los contactos de emergencia y el historial de actividad.

voluntariosiduuidPKkeycloak_idvarcharUNQnombrevarchardnivarcharUNQemailvarcharUNQtelefonovarcharmunicipiovarcharfecha_nacimientodatedireccionvarcharfoto_urlvarcharconductor_habilitadoboolfecha_altadatefecha_bajadateestadoenumcreated_attimestamptzupdated_attimestamptzrolesiduuidPKnombrevarcharUNQnivelintdescripcionvarcharpermisosjsonbvoluntario_rolesiduuidPKvoluntario_iduuidFKrol_iduuidFKfecha_desdedatefecha_hastadatedisponibilidadesiduuidPKvoluntario_iduuidFKfechadatedisponiblebooltipos_acreditacioniduuidPKcodigovarcharUNQnombrevarchardescripcionvarcharcategoriaenumcampos_schemajsonbactivoboolacreditacionesiduuidPKvoluntario_iduuidFKtipo_iduuidFKcategoriaenumfecha_obtenciondatefecha_caducidaddatenumerovarcharentidad_emisoravarchardatos_especificosjsonbdocumento_urlvarchartipos_equipamientoiduuidPKcodigovarcharUNQnombrevarcharsistema_tallasvarcharactivobooltallas_voluntarioiduuidPKvoluntario_iduuidFKtipo_iduuidFKvalorvarcharcontactos_emergenciaiduuidPKvoluntario_iduuidFKnombrevarchartelefonovarcharparentescovarcharorden_preferenciaintvoluntario_eventosiduuidPKvoluntario_iduuidFKtipo_eventoenumpayloadjsonbactor_keycloak_idvarcharcreated_attimestamptz tienedeclaratienetienetieneregistraasignado enclasificaclasifica

voluntario_roles es una tabla intermedia con vigencia (fecha_desde/fecha_hasta): permite reasignar el mismo rol en periodos distintos. voluntario_eventos es el historial de actividad del voluntario (altas, bajas, cambios de rol, fichajes, asignaciones), con payload en JSONB para el contexto de cada evento.

Módulo Servicios y fichaje

Un servicio (preventivo, emergencia, formación u otro) recorre una máquina de estados borrador → publicado → activo → cerrado. Los voluntarios se asocian a un servicio mediante inscripciones_servicio (con un discriminador que distingue inscrito de convocado) y registran su presencia en fichajes.

serviciosiduuidPKtitulovarchardescripcionvarchartipoenumestadoenumfecha_iniciotimestampfecha_fintimestampubicacionvarcharubicacion_latfloatubicacion_lngfloatnumero_voluntariosintcreado_por_keycloak_idvarcharfecha_cierretimestampcreated_attimestamptzupdated_attimestamptzinscripciones_servicioiduuidPKservicio_iduuidFKvoluntario_iduuidFKtipoenumfechatimestampfichajesiduuidPKservicio_iduuidFKvoluntario_iduuidFKhora_entradatimestamphora_salidatimestampautomaticoboolcreated_attimestamptzupdated_attimestamptz tieneregistra

Tanto inscripciones_servicio como fichajes referencian además al voluntario (voluntario_id); esas relaciones cruzan al módulo Voluntarios y se ven en el mapa global.

Módulo Inventario y ubicaciones

El inventario separa materiales y vehiculos en tablas distintas (campos divergentes y distinto corte de permisos), ambos ubicados opcionalmente en un catálogo común de ubicaciones con coordenadas. La asignación de material se modela con asignaciones_material, que apunta a exactamente uno de tres destinos (voluntario, servicio o vehículo); la asignación de vehículos a servicios va en asignaciones_vehiculo. La "devolución" es un borrado lógico: una asignación está activa mientras fecha_devolucion sea nula.

ubicacionesiduuidPKnombrevarcharUNQdescripcionvarcharlatfloatlngfloatcreated_attimestamptzupdated_attimestamptzmaterialesiduuidPKnombrevarchardescripcionvarcharcodigovarcharUNQnumero_serievarchartipoenumcategoriavarcharestadoenumcantidadintubicacion_basevarcharubicacion_base_iduuidFKfecha_adquisiciondatefecha_proxima_revisiondatefoto_urlvarcharcreated_attimestamptzupdated_attimestamptzvehiculosiduuidPKcodigo_internovarcharUNQmatriculavarchartipoenummarca_modelovarcharfecha_itvdateestadoenumubicacion_basevarcharubicacion_base_iduuidFKfoto_urlvarcharcreated_attimestamptzupdated_attimestamptzasignaciones_materialiduuidPKmaterial_iduuidFKvoluntario_iduuidFKservicio_iduuidFKvehiculo_iduuidFKtipoenumcantidadintfecha_asignaciontimestampfecha_devoluciontimestampasignaciones_vehiculoiduuidPKvehiculo_iduuidFKservicio_iduuidFKfecha_asignaciontimestampfecha_devoluciontimestamp ubicaubicase asigna ense asigna ense dota con

La restricción de "exactamente un destino" de asignaciones_material (un material se asigna a un voluntario o a un servicio o como dotación fija de un vehículo, nunca a más de uno) se garantiza con una restricción de tabla, detallada en ADR-031. Las columnas voluntario_id y servicio_id de las asignaciones cruzan a otros módulos: ver el mapa global.

Módulo Notificaciones

Cada voluntario registra sus tokens de envío (dispositivos, uno por plataforma) y cada emisión de aviso queda registrada en notificaciones con sus contadores de envío.

dispositivosiduuidPKvoluntario_iduuidFKfcm_tokenvarcharUNQplataformaenumactivoboolcreated_attimestamptzultima_actualizaciontimestamptznotificacionesiduuidPKservicio_iduuidFKtitulovarcharcuerpovarchartipoenumprioridadenumenviada_attimestamptzenviadas_countintentregadas_countint

Ambas tablas se enlazan con otros módulos: dispositivos pertenece a un voluntario y notificaciones referencia opcionalmente al servicio que la motivó. Esas relaciones se ven en el mapa global.

Mapa global de relaciones

Las siete claves foráneas que cruzan los límites de un módulo son las que cosen el esquema. El módulo Voluntarios y el módulo Servicios actúan como destinos comunes; los módulos Inventario y Notificaciones apuntan hacia ellos.

VoluntariosServicios y fichajeInventario y ubicacionesNotificacionesvoluntariosiduuidPKserviciosiduuidPKinscripciones_serviciovoluntario_iduuidFKservicio_iduuidFKfichajesvoluntario_iduuidFKservicio_iduuidFKasignaciones_materialvoluntario_iduuidFKservicio_iduuidFKasignaciones_vehiculoservicio_iduuidFKdispositivosvoluntario_iduuidFKnotificacionesservicio_iduuidFK se inscribeficharecibe en préstamotiene dispositivousa materialusa vehículomotiva aviso

Enumerados

El esquema usa trece tipos enumerados de PostgreSQL como discriminadores y máquinas de estado:

Enumerado Valores Usado en
estado_voluntario activo · baja · suspendido voluntarios.estado
categoria_acreditacion licencia_oficial · formacion_interna · otro tipos_acreditacion.categoria, acreditaciones.categoria
tipo_servicio preventivo · emergencia · formacion · otro servicios.tipo
estado_servicio borrador · publicado · activo · cerrado servicios.estado
tipo_inscripcion inscrito · convocado inscripciones_servicio.tipo
tipo_material personal · prestable · servicio materiales.tipo
estado_inventario operativo · averiado · perdido · en_uso materiales.estado, vehiculos.estado
tipo_vehiculo furgoneta · pick_up · ambulancia · remolque vehiculos.tipo
tipo_asignacion_material personal · prestamo · servicio · dotacion_vehiculo asignaciones_material.tipo
plataforma_dispositivo android · ios · web dispositivos.plataforma
tipo_notificacion emergencia · servicio · recordatorio · sistema notificaciones.tipo
prioridad_notificacion critica · alta · normal · baja notificaciones.prioridad
tipo_evento_voluntario alta · baja · anonimizacion · cambio de rol · fichajes · inscripciones · asignaciones de material voluntario_eventos.tipo_evento

Notas de modelado

  • Claves primarias uuid: todas las tablas usan id de tipo uuid generado en la capa de aplicación, no por la base de datos. No se usan secuencias ni enteros autoincrementales.
  • Marcas de tiempo: las columnas de auditoría (created_at, updated_at, enviada_at, ultima_actualizacion) son timestamptz (con zona horaria); las marcas de dominio (fecha_inicio, hora_entrada, fecha_asignacion, etc.) son timestamp sin zona.
  • Borrado lógico, nunca físico: las bajas y devoluciones no eliminan filas. Un voluntario se da de baja con estado = baja (o se anonimiza); una asignación se devuelve poniendo fecha_devolucion. No hay ninguna cláusula ON DELETE CASCADE en el esquema: las únicas claves foráneas con borrado restringido explícito son las de materiales/vehiculos/asignaciones_material hacia las tablas que referencian.
  • Columnas JSONB: roles.permisos, tipos_acreditacion.campos_schema, acreditaciones.datos_especificos y voluntario_eventos.payload. La matriz real de permisos por rol no vive en roles.permisos, sino espejada en código backend y cliente (ADR-013).
  • Catálogos pre-poblados: roles, tipos_acreditacion y tipos_equipamiento se cargan con datos canónicos mediante data migrations de Alembic, versionados en Git como parte del esquema.
  • Valores derivados no persistidos: algunos atributos que la API expone (como el recuento de inscritos de un servicio o la duración de un fichaje) se calculan en consulta y no son columnas físicas.

Referencias