# Modelo de datos

Las tablas están agrupadas por prefijo, y el prefijo dice a qué dominio pertenecen.

| Prefijo | Dominio |
|---|---|
| `lab_` | Laboratorio: pacientes, domicilios, órdenes, formularios, configuración |
| `turnero_` | Turnos presenciales: sesiones, turnos, solicitudes, muestras, consentimientos |
| `exam_` | Catálogo de exámenes y sus consentimientos asociados |
| `terms_` | Términos y condiciones del bot y su historial de aceptaciones |
| `admin_`, `roles`, `role_modules` | Usuarios y permisos |
| resto | Conversaciones de WhatsApp, plantillas, logs, configuración del sistema |

## Los cuatro núcleos

### Turno presencial

Es la cadena más larga del sistema. Un paciente entra al laboratorio y genera esto:

```
turnero_sesiones           una fila por día de operación
   └── turnero_turnos      el turno del paciente (código, estado, tiempos)
         ├── turnero_solicitudes    qué se le va a hacer y cuánto se cobró
         │     ├── turnero_examen_items   exámenes pedidos
         │     └── turnero_muestras       muestras a recibir
         ├── turnero_consentimientos      formularios a firmar
         └── turnero_comentarios          notas del personal
```

`turnero_turnos.estado` gobierna el flujo:

```
espera → en_recepcion → en_espera_lugar → en_servicio → finalizado
                                    ausente / cancelado
```

Solo los turnos **finalizados** cuentan como facturación real; los que están en estados intermedios se reportan aparte como "en proceso". Ausentes y cancelados no cuentan.

### Domicilio

```
lab_domicilios
   ├── lab_asignaciones      qué enfermero lo atiende
   ├── lab_domicilio_notas   seguimiento
   └── lab_domicilio_pagos   cobros
```

### Formulario firmado

Un mismo formulario (`lab_formularios`) se firma por dos vías distintas, y cada una guarda en su propia tabla:

| Vía | Tabla | Token |
|---|---|---|
| Turnero | `turnero_consentimientos` | UUID (`?token=`) |
| Domicilios y envíos sueltos | `lab_form_envios` | 64 caracteres hex (`?t=`) |

Las dos las muestra `ver_formulario_enviado.php`, que distingue por el **formato del token**. Es la razón de que existan dos parámetros distintos para lo que parece lo mismo.

La definición del formulario vive en `lab_formularios.esquema`, un JSON con la lista de campos. Las respuestas quedan en `datos_respuestas` (turnero) o `datos_cliente` (envíos), también JSON.

### Conversación de WhatsApp

```
users / conversations          el contacto y su hilo
   ├── messages                cada mensaje
   ├── terms_acceptance        aceptación de términos
   └── message_templates       plantillas aprobadas por Meta (caché local)
```

## Convenciones

- **Timestamps**: `creado_at` / `created_at` según la época en que se creó la tabla. No hay una sola convención.
- **Autor**: `creado_por` guarda `admin_users.id`. Varias tablas lo agregaron después, así que las filas viejas lo tienen en `NULL`.
- **Borrado**: casi todo es borrado físico. No hay *soft delete* generalizado.
- **JSON**: se usa bastante (`esquema`, `datos_respuestas`, `pagos_detalle`, `items_precio`). Guardado como `longtext`, no como tipo `JSON` nativo.

## Cambios de esquema

Van en `migrations/`, con nombre `AAAAMMDD_descripcion.sql`. La convención del repositorio es que sean **idempotentes** — `IF NOT EXISTS` y guardas en los `UPDATE`/`INSERT` — para poder correrlas más de una vez sin daño.

> Un cambio aplicado directo en producción sin dejar la migración correspondiente hace que un entorno nuevo no lo tenga. Si toca el esquema, deje el archivo.

## Inventario completo

{{tablas}}
