325 lines
8.8 KiB
Markdown
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
|
|
|