1. ADD CONSTRAINT IF NOT EXISTS no es estándar en MariaDB < 10.5 — eliminado el bloque FK de admin_users.role_id (la integridad la gestiona la aplicación). 2. AFTER `pdf_path` fallaba porque la columna no existe en lab_form_envios — eliminado el AFTER, la columna se agrega al final de la tabla. Esto evita que la migración falle en cada deploy.
200 lines
11 KiB
SQL
200 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;
|
|
|
|
-- C1a) FK opcional: omitida — ADD CONSTRAINT IF NOT EXISTS no es estándar
|
|
-- en todas las versiones de MariaDB. La columna role_id ya existe; la FK
|
|
-- se gestiona por la aplicación (integridad referencial vía código).
|
|
|
|
-- =============================================================================
|
|
-- 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';
|
|
|
|
-- =============================================================================
|
|
-- 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;
|