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

325 lines
8.8 KiB
Markdown

# 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