8.8 KiB
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
-
WebSocket con Heartbeat
- Envío automático de ping cada 60 segundos
- Detección de conexiones inactivas
- Cierre automático de conexiones sin respuesta
-
Seguimiento de Actividad
- Registro de última actividad en sesiones
- Estado activo/inactivo por usuario
- Timeout de inactividad: 5 minutos
-
Base de Datos
- Campo
lastActivityen sesiones - Campo
isActivepara marcar usuarios conectados - Índices optimizados para consultas rápidas
- Campo
-
Endpoints
GET /api/users/active- Obtener usuarios activos en tiempo realGET /api/admin/sessions- Obtener todas las sesiones con estado de actividad- Ambos requieren autenticación (el segundo requiere rol admin)
Frontend
-
Heartbeat Automático
- Envío de heartbeat cada 30 segundos
- Respuesta automática a pings del servidor
-
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
-
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:
{
"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:
{
"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):
// 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):
// Heartbeat cada 30 segundos
heartbeatInterval = setInterval(() => { ... }, 30000);
// Throttle de actividad: 10 segundos
activityThrottleTimeout = setTimeout(() => { ... }, 10000);
📊 Estados de Usuario
-
Active (Activo)
- Usuario conectado vía WebSocket
- Actividad reciente (< 5 minutos)
- Indicador verde
-
Inactive (Inactivo)
- Usuario conectado pero sin actividad reciente (> 5 minutos)
- Indicador amarillo
-
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:
- Throttling de actividad: evita spam de eventos
- Índices en MongoDB: consultas optimizadas
- Limpieza periódica: cierre de conexiones inactivas
- TTL en sesiones: eliminación automática de sesiones expiradas
🐛 Debugging
Para ver logs de WebSocket en la consola del navegador:
// 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