Files
whatsapp/database/README.md
2026-03-10 18:42:51 -05:00

659 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Base de datos — `usite_whatsapp_bot`
Documentación de las 34 tablas del sistema WhatsApp Bot + Panel Laboratorio Ximena.
Motor: **MariaDB / MySQL 8.x** — Charset: `utf8mb4` — Collation: `utf8mb4_unicode_ci`
---
## Índice rápido
| # | Tabla | Filas (prod) | Dominio |
|---|-------|-------------|---------|
| 1 | [admin\_users](#1-admin_users) | 4 | Autenticación |
| 2 | [autoresponses](#2-autoresponses) | 6 | Bot WhatsApp |
| 3 | [conversations](#3-conversations) | 3 490 | Bot WhatsApp |
| 4 | [file\_request\_uploads](#4-file_request_uploads) | 0 | Solicitud archivos |
| 5 | [file\_requests](#5-file_requests) | 0 | Solicitud archivos |
| 6 | [lab\_actividad\_admin](#6-lab_actividad_admin) | 43 | Auditoría |
| 7 | [lab\_asignaciones](#7-lab_asignaciones) | 4 | Laboratorio |
| 8 | [lab\_autorizaciones](#8-lab_autorizaciones) | 0 | Laboratorio |
| 9 | [lab\_config](#9-lab_config) | 9 | Laboratorio |
| 10 | [lab\_domicilios](#10-lab_domicilios) | 9 | Laboratorio |
| 11 | [lab\_enfermeras](#11-lab_enfermeras) | 1 | Laboratorio |
| 12 | [lab\_form\_envios](#12-lab_form_envios) | 15 | Formularios |
| 13 | [lab\_formularios](#13-lab_formularios) | 3 | Formularios |
| 14 | [lab\_ordenes\_medicas](#14-lab_ordenes_medicas) | 0 | Laboratorio |
| 15 | [lab\_pacientes](#15-lab_pacientes) | 3 | Laboratorio |
| 16 | [lab\_servicios\_extra](#16-lab_servicios_extra) | 0 | Laboratorio |
| 17 | [media\_files](#17-media_files) | 231 | Multimedia |
| 18 | [media\_queue](#18-media_queue) | 7 | Multimedia |
| 19 | [menu\_options](#19-menu_options) | 13 | Bot WhatsApp |
| 20 | [menus](#20-menus) | 2 | Bot WhatsApp |
| 21 | [message\_templates](#21-message_templates) | 2 | Bot WhatsApp |
| 22 | [migrations](#22-migrations) | 4 | Sistema |
| 23 | [notifications](#23-notifications) | 2 073 | Sistema |
| 24 | [operator\_activity](#24-operator_activity) | 227 | Operadores |
| 25 | [role\_modules](#25-role_modules) | 12 | Control de acceso |
| 26 | [roles](#26-roles) | 2 | Control de acceso |
| 27 | [scheduled\_messages](#27-scheduled_messages) | — | Mensajes prog. |
| 28 | [scheduled\_messages\_view](#28-scheduled_messages_view-vista) | — | Vista |
| 29 | [survey\_responses](#29-survey_responses) | 10 | Bot WhatsApp |
| 30 | [system\_config](#30-system_config) | 16 | Configuración |
| 31 | [system\_logs](#31-system_logs) | 0 | Sistema |
| 32 | [terms\_acceptance](#32-terms_acceptance) | 0 | T&C |
| 33 | [terms\_versions](#33-terms_versions) | 2 | T&C |
| 34 | [user\_states](#34-user_states) | 108 | Bot WhatsApp |
| 35 | [users](#35-users) | 3 090 | Usuarios |
| 36 | [webhook\_logs](#36-webhook_logs) | 9 850 | Sistema |
---
## Autenticación
### 1. `admin_users`
Administradores del panel web.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `username` | VARCHAR(50) UNIQUE | Login |
| `password` | VARCHAR(255) | bcrypt |
| `role_id` | INT FK→roles | Rol asignado (NULL = admin clásico) |
| `email` | VARCHAR(100) | |
| `nombre` | VARCHAR(100) | Nombre completo |
| `is_active` | TINYINT(1) | 1 = activo |
| `last_login` | DATETIME | |
| `created_at` | TIMESTAMP | |
**Relaciones:** `role_id``roles.id`
---
## Bot WhatsApp
### 2. `autoresponses`
Respuestas automáticas del bot ante palabras clave.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `keyword` | VARCHAR(100) | Palabra/frase que activa la respuesta |
| `response` | TEXT | Texto de respuesta |
| `is_active` | TINYINT(1) | |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 3. `conversations`
Hilo de mensajes WhatsApp por número de teléfono.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number` | VARCHAR(20) | Número del usuario |
| `contact_name` | VARCHAR(100) | Nombre de WhatsApp |
| `messages` | LONGTEXT (JSON) | Array de mensajes |
| `last_message` | TEXT | Extracto del último mensaje |
| `last_message_at` | DATETIME | |
| `unread_count` | INT | Mensajes no leídos por operador |
| `status` | ENUM | `active`, `archived`, `blocked` |
| `assigned_to` | INT FK→admin_users | Operador asignado |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 4. `file_request_uploads`
Archivos subidos en respuesta a solicitudes.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `request_id` | INT FK→file_requests | |
| `file_path` | VARCHAR(500) | Ruta en servidor |
| `file_type` | VARCHAR(50) | MIME |
| `uploaded_at` | DATETIME | |
---
### 5. `file_requests`
Solicitudes de documentos enviadas por WhatsApp.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number` | VARCHAR(20) | |
| `request_type` | VARCHAR(50) | Tipo de documento solicitado |
| `status` | ENUM | `pending`, `fulfilled`, `expired` |
| `expires_at` | DATETIME | |
| `created_at` | TIMESTAMP | |
---
### 19. `menu_options`
Opciones de submenú del bot (hijos de `menus`).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `menu_id` | INT FK→menus | |
| `option_number` | INT | Tecla que selecciona el usuario |
| `option_text` | VARCHAR(200) | Texto visible |
| `action_type` | VARCHAR(50) | `submenu`, `message`, `url`, `form_link` |
| `action_value` | TEXT | Valor de la acción |
| `is_active` | TINYINT(1) | |
| `sort_order` | INT | |
---
### 20. `menus`
Menús raíz del bot por número de teléfono de negocio.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number_id` | VARCHAR(50) | ID de WhatsApp Business |
| `menu_text` | TEXT | Texto del menú principal |
| `is_active` | TINYINT(1) | |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 21. `message_templates`
Plantillas de mensajes aprobadas por Meta.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `name` | VARCHAR(100) | Nombre interno |
| `display_name` | VARCHAR(150) | Nombre legible |
| `category` | VARCHAR(50) | `MARKETING`, `UTILITY`, `AUTHENTICATION` |
| `language` | VARCHAR(10) | `es`, `en`, etc. |
| `status` | VARCHAR(30) | `APPROVED`, `PENDING`, `REJECTED` |
| `header_type` | VARCHAR(20) | `TEXT`, `IMAGE`, `DOCUMENT`, `NONE` |
| `header_text` | VARCHAR(500) | |
| `body_text` | TEXT | Cuerpo de la plantilla |
| `footer_text` | VARCHAR(300) | |
| `buttons` | LONGTEXT (JSON) | Botones quick-reply / CTA |
| `variables_count` | INT | Número de `{{n}}` en body |
| `meta_template_id` | VARCHAR(50) | ID en Meta Graph API |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 29. `survey_responses`
Respuestas a encuestas del bot.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number` | VARCHAR(20) | |
| `survey_id` | INT | Identificador de encuesta |
| `question_key` | VARCHAR(100) | |
| `answer` | TEXT | |
| `created_at` | TIMESTAMP | |
---
### 34. `user_states`
Estado de conversación del bot por usuario (máquina de estados).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number` | VARCHAR(20) UNIQUE | |
| `state` | VARCHAR(100) | Estado actual del flujo del bot |
| `context` | LONGTEXT (JSON) | Datos contextuales del estado |
| `updated_at` | DATETIME | |
---
## Laboratorio
### 6. `lab_actividad_admin`
Log de acciones de administradores en el laboratorio.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `admin_id` | INT FK→admin_users | |
| `accion` | VARCHAR(100) | Descripción de la acción |
| `entidad` | VARCHAR(50) | Tabla/módulo afectado |
| `entidad_id` | INT | ID del registro afectado |
| `datos_extra` | TEXT (JSON) | Detalles adicionales |
| `ip` | VARCHAR(45) | |
| `created_at` | TIMESTAMP | |
---
### 7. `lab_asignaciones`
Asignaciones de servicios domiciliarios a enfermeras.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `domicilio_id` | INT FK→lab_domicilios | |
| `enfermera_id` | INT FK→lab_enfermeras | |
| `estado` | ENUM | `pendiente`, `aceptado`, `rechazado`, `completado` |
| `fecha_asignacion` | DATETIME | |
| `fecha_respuesta` | DATETIME | |
| `notas` | TEXT | |
---
### 8. `lab_autorizaciones`
Autorizaciones médicas/seguros para servicios del laboratorio.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `paciente_id` | INT FK→lab_pacientes | |
| `tipo` | VARCHAR(50) | Tipo de autorización |
| `numero_autorizacion` | VARCHAR(100) | |
| `aseguradora` | VARCHAR(100) | |
| `fecha_vencimiento` | DATE | |
| `estado` | ENUM | `vigente`, `vencida` |
| `created_at` | TIMESTAMP | |
---
### 9. `lab_config`
Configuración específica del módulo de laboratorio (clavevalor).
| Columna | Tipo | Notas |
|---------|------|-------|
| `clave` | VARCHAR(80) PK | Nombre de la configuración |
| `valor` | LONGTEXT | Valor |
| `updated_at` | TIMESTAMP | |
Ejemplos de claves: `empresa_nombre`, `empresa_nit`, `empresa_direccion`, `empresa_telefono`, `empresa_email`, `empresa_ciudad`, etc.
---
### 10. `lab_domicilios`
Solicitudes de servicio domiciliario de laboratorio.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `paciente_id` | INT FK→lab_pacientes | |
| `fecha_solicitud` | DATE | |
| `hora_solicitud` | TIME | |
| `direccion` | VARCHAR(300) | |
| `ciudad` | VARCHAR(100) | |
| `estado` | ENUM | `pendiente`, `asignado`, `en_camino`, `completado`, `cancelado` |
| `observaciones` | TEXT | |
| `examen_solicitado` | TEXT | |
| `creado_por` | INT FK→admin_users | |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 11. `lab_enfermeras`
Enfermeras/profesionales de campo del laboratorio.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `nombre` | VARCHAR(150) | |
| `telefono` | VARCHAR(20) | |
| `email` | VARCHAR(100) | |
| `phone_number_wa` | VARCHAR(20) | Número WhatsApp para notificaciones |
| `is_active` | TINYINT(1) | |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 12. `lab_form_envios`
Instancias de formularios enviados/completados por pacientes.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `formulario_id` | INT FK→lab_formularios | |
| `paciente_id` | INT FK→lab_pacientes | |
| `phone_number` | VARCHAR(20) | |
| `datos_json` | LONGTEXT (JSON) | Respuestas del formulario |
| `firma_base64` | LONGTEXT | Firma digital en Base64 |
| `pdf_path` | VARCHAR(500) | Ruta del PDF generado |
| `hash_verificacion` | CHAR(64) | SHA-256 del PDF para integridad |
| `estado` | ENUM | `borrador`, `enviado`, `procesado` |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 13. `lab_formularios`
Definición de formularios médicos configurables.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `nombre` | VARCHAR(150) | |
| `descripcion` | TEXT | |
| `categoria` | ENUM | `consentimiento`, `historia_clinica`, `autorizacion`, `encuesta`, `otro` |
| `esquema` | LONGTEXT (JSON) | Definición de campos del formulario |
| `permite_firma` | TINYINT(1) | |
| `requiere_firma` | TINYINT(1) | |
| `version` | SMALLINT | |
| `is_active` | TINYINT(1) | |
| `doc_encabezado` | VARCHAR(200) | Título en PDF |
| `doc_subtitulo` | VARCHAR(200) | Subtítulo en PDF |
| `doc_logo_base64` | LONGTEXT | Logo en Base64 para PDF |
| `doc_color` | VARCHAR(20) | Color principal HEX para PDF |
| `doc_pie_pagina` | VARCHAR(500) | Pie de página del PDF |
| `creado_por` | INT FK→admin_users | |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 14. `lab_ordenes_medicas`
Órdenes médicas digitalizadas vinculadas a pacientes.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `paciente_id` | INT FK→lab_pacientes | |
| `medico` | VARCHAR(150) | |
| `especialidad` | VARCHAR(100) | |
| `fecha_orden` | DATE | |
| `examenes` | TEXT | Exámenes ordenados |
| `archivo_path` | VARCHAR(500) | Imagen/PDF de la orden |
| `estado` | ENUM | `pendiente`, `procesada`, `vigente`, `vencida` |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 15. `lab_pacientes`
Pacientes registrados en el laboratorio.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `nombre` | VARCHAR(150) | |
| `documento` | VARCHAR(30) | Cédula / NIT |
| `tipo_documento` | VARCHAR(20) | CC, TI, CE, PA, NIT |
| `fecha_nacimiento` | DATE | |
| `telefono` | VARCHAR(20) | |
| `email` | VARCHAR(100) | |
| `direccion` | VARCHAR(300) | |
| `eps` | VARCHAR(100) | Aseguradora de salud |
| `phone_number_wa` | VARCHAR(20) | Número WhatsApp → `users.phone_number` |
| `created_at` / `updated_at` | TIMESTAMP | |
---
### 16. `lab_servicios_extra`
Servicios adicionales configurables del laboratorio (transporte, procesamiento especial, etc.).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `nombre` | VARCHAR(100) | |
| `descripcion` | TEXT | |
| `precio` | DECIMAL(10,2) | |
| `is_active` | TINYINT(1) | |
| `created_at` | TIMESTAMP | |
---
## Multimedia
### 17. `media_files`
Archivos multimedia subidos o recibidos por WhatsApp.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `media_id` | VARCHAR(100) | ID en la API de WhatsApp |
| `file_name` | VARCHAR(255) | |
| `file_path` | VARCHAR(500) | Ruta local |
| `file_size` | BIGINT | Bytes |
| `mime_type` | VARCHAR(100) | |
| `phone_number` | VARCHAR(20) | Remitente o destinatario |
| `direction` | ENUM | `incoming`, `outgoing` |
| `created_at` | TIMESTAMP | |
---
### 18. `media_queue`
Cola de transmisión de archivos multimedia grandes.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `media_file_id` | INT FK→media_files | |
| `status` | ENUM | `pending`, `processing`, `done`, `failed` |
| `attempts` | INT | Reintentos |
| `error_message` | TEXT | |
| `created_at` / `updated_at` | TIMESTAMP | |
---
## Mensajes Programados
### 27. `scheduled_messages`
Mensajes de WhatsApp programados para envío futuro.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `user_id` | INT FK→users | Destinatario |
| `template_id` | INT FK→message_templates | Plantilla a usar |
| `template_name` | VARCHAR(100) | Nombre snapshot de la plantilla |
| `template_language` | VARCHAR(10) | `es`, `en` |
| `template_parameters` | LONGTEXT (JSON) | Variables `{{n}}` |
| `message_type` | ENUM | `template`, `text` |
| `message_content` | TEXT | Mensaje libre (si type=text) |
| `scheduled_date` | DATE | Fecha de envío |
| `scheduled_time` | TIME | Hora de envío |
| `status` | ENUM | `pending`, `sent`, `failed`, `cancelled` |
| `sent_at` | DATETIME | |
| `error_message` | TEXT | |
| `created_by` | INT FK→admin_users | Admin que creó el recordatorio |
| `created_at` / `updated_at` | DATETIME | |
---
### 28. `scheduled_messages_view` (VISTA)
Enriquece `scheduled_messages` con datos del usuario, plantilla y nombre del admin.
Columnas adicionales: `user_name`, `phone_number`, `template_display_name`, `template_body`, `template_status`.
---
## Control de Acceso
### 25. `role_modules`
Asociación entre roles y módulos del sistema (permisos).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `role_id` | INT FK→roles | |
| `module_slug` | VARCHAR(100) | Clave del módulo (ej. `lab`, `bot`, `config`) |
---
### 26. `roles`
Roles del sistema para control de acceso basado en roles (RBAC).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `name` | VARCHAR(100) | Nombre legible |
| `slug` | VARCHAR(50) UNIQUE | Clave interna (`admin`, `enfermero`) |
| `description` | TEXT | |
| `color` | VARCHAR(20) | Color HEX para UI |
| `is_system` | TINYINT(1) | 1 = no eliminable |
| `created_at` / `updated_at` | TIMESTAMP | |
Roles de sistema predefinidos: `admin` (id=1), `enfermero` (id=2).
---
## Términos y Condiciones (T&C)
### 32. `terms_acceptance`
Registro de aceptaciones/rechazos de T&C por usuario.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number` | VARCHAR(20) | |
| `version_id` | INT FK→terms_versions | Versión enviada |
| `estado` | ENUM | `pendiente`, `aceptado`, `rechazado` |
| `fecha_envio` | DATETIME | Cuándo se enviaron los T&C |
| `fecha_respuesta` | DATETIME | Cuándo respondió el usuario |
| `ip_origem` | VARCHAR(45) | IP de origen (si aplica) |
---
### 33. `terms_versions`
Versiones publicadas de los Términos y Condiciones.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `version` | VARCHAR(20) | Ej. `v1.0` |
| `titulo` | VARCHAR(200) | |
| `mensaje_bot` | TEXT | Texto enviado por WhatsApp |
| `mensaje_rechazo` | TEXT | Texto si el usuario rechaza |
| `pdf_url` | VARCHAR(500) | URL pública del PDF |
| `pdf_path` | VARCHAR(500) | Ruta local del archivo |
| `es_activa` | TINYINT(1) | Solo una activa a la vez |
| `forzar_reenvio` | TINYINT(1) | 1 = todos deben re-aceptar |
| `created_at` | TIMESTAMP | |
| `created_by` | INT FK→admin_users | |
---
## Configuración y Sistema
### 22. `migrations`
Registro de migraciones de BD aplicadas.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `name` | VARCHAR(255) | Nombre del archivo de migración |
| `applied_at` | TIMESTAMP | |
Migraciones aplicadas: `01_initial.sql`, `02_…`, `03_…`, `05_terms_acceptance.sql`, `06_master_sync.sql`.
---
### 23. `notifications`
Notificaciones del sistema enviadas a admins.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `admin_id` | INT FK→admin_users | NULL = broadcast |
| `type` | VARCHAR(50) | `new_message`, `assignment`, `system` |
| `title` | VARCHAR(200) | |
| `body` | TEXT | |
| `is_read` | TINYINT(1) | |
| `created_at` | TIMESTAMP | |
---
### 24. `operator_activity`
Actividad reciente de operadores (mensajes enviados, conversaciones gestionadas).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `admin_id` | INT FK→admin_users | |
| `action` | VARCHAR(100) | `send_message`, `view_conversation`, etc. |
| `phone_number` | VARCHAR(20) | Número implicado |
| `details` | TEXT (JSON) | |
| `created_at` | TIMESTAMP | |
---
### 30. `system_config`
Configuración global del sistema (clavevalor).
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `config_key` | VARCHAR(100) UNIQUE | |
| `config_value` | TEXT | |
| `description` | VARCHAR(255) | |
| `updated_at` | TIMESTAMP | |
Claves principales: `whatsapp_token`, `whatsapp_phone_number_id`, `whatsapp_verify_token`, `bot_enabled`, `welcome_message`, `terms_message`, `terms_rejection_message`, `terms_pdf_url`, `terms_version`, `terms_force_resend`.
---
### 31. `system_logs`
Logs de errores y eventos del sistema.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `level` | ENUM | `info`, `warning`, `error`, `critical` |
| `message` | TEXT | |
| `context` | LONGTEXT (JSON) | Stack trace, datos extra |
| `created_at` | TIMESTAMP | |
---
### 36. `webhook_logs`
Log de todos los webhooks entrantes de WhatsApp.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `payload` | LONGTEXT (JSON) | Payload completo recibido |
| `event_type` | VARCHAR(50) | `message`, `status`, `read` |
| `phone_number` | VARCHAR(20) | |
| `processed` | TINYINT(1) | |
| `error` | TEXT | Error si falló el procesamiento |
| `created_at` | TIMESTAMP | |
---
## Usuarios
### 35. `users`
Usuarios de WhatsApp que han interactuado con el bot.
| Columna | Tipo | Notas |
|---------|------|-------|
| `id` | INT PK | |
| `phone_number` | VARCHAR(20) UNIQUE | Número de WhatsApp |
| `name` | VARCHAR(100) | Nombre de contacto en WhatsApp |
| `is_blocked` | TINYINT(1) | 1 = bloqueado |
| `bot_enabled` | TINYINT(1) | 1 = bot activo para este usuario |
| `last_interaction` | DATETIME | |
| `terms_pending` | TINYINT(1) | 1 = aún no aceptó T&C |
| `terms_accepted_at` | DATETIME | Fecha de aceptación |
| `terms_version_id` | INT FK→terms_versions | Versión aceptada |
| `created_at` / `updated_at` | TIMESTAMP | |
---
## Diagrama ER simplificado
```
users ──────────────────────────────────┐
│ 1:N terms_acceptance │
│ 1:N scheduled_messages │
│ 1:N conversations │ user_states (1:1 phone_number)
│ │
admin_users ─────── roles ──── role_modules
│ 1:N lab_actividad_admin
│ 1:N lab_domicilios ──── lab_asignaciones ── lab_enfermeras
│ 1:N lab_form_envios ── lab_formularios
│ 1:N lab_ordenes_medicas ── lab_pacientes ── lab_autorizaciones
│ 1:N terms_versions (created_by)
menus ─── menu_options
message_templates ─── scheduled_messages
media_files ─── media_queue
```
---
*Última actualización: generado automáticamente desde comparación local/prod — ver `database/06_master_sync.sql`*