Files
Lizandro GuarnizoandClaude Opus 5 32c209710c Documentación completa del proyecto en el módulo Soporte
21 documentos en cuatro secciones, escritos sobre el comportamiento real del
sistema —incluidos los casos que costaron diagnosticar esta semana.

Manual de usuario (visible para todos): primeros pasos, recepción, toma de
muestras, portal del enfermero y administración. Orientado a tareas concretas,
no a describir pantallas.

Documentación técnica: índice de módulos, turnero, formularios y firma digital,
WhatsApp y bot, domicilios, webhook (migrado de WEBHOOK_ENDPOINTS.md) e
inventario de endpoints.

Arquitectura: visión general, enrutamiento y registro de módulos, roles y
permisos, modelo de datos, integración con WhatsApp, y decisiones tomadas con
su deuda técnica asociada.

Operación: runbook de incidentes ordenado por síntoma, configuraciones críticas
—incluido qué vive en Meta y no en la base— y despliegue.

Se documentan explícitamente las trampas conocidas: role/role_id que hay que
mantener sincronizados, las columnas can_* que el control de acceso no lee, las
URL de plantilla que no se cambian desde el código, y las columnas históricas
que quedaron en NULL sin forma de recuperarlas.

README_DOCS.md apunta al módulo y explica cómo agregar páginas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:14:32 -05:00

105 lines
4.8 KiB
Markdown

# Módulo Turnero
El módulo más grande del sistema: 12 vistas y unos 70 endpoints. Gestiona la atención presencial completa.
## Vistas
| Vista | Para quién | Qué hace |
|---|---|---|
| `dashboard` | Admin, supervisor | Métricas del día, facturación, asistente LIA |
| `historial` | Admin, supervisor | Turnos de varios días, filtros, exportación |
| `bandeja` | Bacteriólogo, admin | Turnos del día con su detalle completo |
| `recepcion` | Recepcionista | Atención en el mostrador |
| `lugar` | Bacteriólogo | Estación de toma de muestras |
| `kiosko` | Público | El paciente saca su turno |
| `display_global` | Público | Pantalla de TV de la sala |
| `verificar_paciente` | Recepción | Consulta rápida de una ficha |
| `chat` | Recepción | Conversación de WhatsApp del turnero |
| `configuracion` | Admin | Lugares, dispositivos, plantillas, pantalla de TV |
`kiosko` y `display_global` son las **únicas rutas públicas** del sistema (`core/Router.php`): no hay quién inicie sesión en un televisor ni en el tótem de la entrada.
## Menú dinámico
`modules/turnero/module.php` no devuelve una lista fija: la arma según **el rol y la IP del equipo**.
```
recepcionista → chat, verificar paciente, TV, y su escritorio
bacteriólogo → bandeja y su estación
admin → todo
```
Si el equipo está en `turnero_dispositivos` (por IP o por cookie `turnero_token`), el usuario ve **solo su puesto**. Si no, los ve todos. Evita que alguien atienda desde el escritorio equivocado.
## Modelo de datos
```
turnero_sesiones un día de operación
└── turnero_turnos código, estado, tiempos, prioridad
├── turnero_solicitudes qué se hace y cuánto se cobró
│ ├── turnero_examen_items
│ └── turnero_muestras
├── turnero_consentimientos
└── turnero_comentarios
```
### Estados
```
espera → en_recepcion → en_espera_lugar → en_servicio → finalizado
ausente / cancelado
```
Solo `finalizado` cuenta como facturación real.
## Consentimientos
Se crean automáticamente desde **dos fuentes** que se acumulan:
| Fuente | Tabla |
|---|---|
| Por examen | `exam_tipo_consentimientos` |
| Por estación destino | `turnero_lugar_consentimientos` |
`get_consentimientos.php` los autocrea si faltan y calcula el estado de cada uno.
> En visitas de *solo entrega de muestras* no aplican los formularios por examen (no hay exámenes), pero **sí los de estación**. Por eso F-LAB-08 se exige igual.
## Tomas prolongadas
El formulario **F-LAB-28** cubre exámenes seriados. La lógica está repartida entre `ver_formulario_enviado.php` (render) y `modules/turnero/api/guardar_toma.php` (guardado).
- El esquema trae secciones para todos los exámenes posibles; se muestran solo las del examen marcado, mediante la `condicion` de cada separador.
- `_tomas_config` en `datos_respuestas` guarda qué ciclos se configuraron para ese paciente.
- Cada firma se guarda en su propio campo (`_tm00_f`, `_tm30_f`, …) junto con la hora y **la identidad de quien firmó**, resuelta en el servidor desde la sesión.
- Al firmar, el endpoint calcula cuándo toca la siguiente toma y actualiza `siguiente_toma_at`.
> La identidad se resuelve **en el servidor**, no se acepta del cliente: cada toma puede firmarla un profesional distinto y esa es la única fuente confiable. Las firmas anteriores al 3 de agosto de 2026 no tienen ese dato y no es recuperable.
## Muestras entre visitas
Una muestra que queda `pendiente` o `rechazada` reaparece cuando el paciente vuelve, con la bandera `es_pendiente_anterior` y los exámenes de la orden original.
Al recibirla, `turnero_muestras.recibida_en_turno_id` registra en qué turno se completó. Historial y bandeja usan ese dato para enlazar ambos turnos en los dos sentidos.
**El turno original no se modifica**: sigue finalizado. Solo se agrega la trazabilidad.
## LIA
`api/ai_chat.php` — asistente sobre Gemini Flash.
| Aspecto | Detalle |
|---|---|
| Contexto | Se arma en cada llamada con hasta 60 turnos del día y sus detalles |
| Historial | Los últimos intercambios se envían para que entienda preguntas de seguimiento |
| Tope de salida | `maxOutputTokens`; si Gemini corta, se avisa con `finishReason` |
| Presupuesto | `lab_config.lia_tokens_usados` contra `LIA_TOKENS_MAX` |
Se contabiliza `totalTokenCount`, que **incluye el contexto de entrada**. Como el contexto va completo en cada pregunta, el gasto por consulta es alto aunque la respuesta sea breve.
## Endpoints propios
Los del turnero usan `api/_helpers.php`, que provee `db()`, `inputJson()`, `jsonOk()`, `jsonError()`, `adminId()`, `requireTurnero()` y `notificarSSE()`.
`notificarSSE()` avisa a las pantallas conectadas para que se refresquen sin recargar.