# Sistema de Keepalive y Seguimiento de Usuarios Activos ## 📝 Descripción El sistema de keepalive permite rastrear en tiempo real qué usuarios están activos y cuándo fue su última actividad. Utiliza el WebSocket existente para mantener una conexión persistente y enviar heartbeats periódicos. ## 🎯 Características ### Backend 1. **WebSocket con Heartbeat** - Envío automático de ping cada 60 segundos - Detección de conexiones inactivas - Cierre automático de conexiones sin respuesta 2. **Seguimiento de Actividad** - Registro de última actividad en sesiones - Estado activo/inactivo por usuario - Timeout de inactividad: 5 minutos 3. **Base de Datos** - Campo `lastActivity` en sesiones - Campo `isActive` para marcar usuarios conectados - Índices optimizados para consultas rápidas 4. **Endpoints** - `GET /api/users/active` - Obtener usuarios activos en tiempo real - `GET /api/admin/sessions` - Obtener todas las sesiones con estado de actividad - Ambos requieren autenticación (el segundo requiere rol admin) ### Frontend 1. **Heartbeat Automático** - Envío de heartbeat cada 30 segundos - Respuesta automática a pings del servidor 2. **Detección de Actividad** - Seguimiento de clicks, teclas, scroll y movimientos del ratón - Throttling de 10 segundos para no sobrecargar el servidor - Envío automático de eventos de actividad 3. **Componente de Usuarios Activos** - Lista de usuarios conectados en tiempo real - Indicadores de estado (activo/inactivo) - Actualización automática cada 30 segundos - Actualización en tiempo real vía WebSocket ## 🚀 Uso ### Ver Usuarios Activos Los administradores pueden ver los usuarios activos en: - **Dashboard principal** - Componente "Usuarios Activos" en la parte superior - **Vista de Sesiones** - `/sessions` - Muestra todas las sesiones con estado de conexión - **Endpoint API**: `GET /api/users/active` ### Ver Estado de Sesiones La vista de **Sesiones** (`/sessions`) ahora muestra información detallada sobre el estado de cada sesión: **Estadísticas mejoradas:** - Total de sesiones - Sesiones válidas (no expiradas) - 🟢 Sesiones conectadas (con actividad reciente < 5 min) - 🟡 Sesiones inactivas (válidas pero sin actividad) - 🔴 Sesiones expiradas - Usuarios únicos **Por cada sesión:** - Estado de validez: ✅ Válida / 🔴 Expirada - Estado de conexión: 🟢 Conectado / 🟡 Inactivo - Última actividad (relativa y absoluta) - Información del dispositivo - Token y fechas de creación/expiración ### Estructura de Respuesta **GET /api/users/active:** ```json { "activeUsers": [ { "username": "admin", "role": "admin", "status": "active", "lastActivity": "2026-01-21T10:30:00.000Z", "connectedViaWebSocket": true }, { "username": "user1", "role": "user", "status": "inactive", "lastActivity": "2026-01-21T10:25:00.000Z", "connectedViaWebSocket": false, "deviceInfo": { "browser": "Chrome", "os": "Windows" } } ], "total": 2, "timestamp": "2026-01-21T10:35:00.000Z" } ``` **GET /api/admin/sessions:** ```json { "sessions": [ { "token": "abc123...", "username": "admin", "fingerprint": "xyz...", "deviceInfo": { "browser": "Chrome", "browserVersion": "120.0", "os": "Linux", "ip": "192.168.1.100" }, "createdAt": "2026-01-21T09:00:00.000Z", "expiresAt": "2026-01-22T09:00:00.000Z", "lastActivity": "2026-01-21T10:30:00.000Z", "isActive": true, "isExpired": false } ], "stats": { "total": 10, "active": 8, "expired": 2, "connected": 5, "inactive": 3, "byUser": { "admin": 3, "user1": 2 } } } ``` ## 🔧 Configuración ### Timeouts y Intervalos **Backend** (`web/backend/services/websocket.js`): ```javascript // Tiempo de inactividad para marcar como inactivo (5 minutos) const INACTIVE_TIMEOUT = 5 * 60 * 1000; // Intervalo para limpiar conexiones inactivas (1 minuto) const CLEANUP_INTERVAL = 60 * 1000; ``` **Frontend** (`web/dashboard/src/App.vue`): ```javascript // Heartbeat cada 30 segundos heartbeatInterval = setInterval(() => { ... }, 30000); // Throttle de actividad: 10 segundos activityThrottleTimeout = setTimeout(() => { ... }, 10000); ``` ## 📊 Estados de Usuario 1. **Active** (Activo) - Usuario conectado vía WebSocket - Actividad reciente (< 5 minutos) - Indicador verde 2. **Inactive** (Inactivo) - Usuario conectado pero sin actividad reciente (> 5 minutos) - Indicador amarillo 3. **Offline** (Desconectado) - Sin conexión WebSocket - No aparece en la lista de usuarios activos ## 🔄 Flujo de Datos ### Conexión WebSocket ``` Cliente conecta → Servidor valida token → Actualiza lastActivity ↓ Servidor envía confirmación de conexión ↓ Cliente inicia heartbeat cada 30s ↓ Servidor responde con pong ↓ Se actualiza lastActivity en DB ``` ### Eventos de Usuario ``` Usuario interactúa (click, tecla, etc.) ↓ Cliente envía evento de actividad (throttled) ↓ Servidor actualiza lastActivity ↓ Broadcast de cambio de estado a otros usuarios ``` ### Desconexión ``` Cliente cierra conexión o timeout ↓ Servidor marca isActive = false en DB ↓ Broadcast de estado offline a otros usuarios ``` ## 🎨 Componente ActiveUsers Ubicación: `web/dashboard/src/components/ActiveUsers.vue` ### Props Ninguna (componente standalone) ### Eventos Escuchados - `user-status-change` - Cambios de estado de usuarios vía WebSocket ### Características - **Actualización automática**: cada 30 segundos - **Actualización en tiempo real**: vía eventos WebSocket - **Indicadores visuales**: - 🟢 Verde: usuario activo - 🟡 Amarillo: usuario inactivo - 📶 Icono de señal: conectado vía WebSocket - **Badges de rol**: admin/user - **Timestamp relativo**: "hace X minutos" ## 🔐 Seguridad - Solo usuarios autenticados pueden ver usuarios activos - El token se valida en cada conexión WebSocket - Las sesiones expiran automáticamente según configuración - Los heartbeats mantienen la sesión activa ## 📈 Escalabilidad El sistema está diseñado para manejar múltiples usuarios concurrentes: 1. **Throttling de actividad**: evita spam de eventos 2. **Índices en MongoDB**: consultas optimizadas 3. **Limpieza periódica**: cierre de conexiones inactivas 4. **TTL en sesiones**: eliminación automática de sesiones expiradas ## 🐛 Debugging Para ver logs de WebSocket en la consola del navegador: ```javascript // En la consola del navegador localStorage.setItem('debug', 'websocket'); ``` Logs del servidor: ``` Cliente WebSocket conectado: username (role) Cliente WebSocket desconectado: username Usuario inactivo detectado: username Cerrando conexión inactiva: username ``` ## 🖥️ Vista de Sesiones Mejorada La vista de Sesiones (`/sessions`) ahora incluye información completa sobre el estado de actividad: ### Estadísticas Ampliadas ``` ┌─────────────────────────────────────────────────────────┐ │ [Total: 10] [Válidas: 8] [🟢 Conectadas: 5] │ │ [🟡 Inactivas: 3] [🔴 Expiradas: 2] [Usuarios: 3] │ └─────────────────────────────────────────────────────────┘ ``` ### Tabla de Sesiones Cada fila muestra: - **Usuario**: nombre del usuario - **Dispositivo**: navegador, OS, IP - **Última Actividad**: tiempo relativo (ej: "Hace 2 minutos") + timestamp exacto - **Token**: primeros 16 caracteres - **Creada**: timestamp de creación - **Expira**: timestamp de expiración - **Estado**: doble indicador - ✅ Válida / 🔴 Expirada - 🟢 Conectado / 🟡 Inactivo (solo si válida) - **Acciones**: botón para eliminar sesión ### Diferencias de Estado **✅ Válida + 🟢 Conectado:** - Sesión no expirada - Usuario con actividad reciente (< 5 minutos) - Probablemente conectado vía WebSocket **✅ Válida + 🟡 Inactivo:** - Sesión no expirada - Usuario sin actividad reciente (> 5 minutos) - WebSocket desconectado o usuario inactivo **🔴 Expirada:** - Sesión pasada la fecha de expiración - Se eliminará automáticamente por TTL de MongoDB - No se puede eliminar manualmente (botón deshabilitado) ## 📝 Notas Adicionales - El sistema es compatible con múltiples pestañas/dispositivos por usuario - Cada conexión WebSocket se rastrea independientemente - Los heartbeats se reinician automáticamente si se reconecta - La actividad del usuario se detecta de forma pasiva (no intrusiva) - La vista de Sesiones se actualiza manualmente (botón "🔄 Actualizar") - Los usuarios activos se actualizan automáticamente cada 30 segundos