Este documento describe la arquitectura de software del Sistema de Gestión de Visitas del Túnel Subfluvial, detallando el diseño técnico, la separación de responsabilidades en capas y cómo interactúan las tecnologías principales del stack: React (Frontend), Node.js/Express (Backend) y PostgreSQL (Base de Datos).
El sistema sigue una arquitectura cliente-servidor desacoplada. A continuación se presenta el flujo general de comunicación entre los componentes del sistema:
El frontend está desarrollado sobre React 18 utilizando TypeScript y compilado con Vite. La interfaz está estilizada usando Tailwind CSS para un diseño moderno y responsivo.
src/pages/: Páginas principales del sistema (Dashboard, Calendario, RegistroVisita, Auditoria, etc.) que gestionan el estado local de los formularios y la renderización de las vistas.src/components/: Componentes UI reutilizables (botones, tablas, diálogos interactivos, componentes de gráficos para estadísticas).src/context/: Manejo del estado global. Contiene el AuthContext.tsx, que controla la sesión del usuario, almacena el token JWT en el localStorage, intercepta la inactividad del usuario para el cierre automático de sesión (session_timeout_minutes) y expone los datos del usuario logueado.src/utils/: Funciones auxiliares y definiciones de tipos estáticos (visitaTypes.ts).El frontend se comunica con el servidor de forma asíncrona a través de la Fetch API de JavaScript utilizando variables de entorno (import.meta.env.VITE_API_URL) para definir la dirección del servidor.
[!NOTE] Todas las peticiones HTTP que requieren autorización adjuntan el token JWT guardado localmente en las cabeceras de la petición:
headers: { 'Authorization': 'Bearer <Token_JWT>' }
El backend está desarrollado en Node.js con TypeScript, estructurado sobre el framework web Express. Sigue un patrón de arquitectura limpia dividida en 4 capas principales de responsabilidad:
[Cliente] ──> [Middleware (JWT)] ──> [Routes] ──> [Controllers] ──> [Services] ──> [Repositories] ──> [PostgreSQL]
src/middleware/):auth.middleware.ts: Intercepta las solicitudes entrantes, extrae el token JWT del encabezado Authorization, lo verifica usando la clave secreta y almacena los datos decodificados en el objeto de la petición (req.usuario). Adicionalmente valida si el rol del usuario posee los permisos adecuados (verificarRol).src/routes/):/api/visitas, /api/usuarios, /api/gestores). Asocia cada ruta con su respectivo controlador y le aplica los middlewares de autenticación necesarios.src/controllers/):req.params), de la query string (req.query) o del cuerpo (req.body), delegan la lógica de negocio a los servicios correspondientes y devuelven la respuesta en formato JSON con el código de estado HTTP adecuado.src/services/):export.service.ts: Utiliza puppeteer-core y @sparticuz/chromium para levantar un navegador headless, renderizar una plantilla HTML en memoria e imprimirla en formato PDF (utilizado para comprobantes individuales de visitas y reportes estadísticos).src/repositories/):La persistencia de datos está delegada en PostgreSQL. La conexión se realiza a través de un pool gestionado por el driver de Node pg (Pool), optimizando la reutilización de conexiones TCP.
SELECT SUM(cantidad_personas)...). La suma de las personas de la nueva visita más las existentes no puede superar la clave capacidad_maxima configurada en la tabla CONFIGURACION (por defecto 300 personas).DIAINHABIL. Si existe un registro coincendente, la visita es rechazada automáticamente.activo.El siguiente diagrama de secuencia detalla cómo viaja la información entre los distintos componentes y capas al registrar una nueva visita guiada (CU-003):
La seguridad es transversal a toda la aplicación y se gestiona bajo los siguientes estándares:
$1, $2, ... en el driver pg).UsuarioService para generar y comparar los hashes de forma segura con un factor de costo elevado.id, email y rol del usuario. Este token tiene un tiempo de expiración dinámico gestionado a través de la clave session_timeout_minutes de la base de datos.AuditoriaService al realizar modificaciones, insertando una fila en la tabla LOGAUDITORIA asociando la fecha y hora exacta (NOW()), la acción descrita y el ID del usuario responsable.