205 lines
11 KiB
SQL
205 lines
11 KiB
SQL
-- =============================================================================
|
|
-- 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;
|