---
id: "US-AUTH-014"
title: "Gestión de Dispositivos"
type: "User Story"
status: "To Do"
priority: "Media"
epic: "OQI-001"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---

# US-AUTH-014: Gestión de Dispositivos

**Version:** 1.0.0
**Fecha:** 2026-01-25
**Estado:** Pendiente
**Story Points:** 5
**Prioridad:** P2 (Media)
**Épica:** [OQI-001](../_MAP.md)

---

## Historia de Usuario

**Como** usuario de Trading Platform
**Quiero** ver y administrar los dispositivos donde tengo sesión activa
**Para** mantener control total sobre mi cuenta y detectar accesos no autorizados

---

## Criterios de Aceptación

### AC-001: Listado de dispositivos activos

**Dado** que estoy autenticado
**Cuando** accedo a Configuración > Seguridad > Dispositivos
**Entonces** debería ver una lista de todos mis dispositivos con sesión activa

### AC-002: Información de cada dispositivo

**Dado** que estoy viendo mi lista de dispositivos
**Cuando** observo cada dispositivo listado
**Entonces** debería ver:
- Icono del navegador (Chrome, Safari, Firefox, etc.)
- Sistema operativo (Windows, macOS, iOS, Android, Linux)
- Modelo/Nombre del dispositivo (si está disponible)
- Ubicación aproximada (Ciudad, País)
- Dirección IP
- Fecha y hora de última actividad
- Badge "Dispositivo actual" si es la sesión activa

### AC-003: Cierre de sesión individual

**Dado** que identifico un dispositivo que no reconozco
**Cuando** hago click en "Cerrar sesión"
**Entonces** debería:
1. Ver diálogo de confirmación
2. Al confirmar, cerrar sesión en ese dispositivo
3. Ver notificación "Dispositivo desconectado"
4. El dispositivo desaparece de la lista
5. Si ese dispositivo intenta hacer request, recibe 401 Unauthorized

### AC-004: Información detallada del navegador

**Dado** que quiero investigar un dispositivo sospechoso
**Cuando** hago click en el dispositivo para ver más detalles
**Entonces** debería ver:
- Versión exacta del navegador
- Versión exacta del SO
- User Agent (para auditoría)
- Historial de actividad en últimas 7 días (gráfico de línea)
- Ubicaciones desde las que se accedió
- Primer acceso registrado
- Último acceso registrado

### AC-005: Indicador de dispositivo actual

**Dado** que estoy viendo mis dispositivos
**Cuando** identifico el dispositivo desde el cual estoy accediendo
**Entonces** debería estar claramente marcado con:
- Badge "🟢 Este dispositivo"
- Ubicado al inicio de la lista
- Color diferenciado (verde o azul)
- SIN botón "Cerrar sesión"

### AC-006: Ordenes de dispositivos

**Dado** que tengo múltiples dispositivos activos
**Cuando** veo la lista
**Entonces** debería:
- Mostrar "Este dispositivo" primero
- Los demás ordenados por última actividad (descendente)
- Mostrar fecha/hora relativa (Hace 2 min, Hace 3 horas, etc.)

### AC-007: Detección de navegadores

**Dado** que accedo desde diferentes navegadores
**Cuando** reviso mis dispositivos
**Entonces** debería ver iconos apropiados:
- 🌐 Chrome
- 🔴 Firefox
- 🧭 Safari
- 🌌 Edge
- 📱 Mobile browsers
- ❓ Desconocido

### AC-008: Datos de sesión activa

**Dado** que tengo una sesión activa
**Cuando** veo los detalles del dispositivo
**Entonces** debería ver:
- Token actual (primeros 10 caracteres) para referencia
- Fecha de creación de la sesión
- Próxima fecha de expiración
- Último refresh de token (si aplica)

### AC-009: Patrón de actividad

**Dado** que quiero monitorear actividad
**Cuando** hago click en "Ver actividad" de un dispositivo
**Entonces** debería ver:
- Gráfico de actividad por hora/día
- Número de requests por período
- Últimas 10 acciones (endpoint, timestamp)
- Horarios de pico de uso

### AC-010: Alertas de nuevos dispositivos

