Files
wallabicher/KEEPALIVE_SYSTEM.md
Omar Sánchez Pizarro 9667ebc83d activity
Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
2026-01-21 10:31:38 +01:00

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

  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:

{
  "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

  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:

// 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