Flujos de negocio¶
Esta página recoge los flujos operativos centrales de Custodiam tal como los vive el usuario final (coordinador, voluntario, jefe de equipo). Los detalles técnicos viven en otras secciones (arquitectura, ADRs); aquí se prioriza la narrativa del negocio.
Roles que interactúan¶
| Rol | Capacidades operativas |
|---|---|
| Voluntario / voluntario en prácticas | Apuntarse a servicios; fichar entrada/salida; ver su perfil. |
| Jefe de equipo | Crea servicios preventivos; gestiona equipo asignado a un servicio; valida fichajes de su equipo. |
| Coordinador | Convoca emergencias; aprueba altas/bajas; revisa actividad. |
| Secretario | Gestiona altas/bajas administrativas; mantiene catálogos. |
| Tesorero | Acceso a métricas de actividad para gestión económica. |
| Admin | Configuración técnica, backups, exportaciones RGPD. No tiene capacidades operativas por sí mismo (ADR-013). |
La matriz completa rol → permisos está espejada en código backend (Python) y cliente (Dart) en lockstep (ADR-013). Cada rol tiene un subconjunto explícito de los cuarenta permisos atómicos del catálogo.
Ciclo del voluntario¶
stateDiagram-v2
[*] --> Alta_pendiente: Secretario crea registro
Alta_pendiente --> Activo: Coordinador aprueba
(Keycloak crea usuario)
Alta_pendiente --> Rechazado: Coordinador deniega
Activo --> Baja_temporal: Voluntario solicita pausa
Baja_temporal --> Activo: Vuelta a operar
Activo --> Baja_definitiva: Solicitud RGPD
o expulsión
Baja_temporal --> Baja_definitiva: Tras tiempo definido
Baja_definitiva --> Anonimizado: Borrado RGPD
(art. 17)
Anonimizado --> [*]
Hitos clave:
- Alta_pendiente crea registro en
voluntariosconestado = 'pendiente'pero no crea usuario en Keycloak todavía. La aprobación del coordinador es la que disparakeycloak_admin.crear_usuario()y envía email de verificación. - Activo → Baja temporal / definitiva son operaciones soft delete (no borran fila). Solo cambian
estadoy registran motivo enaudit_log. - Anonimizado es operación distinta a
baja_definitiva: la baja conserva los datos para auditoría histórica; la anonimización los borra/reemplaza por placeholders en cumplimiento del derecho al olvido (RGPD art. 17). Documentada en endpointDELETE /voluntarios/{id}/anonimizarseparado delDELETEclásico.
Servicio preventivo¶
Un servicio preventivo es la cobertura programada de un evento (carreras, conciertos, ferias, romerías) donde la agrupación se presenta voluntariamente o por convenio.
sequenceDiagram
participant JE as Jefe de equipo
participant App as App
participant API as custodiam-api
participant Vol as Voluntarios
JE->>App: Crea servicio (fecha, lugar, plazas, requisitos)
App->>API: POST /servicios tipo=preventivo
API-->>App: 201 Created
Note over API: Estado = "abierto"
Vol->>App: Ve servicios disponibles
App->>API: GET /servicios?estado=abierto&disponible_para_mi=true
Note over API: Filtra por permisos RBAC
+ acreditaciones requeridas
Vol->>App: Se apunta a servicio
App->>API: POST /servicios/{id}/voluntarios/me
API-->>App: 200 OK
Note over API: Cuando plazas se llenan → estado = "completo"
JE->>API: Valida lista final
API-->>JE: Lista de voluntarios apuntados
Note over API: El día del servicio → estado = "en_curso"
tras primer fichaje
Reglas de negocio:
- Un voluntario solo puede apuntarse si tiene todas las acreditaciones requeridas declaradas en el servicio (ej. carnet B+E + ADR clase II para un servicio que requiere transporte de material).
- El jefe de equipo puede expulsar a un voluntario de un servicio antes de su inicio (con motivo registrado en
audit_log). - La asignación voluntario↔servicio es soft: al borrar un servicio, las filas históricas se conservan con
estado = 'cancelado'para mantener la trazabilidad.
Emergencia activa¶
Una emergencia activa es la convocatoria inmediata para responder a un evento no programado (incendio, inundación, búsqueda).
sequenceDiagram
participant Coord as Coordinador
participant App as App
participant API as custodiam-api
participant Notif as Sistema notificaciones
(FCM + ntfy fallback)
participant Vol as Voluntarios
Coord->>App: Crea convocatoria de emergencia
Note over App: Selecciona filtros:
municipio, acreditaciones,
conductor habilitado
App->>API: POST /servicios tipo=emergencia
API->>API: Filtra voluntarios disponibles
+ permisos RBAC
API->>Notif: Envía push a N voluntarios
Note over Notif: FCM principal,
ntfy fallback automático
Notif-->>Vol: Push notification
(payload + deep link)
Vol->>App: Tap → abre pantalla del servicio
Vol->>API: PATCH /servicios/{id}/voluntarios/me
{respuesta: "acepto"}
API-->>Coord: Notifica respuestas en tiempo real
(vía FCM al coordinador)
Note over Coord: Coord ve quién acepta/rechaza
Diferencia clave con preventivo: el voluntario no se apunta, se le convoca. El sistema empuja la notificación; el voluntario solo acepta o rechaza.
Más detalle de la lógica de notificaciones y el fallback en Notificaciones redundantes.
Fichaje¶
El fichaje registra la presencia real del voluntario en un servicio con timestamp y ubicación opcional.
flowchart TB
subgraph Entrada["Fichaje de entrada"]
A[Voluntario llega al servicio] --> B{¿Está apuntado
al servicio?}
B -->|No| C[Error 403]
B -->|Sí| D[Pulsa Fichar Entrada en la app]
D --> E[App envía POST /fichajes
servicio_id + timestamp + GPS opcional]
E --> F[Backend valida ventana temporal
±1h de inicio del servicio]
F --> G[201 Created — entrada registrada]
end
subgraph Salida["Fichaje de salida"]
H[Voluntario termina servicio] --> I[Pulsa Fichar Salida]
I --> J[POST /fichajes con tipo=salida]
J --> K[201 Created — fichaje cerrado]
end
subgraph Validacion["Validación posterior"]
L[Jefe de equipo] -->|Más tarde| M[Valida fichajes de su equipo]
M --> N[Estado fichaje:
validado o rechazado]
end
Entrada --> Salida
Salida --> Validacion
Reglas operativas:
- Ventana temporal: el fichaje debe ocurrir dentro de ±1 hora del inicio/fin previsto del servicio para considerarse "automático". Fuera de ventana queda en estado
pendiente_validaciony exige aprobación manual del jefe de equipo. - GPS opcional: el voluntario puede compartir ubicación al fichar (para validación de presencia física), pero no es obligatorio. La aplicación pide permiso explícito y guarda preferencia.
- Offline-first: si el voluntario está sin cobertura al fichar (situación habitual en zonas rurales o eventos masivos), el fichaje se persiste en SQLite local del dispositivo y se sincroniza al volver online.
Inventario (módulo previsto en fase Beta)¶
El módulo de inventario gestiona material y vehículos de la agrupación: alta, asignación a voluntarios o servicios, revisión de mantenimiento, baja por desgaste.
Sigue el mismo patrón de Modelo de datos — catálogos tipos_material y tipos_vehiculo extensibles + tabla de instancias con JSONB para campos específicos por tipo (presión de neumáticos, fecha ITV, calibre, color, etc.).
Referencias¶
- Modelo de datos — esquema ER que sostiene estos flujos.
- Notificaciones redundantes — FCM + ntfy.
- Audit log — registro cross-module de operaciones críticas.
- ADR-013 RBAC lockstep — matriz rol → permisos.
- Usuarios de prueba — capacidades reales por rol.