================================================================================ PLAN DE EVOLUCIÓN: BOT WHATSAPP → ERP MULTI-MÓDULO Proyecto: Panel de Laboratorio + WhatsApp Bot Manager Fecha: Abril 2026 ================================================================================ ──────────────────────────────────────────────────────────────────────────────── 1. ESTADO ACTUAL — QUÉ TENEMOS ──────────────────────────────────────────────────────────────────────────────── MÓDULOS YA OPERATIVOS: ✔ WhatsApp Bot – respuestas automáticas, menús, plantillas Meta ✔ Conversaciones – bandeja de entrada, operadores asignados ✔ Mensajes Programados – campañas por fecha/hora ✔ Pacientes – ficha clínica, historial ✔ Domicilios – agenda de servicios a domicilio con flujo de estados ✔ Enfermeras/Personal – portal propio, agenda diaria ✔ Órdenes Médicas – PDF adjunto, autorización ✔ Formularios – builder drag-drop, firma digital, enlace público ✔ Reportes – ingresos, rendimiento de enfermeros, pagos ✔ Actividad/Auditoría – log de cambios por usuario ✔ Usuarios & Roles – RBAC completo (roles + role_modules) ✔ Configuración – tarifas, laboratorio, WhatsApp ARQUITECTURA ACTUAL: • Todos los archivos PHP en la raíz del proyecto (lab_*.php, index.php…) • API separada en /api/ y /api/lab/ • Clases en /classes/ y /services/ • Base de datos: 34 tablas, una sola BD "usite_whatsapp_bot" • RBAC: tabla roles + role_modules + SYSTEM_MODULES en config.php • Sesiones PHP nativas (login en admin_users) PROBLEMA PRINCIPAL PARA CRECER: • Sin sistema de enrutamiento → cada módulo es un archivo suelto en raíz • SYSTEM_MODULES hardcodeado en config.php (hay que editarlo cada vez) • No hay separación de carpetas por módulo (todo mezclado) • Navegación duplicada en cada .php del módulo lab • Sin un punto de entrada único (todo camino directo al .php) ──────────────────────────────────────────────────────────────────────────────── 2. VISIÓN TARGET — ERP MULTI-MÓDULO ──────────────────────────────────────────────────────────────────────────────── CONCEPTO: Un sistema central con un panel unificado donde cada "módulo" es un paquete autocontenido. El core gestiona: autenticación, routing, menú lateral, RBAC, notificaciones y eventos. Los módulos se enchufan al core sin modificar archivos existentes. MÓDULOS PLANIFICADOS (oleadas): OLEADA 0 – Ya en producción (refactorizar para que usen la nueva estructura) - whatsapp_bot → Bot + Conversaciones + Plantillas - lab_domicilios → Agenda de domicilios - lab_pacientes → Pacientes y fichas - lab_formularios → Builder de formularios - lab_reportes → Reportes e indicadores - lab_ordenes → Órdenes médicas - lab_enfermeras → Gestión de personal clínico - sistema → Usuarios, Roles, Configuración OLEADA 1 – Nuevos módulos solicitados - turnero → Sistema de turnos presenciales en recepción OLEADA 2 – Módulos futuros probables - registro_exams → Registro directo de exámenes de laboratorio (sin domicilio: paciente llega a la sede) - facturacion → Facturación electrónica / DIAN (Colombia) - inventario → Reactivos, insumos, stock mínimo - citas → Agenda de citas con calendario visual - resultados → Entrega digital de resultados (portal paciente) - crm_pacientes → Campañas, seguimientos, cohortes ──────────────────────────────────────────────────────────────────────────────── 3. NUEVA ESTRUCTURA DE CARPETAS ──────────────────────────────────────────────────────────────────────────────── / ├── core/ ← Núcleo del ERP (NO tocar por módulos) │ ├── App.php ← Bootstrap, registro de módulos │ ├── Router.php ← Enrutador simple (mapea URL→módulo/acción) │ ├── Auth.php ← Login/logout/sesión (extraído de config.php) │ ├── Rbac.php ← hasModule(), requireModule(), permisos │ ├── ModuleRegistry.php ← Catálogo dinámico de módulos instalados │ ├── Layout.php ← Renderiza sidebar, navbar, footer │ └── Helpers.php ← Funciones globales (esc, jsonOk, etc.) │ ├── modules/ ← Un subdirectorio por módulo │ ├── whatsapp_bot/ │ │ ├── module.php ← Descriptor: nombre, slug, icono, permisos │ │ ├── views/ ← Las páginas (ex lab_*.php migradas) │ │ └── api/ ← Endpoints REST propios del módulo │ │ │ ├── domicilios/ │ │ ├── module.php │ │ ├── views/ │ │ └── api/ │ │ │ ├── turnero/ ← NUEVO ★ (Oleada 1) │ │ ├── module.php │ │ ├── views/ │ │ │ ├── dashboard.php ← Panel administrador (resumen del día) │ │ │ ├── kiosko.php ← Pantalla táctil tomar turno (sin login) │ │ │ ├── display.php ← Pantalla TV cola general (sin login) │ │ │ ├── recepcion.php ← Puesto recepcionista (llamar, solicitud, lugar) │ │ │ ├── lugar.php ← Puesto de servicio: llama turno, firma, atiende │ │ │ └── configuracion.php ← Lugares, exámenes, prioridades, sesiones │ │ └── api/ │ │ ├── create_turno.php ← Genera nuevo turno (kiosko) │ │ ├── llamar_turno.php ← Llama siguiente de una cola │ │ ├── create_solicitud.php ← Crea solicitud con exámenes, pago y lugar destino │ │ ├── cambiar_estado.php ← Avanza estado del turno │ │ ├── get_cola.php ← Cola de un lugar o recepción │ │ ├── sse_turno.php ← Server-Sent Events para pantallas TV │ │ ├── send_consentimiento.php ← Envía enlace de consentimiento por WhatsApp │ │ └── get_consentimientos.php ← Estado de firmas del turno │ │ │ ├── registro_exams/ ← PENDIENTE — Oleada 2 │ │ ├── module.php │ │ ├── views/ │ │ │ ├── registrar.php │ │ │ ├── lista.php │ │ │ └── detalle.php │ │ └── api/ │ │ ├── save_examen.php │ │ ├── get_examenes.php │ │ ├── cambiar_estado.php │ │ └── imprimir_etiqueta.php │ │ │ └── sistema/ │ ├── module.php │ ├── views/ │ │ ├── usuarios.php ← lab_usuarios.php migrado │ │ └── configuracion.php │ └── api/ │ ├── shared/ ← Componentes reutilizables entre módulos │ ├── components/ │ │ ├── sidebar.php ← Menú lateral dinámico (según módulos del rol) │ │ ├── navbar.php │ │ ├── page_header.php │ │ └── modal_confirm.php │ └── js/ │ ├── erp-core.js ← fetch wrapper, toasts, eventos globales │ └── erp-table.js ← Tablas con filtro, paginación, export │ ├── classes/ ← (ya existe, mantener) ├── services/ ← (ya existe, mantener) ├── api/ ← API global (ya existe, mantener para bot) ├── config/ │ └── config.php ← Simplificado: SOLO BD y constantes base │ ├── public/ ← (opcional futuro) assets compilados │ └── assets/ │ └── index.php ← Punto de entrada único → instancia App.php NOTA SOBRE MIGRACIÓN SIN ROMPER NADA: Los archivos lab_*.php actuales permanecen en raíz mientras se migran. Se crea un alias: cada modules/X/views/Y.php incluye el legacy si aún no se ha reescrito. No hay "big bang rewrite". ──────────────────────────────────────────────────────────────────────────────── 4. SISTEMA DE ROLES Y PERMISOS (RBAC EXPANDIDO) ──────────────────────────────────────────────────────────────────────────────── MODELO ACTUAL: roles (id, name, slug, color, is_system) └── role_modules (role_id, module_slug) ← solo read/write implícito MODELO PROPUESTO — RBAC con acciones: ┌─────────────────────────────────────────────────────────────┐ │ roles │ │ id | name | slug | description | color | is_system │ └──────────────────┬──────────────────────────────────────────┘ │ 1:N ┌──────────────────▼──────────────────────────────────────────┐ │ role_permissions (reemplaza role_modules con más granularidad) │ id | role_id | module_slug | can_view | can_create │ │ can_edit | can_delete | can_export | extra_json │ └─────────────────────────────────────────────────────────────┘ extra_json ejemplos: turnero → {"puede_llamar": true, "puede_reasignar": false} reportes → {"rango_max_dias": 90} whatsapp → {"puede_broadcast": true} ROLES DEL SISTEMA A DEFINIR: Slug Nombre Descripción ───────────────────────────────────────────────────────────────── superadmin Super Admin Acceso total, configura el sistema admin Administrador Acceso total sin configuración técnica recepcionista Recepcionista Turnero + Pacientes (Oleada 1) bacteriologo Bacteriólogo Registro exámenes + Resultados (Oleada 2) enfermero Enfermero Portal domicilios (ya existe) supervisor Supervisor Reportes + sin acceso a config operador_bot Operador WhatsApp Solo bandeja de conversaciones readonly Solo lectura Ver dashboards sin editar REGLA: is_system=1 en superadmin y admin → no se pueden borrar. Los demás roles son personalizables por el cliente. FLUJO DE VERIFICACIÓN EN UNA VISTA: 1. ¿Está logueado? → sino → login 2. ¿El rol tiene module_slug? → sino → 403 sin módulo 3. ¿La acción requiere can_edit? → verificar permiso específico 4. ¿Hay restricción extra_json? → verificar campo relevante HELPER PROPUESTO (core/Rbac.php): hasModule($slug) → bool (ya existe en helpers) canDo($slug, $action) → bool (nuevo, $action = view/create/edit/delete/export) requireAction($slug, $action) → lanza 403 si no tiene permiso ──────────────────────────────────────────────────────────────────────────────── 5. MÓDULO TURNERO — DISEÑO DETALLADO ──────────────────────────────────────────────────────────────────────────────── PROPÓSITO: Diseñar, desarrollar e implementar un Sistema de Turnero Inteligente integrado con gestión de pacientes, clasificación por prioridades, flujo de atención por áreas (Recepción y Toma de Muestras) y envío automatizado de consentimientos informados mediante WhatsApp. El sistema optimiza la atención, mejora la trazabilidad del paciente y garantiza el cumplimiento legal mediante la gestión digital de consentimientos. ──── 5.1 PANTALLAS / INTERFACES ──────────────────────────────────────────── A) Kiosko (tablet/touch, sin login) → el paciente selecciona su tipo de prioridad y obtiene su turno B) Pantalla TV / Display (pantalla grande, sin login, una por lugar) → muestra la cola del lugar y el turno siendo llamado en tiempo real → param ?lugar_id=X para que cada sala tenga su propia pantalla C) Puesto Recepción (login requerido) → llama turnos de la cola general → vincula paciente, registra exámenes, recibe pago → crea la Solicitud Interna y asigna el turno a un Lugar D) Puesto Lugar / Estación de Servicio (login requerido, genérico) → llama turnos de su propia cola (los asignados a él por recepción) → muestra exámenes requeridos y estado de consentimientos • el paciente firma directamente en la pantalla del puesto (o en su celular) → realiza el servicio y finaliza el turno → La misma vista sirve para: Toma de Muestras 1, Toma de Muestras 2, Rayos X, Ultrasonido, o cualquier área que se configure E) Panel Admin Turnero (login requerido) → configura Lugares, exámenes, prioridades, sesiones ──── 5.2 SISTEMA DE PRIORIDADES ──────────────────────────────────────────── Código Tipo de paciente Orden motor de cola ────────────────────────────────────────────────────── A Niños 1 (máxima prioridad) B Embarazadas 2 C Adulto mayor 3 D Discapacidad 4 E Paciente general 5 F Muestras pendientes 6 (menor prioridad) Regla: dentro del mismo código se respeta el orden de llegada (FIFO). El motor de cola mezcla todas las filas usando el peso de prioridad + timestamp. ──── 5.3 FLUJO POR ÁREAS ──────────────────────────────────────────────────── ÁREA 1 — RECEPCIÓN ═══════════════════ Estados: espera → en_recepcion → finalizado_recepcion 1. Kiosko/recepcionista genera turno (código + prioridad) 2. Pantalla TV muestra la cola 3. Recepcionista llama siguiente turno → estado "en_recepcion" → (opcional) Mensaje WhatsApp al paciente con su código de turno 4. Se vincula el turno con un número de ventanilla 5. Se registran: • Datos personales del paciente (buscar/crear en lab_pacientes) • Exámenes requeridos (lista de exam_tipos) 6. Sistema consulta si los exámenes requieren consentimientos 7. Si hay consentimientos pendientes: → Se genera enlace único y seguro por paciente → Se envía por WhatsApp usando WhatsAppService + plantilla aprobada Meta Si no se requieren → pasa directamente a área de muestras 8. Turno avanza → "esperando_consentimiento" o "en_espera_muestra" ÁREA 2 — TOMA DE MUESTRAS ══════════════════════════ Estados: en_espera_muestra → en_muestra → finalizado 1. Bacteriólogo/auxiliar llama siguiente de la cola de muestras 2. Sistema BLOQUEA la atención si no existen consentimientos firmados → muestra alerta visual; no permite avanzar el estado 3. Si todos los consentimientos están firmados: → Estado "en_muestra" → Se validan los exámenes registrados en recepción 4. Al terminar la toma: estado "finalizado" ──── 5.4 CONSENTIMIENTOS INFORMADOS ───────────────────────────────────────── INTEGRACIÓN CON MÓDULO FORMULARIOS (REUTILIZAR lo que ya existe): • Los consentimientos son Formularios del módulo lab_formularios/ • Se marca en la configuración del formulario si es de tipo "consentimiento" usando un campo nuevo: tipo ENUM(formulario, consentimiento) • Enlace público ya existe en el módulo → se reutiliza tal cual • Firma digital ya implementada → se reutiliza (canvas + checkbox legal) CATÁLOGO DE TIPOS DE EXAMEN (exam_tipos): • Listado maestro de exámenes que ofrece el laboratorio (código + nombre) • Se crea en FASE 3 (Oleada 1) para dar soporte al turnero • La misma tabla se usa en Oleada 2 (registro_exams) sin cambios • Administrado desde la vista Configuración > Exámenes y Consentimientos RELACIÓN EXAMEN ↔ CONSENTIMIENTO (exam_tipo_consentimientos): • Un consentimiento (formulario) puede cubrir VARIOS tipos de examen • Un examen puede estar en un solo consentimiento o en ninguno • Se configura UNA VEZ en el panel de administración, no en cada turno • Ejemplo: "Toma de muestra de sangre" → consentimiento id=3 ("Consentimiento hemograma") "Glucosa en ayunas" → consentimiento id=3 "Cultivo de orina" → consentimiento id=5 ("Consentimiento urocultivo") "Presión arterial" → (sin consentimiento) FLUJO DE CONSENTIMIENTOS: 1. Recepción selecciona exámenes del turno (de la lista exam_tipos) 2. Sistema busca en exam_tipo_consentimientos qué formularios aplican para los exámenes seleccionados → deduplica si varios exámenes comparten el mismo consentimiento → lista mínima de consentimientos 3. Por cada consentimiento pendiente: • Se genera un token único (UUID) → link = /ver_formulario.php?token=XXX • Se registra en turnero_consentimientos con estado "pendiente" 4. (Opcional) Recepción envía enlace por WhatsApp para pre-firma mientras el paciente espera en cola del Lugar 5. En el Lugar (segunda llamada), el paciente puede firmar: OPCIÓN A: Hace clic en el enlace de WhatsApp en su celular OPCIÓN B: El auxiliar muestra la pantalla del puesto al paciente y firma directamente ahí (mismo ver_formulario_enviado.php) 6. Al firmar → estado "firmado" en turnero_consentimientos 7. Vista del Lugar muestra ✓ verde / ✗ rojo en tiempo real (polling 5s) BLOQUEO total si alguno pendiente → no se puede iniciar el servicio MOMENTO DE LA FIRMA: • Preferiblemente antes de la segunda llamada (via WhatsApp, mientras espera) • Alternativamente EN la estación del Lugar (tablet del puesto) • NUNCA después de iniciado el servicio EVIDENCIA REGISTRADA POR FIRMA: • Fecha y hora exacta • IP del firmante • User-Agent (dispositivo) • Versión del formulario/consentimiento al momento de firmar ──── 5.5 TABLAS BD NUEVAS ──────────────────────────────────────────────────── exam_tipos ← catálogo maestro de exámenes del laboratorio id, codigo VARCHAR(20), ← ej. "HEM", "GLU", "URIN" nombre VARCHAR(150), ← ej. "Hemograma completo" categoria VARCHAR(80), ← ej. "Hematología", "Química" activo TINYINT(1) NOTA: Esta tabla es compartida con Oleada 2 (registro_exams). En Oleada 2 se le agregan columnas precio_base, requiere_ayunas, etc. exam_tipo_consentimientos ← relación M:N examen ↔ consentimiento id, exam_tipo_id INT FK exam_tipos, formulario_id INT FK lab_formularios, ← debe tener tipo='consentimiento' UNIQUE KEY (exam_tipo_id, formulario_id) NOTA: Si un examen no tiene registro aquí, no se exige consentimiento. Si varios exámenes del mismo turno apuntan al mismo formulario_id, se genera UN SOLO consentimiento (deduplicado en la lógica PHP). turnero_lugares ← sub-módulo: estaciones/lugares de servicio id, nombre VARCHAR(100), ← ej. "Toma de Muestras 1", "Rayos X" descripcion TEXT, activo TINYINT(1), sort_order INT ← orden en la pantalla TV general NOTA: Recepción NO es un lugar; es el primer paso implícito del flujo. Cada lugar tiene su propia cola y su propia pantalla TV. turnero_prioridades ← catálogo editable de códigos A-F id, codigo CHAR(1) UNIQUE, nombre VARCHAR(100), orden_peso INT, ← número menor = mayor prioridad color VARCHAR(7), activo TINYINT(1) turnero_sesiones id, fecha DATE, abierto_por INT FK admin_users, cerrado_por INT FK admin_users, inicio_at DATETIME, fin_at DATETIME turnero_turnos id, sesion_id FK turnero_sesiones, numero INT, ← correlativo dentro de la sesión codigo VARCHAR(10), ← "A001", "B012" prioridad_id INT FK turnero_prioridades, paciente_nombre VARCHAR(150), ← capturado en kiosko (opcional) paciente_cel VARCHAR(20), estado ENUM( espera, ← código asignado, en cola general en_recepcion, ← recepcionista lo está procesando en_espera_lugar, ← solicitud creada, en cola del Lugar en_servicio, ← siendo atendido en el Lugar finalizado, ← proceso completo ausente, ← no se presentó cancelado ), lugar_destino_id INT FK turnero_lugares NULL, ← asignado por recepción creado_at DATETIME, llamado_recepcion_at DATETIME, inicio_recepcion_at DATETIME, fin_recepcion_at DATETIME, llamado_lugar_at DATETIME, inicio_lugar_at DATETIME, fin_lugar_at DATETIME, atendido_recepcion_por INT FK admin_users NULL, atendido_lugar_por INT FK admin_users NULL turnero_solicitudes ← solicitud interna de agendamiento (crea recepción) id, turno_id INT FK turnero_turnos UNIQUE, ← 1 solicitud por turno paciente_id INT FK lab_pacientes, ← vinculado en recepción lugar_id INT FK turnero_lugares, ← lugar de destino total_cobrado DECIMAL(10,2), metodo_pago ENUM(efectivo, transferencia, tarjeta, eps, cortesia), observaciones TEXT, creado_por INT FK admin_users, creado_at DATETIME turnero_examen_items ← exámenes de la solicitud id, solicitud_id FK turnero_solicitudes, exam_tipo_id INT FK exam_tipos, creado_at DATETIME turnero_consentimientos ← consentimientos del turno (deduplicados) id, turno_id FK turnero_turnos, formulario_id INT FK lab_formularios, token VARCHAR(64) UNIQUE, ← enlace único de firma estado ENUM(pendiente, enviado, visto, firmado, rechazado), enviado_at DATETIME, firmado_at DATETIME, ip_firma VARCHAR(45), ua_firma VARCHAR(500), version_formulario INT ← snapshot de la versión al momento de firma formularios.tipo ← columna nueva en tabla existente lab_formularios ALTER TABLE lab_formularios ADD COLUMN tipo ENUM('formulario','consentimiento') DEFAULT 'formulario'; DIAGRAMA DE RELACIONES CLAVE: lab_formularios (tipo='consentimiento') │ 1 │ exam_tipo_consentimientos ─────── exam_tipos (M:N) │ 1 │ N turnero_examen_items │ N │ 1 turnero_solicitudes ───── turnero_lugares │ 1 │ 1 turnero_turnos │ 1 │ N turnero_consentimientos (un registro por formulario distinto requerido por el turno) ──── 5.6 INTEGRACIONES CON MÓDULOS EXISTENTES ────────────────────────────── • lab_pacientes → buscar/crear paciente al crear la solicitud en recepción • lab_formularios → los consentimientos SON formularios del sistema • ver_formulario_enviado.php → página pública de firma (ya funcional) se abre también desde la pantalla del Lugar • WhatsAppService → envío del enlace de consentimiento (opcional, entre llamadas) • Plantillas Meta → crear plantilla aprobada "consentimiento_turno" • exam_tipos → catálogo compartido con Oleada 2 (registro_exams) ──── 5.7 PANTALLA TV / DISPLAY ───────────────────────────────────────────── Hay VARIOS tipos de pantalla TV, todas sin login: TV RECEPCIÓN (?display=recepcion) • Cola general (turnos en estado 'espera' ordenados por prioridad) • Turno actualmente en recepción (código grande + "DIRÍJASE A RECEPCIÓN") TV POR LUGAR (?display=lugar&lugar_id=X) • Cola del Lugar X (turnos en 'en_espera_lugar' con ese lugar_destino_id) • Turno en servicio activo del Lugar X (código grande) • Cadaestación tiene su propia TV configurada con su lugar_id COMPORTAMIENTO COMÚN: • Actualización por SSE en tiempo real sin reload • Colores grandes por código de prioridad • Animación + sonido corto al llamar un turno ──────────────────────────────────────────────────────────────────────────────── 6. MÓDULO REGISTRO DE EXÁMENES — DISEÑO DETALLADO [OLEADA 2 — pendiente] ──────────────────────────────────────────────────────────────────────────────── CONCEPTO: Registrar exámenes de análisis clínico cuando el paciente llega a la sede (a diferencia de lab_domicilios que es a domicilio). Incluye: recepción de muestra, trazabilidad, estado de procesamiento, y eventualmente entrega de resultados. TABLAS BD NUEVAS: exam_tipos id, codigo (ej. "HEM", "GLU"), nombre, categoria, precio_base, requiere_ayunas TINYINT, instrucciones TEXT, activo exam_ordenes (la "orden de trabajo" del laboratorio) id, paciente_id FK lab_pacientes, numero_orden VARCHAR(20) UNIQUE, ← ej. "ORD-2026-00123" origen ENUM(presencial, domicilio, whatsapp, referido), medico_remitente VARCHAR(150), entidad_pagadora VARCHAR(150), tipo_pago ENUM(particular, eps, convenio), total_cobrado DECIMAL(10,2), estado ENUM(pendiente, en_proceso, parcial, completado, entregado, anulado), observaciones TEXT, recibido_por INT FK admin_users, creado_at, actualizado_at exam_items (los exámenes individuales dentro de una orden) id, orden_id FK exam_ordenes, tipo_id FK exam_tipos, estado ENUM(pendiente, muestra_tomada, en_analisis, resultado_listo, entregado), muestra_tipo VARCHAR(50), ← sangre, orina, hisopado... muestra_recibida_at, resultado TEXT, resultado_pdf VARCHAR(300), procesado_por INT FK admin_users, entregado_at exam_etiquetas (para imprimir en los tubos) id, item_id FK exam_items, codigo_barras VARCHAR(50) UNIQUE, impreso_at, impreso_por INT FK admin_users FLUJO: 1. Recepcionista busca/crea paciente (reutiliza lab_pacientes) 2. Crea orden → agrega exámenes de la lista exam_tipos 3. Sistema genera número de orden y código de barras por tubo 4. Se imprime etiqueta (ZPL o PDF) 5. Bacteriólogo cambia estado → en_análisis → resultado_listo 6. Administrador entrega resultados (descarga PDF / enlace portal) RELACIÓN CON MÓDULOS EXISTENTES: • Paciente → usa lab_pacientes (ya existe) • Si viene de un domicilio → exam_ordenes.origen = 'domicilio', vincular con lab_domicilios (campo opcional domicilio_id) • Si tiene orden médica adjunta → vincular con lab_ordenes_medicas ──────────────────────────────────────────────────────────────────────────────── 7. BASE DE DATOS — PLAN DE MIGRACIONES ──────────────────────────────────────────────────────────────────────────────── REGLA: todas las migraciones son ADITIVAS (ALTER ADD, CREATE TABLE). NUNCA DROP COLUMN ni RENAME en producción sin respaldo previo. Migración 001 – RBAC expandido ALTER TABLE role_modules ADD COLUMN can_view TINYINT(1) DEFAULT 1; ALTER TABLE role_modules ADD COLUMN can_create TINYINT(1) DEFAULT 0; ALTER TABLE role_modules ADD COLUMN can_edit TINYINT(1) DEFAULT 0; ALTER TABLE role_modules ADD COLUMN can_delete TINYINT(1) DEFAULT 0; ALTER TABLE role_modules ADD COLUMN can_export TINYINT(1) DEFAULT 0; ALTER TABLE role_modules ADD COLUMN extra_json JSON NULL; RENAME TABLE role_modules TO role_permissions; ← (o alias) Migración 002 – Nuevos roles INSERT INTO roles (name, slug, description, color, is_system) VALUES ('Super Admin', 'superadmin', 'Acceso total al sistema', '#dc3545', 1), ('Recepcionista', 'recepcionista', 'Turnero y recepción de muestras', '#198754', 0), ('Bacteriólogo', 'bacteriologo', 'Análisis y resultados', '#0dcaf0', 0), ('Supervisor', 'supervisor', 'Solo reportes y consultas', '#fd7e14', 0), ('Operador Bot', 'operador_bot', 'Gestión de conversaciones', '#6f42c1', 0); Migración 003 – Turnero [Oleada 1] CREATE TABLE exam_tipos (...) ← catálogo maestro compartido con Oleada 2 CREATE TABLE exam_tipo_consentimientos(...) ← M:N: examen ↔ formulario consentimiento CREATE TABLE turnero_lugares (...) ← sub-módulo: estaciones configurables CREATE TABLE turnero_prioridades (...) ← catálogo A-F configurable CREATE TABLE turnero_sesiones (...) ← sesión diaria de atención CREATE TABLE turnero_turnos (...) ← turno con lugar_destino_id CREATE TABLE turnero_solicitudes (...) ← solicitud interna de agendamiento CREATE TABLE turnero_examen_items (...) ← exámenes de la solicitud CREATE TABLE turnero_consentimientos (...) ← firma digital por consentimiento ALTER TABLE lab_formularios ADD COLUMN tipo ENUM('formulario','consentimiento') DEFAULT 'formulario' Migración 004 – SYSTEM_MODULES dinámica (mover de config.php a BD) [Oleada 1] CREATE TABLE system_modules ( slug VARCHAR(100) PK, name VARCHAR(150), icon VARCHAR(50), ← "fas fa-vials" category VARCHAR(50), ← "lab", "bot", "sistema", "clinico" route VARCHAR(200), ← URL base del módulo is_active TINYINT(1), sort_order INT, created_at TIMESTAMP ) Poblar con los módulos actuales + turnero. registro_exams se agrega en Migración 005 (Oleada 2). config.php mantiene el array como fallback hasta que la BD esté lista. Migración 005 – Registro de exámenes [Oleada 2] -- exam_tipos ya existe desde Migración 003; solo agregar columnas: ALTER TABLE exam_tipos ADD COLUMN precio_base DECIMAL(10,2) NULL; ALTER TABLE exam_tipos ADD COLUMN requiere_ayunas TINYINT(1) DEFAULT 0; ALTER TABLE exam_tipos ADD COLUMN instrucciones TEXT NULL; CREATE TABLE exam_ordenes (...) CREATE TABLE exam_items (...) CREATE TABLE exam_etiquetas(...) ──────────────────────────────────────────────────────────────────────────────── 8. ROUTER Y PUNTO DE ENTRADA ──────────────────────────────────────────────────────────────────────────────── OPCIÓN RECOMENDADA (sin framework, compatible con estructura actual): index.php → incluye core/App.php App.php → lee $_GET['m'] (módulo) y $_GET['v'] (vista) → verifica sesión + permisos via Rbac.php → incluye modules/{m}/views/{v}.php → si no existe → 404 amigable URLS LIMPIAS con .htaccess: /turnero/dashboard → ?m=turnero&v=dashboard /turnero/display → ?m=turnero&v=display (sin login) /lab/domicilios → ?m=domicilios&v=index /lab/pacientes → ?m=lab_pacientes&v=index .htaccess ya existe en el proyecto → solo agregar RewriteRules. COMPATIBILIDAD: Los lab_*.php en raíz siguen funcionando directamente. El router añade una capa adicional, no reemplaza lo existente. Migración gradual: mover módulos uno a uno al nuevo sistema. ──────────────────────────────────────────────────────────────────────────────── 9. LAYOUT Y NAVEGACIÓN UNIFICADA ──────────────────────────────────────────────────────────────────────────────── PROBLEMA ACTUAL: Cada lab_*.php repite el mismo sidebar a mano (>50 líneas duplicadas). Si se agrega un módulo hay que editar todos los archivos. SOLUCIÓN: shared/components/sidebar.php → se genera dinámicamente desde: 1. La tabla system_modules (activos) 2. Filtrado por los módulos que tiene el rol del usuario logueado 3. Agrupados por "category" (Bot, Laboratorio, Clínico, Sistema) Cada layout nueva vista incluye: El sidebar detecta la URL activa y resalta el elemento correspondiente. GRUPOS DEL MENÚ LATERAL: 🤖 WhatsApp Conversaciones | Bot & Menús | Plantillas | Programados 🏥 Laboratorio Dashboard | Domicilios | Pacientes | Enfermeras | Órdenes 🧪 Clínico (Oleada 2) Registro Exámenes | Resultados 🎟️ Turnero (Oleada 1) Dashboard | Recepción | Toma de Muestras | Kiosko | Configuración 📊 Reportes Ingresos | Rendimiento | Exportar ⚙️ Sistema Usuarios & Roles | Configuración | Actividad ──────────────────────────────────────────────────────────────────────────────── 10. PLAN DE IMPLEMENTACIÓN — FASES ──────────────────────────────────────────────────────────────────────────────── ── BASE DEL SISTEMA ───────────────────────────────────────────────────────── FASE 0 – Preparación (1-2 días) [SIN impacto en producción] ✅ COMPLETADA ✓ Crear carpetas: core/, modules/, shared/ ✓ Extraer Auth.php y Rbac.php desde config.php y _helpers.php ✓ Crear shared/components/sidebar.php unificado ✓ Migración 001: expandir role_permissions (columnas can_*) ✓ Migración 002: insertar nuevos roles ✓ Agregar nuevos slugs a SYSTEM_MODULES en config.php FASE 1 – Core: Router y estructura modular (1 semana) ✅ COMPLETADA ✓ Crear core/Router.php y core/App.php ✓ Crear core/Layout.php, core/Helpers.php (core/Rbac.php ya existía de FASE 0) ✓ Punto de entrada erp.php (coexiste con index.php legacy) ✓ Activar .htaccess con URLs limpias (/modulo/vista → erp.php?m=&v=) ✓ Mover módulos existentes a modules/ (module.php + views/index.php stubs para 11 módulos) FASE 2 – SYSTEM_MODULES dinámica (2 días) ✅ COMPLETADA ✓ Migración 004: tabla system_modules (con INSERT IGNORE, oleada, sort_order) ✓ core/ModuleRegistry.php: lee BD → module.php → SYSTEM_MODULES (fallback en cascada) ✓ Sidebar lee desde ModuleRegistry en lugar de config.php (dinámico por categoría) ✓ Interfaz /erp.php?m=usuarios&v=modulos (toggle activo + sort_order) ── MÓDULOS NUEVOS ──────────────────────────────────────────────────────────── FASE 3 – Turnero MVP — Oleada 1 FASE 3.1 – Base de datos y configuración (1 día) ✅ COMPLETADA ────────────────────────────────────────────────── ✓ Migración 003: crear tablas CREATE exam_tipos ← catálogo maestro (compartido con Oleada 2) CREATE exam_tipo_consentimientos ← M:N: examen↔formulario CREATE turnero_lugares ← estaciones de servicio configurables CREATE turnero_prioridades (insertar datos A-F por defecto) CREATE turnero_sesiones CREATE turnero_turnos ← con lugar_destino_id CREATE turnero_solicitudes ← solicitud interna de agendamiento CREATE turnero_examen_items ← FK solicitud_id CREATE turnero_consentimientos ALTER lab_formularios ADD tipo ENUM(formulario, consentimiento) ✓ modules/turnero/module.php (descriptor) ✓ Registrar slug 'turnero' en system_modules ✓ Asignar módulo turnero a roles recepcionista y bacteriologo ✅ FASE 3.2 – Motor de cola y API core (1 día) [COMPLETADA] ────────────────────────────────────────────── ✓ api/create_turno.php • Crea/abre sesión del día si no existe • Genera número correlativo + código (ej. "A001") con FOR UPDATE • Admite paciente_nombre + paciente_cel (opcional) • Retorna código, número y posición en cola ✓ api/llamar_turno.php • Recibe area (recepcion|lugar) + lugar_id • Motor de prioridades: SELECT menor orden_peso → menor creado_at • Área lugar: solo turnos en estado en_espera_lugar para ese lugar • Retorna turno llamado o null si cola vacía ✓ api/cambiar_estado.php • Avanza estado con mapa de transiciones explícito • Bloquea en_espera_lugar→en_servicio si hay consentimientos pendientes (422) • Registra timestamps llamado_at / inicio_at / fin_at por área ✓ api/get_cola.php • Cola actual por área (recepcion | lugar + lugar_id) • Turno activo + listado + estadísticas de sesión ✓ api/sse_turno.php • SSE: emite 'cola_update' cuando cambia sse_ping_at en la sesión • ALTER TABLE IF NOT EXISTS para sse_ping_at (idempotente) • Keep-alive ": ping" cada 15 s, forzar refresh cada 30 s • Compatible con pantalla TV sin necesidad de polling activo ✅ FASE 3.3 – Pantallas sin login (1 día) [COMPLETADA] ──────────────────────────────────────── ✓ views/kiosko.php • Pantalla táctil fullscreen 3 pasos: prioridad → datos → ticket • Botones A-F cargados de BD (icono + nombre + descripción + color) • Campo opcional: nombre y celular con validación de formato • Muestra código + posición en cola; auto-reinicio tras 30 s • Sin login; fetch POST a create_turno.php ✓ views/display.php • Pantalla TV fullscreen, sin login (HTML puro, sin