**Dado** que inicio sesión desde un nuevo dispositivo
**Cuando** completo el login
**Entonces** debería:
1. Ver notificación in-app "Nuevo dispositivo conectado"
2. Recibir email con detalles: navegador, SO, ubicación, IP
3. Link en email para cerrar sesión inmediatamente si no fui yo

---

## Mockup

```
┌─────────────────────────────────────────────────────────┐
│  Configuración > Seguridad > Dispositivos              │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Dispositivos activos                                   │
│  Administra dónde está abierta tu sesión               │
│                                                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │                                                  │   │
│  │  🌐 Chrome en Windows              🟢 Este      │   │
│  │                                    dispositivo  │   │
│  │  San Francisco, Estados Unidos • 201.45.67.89  │   │
│  │  Última actividad: Hace 2 minutos               │   │
│  │                                                  │   │
│  │  [Ver más detalles]                             │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │                                                  │   │
│  │  📱 Safari en iPhone                [Cerrar] │   │
│  │                                                  │   │
│  │  Ciudad de México, México • 189.203.45.12      │   │
│  │  Última actividad: Hace 3 horas                 │   │
│  │                                                  │   │
│  │  [Ver más detalles]                             │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │                                                  │   │
│  │  🔴 Firefox en Linux                [Cerrar] │   │
│  │                                                  │   │
│  │  Madrid, España • 85.123.45.67                  │   │
│  │  Última actividad: Hace 2 días                  │   │
│  │                                                  │   │
│  │  [Ver más detalles]                             │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  ────────────────────────────────────────────────────  │
│                                                         │
│  Información de seguridad                               │
│  • Total de sesiones activas: 3                        │
│  • Última sesión nueva: 3 horas atrás                  │
│  • Si ves un dispositivo desconocido, ciérralo        │
│                                                         │
└─────────────────────────────────────────────────────────┘

Modal de detalles:
┌─────────────────────────────────────────────────────────┐
│                                                         │
│  Detalles del dispositivo                               │
│                                                         │
│  🌐 Chrome 130.0.0.0                                    │
│  Windows 11 (Build 23631)                               │
│                                                         │
│  Ubicación:                                             │
│  San Francisco, Estados Unidos (37.7749°, -122.4194°)  │
│                                                         │
│  IP: 201.45.67.89                                       │
│  ISP: Verizon Communications                            │
│                                                         │
│  Sesión:                                                │
│  Creada: 25 Ene 2026, 14:30 CST                        │
│  Última actividad: Hace 2 minutos                       │
│  Próxima expiración: 24 Feb 2026, 14:30 CST             │
│  Token: abc123def...                                    │
│                                                         │
│  Actividad (últimas 24 horas):                          │
│  [Gráfico de línea con actividad por hora]              │
│                                                         │
│  Últimos requests:                                      │
│  14:45 - GET /api/portfolio                             │
│  14:43 - GET /api/market/BTC                            │
│  14:41 - POST /api/orders                               │
│                                                         │
│  ┌──────────────────────┐  ┌──────────────────────┐    │
│  │       Volver         │  │   Cerrar sesión      │    │
│  └──────────────────────┘  └──────────────────────┘    │
│                                                         │
└─────────────────────────────────────────────────────────┘

Modal de confirmación:
┌─────────────────────────────────────────────────────────┐
│                                                         │
│              ⚠️ Cerrar sesión en dispositivo?          │
│                                                         │
│  Se cerrará la sesión de:                              │
│  📱 Safari en iPhone                                    │
│  Ciudad de México, México                               │
│                                                         │
│  Esta acción no se puede deshacer. El dispositivo      │
│  deberá iniciar sesión nuevamente.                      │
│                                                         │
│  ┌──────────────────────┐  ┌──────────────────────┐    │
│  │      Cancelar        │  │   Cerrar sesión      │    │
│  └──────────────────────┘  └──────────────────────┘    │
│                                                         │
└─────────────────────────────────────────────────────────┘

Email de nuevo dispositivo:
┌─────────────────────────────────────────────────────────┐
│  De: Trading Platform Security <security@trading.com>  │
│  Asunto: Nuevo dispositivo conectado a tu cuenta        │
│                                                         │
│  Hola Juan,                                             │
│                                                         │
│  Se inició sesión en tu cuenta desde un nuevo          │
│  dispositivo:                                           │
│                                                         │
│  🌐 Chrome en Windows                                   │
│  📍 San Francisco, Estados Unidos                       │
│  🕐 25 de Enero, 2026 a las 14:30 CST                  │
│  🌐 IP: 201.45.67.89                                   │
│                                                         │
│  ¿Fuiste tú?                                            │
│  Si reconoces esta actividad, puedes ignorar este      │
│  email.                                                 │
│                                                         │
│  ¿No fuiste tú?                                         │
│  ┌──────────────────────────────────────────────┐      │
│  │    Cerrar sesión en este dispositivo         │      │
│  └──────────────────────────────────────────────┘      │
│                                                         │
│  Ver todos mis dispositivos:                            │
│  [https://trading.example.com/settings/devices]         │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

## Tareas Técnicas

### Database (DB)

- [ ] Tabla `user_sessions` (ver US-AUTH-012):
  - Verificar campos: device_type, device_name, browser, os, ip_address, location_city, location_country
  - Agregar si falta: user_agent (TEXT para auditoría)
  - Agregar si falta: last_activity_details (JSONB para tracking fino)

- [ ] Tabla `device_activity_log`:
  ```sql
  CREATE TABLE device_activity_log (
    id UUID PRIMARY KEY,
    session_id UUID REFERENCES user_sessions(id) ON DELETE CASCADE,
    endpoint VARCHAR(255),
    method VARCHAR(10), -- GET, POST, PUT, DELETE, etc.
    status_code INTEGER,
    response_time_ms INTEGER,
    created_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_session_created (session_id, created_at),
    INDEX idx_created (created_at)
  );
  ```

### Backend (BE)

- [ ] Endpoint `GET /api/auth/devices`
  - Listar todos los dispositivos activos del usuario
  - Marcar dispositivo actual
  - Ordenar por última actividad DESC
  - Incluir: device_type, device_name, os, browser, ip, location, last_activity
  - Response: HTTP 200

- [ ] Endpoint `GET /api/auth/devices/:id`
  - Obtener detalles completos de un dispositivo
  - Incluir: user_agent, histórico de actividad (7 días), primero/último acceso
  - Incluir: gráfico de actividad por hora
  - Incluir: últimos 10 requests
  - Response: HTTP 200 o 404

- [ ] Endpoint `DELETE /api/auth/devices/:id`
  - Cerrar sesión en dispositivo específico
  - Invalidar tokens asociados
  - Loguear la acción en audit trail
  - Enviar email al usuario
  - Response: HTTP 204 o 401/404

- [ ] Service `DeviceService`
  - `getAllDevices(userId)`
  - `getDeviceDetails(userId, deviceId)`
  - `terminateDevice(userId, deviceId)`
  - `isCurrentDevice(userId, sessionId)`
  - `getDeviceActivitySummary(deviceId, days)`
  - `getLastNRequests(deviceId, limit)`

- [ ] Service `DeviceDetectionService` (mejorado)
  - `parseUserAgent()` - ya existe en US-AUTH-012
  - `extractBrowserIcon()` - nuevo
  - `getDeviceFingerprint()` - nuevo para consistencia

- [ ] Logging de actividad
  - Hook/middleware para loguear cada request en `device_activity_log`
  - Incluir: endpoint, método, status code, tiempo de respuesta
  - Asociar a session_id actual

- [ ] Email de notificación
  - Template "Nuevo dispositivo conectado"
  - Incluir link para cerrar sesión desde email
  - Usar SendGrid o similar

- [ ] Tests unitarios (12 casos)
- [ ] Tests de integración (8 escenarios)

### Frontend (FE)

- [ ] Página `Settings/Security/Devices.tsx` (nueva)
- [ ] Componente `DeviceCard.tsx` (nuevo)
- [ ] Componente `DeviceDetailsModal.tsx` (nuevo)
- [ ] Modal de confirmación de cierre
- [ ] Gráfico de actividad (line chart con lightweight-charts)
- [ ] Tabla de últimos requests
- [ ] Función para obtener icono de navegador
- [ ] Badge "Este dispositivo" con lógica de sesión actual
- [ ] Ordenamiento automático por última actividad
- [ ] Tests con React Testing Library

### Testing (QA)

- [ ] E2E: Ver lista de dispositivos
- [ ] E2E: Ver detalles de dispositivo
- [ ] E2E: Cerrar sesión en dispositivo individual
- [ ] E2E: Confirmar cierre desde modal
- [ ] E2E: Dispositivo desaparece después de cerrar
- [ ] E2E: Email se envía en nuevo dispositivo
- [ ] Performance: Lista de dispositivos < 300ms
- [ ] Performance: Detalles de dispositivo < 500ms
- [ ] Seguridad: No mostrar tokens completos
- [ ] Seguridad: Solo usuario propietario puede ver/cerrar

---

## Dependencias

- **Bloqueantes:**
  - US-AUTH-012: Gestión de Sesiones (tabla user_sessions)
  - Sistema de geolocalización (de US-AUTH-012)

- **Relacionadas:**
  - US-AUTH-002: Login (sesión inicial)
  - US-AUTH-013: Cambio de contraseña (seguridad complementaria)

---

## Definition of Ready (DoR)

- [ ] API contract definido y aprobado
- [ ] Mockups validados con UX
- [ ] Esquema de BD detallado
- [ ] Servicio de email configurado
- [ ] Estructura de logs de actividad definida

---

## Definition of Done (DoD)

- [ ] Endpoint GET /api/auth/devices implementado
- [ ] Endpoint GET /api/auth/devices/:id implementado
- [ ] Endpoint DELETE /api/auth/devices/:id implementado
- [ ] Tabla device_activity_log creada
- [ ] Logging de actividad funcional
- [ ] Página Settings/Security/Devices.tsx implementada
- [ ] Componentes DeviceCard y DeviceDetailsModal implementados
- [ ] Gráfico de actividad funcional
- [ ] Email de notificación configurable
- [ ] Tests unitarios con 80%+ cobertura
- [ ] Tests de integración pasando
- [ ] Tests E2E implementados
- [ ] Documentación actualizada
- [ ] QA aprobado en staging
- [ ] Deploy a producción exitoso

---

## Notas Técnicas

### Device Identification

```typescript
interface DeviceInfo {
  id: string; // session_id
  browser: string; // "Chrome 130"
  os: string; // "Windows 11"
  device_type: "desktop" | "mobile" | "tablet" | "unknown";
  device_name: string; // "Chrome on Windows"
  ip_address: string;
  location: {
    city: string;
    country: string;
    latitude?: number;
    longitude?: number;
  };
  user_agent: string;
  is_current: boolean;
  last_activity: Date;
  created_at: Date;
  expires_at: Date;
}
```

### Browser Icons Mapping

```typescript
const BROWSER_ICONS = {
  'Chrome': '🌐',
  'Firefox': '🔴',
  'Safari': '🧭',
  'Edge': '🌌',
  'Opera': '⭕',
  'Mobile': '📱',
  'Unknown': '❓'
};
```

### Activity Graph Data

```typescript
interface ActivityDataPoint {
  hour: number; // 0-23
  date: string; // "2026-01-25"
  request_count: number;
  timestamp: Date;
}

