up
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
-- ============================================================
|
||||
-- Migration: 04_add_domicilio_cobro_fields
|
||||
-- Agrega campos de seguro, autorización y cobro a lab_domicilios
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE `lab_domicilios`
|
||||
ADD COLUMN IF NOT EXISTS `seguro_nombre` VARCHAR(150) DEFAULT NULL
|
||||
COMMENT 'Nombre del seguro cuando tipo_cliente = seguro'
|
||||
AFTER `tipo_cliente`,
|
||||
|
||||
ADD COLUMN IF NOT EXISTS `autorizacion` VARCHAR(100) DEFAULT NULL
|
||||
COMMENT 'Número de autorización del seguro'
|
||||
AFTER `seguro_nombre`,
|
||||
|
||||
ADD COLUMN IF NOT EXISTS `copago_laboratorio` DECIMAL(12,2) DEFAULT NULL
|
||||
COMMENT 'Copago que asume el laboratorio'
|
||||
AFTER `autorizacion`,
|
||||
|
||||
ADD COLUMN IF NOT EXISTS `valor_domicilio` DECIMAL(12,2) DEFAULT NULL
|
||||
COMMENT 'Valor a cobrar al cliente por el domicilio'
|
||||
AFTER `copago_laboratorio`,
|
||||
|
||||
ADD COLUMN IF NOT EXISTS `valor_copago` DECIMAL(12,2) DEFAULT NULL
|
||||
COMMENT 'Valor del copago a cobrar al cliente'
|
||||
AFTER `valor_domicilio`;
|
||||
|
||||
-- Actualizar ENUM tipo_cliente para quitar eps y dejar solo particular/seguro
|
||||
ALTER TABLE `lab_domicilios`
|
||||
MODIFY COLUMN `tipo_cliente` ENUM('particular','seguro') NOT NULL DEFAULT 'particular'
|
||||
COMMENT 'Si el servicio es particular o por seguro';
|
||||
@@ -0,0 +1,49 @@
|
||||
-- ============================================================
|
||||
-- Migration: 05_terms_acceptance
|
||||
-- Sistema de aceptación de términos y condiciones
|
||||
-- ============================================================
|
||||
|
||||
-- Tabla de versiones de términos (cada vez que cambia el documento)
|
||||
CREATE TABLE IF NOT EXISTS `terms_versions` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`version` VARCHAR(50) NOT NULL COMMENT 'Ej: 1.0, 2.0, 2026-03',
|
||||
`documento_url` VARCHAR(500) DEFAULT NULL COMMENT 'URL pública del documento PDF',
|
||||
`documento_nombre` VARCHAR(255) DEFAULT NULL COMMENT 'Nombre original del archivo',
|
||||
`mensaje_aceptacion` TEXT NOT NULL COMMENT 'Mensaje que se envía al usuario para aceptar',
|
||||
`mensaje_rechazo` TEXT NOT NULL COMMENT 'Mensaje que se envía si el usuario rechaza',
|
||||
`forzar_reenvio` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 = reenviar a todos los usuarios aunque ya aceptaron',
|
||||
`activa` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1 = es la versión vigente',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_activa` (`activa`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Tabla de aceptaciones de usuarios
|
||||
CREATE TABLE IF NOT EXISTS `terms_acceptance` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` INT(11) NOT NULL COMMENT 'FK a users.id',
|
||||
`terms_version_id` INT(11) NOT NULL COMMENT 'FK a terms_versions.id',
|
||||
`phone_number` VARCHAR(20) NOT NULL COMMENT 'Copia desnormalizada para auditoría',
|
||||
`estado` ENUM('pendiente','aceptado','rechazado') NOT NULL DEFAULT 'pendiente',
|
||||
`fecha_envio` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Cuando se envió el mensaje de términos',
|
||||
`fecha_respuesta` TIMESTAMP NULL DEFAULT NULL COMMENT 'Cuando el usuario respondió',
|
||||
`ip_referencia` VARCHAR(45) DEFAULT NULL COMMENT 'IP del webhook si disponible',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_version` (`user_id`, `terms_version_id`),
|
||||
KEY `idx_estado` (`estado`),
|
||||
KEY `idx_phone` (`phone_number`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Columna en users para saber si está esperando respuesta de términos
|
||||
ALTER TABLE `users`
|
||||
ADD COLUMN IF NOT EXISTS `terms_pending` TINYINT(1) NOT NULL DEFAULT 0
|
||||
COMMENT '1 = se enviaron términos y se espera respuesta'
|
||||
AFTER `welcome_sent_at`,
|
||||
ADD COLUMN IF NOT EXISTS `terms_accepted_at` TIMESTAMP NULL DEFAULT NULL
|
||||
COMMENT 'Última vez que aceptó los términos vigentes'
|
||||
AFTER `terms_pending`,
|
||||
ADD COLUMN IF NOT EXISTS `terms_version_id` INT(11) NULL DEFAULT NULL
|
||||
COMMENT 'Versión de términos que aceptó'
|
||||
AFTER `terms_accepted_at`;
|
||||
@@ -0,0 +1,204 @@
|
||||
-- =============================================================================
|
||||
-- 06_master_sync.sql
|
||||
-- Migración maestra de sincronización local ↔ producción
|
||||
-- Generada: 2025-01-01
|
||||
--
|
||||
-- INSTRUCCIONES DE APLICACIÓN:
|
||||
-- LOCAL (Docker MySQL):
|
||||
-- docker exec whatsapp-dev-mysql mysql -uroot -proot_password_2026 \
|
||||
-- usite_whatsapp_bot < database/06_master_sync.sql
|
||||
--
|
||||
-- PRODUCCIÓN (desde el contenedor app):
|
||||
-- - Aplica SOLO las secciones marcadas [SOLO PROD] si prod ya las tiene,
|
||||
-- o la migración completa en instalaciones nuevas.
|
||||
--
|
||||
-- GARANTÍA DE SEGURIDAD:
|
||||
-- Este script es COMPLETAMENTE NO DESTRUCTIVO. No contiene DROP TABLE,
|
||||
-- TRUNCATE, DELETE ni UPDATE. Todas las operaciones usan IF NOT EXISTS o
|
||||
-- INSERT IGNORE, por lo que correrlo en un servidor con datos existentes
|
||||
-- solo creará lo que falte sin modificar ni eliminar nada.
|
||||
--
|
||||
-- RESUMEN DE CAMBIOS:
|
||||
-- A) Tablas solo en LOCAL → agregar a producción y futuras instalaciones:
|
||||
-- - scheduled_messages
|
||||
-- - scheduled_messages_view (VIEW)
|
||||
-- B) Tablas solo en PROD → agregar a local y futuras instalaciones:
|
||||
-- - roles
|
||||
-- - role_modules
|
||||
-- - lab_config
|
||||
-- C) Columnas en PROD que faltan en LOCAL y futuras instalaciones:
|
||||
-- - admin_users.role_id
|
||||
-- - lab_form_envios.hash_verificacion
|
||||
-- - lab_formularios.doc_encabezado, doc_subtitulo, doc_logo_base64,
|
||||
-- doc_color, doc_pie_pagina
|
||||
-- D) Ya cubierto en 05_terms_acceptance.sql (no se repite):
|
||||
-- - terms_versions, terms_acceptance
|
||||
-- - users.terms_pending, terms_accepted_at, terms_version_id
|
||||
-- =============================================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET foreign_key_checks = 0;
|
||||
|
||||
-- =============================================================================
|
||||
-- C0) COLUMNAS: message_templates (guard por si 02 no aplicó completo)
|
||||
-- =============================================================================
|
||||
ALTER TABLE `message_templates`
|
||||
ADD COLUMN IF NOT EXISTS `body_text` TEXT DEFAULT NULL COMMENT 'Texto del cuerpo con variables {{1}},{{2}}…',
|
||||
ADD COLUMN IF NOT EXISTS `components` LONGTEXT DEFAULT NULL COMMENT 'Componentes JSON completos de la plantilla',
|
||||
ADD COLUMN IF NOT EXISTS `example_parameters` LONGTEXT DEFAULT NULL COMMENT 'Ejemplos de valores para los parámetros',
|
||||
ADD COLUMN IF NOT EXISTS `header_text` VARCHAR(255) DEFAULT NULL COMMENT 'Texto del header',
|
||||
ADD COLUMN IF NOT EXISTS `header_type` ENUM('text','image','video','document') DEFAULT NULL COMMENT 'Tipo de header',
|
||||
ADD COLUMN IF NOT EXISTS `footer_text` VARCHAR(255) DEFAULT NULL COMMENT 'Texto del footer',
|
||||
ADD COLUMN IF NOT EXISTS `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
|
||||
|
||||
ALTER TABLE `message_templates`
|
||||
ADD INDEX IF NOT EXISTS `idx_template_language` (`template_name`, `language_code`);
|
||||
|
||||
-- =============================================================================
|
||||
-- A1) TABLA: scheduled_messages (local → prod / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
CREATE TABLE IF NOT EXISTS `scheduled_messages` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`template_id` int(11) DEFAULT NULL,
|
||||
`template_name` varchar(100) DEFAULT NULL,
|
||||
`template_language` varchar(10) DEFAULT 'es',
|
||||
`template_parameters` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL
|
||||
COMMENT 'Parámetros para las variables de la plantilla'
|
||||
CHECK (json_valid(`template_parameters`)),
|
||||
`message_type` enum('text','template') DEFAULT 'template',
|
||||
`message_content` text DEFAULT NULL COMMENT 'Contenido del mensaje si es tipo text',
|
||||
`scheduled_date` date NOT NULL,
|
||||
`scheduled_time` time NOT NULL,
|
||||
`status` enum('pending','sent','failed','cancelled') DEFAULT 'pending',
|
||||
`sent_at` datetime DEFAULT NULL,
|
||||
`error_message` text DEFAULT NULL,
|
||||
`created_by` int(11) DEFAULT NULL COMMENT 'ID del admin que creó el recordatorio',
|
||||
`created_at` datetime DEFAULT current_timestamp(),
|
||||
`updated_at` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_scheduled_date` (`scheduled_date`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_scheduled_datetime` (`scheduled_date`,`scheduled_time`,`status`),
|
||||
CONSTRAINT `scheduled_messages_ibfk_1`
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- =============================================================================
|
||||
-- A2) VISTA: scheduled_messages_view (local → prod / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
CREATE OR REPLACE VIEW `scheduled_messages_view` AS
|
||||
SELECT
|
||||
`sm`.`id`,
|
||||
`sm`.`user_id`,
|
||||
`sm`.`template_id`,
|
||||
`sm`.`template_name`,
|
||||
`sm`.`template_language`,
|
||||
`sm`.`template_parameters`,
|
||||
`sm`.`message_type`,
|
||||
`sm`.`message_content`,
|
||||
`sm`.`scheduled_date`,
|
||||
`sm`.`scheduled_time`,
|
||||
`sm`.`status`,
|
||||
`sm`.`sent_at`,
|
||||
`sm`.`error_message`,
|
||||
`sm`.`created_by`,
|
||||
`sm`.`created_at`,
|
||||
`sm`.`updated_at`,
|
||||
`u`.`name` AS `user_name`,
|
||||
`u`.`phone_number` AS `phone_number`,
|
||||
`mt`.`name` AS `template_display_name`,
|
||||
`mt`.`body_text` AS `template_body`,
|
||||
`mt`.`status` AS `template_status`
|
||||
FROM `scheduled_messages` `sm`
|
||||
LEFT JOIN `users` `u` ON `sm`.`user_id` = `u`.`id`
|
||||
LEFT JOIN `message_templates` `mt` ON `sm`.`template_id` = `mt`.`id`
|
||||
ORDER BY `sm`.`scheduled_date` DESC, `sm`.`scheduled_time` DESC;
|
||||
|
||||
-- =============================================================================
|
||||
-- B1) TABLA: roles (prod → local / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
CREATE TABLE IF NOT EXISTS `roles` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(100) NOT NULL COMMENT 'Nombre legible del rol',
|
||||
`slug` varchar(50) NOT NULL COMMENT 'Clave interna (enfermero, admin, …)',
|
||||
`description` text DEFAULT NULL,
|
||||
`color` varchar(20) DEFAULT '#6c757d' COMMENT 'Color HEX para la UI',
|
||||
`is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '1 = no se puede eliminar',
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_slug` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Datos semilla mínimos de roles del sistema
|
||||
INSERT IGNORE INTO `roles` (`id`, `name`, `slug`, `description`, `is_system`) VALUES
|
||||
(1, 'Administrador', 'admin', 'Acceso completo al sistema', 1),
|
||||
(2, 'Enfermero', 'enfermero', 'Acceso a módulos de laboratorio y atención', 1);
|
||||
|
||||
-- =============================================================================
|
||||
-- B2) TABLA: role_modules (prod → local / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
CREATE TABLE IF NOT EXISTS `role_modules` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`role_id` int(11) NOT NULL,
|
||||
`module_slug` varchar(100) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_role_module` (`role_id`, `module_slug`),
|
||||
CONSTRAINT `fk_rm_role`
|
||||
FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- =============================================================================
|
||||
-- B3) TABLA: lab_config (prod → local / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
CREATE TABLE IF NOT EXISTS `lab_config` (
|
||||
`clave` varchar(80) NOT NULL,
|
||||
`valor` longtext NOT NULL DEFAULT '',
|
||||
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`clave`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- =============================================================================
|
||||
-- C1) COLUMNA: admin_users.role_id (prod → local / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
ALTER TABLE `admin_users`
|
||||
ADD COLUMN IF NOT EXISTS `role_id` int(11) DEFAULT NULL AFTER `password`;
|
||||
|
||||
-- C1a) FK opcional: se añade solo si no existe ya
|
||||
-- (MariaDB/MySQL 10.x: ADD CONSTRAINT IF NOT EXISTS no es estándar,
|
||||
-- se ignora el error si ya existe usando INSERT IGNORE pattern)
|
||||
ALTER TABLE `admin_users`
|
||||
ADD CONSTRAINT IF NOT EXISTS `fk_admin_role`
|
||||
FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`)
|
||||
ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- =============================================================================
|
||||
-- C2) COLUMNA: lab_form_envios.hash_verificacion (prod → local)
|
||||
-- =============================================================================
|
||||
ALTER TABLE `lab_form_envios`
|
||||
ADD COLUMN IF NOT EXISTS `hash_verificacion` char(64) DEFAULT NULL
|
||||
COMMENT 'SHA-256 del PDF generado, para verificación de integridad'
|
||||
AFTER `pdf_path`;
|
||||
|
||||
-- =============================================================================
|
||||
-- C3) COLUMNAS: lab_formularios doc_* (prod → local / instalaciones nuevas)
|
||||
-- =============================================================================
|
||||
ALTER TABLE `lab_formularios`
|
||||
ADD COLUMN IF NOT EXISTS `doc_encabezado` varchar(200) DEFAULT NULL COMMENT 'Título principal del documento PDF',
|
||||
ADD COLUMN IF NOT EXISTS `doc_subtitulo` varchar(200) DEFAULT NULL COMMENT 'Subtítulo / razón social',
|
||||
ADD COLUMN IF NOT EXISTS `doc_logo_base64` longtext DEFAULT NULL COMMENT 'Logo en Base64 para el PDF',
|
||||
ADD COLUMN IF NOT EXISTS `doc_color` varchar(20) DEFAULT NULL COMMENT 'Color principal HEX (#RRGGBB)',
|
||||
ADD COLUMN IF NOT EXISTS `doc_pie_pagina` varchar(500) DEFAULT NULL COMMENT 'Texto del pie de página';
|
||||
|
||||
-- =============================================================================
|
||||
-- FIN
|
||||
-- =============================================================================
|
||||
SET foreign_key_checks = 1;
|
||||
|
||||
-- Verificación rápida (opcional, descomentar para depuración)
|
||||
-- SELECT 'scheduled_messages' AS tabla, COUNT(*) AS filas FROM scheduled_messages
|
||||
-- UNION ALL SELECT 'roles', COUNT(*) FROM roles
|
||||
-- UNION ALL SELECT 'role_modules', COUNT(*) FROM role_modules
|
||||
-- UNION ALL SELECT 'lab_config', COUNT(*) FROM lab_config;
|
||||
@@ -0,0 +1,658 @@
|
||||
# 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 (clave–valor).
|
||||
|
||||
| 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 (clave–valor).
|
||||
|
||||
| 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`*
|
||||
Reference in New Issue
Block a user