Data Model — 004 Panel de analítica
Fuente: spec.md FR-001…FR-010 + research R1…R7. Esta feature NO crea tablas (FR-006/S-07); el modelo describe (a) lecturas agregadas, (b) la enmienda S-05 pendiente a Cita (propiedad 001) y (c) la forma del agregado. Dinero en céntimos enteros, tiempo en timestamptz zona Europe/Madrid, textos es-ES.
1. Enmienda S-05 a Cita (001, prerrequisito bloqueante)
Propiedad de la 001 (001 FR-006); aquí solo migración + escritura al reservar + semilla. La página 004 solo lee.
Prisma: precioCongeladoCentimos Int. Sin índice nuevo (el existente [clinicaId, inicio] cubre la ventana).
2. Lecturas agregadas (efímeras, sin persistencia)
Una sola foto coherente por carga: ahora = capturarAhora() → semanas = semanasAnalitica(ahora) → una lectura de citas con clinicaId + inicio ∈ [S-8.inicio, S-1.fin] + profesionales/servicios de la clínica. Nunca mezcla mitades de dos estados (edge spec).
3. Forma del agregado (contrato contracts/analitica.md)
AnaliticaClinica {
clinica: { id, nombre, jornada: "09:00–20:00, Lun–Vie" (etiquetarJornada vigente) }
ventana: { semanas: [S-8 … S-1 con etiqueta + rango], generadaCon: ahora ISO }
tasas: [{ profesionalId, nombre, tasa: 7.3|null, texto: "7,3 %"|"—", partes: {noAsistidas, total} }]
ocupaciones: [{ profesionalId, nombre, ocupacion: 25.1, minutos: 6615, denominador: 26400 }]
ingresos: { porServicio: [{ servicioId, nombre, citas: 126, centimos: 504000, texto: "5.040,00 €" }], totalCentimos: 1435500, totalTexto: "14.355,00 €" }
evolucion: [{ n: 8…1, etiqueta: "S-8: 03/08/2026–07/08/2026", citas, completadas, noAsistidas, canceladas, ingresosCentimos, ingresosTexto }]
sinDesenlace: number // reservadas con fin pasado, solo informativa
}
4. Diagrama (texto)
sesión (misma clave agenda, FR-001) ──► clinicaId
ahora = capturarAhora() ──► semanasAnalitica(ahora) [S-8…S-1, curso fuera]
clinica(vigente: jornada+dias) ──► denominadorOcupacion ──► ocupación (declara jornada)
citas[clinicaId + ventana] ──┬──► tasa (no_asistida/total, con canceladas)
├──► ocupación (min completadas / denominador)
├──► ingresos (Σ precioCongelado de completadas, al céntimo)
└──► evolución (8 filas, suma = historia)
profesionales/servicios[clinicaId, activos+inactivos] ──► dimensiones (bajas cuentan)
sin escritura: cero POST/PATCH/DELETE; diff BD antes/después = 0 (SC-004)