// Graficar: últimas 24 horas con actividad por hora
// Líneas suave, mostrar puntos de máxima actividad
```

### Current Device Detection

El dispositivo "actual" se detecta comparando:
1. Session token actual en localStorage/cookie
2. Session ID del request
3. El primer dispositivo con `expires_at > now()` y session_id === actual es "Este dispositivo"

### Email Trigger

Se dispara email de "Nuevo dispositivo" cuando:
```typescript
const isNewDevice = !existingSession ||
  (existingSession.device_name !== currentDevice.device_name) ||
  (existingSession.ip_address !== currentDevice.ip_address);
```

### Audit Trail

Cada acción se registra:
```
- Dispositivo X cerrado por usuario Y
- Timestamp: 2026-01-25 14:30:00
- Reason: manual_close
- IP del usuario que cerró: admin_ip
```

---

## Requerimientos Relacionados

- [RF-AUTH-007: Gestión de Dispositivos](../requerimientos/RF-AUTH-007-devices.md)

## Especificaciones Relacionadas

- [ET-AUTH-002: JWT Tokens](../especificaciones/ET-AUTH-002-jwt.md)
- [ET-AUTH-003: Database](../especificaciones/ET-AUTH-003-database.md)
- [ET-AUTH-006: Session Management](../especificaciones/ET-AUTH-006-sessions.md)
