# Parte 3 — Auditoría crítica de reportes y dashboards existentes (FASE 3)

> Alcance auditado: **26 artefactos analíticos** — 16 reportes Excel (35 hojas de datos), 4 dashboards, 2 pantallas de historial remoto, 3 vistas de la pantalla de inicio y 1 hub de navegación.
> Método: lectura del código de generación de cada artefacto y de las consultas SQL que lo alimentan, contrastadas con el esquema y los datos vivos.
> Escala de utilidad: 1 = no soporta ninguna decisión; 10 = soporta una decisión de inversión o de política con evidencia defendible.

---

## 3.1 Inventario completo

### Reportes Excel — `?c=reportes&a=list` → `download&report={ID}`

Catálogo formal declarado en [ReportesController::getReportCatalog](../../app/controllers/ReportesController.php#L24), con código, título, descripción e **iconos y filtros declarados por reporte**. Generación por despacho dinámico `build{ReportId}` y salida XLSX con hoja de portada ([core/ExcelReport.php](../../core/ExcelReport.php)).

| Código | Título | Hojas | Filtros declarados | Nota |
|---|---|---|---|---|
| RES001 | Detalle de Reservas | 3 | fechas, sede, área, categoría, estado | **6,5** |
| RES002 | Cancelaciones y Rechazos | 3 | fechas, sede, categoría | **3,0** |
| RES003 | No Asistencias (No-Show) | 3 | fechas, sede, área, categoría | **7,0** |
| ESP001 | Ocupación de Espacios | 3 | fechas, sede, área, categoría | **5,0** |
| ESP003 | Horas Pico y Distribución | 2 | fechas, sede, área, categoría | **6,0** |
| ESP004 | Impacto de Bloqueos | 1 | fechas, sede | **4,0** |
| ACT001 | Inventario de Activos | 3 | sede, área | **1,0** |
| ACT002 | Uso de Recursos | 1 | fechas, sede, área, categoría | **7,5** |
| LAB001 | Sesiones de Práctica Libre | 3 | fechas, sede, área, categoría | **7,0** |
| LAB002 | Préstamos Inmediatos | 1 | fechas, sede, categoría | **4,5** |
| WRK001 | Historial de Aprobaciones | 2 | fechas, sede, área, categoría | **7,5** |
| EVE001 | Eventos Realizados | 2 | fechas, sede, área, categoría | **3,5** |
| ADV001 | Comportamiento de Usuarios | 2 | fechas, sede, área, categoría | **6,5** |
| ADV002 | Eficiencia Operativa Global | 3 | fechas | **3,5** |
| ADV003 | Auditoría de Accesos | 2 | fechas | **1,0** |
| ADV004 | Tickets de Soporte | 1 | fechas | **1,5** |

> Hueco de numeración: **no existe ESP002**. Sugiere un reporte planificado y no construido (probablemente el de ocupación con denominador).

### Dashboards y pantallas

| Artefacto | Ruta | Contenido | Nota |
|---|---|---|---|
| Hub de dashboards | `graficas&a=list` | 3 tarjetas de navegación | **3,0** |
| **Uso de espacios** | `graficas&a=dashboardEspacios` | 4 KPIs con delta, heatmap 7×24, top 10 / bottom 10, por categoría, tendencia 12 semanas, bloqueos | **6,5** |
| **Gestión de reservas** | `graficas&a=dashboardReservas` | 4 KPIs con delta, embudo, por estado, heatmap de no-show, tendencia, por área, por sede | **5,5** |
| **Inventario de activos** | `graficas&a=dashboardActivos` | 4 KPIs, por estado, por tipo, por sede | **1,0** |
| **Dashboard Guacamole** | `guacDashboard&a=index` | 12 tarjetas + 5 gráficas (actividad, heatmap, top conexiones, top usuarios, duración) + tabla de actividad reciente | **5,0** |
| Historial de conexiones | `guacHistorial&a=connections` | Filtros, 6 chips de resumen, DataTables, export CSV + XLSX de 6 hojas | **6,0** |
| Historial de logins | `guacHistorial&a=users` | Ídem sobre logins | **2,0** |
| Inicio — operacional | `home` | 4 KPIs del día, 4 contadores, próximas reservas, 5 accesos rápidos | **6,0** |
| Inicio — activos | `home` (vista de activos) | 4 KPIs de estado + préstamos activos | **2,0** |
| Inicio — técnico | `home` (vista técnica) | Estado de BD, caché, última migración, último seeder | **5,5** |

### API de datos
`graficas&a=dataApi&chart={nombre}` expone **14 series** en JSON con lista blanca (`heatmap`, `topEspacios`, `bottomEspacios`, `porCategoria`, `tendencia`, `bloqueos`, `funnel`, `porEstado`, `noShowHeatmap`, `porArea`, `porSede`, `activosPorEstado`, `activosPorTipo`, `activosPorSede`). **Es la mejor pieza reutilizable para BI que existe hoy**, aunque devuelve el resultado crudo del modelo sin contrato estable ni versionado.

---

## 3.2 Fichas de auditoría

### RES001 — Detalle de Reservas · **6,5 / 10**

- **Muestra:** 28 columnas por reserva (sede, área, categoría, espacio, capacidad, fecha, día, horas, duración, recurso, solicitante, documento, email, tipo, programa, estado, aprobación con tiempo en horas, estado de entrega, **horas reales de entrega y devolución**, QR, comentarios, fecha de solicitud y **anticipación en días**). Más resumen por espacio (con tasas de completación y no-show) y resumen por fecha.
- **Para quién:** coordinador de laboratorios y auxiliar de mostrador, como fuente de verdad transaccional; analista, como base para tabla dinámica.
- **Decisión que permite:** auditar casos individuales y reconstruir a mano casi cualquier métrica. Es el reporte más completo del sistema.
- **Qué le falta:** (a) **no incluye las cancelaciones** — universo incompleto; (b) `Área` sale vacía en el 100 % de las filas (dimensión rota); (c) no distingue canal de origen; (d) no marca si la reserva es parte de una serie; (e) `Capacidad` es el aforo de la agenda, no el número de asistentes, y no hay columna de personas atendidas.
- **Cómo mejorarlo:** añadir columnas `Canal`, `EsRecurrente`, `PersonasAtendidas` (`CupoConsumido`), `MinutosRetrasoLlegada`, `MinutosUsoReal`; unificar con `citas_canceladas` mediante una columna `EstadoFinal`; resolver el área.
- **Justificación de la nota:** completísimo a nivel de fila, pero mide un universo incompleto y su dimensión organizativa está en blanco.

### RES002 — Cancelaciones y Rechazos · **3,0 / 10**

- **Muestra:** hoja de cancelaciones (con canal, motivo, fecha de cancelación y **antelación en horas**, más «Tipo Cancelación» clasificado por temporalidad: Tardía <2 h / Mismo día <24 h / Anticipada ≥24 h), hoja de rechazos y resumen mensual con horas perdidas.
- **Para quién:** coordinador de laboratorios y director académico.
- **Decisión que permite:** en teoría, ajustar las políticas `DiasCancelar`/`HorasCancelar`. En la práctica, **poca**.
- **Qué le falta y por qué la nota es baja:**
  1. La hoja de rechazos filtra **sólo por `Estado=5`** sin exigir `NegadoPorUserId IS NOT NULL` → **mezcla decisiones humanas con expiraciones automáticas del cron**, y su columna «Tiempo Respuesta (h)» mide, para las expiradas, «tiempo hasta que empezó la franja». **Es un número que parece un SLA y no lo es.**
  2. `getCancelaciones` usa **`INNER JOIN agendas`**, y las reservas de activo tienen `IdAgenda=0` → **las cancelaciones de equipos desaparecen del reporte oficial de cancelaciones.**
  3. `CanceladaMotivo` es texto libre autorrellenado con literales genéricos → **la clasificación por causa no existe**; sólo hay clasificación por temporalidad.
  4. No expone la **tasa** de cancelación (sólo conteos), y no distingue cancelación neta de reagendamiento (concepto inexistente).
- **Cómo mejorarlo:** separar rechazo de expiración con el discriminante `NegadoPorUserId`; cambiar a `LEFT JOIN`; introducir un catálogo `MotivoCierreTipo`; añadir tasa contra el universo unificado; añadir la comparación «antelación real vs. ventana configurada por agenda» para responder si la política se cumple.

### RES003 — No Asistencias · **7,0 / 10**

- **Muestra:** detalle de no-shows con horas desperdiciadas, hoja de **reincidentes** (con tasa individual y último no-show) y hoja **por franja horaria** con tasa por día y hora.
- **Para quién:** coordinador de laboratorios (para sancionar) y director académico (para política).
- **Decisión que permite:** **decisiones reales y accionables** — a quién sancionar, qué franjas sobre-reservar, si la política anti-no-show funciona.
- **Qué le falta:** (a) los reincidentes se agrupan por `DocumentoSolicitante` porque los *walk-in* no traen `IdCliente` → **doble conteo si el documento viene sucio**; (b) no distingue no-show automático (cron) de detectado por staff, que es la métrica de gestión; (c) no cruza con `agendas.BloqueoLlegadaTarde`/`TiempoLlegadaTarde` para evaluar la política; (d) no muestra el efecto de las sanciones (¿bajó el no-show tras bloquear?).
- **Riesgo crítico de interpretación:** **el estado `4` sólo lo genera el cron, y el cron no está programado.** Hoy este reporte, el mejor del sistema, mide un fenómeno que **no se está materializando**.
- **Nota:** la más alta de la familia de reservas porque las tres hojas responden preguntas distintas y todas conducen a una acción.

### ESP001 — Ocupación de Espacios · **5,0 / 10**

- **Muestra:** por espacio: total de reservas, reservas efectivas, **horas reservadas**, tasa de no-show, promedio de duración y total de bloqueos. Más resumen por categoría (con `capacidad_total`) y por sede.
- **Para quién:** director de infraestructura y coordinador de laboratorios.
- **Decisión que permite:** comparar espacios entre sí; identificar el más y el menos usado.
- **Qué le falta — y es lo que define la nota:** **no calcula ocupación.** Calcula **horas reservadas**, que es sólo el numerador. Sin el denominador (horas ofertadas) no se puede responder «¿estoy usando mi capacidad?», sólo «¿cuál se usa más?». El nombre del reporte promete algo que el contenido no entrega: **es el desalineamiento nombre↔contenido más caro del sistema**, porque un director leerá «Ocupación» y asumirá un porcentaje.
- **Cómo mejorarlo:** construir `fct_capacidad_ofrecida` (Parte 7, habilitador 4) y añadir tres columnas: `HorasOfertadas`, `HorasBloqueadas`, **`%Ocupacion = HorasReservadas / (HorasOfertadas − HorasBloqueadas)`**. Con eso este reporte pasa de 5 a 9.

### ESP003 — Horas Pico y Distribución · **6,0 / 10**

- **Muestra:** distribución por día de la semana × hora, y ranking de franjas.
- **Para quién:** coordinador de laboratorios (para dimensionar turnos de monitor) y director académico (para negociar la malla).
- **Decisión que permite:** decidir turnos de personal y detectar franjas muertas candidatas a cerrar.
- **Qué le falta:** (a) `GROUP BY HOUR(HoraInicio)` con horas no canónicas → **cardinalidad creciente y huecos artificiales**; (b) no separa práctica libre de reserva de aula, que tienen curvas **radicalmente distintas** (una plana, otra con picos a las 7 y 9); (c) no muestra la ocupación relativa de la franja (una franja con 3 reservas de 3 posibles está saturada; con 3 de 30 está vacía); (d) no marca festivos ni recesos.
- **Cómo mejorarlo:** dimensión de franja por rangos; segmentar por canal; añadir `%OcupacionFranja`.

### ESP004 — Impacto de Bloqueos · **4,0 / 10**

- **Muestra:** una hoja: bloqueos con duración en horas, motivo y estado.
- **Para quién:** director de infraestructura.
- **Decisión que permite:** poca. Es un listado, no un análisis de impacto.
- **Qué le falta:** (a) **usa `INNER JOIN agendas`, por lo que excluye todos los bloqueos globales (`IdAgenda=-1`)** — el impacto de los bloqueos masivos, que son los que más duelen, **es invisible**; (b) `Motivo` es texto libre → no se puede agrupar por causa; (c) **no calcula el impacto real**: horas ofertadas perdidas, reservas afectadas, personas afectadas, ni demanda desplazada; (d) el rango horario se repite por día, así que la duración calculada es engañosa para bloqueos multi-día.
- **Cómo mejorarlo:** `LEFT JOIN` y tratamiento del centinela; catálogo `TipoBloqueo`; columnas `HorasOfertadasPerdidas`, `ReservasCanceladasPorBloqueo`, `PersonasAfectadas`.

### ACT001 — Inventario de Activos · **1,0 / 10**

- **Muestra:** inventario con valor, y resúmenes por tipo y por sede con `valor_servicio`, `valor_inmovilizado` y `% productividad`.
- **Para quién:** director financiero y director TIC.
- **Estado real:** **la tabla `activos` tiene 0 filas.** El reporte está bien construido y devuelve vacío. Además el seeder nunca asigna `IdAreaUni`, por lo que cualquier filtro por área saldría vacío incluso con datos.
- **Qué le falta estructuralmente:** sin `FechaCompra`, `VidaUtilMeses`, `FinGarantia`, `Marca`, `Modelo` ni `Placa`, el `Valor` es **un monto sin edad**: no se puede depreciar, ni calcular antigüedad del parque, ni cobertura de garantía.
- **Nota 1,0** no por mala construcción sino porque **no puede entregar información**. Con `activos` poblada y cuatro columnas añadidas sube a 7.

### ACT002 — Uso de Recursos · **7,5 / 10**

- **Muestra:** por unidad de inventario: veces asignado, **horas de uso**, promedio de duración, **última asignación** y **frecuencia semanal**.
- **Para quién:** coordinador de laboratorios y director TIC.
- **Decisión que permite:** **decisiones de compra y de baja.** Es el reporte que identifica equipos ociosos y equipos sobreexplotados — y en producción ese hallazgo fue brutal (10 equipos de 764 con el 80 % del uso).
- **Qué le falta:** (a) son **horas agendadas, no horas usadas** (el uso real requiere `HoraEntrega`/`HoraDevolucion` como `datetime`); (b) sólo cubre `agendas_recursos`, **no `activos`**; (c) no incluye horas de sesión remota; (d) no incluye disponibilidad técnica ni downtime; (e) no lista explícitamente los **equipos con cero uso** (hay que buscarlos a ojo en la cola de la lista).
- **Cómo mejorarlo:** hoja dedicada «Equipos sin uso en el periodo»; columna de horas remotas; columna `DiasEnMantenimiento`.
- **Nota alta** porque, con las limitaciones dichas, es el reporte que más directamente mueve dinero.

### LAB001 — Sesiones de Práctica Libre · **7,0 / 10**

- **Muestra:** 19 columnas por sesión, incluidas **hora real de inicio y fin**, duración programada vs. real, **código Guacamole**, tipo de usuario y programa. Más hoja por computador (con **días sin uso**) y hoja **por programa**.
- **Para quién:** coordinador de laboratorios, decano (vía programa), director TIC.
- **Decisión que permite:** dimensionar la sala, redistribuir equipos, y **atribuir el uso a programas académicos** — el único reporte del sistema que llega a la dimensión académica.
- **Qué le falta:** (a) **la hoja por programa agrupa por texto libre** → a escala real producirá decenas de variantes de la misma cadena; (b) identifica los laboratorios por `agendas.PortalPracticaLibre=1`, **no por el marcador real `__origen`** que escribe el controlador → **contamina el KPI con reservas ordinarias hechas en agendas que además permiten práctica libre**; (c) sin denominador de capacidad de sala; (d) `Cód. Guacamole` se muestra pero no se cruza con el historial real de sesiones; (e) no captura el serial entregado (la generación anterior sí).
- **Cómo mejorarlo:** filtrar por `__origen`; catalogar programa; añadir `%OcupacionSala`; unir con `fct_sesion_remota`.

### LAB002 — Préstamos Inmediatos · **4,5 / 10**

- **Muestra:** una hoja con recurso, fecha, horas de entrega y devolución, duración en minutos y solicitante.
- **Para quién:** auxiliar de mostrador y coordinador.
- **Qué le falta:** (a) **mismo defecto de identificación**: filtra por `agendas.PermitePrestamoInmediato=1` en lugar del marcador `__origen` → **el KPI está contaminado**; (b) la duración se calcula con `time` sin fecha → **cualquier préstamo que cruce medianoche da un valor negativo**; (c) no distingue préstamo cerrado de préstamo abierto/vencido; (d) no captura condición del equipo al entregar ni al recibir; (e) no hay funcionario que entrega vs. funcionario que recibe.
- **El hueco más grave:** **no existe una hoja de «préstamos abiertos vencidos»**, que es la única información operativa urgente de este proceso. En la base viva hay 4 préstamos abiertos, algunos de hace más de un mes. En producción, el 50,1 % de las órdenes se devolvió tarde.

### WRK001 — Historial de Aprobaciones · **7,5 / 10**

- **Muestra:** por solicitud: decisión, operador, fecha, **tiempo de respuesta en horas** y **«Cumple SLA»**. Más hoja **por operador** con % de aprobación, tiempo promedio y % de cumplimiento de SLA.
- **Para quién:** director TIC / jefe de servicio (gestión de equipo), coordinador.
- **Decisión que permite:** **gestión real de desempeño y de carga de trabajo.** Es, junto a ACT002 y RES003, uno de los tres reportes que soportan una decisión de gestión.
- **Qué le falta:** (a) **el umbral de SLA está hardcodeado en 4 horas** ([ReportesModel.php:1005](../../app/models/ReportesModel.php#L1005)) y no es configurable — no hay parámetro en `configuraciones`; (b) **no separa expiraciones de rechazos**, así que el tiempo de respuesta de las expiradas es espurio; (c) **no expone el backlog** (pendientes sin decidir y su antigüedad), que es la métrica que anticipa el problema en lugar de describirlo; (d) no mide la **tasa de expiración por no-decisión**, que es el indicador de incumplimiento del equipo de aprobación.
- **Cómo mejorarlo:** parametrizar el SLA; añadir hojas de backlog y de expiraciones; separar los dos hechos.

### EVE001 — Eventos Realizados · **3,5 / 10**

- **Muestra:** listado de «eventos» con espacio, capacidad, organizador y tipo; resumen mensual.
- **Para quién:** dirección de eventos / extensión.
- **Problema de fondo:** **el sistema no tiene concepto de «evento»**. El reporte infiere eventos a partir de reservas en ciertas categorías. Por tanto su universo es una convención, no un dato.
- **Qué le falta:** sin asistentes reales (`citas` no guarda asistentes), sin costo, sin ingreso, sin público objetivo, sin difusión. Un director de extensión no puede decidir nada con esto.
- **Cómo mejorarlo:** o se modela «evento» como entidad de primera clase (con asistentes, costo, público), o el reporte debe renombrarse a «Reservas de espacios de gran aforo» para no prometer lo que no es. **Recomendación: renombrar y fusionar con ESP001.**

### ADV001 — Comportamiento de Usuarios · **6,5 / 10**

- **Muestra:** por tipo de usuario: usuarios activos, reservas, promedio por usuario, tasas de no-show y de cancelación, horas reservadas y **anticipación promedio**. Más Top 50 usuarios con espacios distintos usados.
- **Para quién:** director académico, decano, coordinador.
- **Decisión que permite:** política diferenciada por segmento (estudiante vs. docente vs. externo) y detección de usuarios problemáticos.
- **Qué le falta:** (a) **la tasa de cancelación es cero por construcción** (usa `Estado=2`); (b) `Programa` es texto libre; (c) no hay cohortes ni retención (falta fecha de vinculación); (d) el Top 50 es de volumen, no de **valor** ni de **impacto** (un usuario con 50 reservas y 40 % de no-show es más relevante que uno con 60 reservas y 0 %); (e) no separa el usuario final del operador que reserva en nombre de terceros — en producción, los 59 clientes de cola larga eran coordinadores, no estudiantes.
- **Cómo mejorarlo:** corregir el universo de cancelación; ordenar el Top por horas desperdiciadas además de por volumen; marcar los reservantes por delegación.

### ADV002 — Eficiencia Operativa Global · **3,5 / 10**

- **Muestra:** KPIs globales (total, completadas, tasa de completación, **tasa de no-show**, **tasa de cancelación**, satisfacción de demanda, espacios activos, usuarios activos), eficiencia por sede y tendencia mensual de 6 meses.
- **Para quién:** **es el reporte de dirección.** El que llega a un comité.
- **Por qué la nota es baja pese a ser el más ambicioso:** es el artefacto donde los defectos estructurales hacen más daño, porque es el que menos contexto lleva.
  1. **`tasa_cancelacion` cuenta `citas.Estado=2` → reportará ~0 % mientras las cancelaciones reales se acumulan en otra tabla.** Un comité verá «0 % de cancelación» cuando la cifra real de la generación anterior fue 12,6 %.
  2. **`satisfaccion_demanda` = `Estado IN (1,3) / COUNT(*)`** sobre un universo que **excluye las canceladas** → **sobreestima sistemáticamente**.
  3. **No hay ninguna métrica de capacidad ni de ocupación.** «Espacios activos» es un conteo de catálogo, no de uso.
  4. `usuarios_activos` usa `IFNULL(IdCliente, DocumentoSolicitante)` → mezcla dos identificadores y **cuenta doble** cuando el documento viene sucio.
  5. La tendencia mensual es de 6 meses fijos e **ignora los filtros de fecha del usuario**.
- **Cómo mejorarlo:** es el reporte que más urge corregir, porque es el que más se usa para decidir. Universo unificado, denominador de capacidad, y comparativa contra el mismo periodo del semestre anterior en lugar de «últimos 6 meses».

### ADV003 — Auditoría de Accesos · **1,0 / 10**

- **Muestra:** log de acceso (con duración de sesión) y log de cambios (con datos anteriores y nuevos).
- **Para quién:** oficial de seguridad, auditoría interna.
- **Estado real:** **`log_acceso` tiene 3 filas y `log_modules` tiene 0.** En la producción anterior, **0 y 0 tras tres años**. Los flags `LOG_*` están todos en `true`: **el problema es de código, no de configuración** — `LogUrlsModel::saveLog()` no tiene llamadores y ningún modelo tiene `$LOG=true`.
- Además, aun con datos, la columna «Duración (min)» **no es calculable**: `CierreSesion` está NULL en el 100 % de las filas porque el cierre sólo se registra en logout explícito.
- **Nota 1,0.** El reporte está construido y espera datos que nunca llegan. **Es el KPI más elocuente del estado de gobierno del sistema.**

### ADV004 — Tickets de Soporte · **1,5 / 10**

- **Muestra:** listado de tickets con prioridad, estado, mensaje y respuesta.
- **Estado real:** 0 filas, y **el ciclo de vida está truncado**: no existe interfaz para responder ni cerrar. Todos los tickets quedarán en «Abierto» para siempre, así que la columna «Estado» no tendrá varianza y «Respuesta» estará siempre vacía.
- **Y no es la fuente real de incidencias**: la historia de incidencias de la institución vive en `clientes_bloqueos.Motivo` (226 casos de daño y 101 de no devolución en producción).

### Dashboard «Uso de espacios» · **6,5 / 10**

- **Contiene:** 4 KPIs con **variación contra el periodo anterior** (`getKpisPrevious` + helper `delta()` — buena práctica que hay que reconocer): reservas completadas, satisfacción de demanda, tasa de cancelación, tasa de no-show. Heatmap de ocupación 7×24, **top 10 y bottom 10 de espacios** (sobre y subutilización en la misma pantalla — decisión de diseño acertada), reservas por categoría, tendencia de 12 semanas, y bloqueos por agenda.
- **Para quién:** director de infraestructura, coordinador de laboratorios.
- **Decisión que permite:** identificar espacios candidatos a cerrar o reasignar, y franjas saturadas.
- **Qué le falta:** (a) el KPI de cancelación es estructuralmente ~0; (b) el heatmap cuenta **reservas**, no ocupación relativa: una franja con 2 reservas en un auditorio y 2 en un cubículo se pintan igual; (c) **la ocupación de agendas multi-hora está subestimada** porque el mapa de ocupación agrupa por clave `HH:MM-HH:MM` **exacta** en lugar de por solapamiento — una reserva 08:00–10:00 no consume los slots intermedios (defecto verificado en [CitasController.php:2740](../../app/controllers/CitasController.php#L2740), afecta a 8 de 15 agendas activas); (d) sin drill-down: no se puede hacer clic en una celda del heatmap para ver las reservas.
- **Nota:** el mejor dashboard del sistema. Con denominador de capacidad y drill-down llegaría a 9.

### Dashboard «Gestión de reservas» · **5,5 / 10**

- **Contiene:** 4 KPIs con delta (total solicitudes, pendientes, no-shows, satisfacción de demanda), **embudo de conversión**, reservas por estado, **heatmap de no-show**, tendencia semanal, por área y por sede.
- **Para quién:** coordinador, jefe de servicio.
- **Qué le falta:** (a) **«Reservas por área» devuelve `Sin área` para el 100 %** — es un gráfico que ocupa espacio y no informa nada, y ya está en producción; (b) el embudo se alimenta de `getKpis`, que no ve las cancelaciones → **el embudo no tiene la fuga más importante**; (c) «Pendientes» no muestra antigüedad (un pendiente de 3 días es distinto de uno de 3 minutos); (d) no hay tiempo de aprobación ni SLA, que sí existen en WRK001 y deberían estar aquí.
- **Acción recomendada inmediata:** **retirar el gráfico «por área» hasta que la dimensión esté poblada.** Un gráfico vacío en producción daña la credibilidad del módulo entero.

### Dashboard «Inventario de activos» · **1,0 / 10**

- 4 KPIs (total, disponibles, **tasa de utilización**, valor total) y 3 gráficas por estado, tipo y sede. **Todo sobre una tabla de 0 filas.**
- Y el KPI «tasa de utilización» = `Estado=2 / (Estado 1+2)` **mide una etiqueta manual que nadie mantiene**, no uso real. Con datos, seguiría siendo engañoso. **Es el KPI más peligroso del sistema**: tiene nombre de métrica de uso y es una foto de captura manual.

### Dashboard Guacamole · **5,0 / 10**

- **Contiene:** 6 tarjetas de inventario (sesiones activas, usuarios, grupos, conexiones, grupos de conexión, perfiles) y 6 de uso dependientes del rango (sesiones, tiempo total, duración promedio, sesión más larga, usuarios distintos, conexiones usadas); 5 gráficas (actividad en el tiempo con dos series, heatmap hora × día, top conexiones, top usuarios, distribución de duración en 6 buckets) y tabla de actividad reciente. Selector de rango 7/14/30/90/Todo.
- **Lo que está bien:** `GuacHistorialStats` calcula mediana además de media, distingue sesiones activas de cerradas, construye un **eje de fechas denso** (sin él los días sin uso desaparecen y la tendencia miente) y descarta duraciones incoherentes. Es la mejor ingeniería analítica del proyecto.
- **Qué le falta y qué lo rompe:**
  1. **`guacamole_connection_history` tiene 0 filas y el servidor configurado es inalcanzable** → las 5 gráficas y las 6 tarjetas de uso renderizan vacías. **El diferenciador comercial es hoy indemostrable.**
  2. **«Top usuarios» mostrará una sola barra: `guacadmin`** — todos navegan con la cuenta de servicio.
  3. **~9–10 llamadas REST sin caché por cada carga de página**, y **se descarga el historial completo en cada visita** para filtrarlo en memoria. **Insostenible a partir de decenas de miles de sesiones: es el riesgo que arruina una demo en vivo.**
  4. **No hay concurrencia** (la métrica más pedida del módulo). Los datos lo permiten con un barrido de eventos; la función no existe.
  5. **No hay tasa de fallo de conexión** (imposible desde Guacamole, ver Parte 2) ni disponibilidad de equipos (posible con `GuacdProbe`, que está construido y sin persistir).
  6. `byHour()` y `byWeekday()` están implementados y son **código muerto**: nadie los llama.
  7. No hay estado vacío diseñado: con 0 filas se pintan ejes en blanco.
  8. Sin ninguna prueba unitaria, pese a que el servicio se declara «puro y testeable».

### Historial de conexiones remotas · **6,0 / 10**
Filtros `contains` resueltos por Guacamole + rango resuelto en PHP (**la API REST no admite filtro por fechas**), 6 chips de resumen, DataTables client-side y export **XLSX de 6 hojas** (Portada, Resumen, Detalle, Por conexión, Por usuario, Por día). Buena estructura de export. Limitado por lo mismo: sin datos, sin atribución de persona y con filtrado en memoria.

### Historial de logins de Guacamole · **2,0 / 10**
Mide logins a la webapp de Guacamole. Como Klee entra con la cuenta de servicio y **reutiliza el token cacheado 50 minutos**, esta pantalla **no mide personas ni intentos de acceso a reservas**. Es ruido operativo del administrador presentado como métrica.

### Inicio — vista operacional · **6,0 / 10**
4 KPIs del día (reservas activas hoy, **pre-reservas por aprobar**, entregas pendientes hoy, bloqueos vigentes hoy), 4 contadores de contexto, próximas reservas y 5 accesos rápidos. **Es un buen panel operativo del día**: responde «qué tengo que hacer hoy». Le falta: antigüedad del backlog de aprobación, préstamos vencidos sin devolver (la urgencia real), y estado de la cola de correo. No es un dashboard de gestión y no pretende serlo — la nota reconoce que cumple su propósito.

### Inicio — vista de activos · **2,0 / 10**
4 KPIs de estado sobre `activos` (vacía) y préstamos activos. Además **su filtro de préstamos está contaminado** por las 3 filas con `TipoReserva=''`.

### Inicio — vista técnica · **5,5 / 10**
Estado de BD, estadísticas de caché, última migración, último seeder. **Es observabilidad real y útil**, y es la única pantalla de salud del sistema. Le falta lo que más importa operativamente: estado de la cola de correo (19 correos varados y nadie lo sabe), última ejecución de cada cron, y salud de la conexión con Guacamole (`bin/guac-smoke` existe y no está cableado a ninguna pantalla).

### Hub de dashboards · **3,0 / 10**
Tres tarjetas de navegación con descripción. Correcto como índice, pero **debería ser el dashboard ejecutivo** (ver Parte 4, DB-01): es la primera pantalla que ve alguien que entra a «Analítica» y no comunica ningún número.

---

## 3.3 Tabla resumen ordenada por utilidad

| # | Artefacto | Nota | Veredicto |
|---|---|---|---|
| 1 | ACT002 Uso de Recursos | **7,5** | Conservar y ampliar. Mueve dinero |
| 2 | WRK001 Historial de Aprobaciones | **7,5** | Conservar. Parametrizar SLA y añadir backlog |
| 3 | RES003 No Asistencias | **7,0** | Conservar. **Depende de que el cron corra** |
| 4 | LAB001 Sesiones de Práctica Libre | **7,0** | Conservar. Corregir el filtro de origen |
| 5 | Dashboard Uso de espacios | **6,5** | Conservar. Falta denominador y drill-down |
| 6 | RES001 Detalle de Reservas | **6,5** | Conservar. Unificar universo |
| 7 | ADV001 Comportamiento de Usuarios | **6,5** | Conservar. Corregir cancelación |
| 8 | ESP003 Horas Pico | **6,0** | Conservar. Segmentar por canal |
| 9 | Historial de conexiones remotas | **6,0** | Conservar. Mover agregación a SQL |
| 10 | Inicio — operacional | **6,0** | Conservar. Añadir urgencias reales |
| 11 | Dashboard Gestión de reservas | **5,5** | **Retirar el gráfico «por área»** |
| 12 | Inicio — técnico | **5,5** | Ampliar a salud de crons y colas |
| 13 | Dashboard Guacamole | **5,0** | Rearquitecturar la agregación antes de escalar |
| 14 | ESP001 Ocupación de Espacios | **5,0** | **Renombrar o completar con denominador** |
| 15 | LAB002 Préstamos Inmediatos | **4,5** | Corregir filtro y `datetime`. Añadir vencidos |
| 16 | ESP004 Impacto de Bloqueos | **4,0** | Corregir el JOIN. Medir impacto real |
| 17 | ADV002 Eficiencia Operativa Global | **3,5** | **Máxima prioridad de corrección**: es el que va a comité |
| 18 | EVE001 Eventos Realizados | **3,5** | **Renombrar y fusionar** con ESP001 |
| 19 | Hub de dashboards | **3,0** | Convertir en dashboard ejecutivo |
| 20 | RES002 Cancelaciones y Rechazos | **3,0** | **Rehacer**: separa mal los tres hechos |
| 21 | Historial de logins Guacamole | **2,0** | **Ocultar** hasta que haya identidad nominal |
| 22 | Inicio — vista de activos | **2,0** | Bloquear hasta poblar `activos` |
| 23 | ADV004 Tickets de Soporte | **1,5** | Bloquear hasta que exista atención de tickets |
| 24 | ACT001 Inventario de Activos | **1,0** | Bloquear hasta poblar `activos` |
| 25 | ADV003 Auditoría de Accesos | **1,0** | Bloquear hasta activar la ingesta de logs |
| 26 | Dashboard Inventario de activos | **1,0** | Bloquear. **Y retirar el KPI «tasa de utilización»**, que engaña |

**Nota media global: 4,3 / 10.**

---

## 3.4 Los diez huecos analíticos más graves, por costo de oportunidad

| # | Hueco | Por qué cuesta caro |
|---|---|---|
| 1 | **No existe % de ocupación real** | Es la pregunta que financia la compra del sistema. Sin ella no se puede justificar ni una inversión ni un cierre de espacio |
| 2 | **La tasa de cancelación reporta cero** | Un comité decide con una cifra falsa. En producción la real fue 12,6 % |
| 3 | **No hay dimensión académica** | Sin facultad ni programa no hay conversación con decanos, y los decanos son quienes tienen presupuesto |
| 4 | **No hay uso real vs. reservado** | El desperdicio de capacidad (reservar y no usar) es el hallazgo más rentable que un sistema así puede producir, y es invisible |
| 5 | **No hay demanda insatisfecha** | Los intentos de reserva rechazados por cupo lleno, festivo o bloqueo **no se persisten en ninguna parte**. Es la métrica que justifica abrir capacidad, y no existe |
| 6 | **No hay atribución de persona en el remoto** | El KPI más vendible del diferenciador comercial (horas remotas por estudiante y programa) es imposible |
| 7 | **No hay disponibilidad de equipos** | Sin uptime, MTBF ni MTTR no se puede gestionar mantenimiento ni negociar garantías. El motor (`GuacdProbe`) está construido y sin persistir |
| 8 | **No hay backlog ni antigüedad de backlog** | Los dashboards describen el pasado; nadie ve el problema que se está formando |
| 9 | **No hay dimensión tiempo con periodo académico** | Sin ella, «comparativo por semestre» y toda comparación año contra año son imposibles. Es lo primero que pide un vicerrector |
| 10 | **No hay auditoría de datos** | 0 filas en `log_modules` → sin SCD2, sin trazabilidad de cambios de política, y sin poder explicar por qué una serie histórica cambió |

---

## 3.5 Qué debe jubilarse o fusionarse

| Acción | Artefacto | Razón |
|---|---|---|
| **Fusionar** | EVE001 → dentro de ESP001 como una hoja «Espacios de gran aforo» | «Evento» no existe como entidad; el reporte promete lo que no puede entregar |
| **Fusionar** | RES002 → dividir en dos: «Cancelaciones» (con catálogo de motivos) y «Decisiones de aprobación» (dentro de WRK001, junto a rechazos y expiraciones separados) | Hoy mezcla tres hechos distintos en un solo artefacto |
| **Renombrar** | ESP001 «Ocupación de Espacios» → «Horas reservadas por espacio» hasta que exista el denominador | El nombre miente y un director lo leerá como porcentaje |
| **Retirar de la vista** | Gráfico «Reservas por área» del dashboard de reservas | Devuelve 100 % «Sin área». Un gráfico vacío en producción daña la credibilidad del módulo |
| **Retirar el KPI** | «Tasa de utilización» del dashboard de activos | Mide una etiqueta manual y tiene nombre de métrica de uso. Es el KPI más engañoso del sistema |
| **Ocultar tras bandera** | ACT001, ADV003, ADV004, dashboard de activos, vista de activos del inicio, historial de logins Guacamole | Seis artefactos que hoy sólo pueden mostrar vacío o ruido. Mostrarlos vacíos en una demo cuesta más que no tenerlos |
| **Cablear lo ya construido** | `byHour()`, `byWeekday()` (código muerto), `guacConexiones/testJson`, `resourceDetail`/`resourceHistory`/`resourceToggleBlock` del tablero de préstamos | Cinco funcionalidades terminadas en backend y sin un solo botón. Es el trabajo analítico más barato disponible |

---

*Continúa en la [Parte 4 — Diseño de nuevos dashboards](04_DASHBOARDS.md).*
