Files
whatsapp/PLAN_ERP_MULTIMODULO.txt
2026-04-18 23:41:01 -05:00

1069 lines
60 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
================================================================================
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:
<?php include APP_ROOT . '/shared/components/sidebar.php'; ?>
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 <?php)
• ?display=recepcion → cola general
• ?display=lugar&lugar_id=X → cola del Lugar X
• SSE EventSource a sse_turno.php con reconexión exponencial
• Código activo gigante con color de prioridad + lista de espera
• Web Audio API para beep al llamar — sin archivos externos
• Stats footer: en espera / atendidos / total / tiempo promedio
✅ FASE 3.4 Puesto de Recepción (1 día) [COMPLETADA]
────────────────────────────────────────
✓ views/recepcion.php
• Requiere login + módulo turnero; layout 2 columnas: cola | ficha
• Cola izquierda: turnos 'espera' con color de prioridad, polling 8 s
• Botón "Llamar siguiente" → llama_turno.php area=recepcion
• Ficha derecha al llamar:
- Nombre del kiosko pre-cargado en buscador
- Buscador de paciente: GET /api/lab/get_pacientes.php?busqueda=
- Selector de lugar destino + checkboxes de exámenes por categoría
- Campo cobro + forma de pago + observaciones
- Sección consentimientos (aparece tras guardar si aplican)
- Botón "Pasar a lugar" → cambiar_estado en_espera_lugar
- Botón "Ausente"
✓ api/create_solicitud.php
• POST, requireTurnero(); validaciones completas
• DELETE + INSERT (permite re-guardar para correcciones)
• Inserta turnero_solicitudes + N turnero_examen_items en transacción
• Devuelve solicitud + consentimientos_requeridos (estado actual de c/u)
✓ api/send_consentimiento.php
• Deduplica formularios: N exámenes → M formularios distintos (M ≤ N)
• Genera UUID por cada formulario; INSERT IGNORE para no duplicar
• No reenvía consentimientos ya firmados o rechazados
• Intenta sendTemplateMessage('consentimiento_turno'); fallback texto plano
• Normaliza celular (+57 por defecto Colombia)
• Registra enviado_at; retorna lista con enlace_firma por c/u
• Retorna lista de consentimientos enviados
✅ FASE 3.5 Puesto Lugar / Estación de Servicio (1 día) [COMPLETADA]
────────────────────────────────────────────────────────
✓ views/lugar.php (?lugar_id=X)
• Genérica: funciona para cualquier lugar (Muestras, Rayos X, etc.)
• Overlay selector si no viene lugar_id en URL; botón "Cambiar lugar"
• Requiere login (isUserLoggedIn)
• Cola izquierda: turnos 'en_espera_lugar' del lugar, polling 7 s
• Botón "Llamar siguiente" → llamar_turno.php area=lugar
• Ficha derecha al llamar (carga vía get_consentimientos.php?incluir_solicitud=1):
- Datos del paciente (nombre, doc, fecha nac, celular)
- Exámenes como pills coloreadas
- Consentimientos con estado visual (firmado/enviado/visto/pendiente)
- BLOQUEO: "Iniciar atención" disabled + banner rojo si hay pendientes
- Botón "Reenviar WhatsApp" → send_consentimiento.php
- Botón "Firmar aquí" → abre ver_formulario_enviado.php en modal/iframe
- "Iniciar atención" → cambiar_estado en_servicio (validado en API)
- "Finalizar" → estado finalizado
- "Regresar a cola" → estado en_espera_lugar
- "Ausente" → estado ausente
• Polling de consentimientos cada 5 s mientras hay turno activo
✓ api/get_consentimientos.php
• GET público dentro del módulo (ruta protegida por la vista)
• ?turno_id=X → retorna arreglo de consentimientos con nombre del formulario
• ?incluir_solicitud=1 → también retorna solicitud + paciente + exámenes
FASE 3.6 Firma digital (reutilizar formularios) (0.5 días) ✅ COMPLETADA
──────────────────────────────────────────────────────────────
✅ Marcar formularios de consentimiento en la interfaz de admin:
lab_formularios → campo tipo = 'consentimiento'
✅ Al firmar ver_formulario_enviado.php:
• Detectar si el token corresponde a un turno (turnero_consentimientos)
• Actualizar turnero_consentimientos.estado = 'firmado'
• Registrar ip_firma, ua_firma, firmado_at, version_formulario
• Guardar firma_svg (base64 PNG) en turnero_consentimientos
• Notificar SSE → lugar.php/recepcion.php actualizan en tiempo real
✅ Vista lugar.php tiene botón "Firmar aquí" → abre el mismo
ver_formulario_enviado.php en un modal (iframe), con canvas de firma
para firma física en la tablet del puesto
✅ lugar.php detecta la firma en tiempo real (polling 5s) +
postMessage instantáneo desde el iframe al firmarse
FASE 3.7 Panel Admin Turnero + configuración (0.5 días) ✅ COMPLETADA
───────────────────────────────────────────────────────────
✅ views/configuracion.php — 4 pestañas:
TAB 1: Lugares ✅
• CRUD de turnero_lugares (nombre, descripción, activo, orden)
• Cada lugar muestra su URL de display → botón copia rápida
• URLs de recepción y kiosko también accesibles
• API: save_lugar.php (GET/POST crear/actualizar/eliminar con guardia FK)
TAB 2: Exámenes y Consentimientos ✅
• CRUD de exam_tipos (código, nombre, categoría, activo)
• Por cada exam_tipo: selector de consentimiento (formularios tipo='consentimiento')
→ Guarda/actualiza en exam_tipo_consentimientos (deduplicado)
• Vista inversa: por consentimiento → lista de exámenes vinculados
• API: save_ex_tipo.php (GET/POST; eliminación bloqueada si hay solicitudes)
TAB 3: Prioridades ✅
• Edición de nombre, color, orden, activo (sin eliminación)
• Picker de color sincronizado con campo hexadecimal
• API: save_prioridad.php (validación de formato #RRGGBB)
TAB 4: Sesión y WhatsApp ✅
• Abrir / cerrar / reabrir sesión del día con un clic
• Historial de sesiones (últimas 30)
• Configuración de plantilla WhatsApp (nombre + código idioma)
• API: sesion_turno.php (acciones: abrir, cerrar, reabrir, config_wa)
✅ views/dashboard.php (admin)
• Resumen del día: turnos atendidos, tiempo promedio, pendientes
• KPI cards + barras por prioridad + tarjetas por lugar
• Tabla detalle de todos los turnos con búsqueda local
• Consentimientos del día (desglose por estado)
• Selector de fecha (consulta histórica)
• Auto-refresh cada 30s (solo si fecha = hoy)
• API: get_dashboard.php (consultas agregadas por sesión)
• Exportar CSV: export_csv.php (BOM UTF-8, 24 columnas, listo para Excel)
FASE 4 Oleada 2 (Registro de Exámenes + futuros)
FASE 4.1 Base de datos (migration 005) ✅ COMPLETADA
─────────────────────────────────────────────────────
✓ migrations/005_registro_exams.sql
ALTER exam_tipos → precio_base, requiere_ayuno, horas_ayuno, instrucciones
CREATE exam_ordenes (código EX-YYYYMMDD-NNNN, prioridad, estado, FK paciente)
CREATE exam_items (estado por ítem, notas_tecnico)
CREATE exam_muestras (trazabilidad: tipo, código_barras, estado)
CREATE exam_resultados (campo, valor, unidad, referencia, es_anormal)
UPDATE system_modules SET is_active=1 WHERE slug='registro_exams'
INSERT role_module_access para bacteriólogo y recepcionista
✓ run_005_registro_exams.php (runner idempotente)
FASE 4.2 Módulo descriptor y helpers ✅ COMPLETADA
─────────────────────────────────────────────────────
✓ modules/registro_exams/module.php
✓ modules/registro_exams/api/_helpers.php
requireExams(), generarCodigoOrden(), jsonOk(), jsonError(), db()
FASE 4.3 Lista del día ✅ COMPLETADA
─────────────────────────────────────────────────────
✓ modules/registro_exams/views/lista.php
KPI cards (total/pendientes/en_proceso/completas)
Filtros: fecha + estado + búsqueda libre
Auto-refresh 45 s; paginación
✓ modules/registro_exams/api/get_ordenes.php
GET ?fecha=&estado=&busqueda=&page=&limit=
Incluye edad calculada, contadores de ítems y muestras
FASE 4.4 Nueva orden ✅ COMPLETADA
─────────────────────────────────────────────────────
✓ modules/registro_exams/views/nueva_orden.php
Buscador de paciente (reutiliza GET /api/lab/get_pacientes.php)
Catálogo de exámenes en checkbox agrupados por categoría
Filtro de búsqueda en catálogo; badge de ayuno y precio
Pre-carga paciente si viene ?solicitud_id= del turnero
✓ modules/registro_exams/api/save_orden.php
POST crear/editar; genera código EX-YYYYMMDD-NNNN
Sync de ítems: inserta nuevos, elimina pendientes removidos
Redirige a orden creada al guardar
FASE 4.5 Detalle de orden + resultados ✅ COMPLETADA
─────────────────────────────────────────────────────
✓ modules/registro_exams/views/orden.php
Cards: paciente, datos médicos (prioridad + estado badges)
Tabla de muestras + modal "Registrar muestra" (tipo + barcode + estado)
Lista de ítems con estado individual + dropdown cambio de estado
Modal de resultados: tabla editable (campo/valor/unidad/referencia/anormal)
Botón "Marcar entregada"; auto-cierre de orden cuando todos listos
✓ modules/registro_exams/api/get_orden.php
GET ?id= → orden + ítems + resultados + muestras
✓ modules/registro_exams/api/save_resultado.php
POST reemplaza resultados de un ítem; auto-marca resultado_listo
Auto-cierra orden a 'completa' si todos los ítems tienen resultado
✓ modules/registro_exams/api/cambiar_estado_item.php
POST tipo=item|muestra|orden; crea muestras nuevas (tipo=muestra, id=null)
Al crear muestra: pasa ítems pendientes a muestra_tomada + orden a en_proceso
FASE 4.6 Etiqueta imprimible ✅ COMPLETADA
─────────────────────────────────────────────────────
✓ modules/registro_exams/views/etiqueta.php
Página autónoma A6 landscape (sin sidebar, sin Layout::open)
Código de barras visual (fuente Libre Barcode 128 via Google Fonts)
Datos: paciente, doc, edad, EPS, prioridad, lista de exámenes
Aviso de ayuno si algún ítem lo requiere
window.print() automático al cargar (delay 800 ms para fuente)
□ Facturación, Inventario, CRM, Portal Paciente…
□ API pública con tokens (para integraciones)
□ App móvil (portal enfermero actual → Progressive Web App)
────────────────────────────────────────────────────────────────────────────────
11. CONVENCIONES TÉCNICAS A SEGUIR
────────────────────────────────────────────────────────────────────────────────
NOMENCLATURA:
• Tablas BD: snake_case, prefijadas por módulo (turnero_, exam_, lab_)
• Archivos PHP: snake_case (save_turno.php, get_examenes.php)
• Clases PHP: PascalCase (TurneroService.php, ExamOrder.php)
• Slugs: siempre lowercase con guiones (turnero, registro-exams)
• API endpoints: REST-ish, verbos en el nombre (get_, save_, delete_)
SEGURIDAD:
• Toda API: requireMethod() + verificar sesión + verificar permiso
• Parámetros: siempre sanitizar y tipificar antes de usar en SQL
• Queries: siempre PDO preparado (ya implementado en Database.php)
• Pantallas sin login (kiosko, display): NUNCA exponer datos sensibles,
solo número de turno y servicio.
• Subida de archivos: misma lógica de /upload.php (validar MIME + ext)
• CSRF: para formularios de mutación, incluir token en sesión
ESTILO DE CÓDIGO:
• Frontend: Bootstrap 5 + Font Awesome 6 (ya en uso, mantener)
• Sin jQuery nuevo; usar fetch() nativo (ya en uso)
• Toasts de notificación: usar patrón ya existente en index.php
• Responsive: mobile-first (portal enfermero se usa desde celular)
API RESPONSE FORMAT (ya establecido, mantener):
Éxito: { "ok": true, "data": {...}, "message": "..." }
Error: { "ok": false, "error": "...", "code": 4XX }
────────────────────────────────────────────────────────────────────────────────
12. DECISIONES CONFIRMADAS
────────────────────────────────────────────────────────────────────────────────
✔ 1. Sede única — No se requiere sede_id en las tablas.
✔ 2. Facturación electrónica DIAN — No se maneja en esta fase.
Queda pendiente para una oleada futura.
✔ 3. Portal de resultados para pacientes — No se requiere aún.
La entrega de resultados es solo gestión interna por ahora.
✔ 4. App móvil / PWA — No se usará PWA.
Solo se aplica diseño responsive a: pantalla TV (display) y kiosko.
El resto del sistema funciona como web normal desde PC.
✔ 5. Multi-tenant — Instalación para un solo cliente.
Sin aislamiento multi-tenant en la BD.
✔ 6. Consentimientos por examen — Se configura UNA VEZ en el panel admin.
Relación M:N: exam_tipos ↔ lab_formularios (exam_tipo_consentimientos).
El recepcionista no los marca manualmente; el sistema los calcula
automáticamente según los exámenes del turno.
────────────────────────────────────────────────────────────────────────────────
12B. DECISIONES PENDIENTES DE CONFIRMAR
────────────────────────────────────────────────────────────────────────────────
1. ¿Los exámenes integran con algún analizador automático (interfaz LIS)
o el resultado se digita manual?
(Impacta diseño de Oleada 2 — registro_exams)
2. ¿El turno se puede tomar ANTES de llegar (turno virtual por WhatsApp)?
(Conectaría el módulo Turnero con el Bot de WhatsApp)
3. ¿Cuántas ventanillas de Recepción y cuántas estaciones de servicio
(Toma de Muestras, Rayos X, etc.) se configurarán inicialmente?
(Ayuda a diseñar la pantalla TV y el layout de recepción)
4. ¿Debe bloquearse TOTALMENTE la atención si hay un consentimiento pendiente,
o solo mostrar advertencia y dejar que el auxiliar decida continuar?
────────────────────────────────────────────────────────────────────────────────
13. RESUMEN EJECUTIVO
────────────────────────────────────────────────────────────────────────────────
Lo que TENEMOS es una base sólida:
✓ BD bien estructurada con 34 tablas
✓ RBAC funcional (roles + módulos)
✓ API consistente con helpers reutilizables
✓ Autenticación robusta con bcrypt
✓ Integración WhatsApp activa
✓ Módulos de laboratorio maduros
Lo que HAY QUE CONSTRUIR para el ERP:
→ Estructura de carpetas por módulo (core/ + modules/) ✓ hecho
→ Router centralizado y sidebar dinámico ✓ hecho
→ RBAC con granularidad de acciones (can_view/create/edit/delete/export)
→ Módulo Turnero — Oleada 1 (5-7 días)
FASE 3.1 BD y configuración (turnero_lugares + solicitudes + exam_tipos)
FASE 3.2 Motor de cola + API core (create_solicitud, llamar, SSE)
FASE 3.3 Pantallas sin login (kiosko + display TV por lugar)
FASE 3.4 Puesto de Recepción (solicitud + asignar lugar)
FASE 3.5 Puesto Lugar/Estación genérico (consentimientos + servicio)
FASE 3.6 Firma digital (reutilizar formularios, firmar en tablet)
FASE 3.7 Panel Admin + configuración (4 tabs)
→ SYSTEM_MODULES en BD (en lugar de hardcoded en config.php) ✓ hecho
→ Módulo Registro de Exámenes — Oleada 2 (5-7 días, pendiente)
Estrategia: EVOLUCIÓN INCREMENTAL, no reescritura.
El sistema sigue funcionando en producción mientras se construyen
los nuevos módulos en paralelo. Solo se migra lo viejo al nuevo
sistema cuando el nuevo está validado y estable.
================================================================================
Documento preparado por GitHub Copilot — Abril 2026
Próxima revisión: tras confirmar decisiones de la sección 12
================================================================================