[TASK-2026-01-25-FRONTEND-ANALYSIS] docs: Add frontend specifications and user stories

- Add 5 frontend specification documents (ET-*-frontend.md):
  - ET-AUTH-006: Authentication module frontend spec
  - ET-ML-008: ML Signals module frontend spec
  - ET-LLM-007: LLM Agent module frontend spec
  - ET-PFM-008: Portfolio Manager frontend spec (design)
  - ET-MKT-003: Marketplace frontend spec (design)

- Add 8 new user stories:
  - US-AUTH-013: Global logout
  - US-AUTH-014: Device management
  - US-ML-008: Ensemble signal view
  - US-ML-009: ICT analysis view
  - US-ML-010: Multi-symbol scan
  - US-LLM-011: Execute trade from chat
  - US-PFM-013: Rebalance alerts
  - US-PFM-014: PDF report generation

- Update task index with completed analysis

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Adrian Flores Cortes 2026-01-25 01:47:27 -06:00
parent 3be1d324db
commit cdec253b02
15 changed files with 8004 additions and 3 deletions

View File

@ -0,0 +1,514 @@
---
id: "US-AUTH-013"
title: "Logout Global"
type: "User Story"
status: "To Do"
priority: "Alta"
epic: "OQI-001"
story_points: 3
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-AUTH-013: Logout Global
**Version:** 1.0.0
**Fecha:** 2026-01-25
**Estado:** Pendiente
**Story Points:** 3
**Prioridad:** P1 (Alta)
**Épica:** [OQI-001](../_MAP.md)
---
## Historia de Usuario
**Como** usuario de Trading Platform
**Quiero** poder cerrar sesión en todos mis dispositivos simultáneamente
**Para** asegurarme de que mi cuenta está completamente segura, especialmente si creo que ha sido comprometida o si pierdo un dispositivo
---
## Criterios de Aceptación
### AC-001: Opción de logout global en perfil
**Dado** que estoy autenticado y en mi perfil
**Cuando** accedo a Configuración > Seguridad > Sesiones
**Entonces** debería ver un botón "Cerrar sesión en todos los dispositivos" o similar
### AC-002: Confirmación de logout global
**Dado** que quiero cerrar sesión en todos mis dispositivos
**Cuando** hago click en el botón de logout global
**Entonces** debería ver un modal de confirmación que indique:
- "Esto cerrará sesión en TODOS tus dispositivos"
- "Incluida esta sesión actual"
- "Tendrás que volver a iniciar sesión"
- Botón "Cancelar" y "Cerrar todas las sesiones"
### AC-003: Invalidación de todos los tokens
**Dado** que confirmo el logout global
**Cuando** se ejecuta la acción
**Entonces** debería:
1. Invalidar TODOS los tokens JWT de todas las sesiones
2. Invalidar TODOS los refresh tokens
3. Marcar todas las sesiones como "closed" en la DB
4. No permitir que ningún token anterior funcione
### AC-004: Redirección a login
**Dado** que logout global se completó exitosamente
**Cuando** se cierre la sesión
**Entonces** debería:
1. Mostrar mensaje "Sesión cerrada en todos los dispositivos"
2. Redirigir a la página de login después de 2 segundos
3. Limpiar localStorage y cookies
4. No permitir acceso a rutas protegidas
### AC-005: Email de notificación
**Dado** que ejecuté logout global
**Cuando** se cierre la sesión
**Entonces** debería recibir email en la dirección registrada indicando:
- "Se cerró sesión en todos tus dispositivos"
- Fecha y hora
- Si no fuiste tú, link para cambiar contraseña
### AC-006: Impossibilidad de continuar con tokens antiguos
**Dado** que hice logout global
**Cuando** intento usar un token anterior en cualquier dispositivo
**Entonces** debería recibir:
- Código 401 Unauthorized
- Mensaje "Sesión inválida"
- Redirección a login
### AC-007: Operación atómica
**Dado** que inicio logout global
**Cuando** hay una falla de red durante el proceso
**Entonces** debería:
- Reintentar automáticamente 3 veces
- Si continúa fallando, mostrar error al usuario
- Los tokens deben estar invalidados (garantizar atomicidad)
### AC-008: Auditoria y registro
**Dado** que ejecuté logout global
**Cuando** se complete la acción
**Entonces** debería:
- Quedar registrado en logs de auditoria
- Incluir timestamp, user_id, tipo de acción
- Ser visible en historial de sesiones como "Cerrado por logout global"
---
## Mockup
```
┌─────────────────────────────────────────────────────────────┐
│ Configuración > Seguridad > Sesiones │
├─────────────────────────────────────────────────────────────┤
│ │
│ Sesiones activas │
│ Gestiona dónde está abierta tu cuenta │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 💻 Chrome en macOS 🟢 Esta sesión │ │
│ │ San Francisco, Estados Unidos • 201.45.67.89 │ │
│ │ Última actividad: Hace 2 minutos │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 📱 Safari en iPhone [Cerrar sesión]│ │
│ │ Ciudad de México, México • 189.203.45.12 │ │
│ │ Última actividad: Hace 3 horas │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 🔒 CERRAR SESIÓN EN TODOS LOS DISPOSITIVOS │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ Esto cerrará sesión en esta y todas las otras │
│ sesiones. Tendrás que volver a iniciar sesión. │
│ │
└─────────────────────────────────────────────────────────────┘
Modal de confirmación:
┌─────────────────────────────────────────────────────────────┐
│ │
│ ⚠️ Cerrar sesión en todos los dispositivos │
│ │
│ Esto cerrará sesión INMEDIATAMENTE en: │
│ │
│ • Esta sesión (Chrome en macOS) │
│ • Safari en iPhone │
│ • Firefox en Windows │
│ │
│ Se cerrarán 3 sesiones en total. │
│ │
│ Si no fuiste tú, considera cambiar tu contraseña después. │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Cancelar │ │ Cerrar todo │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Email de notificación:
┌─────────────────────────────────────────────────────────────┐
│ De: Trading Platform Security <security@trading.com>
│ Asunto: Se cerró sesión en todos tus dispositivos │
│ │
│ Hola Juan, │
│ │
│ Se cerró sesión en TODOS tus dispositivos. │
│ │
│ 🕐 25 de Enero, 2026 a las 14:30 CST │
│ 📍 Desde: San Francisco, Estados Unidos │
│ │
│ ¿Fuiste tú? │
│ Si reconoces esta actividad, puedes ignorar este email. │
│ │
│ ¿No fuiste tú? │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Cambiar contraseña inmediatamente │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Para seguridad adicional, considera: │
│ • Verificar tu email de recuperación │
│ • Revisar actividades recientes │
│ • Habilitar autenticación de dos factores │
│ │
└─────────────────────────────────────────────────────────────┘
Mensaje después de logout:
┌─────────────────────────────────────────────────────────────┐
│ │
│ ✓ Sesión cerrada en todos los dispositivos │
│ │
│ Se cerrará sesión automáticamente en 2 segundos... │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## Tareas Técnicas
### Database (DB)
- [ ] Tabla `user_sessions` (ya existe en US-AUTH-012)
- Verificar columnas: `expires_at`, `status`
- Agregar índice: `idx_user_active` (user_id, WHERE status = 'active')
- [ ] Tabla `session_audit_log`:
```sql
CREATE TABLE session_audit_log (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id) NOT NULL,
action VARCHAR(100) NOT NULL, -- 'logout_global', 'logout_single', etc.
session_id UUID REFERENCES user_sessions(id),
ip_address VARCHAR(45),
user_agent TEXT,
created_at TIMESTAMP DEFAULT NOW(),
INDEX idx_user_created (user_id, created_at),
INDEX idx_action_created (action, created_at)
);
```
### Backend (BE)
- [ ] Endpoint `POST /api/v1/auth/logout-all`
- Autenticación requerida
- Parámetro: `confirmation: boolean`
- Respuesta: `{ success: boolean, message: string, redirectUrl: string }`
- Rate limit: 1 request/min por usuario
- [ ] Service `LogoutService`
- `logoutGlobal(userId: string)`
- Buscar todas las sesiones activas del usuario
- Invalidar todos los tokens
- Marcar sesiones como 'closed'
- Registrar en auditoria
- Retornar conteo de sesiones cerradas
- [ ] Invalidación de tokens:
- Crear tabla/cache de tokens invalidados (blacklist)
- Middleware: verificar si token está en blacklist
- Usar Redis para expiración automática
- [ ] Email notification:
- Template: `logout-all.html`
- Enviar a dirección registrada
- Incluir: fecha, hora, ubicación, link de seguridad
- Service: `EmailService.sendLogoutAllNotification()`
- [ ] Logging y auditoria:
- Registrar en `session_audit_log`
- Incluir: timestamp, user_id, acción, IP, user_agent
- Service: `AuditService.logLogoutAll()`
- [ ] Tests unitarios (8 casos)
- Logout exitoso
- Logout con error de DB
- Email enviado correctamente
- Tokens invalidados
- Auditoria registrada
- Rate limiting
- Concurrencia (múltiples requests simultáneos)
- Validación de autenticación
- [ ] Tests de integración (5 escenarios)
- Logout global desde múltiples dispositivos
- Verificar 401 con tokens anteriores
- Email recibido
- Auditoria registrada
- Redirección correcta
### Frontend (FE)
- [ ] Componente `LogoutAllButton.tsx`
- Botón de logout global
- En Settings > Security > Sessions
- [ ] Modal `LogoutAllConfirmationModal.tsx`
- Mostrar lista de sesiones que se cerrarán
- Advertencia clara
- Botones Cancelar/Confirmar
- [ ] Integración en `Sessions.tsx`
- Agregar botón y modal
- Manejar respuesta de API
- Mostrar mensaje de éxito
- Redirigir a login
- [ ] Servicio `AuthService`
- Método `logoutAll(): Promise<{ success: boolean }>`
- Llamar a POST /api/v1/auth/logout-all
- Limpiar tokens locales
- Redirigir a login
- [ ] Tests con React Testing Library
- Renderizar componente
- Click en botón
- Mostrar modal
- Enviar confirmación
- Verificar redirección
### Testing (QA)
- [ ] E2E: Logout global exitoso
- [ ] E2E: Modal de confirmación
- [ ] E2E: Email recibido
- [ ] E2E: Tokens invalidados en todos los dispositivos
- [ ] E2E: Redirección a login
- [ ] E2E: Auditoria registrada
- [ ] Test de concurrencia: Múltiples logouts globales simultáneos
- [ ] Test de seguridad: Tokens antiguos no funcionan
- [ ] Performance: Logout global < 500ms
---
## Dependencias
- **Bloqueantes:**
- US-AUTH-012: Gestión de Sesiones (para tablas y flujos)
- Servicio de email configurado
- **Relacionadas:**
- US-AUTH-002: Login genera tokens
- US-AUTH-014: Cambio de contraseña por seguridad
---
## Definition of Ready (DoR)
- [ ] Mockups aprobados
- [ ] API contract definido
- [ ] Estrategia de invalidación de tokens definida
- [ ] Template de email diseñado
- [ ] Esquema de auditoria revisado
---
## Definition of Done (DoD)
- [ ] Código implementado y revisado
- [ ] Tests unitarios con 80%+ cobertura
- [ ] Tests de integración pasando
- [ ] Tests E2E implementados
- [ ] Email de notificación funcional
- [ ] Auditoria registrada correctamente
- [ ] Rate limiting configurado
- [ ] Tokens invalidados en todos los dispositivos
- [ ] Redirección a login funcional
- [ ] Documentación actualizada
- [ ] QA aprobado en staging
- [ ] Deploy a producción exitoso
---
## Notas Técnicas
### Estrategia de Invalidación de Tokens
**Opción 1: Token Blacklist (Recomendado)**
```typescript
// En Redis, crear entrada para cada token invalidado
await redis.setex(
`token_blacklist:${jti}`,
tokenExpirationTime,
'revoked'
);
// En middleware, verificar si token está en blacklist
const isBlacklisted = await redis.exists(`token_blacklist:${jti}`);
if (isBlacklisted) {
throw new UnauthorizedException('Token revoked');
}
```
**Opción 2: Token Version (Alternativa)**
```typescript
// En tabla users, guardar version_token
// Al hacer logout global, incrementar version
UPDATE users SET token_version = token_version + 1 WHERE id = ?
// En JWT, incluir token_version
const token = generateJWT({
sub: user.id,
token_version: user.token_version,
...
});
// En middleware, validar que token_version coincida
const user = await findUser(jti.sub);
if (token.token_version !== user.token_version) {
throw new UnauthorizedException('Token revoked');
}
```
Recomendamos Opción 1 (Redis) por precisión inmediata.
### Flujo de Logout Global
```
1. Usuario hace click en "Cerrar sesión en todos los dispositivos"
2. Frontend muestra modal de confirmación
3. Usuario confirma
4. Frontend envía POST /api/v1/auth/logout-all
5. Backend:
a. Verifica autenticación
b. Busca todas las sesiones del usuario
c. Marca todas como 'closed'
d. Invalida todos los tokens en Redis/Cache
e. Registra acción en auditoria
f. Envía email de notificación
6. Frontend recibe respuesta exitosa
7. Frontend limpia tokens locales
8. Frontend muestra mensaje "Sesión cerrada"
9. Frontend redirige a /login después de 2 segundos
```
### Rate Limiting
```typescript
// Usar express-rate-limit o similar
const logoutAllLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minuto
max: 1, // 1 request por minuto
message: 'Solo puedes hacer logout global 1 vez por minuto'
});
app.post('/api/v1/auth/logout-all', logoutAllLimiter, logoutAllHandler);
```
### Transacción en DB
```typescript
async function logoutGlobal(userId: string) {
return await db.$transaction(async (tx) => {
// 1. Buscar sesiones
const sessions = await tx.userSessions.findMany({
where: { user_id: userId, status: 'active' }
});
// 2. Marcar como closed
await tx.userSessions.updateMany({
where: { user_id: userId, status: 'active' },
data: { status: 'closed', expires_at: new Date() }
});
// 3. Registrar auditoria
await tx.sessionAuditLog.create({
data: {
user_id: userId,
action: 'logout_global',
created_at: new Date()
}
});
return sessions.length;
});
}
```
### Email Template
```html
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.container { max-width: 600px; margin: 0 auto; }
.header { background-color: #f44336; color: white; padding: 20px; }
.content { padding: 20px; }
.warning { background-color: #fff3cd; padding: 10px; border-left: 4px solid #ffc107; }
.button { background-color: #2196f3; color: white; padding: 10px 20px; text-decoration: none; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Sesión cerrada en todos tus dispositivos</h1>
</div>
<div class="content">
<p>Hola {{ user_name }},</p>
<p>Se cerró sesión en TODOS tus dispositivos.</p>
<div class="warning">
<strong>Detalles:</strong><br>
Fecha: {{ date }} a las {{ time }} {{ timezone }}<br>
Ubicación: {{ location }}<br>
</div>
<p>¿Fuiste tú? Si reconoces esta actividad, puedes ignorar este email.</p>
<p>¿No fuiste tú? Considera cambiar tu contraseña inmediatamente:</p>
<a href="{{ password_reset_url }}" class="button">Cambiar contraseña</a>
</div>
</div>
</body>
</html>
```
---
## Requerimientos Relacionados
- [RF-AUTH-007: Logout Global](../requerimientos/RF-AUTH-007-logout-global.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)

View File

@ -0,0 +1,505 @@
---
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)

View File

@ -0,0 +1,442 @@
---
id: "US-ML-008"
title: "Ver Señal Ensemble"
type: "User Story"
status: "Pending"
priority: "Alta"
epic: "OQI-006"
project: "trading-platform"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-ML-008: Ver Señal Ensemble
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | US-ML-008 |
| **Épica** | OQI-006 - Señales ML y Predicciones |
| **Módulo** | ml-signals |
| **Prioridad** | P0 (Alta) |
| **Story Points** | 5 |
| **Sprint** | Sprint 8 |
| **Estado** | Pendiente |
| **Asignado a** | Por asignar |
---
## Historia de Usuario
**Como** trader/inversor,
**quiero** ver la señal combinada (ensemble) de múltiples modelos ML con sus contribuciones individuales,
**para** tomar decisiones más informadas y confiar en predicciones robustas de múltiples fuentes.
## Descripción Detallada
El usuario debe poder ver una vista integrada que combina las predicciones de múltiples modelos ML (LSTM, RandomForest, SVM, etc.) en una señal consolidada (ensemble). La vista debe mostrar:
1. **Señal Ensemble Principal:** La decisión combinada (BUY/SELL/HOLD) con confianza agregada
2. **Confianza Combinada:** Porcentaje agregado considerando pesos de cada modelo
3. **Contribuciones Individuales:** Lista de modelos participantes con sus predicciones y pesos
4. **Scoring Detallado:** Score de cada modelo, peso asignado, contribución a la decisión final
5. **Votación de Modelos:** Cuántos modelos votaron por cada acción
6. **Consenso:** Nivel de acuerdo entre modelos
---
## Mockups/Wireframes
```
┌──────────────────────────────────────────────────────────────────┐
│ ENSEMBLE SIGNAL BTCUSDT │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ ENSEMBLE DECISION │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ Signal: 🟢 BUY │ │
│ │ Confidence: ████████░ 82% │ │
│ │ Score: 8.2/10 │ │
│ │ Consensus: STRONG (4/5 models agree) │ │
│ │ │ │
│ │ Entry Price Avg: $89,450.00 │ │
│ │ TP1: $89,650 (+0.22%) | TP2: $89,850 (+0.45%) │ │
│ │ TP3: $90,050 (+0.67%) | SL: $89,150 (-0.33%) │ │
│ │ │ │
│ │ Generated: 2026-01-25 10:30:15 UTC │ │
│ │ Expires: 2026-01-25 14:30:15 UTC (4h horizon) │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ MODEL CONTRIBUTIONS │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ [Model Distribution] │ │
│ │ │ │
│ │ 🟢 BUY: 4 models (80%) ████████░░ │ │
│ │ 🔴 SELL: 1 model (20%) ██░░░░░░░░ │ │
│ │ 🔵 HOLD: 0 models (0%) ░░░░░░░░░░ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ DETAILED MODEL VOTING │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ Model Name Prediction Score Weight Contribution│ │
│ │ ─────────────────────────────────────────────────────────│ │
│ │ ✓ LSTM 🟢 BUY 87% 25% 21.75% │ │
│ │ ✓ RandomForest 🟢 BUY 85% 30% 25.50% │ │
│ │ ✓ SVM 🟢 BUY 78% 20% 15.60% │ │
│ │ ✓ Transformer 🟢 BUY 81% 15% 12.15% │ │
│ │ ✗ GradientBoosting 🔴 SELL 72% 10% -7.20%* │ │
│ │ │ │
│ │ *Negative contribution indicates minority prediction │ │
│ │ │ │
│ │ CONSENSUS ANALYSIS: │ │
│ │ • 4 out of 5 models predict BUY (strong agreement) │ │
│ │ • Confidence scores range from 72% to 87% (tight) │ │
│ │ • 1 outlier (GradientBoosting) predicts SELL │ │
│ │ • Overall consensus strength: 80% (STRONG) │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ HISTORICAL MODEL PERFORMANCE │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ Model Name Accuracy Win Rate Last 7d Trend │ │
│ │ ─────────────────────────────────────────────────────────│ │
│ │ LSTM 84.2% 71.5% 72% ↑ Good │ │
│ │ RandomForest 82.1% 68.9% 69% ↑ Good │ │
│ │ SVM 79.8% 65.3% 66% → Stable │ │
│ │ Transformer 81.5% 70.2% 71% ↑ Good │ │
│ │ GradientBoosting 76.2% 61.4% 62% ↓ Declining│ │
│ │ │ │
│ │ Ensemble (Combined) 85.6% 75.1% 76% ↑ Excellent│ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ [View Technical Context] [Compare Models] [View Signal History] │
│ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ MODEL COMPARISON CHART │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Prediction Heatmap: │
│ │
│ LSTM RF SVM TRF GB ENS │
│ BTCUSDT [87%] [85%][78%][81%][72%][82%] 🟢 BUY │
│ ETHUSDT [84%] [86%][75%][80%][70%][81%] 🟢 BUY │
│ XRPUSDT [81%] [79%][72%][76%][68%][77%] 🟢 BUY │
│ SOLUSDT [76%] [74%][69%][71%][65%][72%] 🟡 HOLD (Weak) │
│ │
│ Legend: ENS = Ensemble Vote │
│ │
│ Consensus Strength Graph: │
│ │
│ 100% │ │
│ │ ╱─╲ │
│ 80% │ ╱─ ╲╱╲ │
│ │ ╱─ ╲─╲ │
│ 60% │╱─ ╲─── │
│ │────────────────────► time │
│ 40% │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
---
## Criterios de Aceptación
**Escenario 1: Ver señal ensemble**
```gherkin
DADO que el usuario está autenticado en Trading Platform
CUANDO navega a "ML Signals > Ensemble" para un símbolo (ej: BTCUSDT)
ENTONCES ve la señal ensemble con:
- Decisión principal (BUY/SELL/HOLD)
- Confianza combinada (%)
- Score de 0 a 10
- Nivel de consenso (STRONG/MODERATE/WEAK)
- Número de modelos votando por cada acción
Y se muestra el timestamp de generación y expiración
```
**Escenario 2: Ver contribuciones de modelos**
```gherkin
DADO que el usuario está viendo una señal ensemble
CUANDO expande la sección "Model Contributions"
ENTONCES ve una tabla con:
- Nombre de cada modelo
- Predicción individual (BUY/SELL/HOLD)
- Score/confianza de cada modelo (%)
- Peso asignado a cada modelo (%)
- Contribución calculada al resultado final
Y las filas están ordenadas por peso (mayor a menor)
```
**Escenario 3: Ver votación de modelos**
```gherkin
DADO que existen 5 modelos en el ensemble
CUANDO veo la distribución de votos
ENTONCES se muestra:
- Gráfico de barras: cuántos modelos votaron por cada acción
- Porcentaje: 80% BUY, 20% SELL, 0% HOLD
- Indicador visual de consenso (fuerte/moderado/débil)
- Descripción: "4 out of 5 models agree on BUY"
```
**Escenario 4: Ver performance histórico de modelos**
```gherkin
DADO que el usuario quiere evaluar fiabilidad de cada modelo
CUANDO expande "Historical Model Performance"
ENTONCES ve para cada modelo:
- Accuracy (%)
- Win Rate en los últimos 7 días (%)
- Tendencia (↑/→/↓)
- Comparación con ensemble
```
**Escenario 5: Detectar outliers**
```gherkin
DADO que 1 modelo predice diferente al ensemble (ej: SELL vs BUY)
CUANDO veo la tabla de contribuciones
ENTONCES:
- Se destaca visualmente con icono ✗ (en lugar de ✓)
- Se muestra con color diferente (rojo vs verde)
- Se incluye nota: "Minority prediction"
- Contribución se resta del total (negativa)
```
**Escenario 6: Comparar modelos lado a lado**
```gherkin
DADO que quiero evaluar predicciones de todos los modelos
CUANDO hago click en "Compare Models"
ENTONCES se abre una vista con:
- Heatmap de predicciones por símbolo
- Scores de cada modelo lado a lado
- Tendencia de consenso en tiempo (gráfico)
- Botón para exportar comparación
```
## Criterios Adicionales
- [ ] Debe cargar en menos de 1.5 segundos
- [ ] Soportar 5-10 modelos simultáneamente
- [ ] Actualizar automáticamente cada 30 segundos (si hay nuevas señales)
- [ ] Ser responsive en mobile
- [ ] Mostrar claramente cuál es el modelo más confiable
- [ ] Detectar y resaltar predicciones outliers
- [ ] Permitir ponderar dinámicamente los modelos (admin)
---
## Tareas Técnicas
**Backend:**
- [ ] BE-ML-016: Crear endpoint GET /api/ml/ensemble/:symbol
- [ ] BE-ML-017: Implementar cálculo de confianza combinada (weighted average)
- [ ] BE-ML-018: Implementar votación y consenso de modelos
- [ ] BE-ML-019: Obtener scores individuales de cada modelo
- [ ] BE-ML-020: Calcular performance histórico de modelos
- [ ] BE-ML-021: Endpoint GET /api/ml/ensemble/:symbol/models (detalle)
- [ ] BE-ML-022: Endpoint GET /api/ml/ensemble/comparison (heatmap)
**Frontend:**
- [ ] FE-ML-035: Crear componente `EnsembleSignal.tsx`
- [ ] FE-ML-036: Crear componente `ModelVoting.tsx`
- [ ] FE-ML-037: Crear componente `ModelContributions.tsx` (tabla)
- [ ] FE-ML-038: Crear componente `ConsensusIndicator.tsx`
- [ ] FE-ML-039: Crear componente `ModelPerformance.tsx`
- [ ] FE-ML-040: Crear componente `ModelComparison.tsx` (heatmap)
- [ ] FE-ML-041: Implementar auto-refresh cada 30 segundos
- [ ] FE-ML-042: Agregar indicadores visuales para outliers
**Tests:**
- [ ] TEST-ML-016: Test de cálculo de confianza combinada
- [ ] TEST-ML-017: Test de votación de modelos
- [ ] TEST-ML-018: Test E2E de vista ensemble
- [ ] TEST-ML-019: Test de detección de outliers
---
## Dependencias
**Depende de:**
- [ ] RF-ML-003: Múltiples modelos ML entrenados (LSTM, RF, SVM, Transformer, GB)
- [ ] RF-ML-004: Sistema de pesos y scoring de modelos
- [ ] US-ML-001: Ver señal básica - Estado: Completado
**Bloquea:**
- [ ] US-ML-009: Configurar ensemble (admin puede cambiar pesos)
- [ ] US-ML-010: Histórico de ensemble signals
---
## Notas Técnicas
**Endpoints involucrados:**
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | /api/ml/ensemble/:symbol | Obtener señal ensemble actual |
| GET | /api/ml/ensemble/:symbol/models | Detalle de cada modelo |
| GET | /api/ml/ensemble/comparison | Heatmap de predicciones |
| GET | /api/ml/ensemble/:symbol/performance | Performance histórico |
**Query Parameters - Ensemble Signal:**
```
GET /api/ml/ensemble/BTCUSDT?
include_performance=true&
include_comparison=false
```
**Response esperado:**
```typescript
interface EnsembleSignalResponse {
ensemble: {
symbol: string;
action: 'BUY' | 'SELL' | 'HOLD';
confidence: number; // weighted average, 0-100
score: number; // 0-10
consensus_strength: 'STRONG' | 'MODERATE' | 'WEAK';
timestamp: string;
expires_at: string;
entry_price: number;
tp1: number;
tp2: number;
tp3: number;
sl: number;
};
model_votes: {
buy_count: number;
sell_count: number;
hold_count: number;
total_models: number;
buy_percentage: number;
sell_percentage: number;
hold_percentage: number;
};
models: ModelContribution[];
consensus_analysis: {
all_agree: boolean;
minority_models: string[];
agreement_percentage: number;
description: string;
};
}
interface ModelContribution {
model_id: string;
model_name: string;
prediction: 'BUY' | 'SELL' | 'HOLD';
score: number; // 0-100
confidence: number; // 0-100
weight: number; // 0-100, suma con otros = 100
contribution: number; // score * weight
is_outlier: boolean;
performance?: ModelPerformance;
}
interface ModelPerformance {
accuracy: number; // last 100 predictions
win_rate: number; // last 7 days
total_signals: number;
correct_signals: number;
trend: 'UP' | 'STABLE' | 'DOWN';
last_updated: string;
}
```
**Cálculos:**
```typescript
// Confianza combinada (weighted average)
ensemble_confidence = sum(model.score * model.weight) / 100
// Votación
buy_percentage = (buy_count / total_models) * 100
// Contribución de cada modelo
contribution = model.score * model.weight / 100
// Consenso
consensus_strength = all_models_agree ? 'STRONG' :
buy_percentage > 60 ? 'MODERATE' : 'WEAK'
```
**Componentes UI:**
- `EnsembleSignal`: Container principal
- `EnsembleHeader`: Decisión + confianza + consenso
- `ModelVoting`: Distribución de votos (barras)
- `ModelContributions`: Tabla detallada
- `ConsensusIndicator`: Visual de acuerdo
- `ModelPerformance`: Stats históricos
- `ModelComparison`: Heatmap
- `OutlierBadge`: Indicador de predicción minoritaria
**Estado (Zustand):**
```typescript
interface EnsembleStore {
ensemble: EnsembleSignalResponse | null;
selectedSymbol: string;
isLoading: boolean;
lastUpdated: string;
autoRefreshInterval: number; // 30000 ms
fetchEnsemble: (symbol: string) => Promise<void>;
setAutoRefresh: (enabled: boolean) => void;
compareModels: () => void;
}
```
---
## Definition of Ready (DoR)
- [x] Historia claramente escrita (quién, qué, por qué)
- [x] Criterios de aceptación definidos
- [x] Story points estimados
- [x] Dependencias identificadas
- [x] Modelos ML disponibles (LSTM, RF, SVM, Transformer, GB)
- [x] Diseño/mockup disponible
## Definition of Done (DoD)
- [ ] Código implementado según criterios
- [ ] Tests unitarios escritos y pasando (>80% coverage)
- [ ] Tests E2E pasando
- [ ] Code review aprobado
- [ ] Documentación actualizada
- [ ] QA aprobado en staging
- [ ] Auto-refresh funciona sin memory leaks
- [ ] Performance: carga < 1.5s
- [ ] Mobile responsive
- [ ] Outliers detectados y resaltados correctamente
- [ ] Desplegado en producción
---
## Historial de Cambios
| Fecha | Cambio | Autor |
|-------|--------|-------|
| 2026-01-25 | Creación | Requirements-Analyst |
---
**Creada por:** Requirements-Analyst
**Fecha:** 2026-01-25
**Última actualización:** 2026-01-25

View File

@ -0,0 +1,495 @@
---
id: "US-ML-009"
title: "Ver Análisis ICT"
type: "User Story"
status: "Pending"
priority: "Alta"
epic: "OQI-006"
project: "trading-platform"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-ML-009: Ver Análisis ICT
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | US-ML-009 |
| **Épica** | OQI-006 - Señales ML y Predicciones |
| **Módulo** | ml-signals |
| **Prioridad** | P0 (Alta) |
| **Story Points** | 5 |
| **Sprint** | Sprint 8 |
| **Estado** | Pendiente |
| **Asignado a** | Por asignar |
---
## Historia de Usuario
**Como** trader/inversor,
**quiero** ver el análisis ICT (Inner Circle Trader) que incluye zonas de liquidez, fair value gaps, y order blocks,
**para** identificar puntos de entrada/salida de alto potencial basados en la metodología ICT.
## Descripción Detallada
El usuario debe poder visualizar en el chart de precios un análisis completo de la metodología ICT que incluya:
1. **Zonas de Liquidez (Liquidity Zones)**: Áreas donde se acumulan órdenes de compra/venta
2. **Fair Value Gaps (FVGs)**: Brechas de precio donde no hay transacciones (gaps de aire)
3. **Order Blocks (OB)**: Bloques de órdenes que actúan como soporte/resistencia
4. **Puntos de Interés (POI)**: Zonas clave de reversión y manipulación de precios
Cada elemento debe ser interactivo mostrando detalles como tamaño de la zona, potencia, fechas de formación, y probabilidad de inversión de precio.
## Mockups/Wireframes
```
┌──────────────────────────────────────────────────────────────────┐
│ ICT ANALYSIS - BTCUSDT 4h │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Controls: │
│ [Liquidity Zones ☑] [FVGs ☑] [Order Blocks ☑] [POI ☑] │
│ [Bias: Bullish ▼] [Threshold: Medium ▼] [Legend] │
│ │
│ ══════════════════════════════════════════════════════════════ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ BTCUSDT / 4H Chart │ │
│ │ │ │
│ │ ╱╲ │ │
│ │ ╱┌──┐╲ 🔵 Order Block │ │
│ │ ╱╲ ╱│ 🔵 │╲ (Bullish, 8.2/10) │ │
│ │ ╱┌──┐╲ │ │ ╲ Entry: $89,200 │ │
│ │ │ 🟢│ ╲ │ │ ╲ Strength: 95% │ │
│ │ ╱┌───┼────┼───╲╱ │ │ ╲ │ │
│ │ │ 🟡 │ 🔴 │ ║ │ │ ╲ ☑ Liquidity Zone │ │
│ │╱───┼────┼────┼──║──────┼────┼──────╲ Above: $90,100 │ │
│ │─────┼────┼────┼──║──────┼────┼─────── Strength: High │ │
│ │ │ │ │ ║ │ │ Probability: 75% │ │
│ │ │ │ │ ║ │ 🔘 │ │ │
│ │ │ │ │ ║ │ 🟣 │ 🟡 Fair Value Gap │
│ │ └────┴────┴──║──────┴────┴── $89,850 - $89,650 │
│ │ ║ Gap Size: 0.2% │
│ │ ║ Type: Bullish Breaker │
│ │ │
│ │ [Zoom] [Reset] [Compare] [Backtest This] [Alerts] │
│ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ICT ELEMENTS FOUND (16) │
│ ═════════════════════════════════════════════════════════════ │
│ │
│ ┌─ LIQUIDITY ZONES (4) ─────────────────────────────────────┐ │
│ │ ☑ Above Current Price: │ │
│ │ • $90,100 - $90,500 (Strength: 94%) - Last 3H ago │ │
│ │ • $91,200 - $91,800 (Strength: 87%) - Last 8H ago │ │
│ │ ☑ Below Current Price: │ │
│ │ • $88,500 - $88,200 (Strength: 91%) - Last 2H ago │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ FAIR VALUE GAPS (3) ──────────────────────────────────────┐ │
│ │ • $89,850 - $89,650 (Bullish Breaker, Gap Size: 0.2%) │ │
│ │ ├─ Formed: 45 min ago │ │
│ │ ├─ Status: Unmitigated (Not touched by price) │ │
│ │ └─ Probability: High that will be filled in 4-8H │ │
│ │ • $87,900 - $87,500 (Bearish Breaker, Gap Size: 0.4%) │ │
│ │ ├─ Formed: 6H ago │ │
│ │ ├─ Status: Partially Mitigated │ │
│ │ └─ Probability: Medium that will be retested │ │
│ │ • $90,200 - $89,950 (Bullish Breaker, Gap Size: 0.25%) │ │
│ │ ├─ Formed: 2H ago │ │
│ │ ├─ Status: Unmitigated │ │
│ │ └─ Probability: Very High (needs mitigation) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ ORDER BLOCKS (5) ────────────────────────────────────────┐ │
│ │ ☑ Bullish Order Block: │ │
│ │ • Entry: $89,200 - $89,350 (Strength: 95%, Score: 8.2) │ │
│ │ • Formed during strong uptrend 3H ago │ │
│ │ • Touch points: 2 (May retry) │ │
│ │ • Next resistance: $90,100 (Liquidity Zone) │ │
│ │ ☑ Bearish Order Block: │ │
│ │ • Entry: $90,500 - $90,650 (Strength: 88%, Score: 7.9) │ │
│ │ • Formed during downtrend 6H ago │ │
│ │ • Touch points: 1 (Fresh block) │ │
│ │ • Next support: $89,500 (FVG area) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ POINTS OF INTEREST (4) ──────────────────────────────────┐ │
│ │ • $90,100 (Swing High + Liquidity Zone) │ │
│ │ ├─ Type: Supply/Resistance │ │
│ │ ├─ Confluence: 3 levels │ │
│ │ └─ Probability of reversal: 82% │ │
│ │ • $88,500 (Swing Low + Liquidity Zone) │ │
│ │ ├─ Type: Demand/Support │ │
│ │ ├─ Confluence: 2 levels │ │
│ │ └─ Probability of bounce: 76% │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
---
## Criterios de Aceptación
**Escenario 1: Mostrar análisis ICT completo**
```gherkin
DADO que el usuario está en la pantalla de chart
CUANDO abre la sección "ICT Analysis"
ENTONCES se visualizan en el chart:
- Zonas de liquidez (coloreadas y etiquetadas)
- Fair Value Gaps (dibujados como rectángulos vacíos)
- Order Blocks (rectángulos rellenos con poder)
- Puntos de Interés (círculos/estrelas destacadas)
Y cada elemento tiene color diferenciado (bullish/bearish)
Y se muestra un panel lateral con listado de todos los elementos
```
**Escenario 2: Filtrar elementos ICT**
```gherkin
DADO que el usuario está viendo el análisis ICT
CUANDO desactiva un tipo de elemento (ej: FVGs)
ENTONCES desaparecen del chart
Y se actualiza el contador en el panel lateral
Y el resto de elementos se mantienen visibles
```
**Escenario 3: Ver detalles de zona de liquidez**
```gherkin
DADO que el usuario está en ICT Analysis
CUANDO hace hover/click en una zona de liquidez
ENTONCES aparece un tooltip/modal con:
- Rango de precios (high-low)
- Fortaleza/poder de la zona (%)
- Fecha de formación
- Número de toques/veces que fue tocada
- Probabilidad de que el precio vuelva a esa zona
- Botón para crear orden en esa zona
```
**Escenario 4: Ver detalles de Fair Value Gap**
```gherkin
DADO que el usuario está en ICT Analysis
CUANDO hace click en un FVG
ENTONCES aparece un modal con:
- Rango del gap (precio alto - precio bajo)
- Tipo de gap (Bullish Breaker / Bearish Breaker / Continuation)
- Tamaño del gap (en pips/%)
- Estado (Unmitigated / Partially mitigated / Fully mitigated)
- Fecha de formación
- Probabilidad de que se cierre el gap (%)
- Momento estimado de cierre
- [Ver en chart] [Crear alerta] [Crear orden]
```
**Escenario 5: Ver detalles de Order Block**
```gherkin
DADO que el usuario está en ICT Analysis
CUANDO hace click en un Order Block
ENTONCES aparece un modal con:
- Rango de entrada del bloque
- Tipo (Bullish / Bearish)
- Score de fortaleza (1-10)
- Potencia del bloque (%)
- Número de veces que fue tocado
- Formación: qué vela/candle lo creó
- Próxima resistencia/soporte
- [Crear orden en este bloque] [Crear alerta]
```
**Escenario 6: Cambiar timeframe**
```gherkin
DADO que el usuario está en ICT Analysis
CUANDO cambia el timeframe (ej: 1H → 4H → 1D)
ENTONCES se recalcula y redibuja todo el análisis ICT
Y los elementos cambian según el timeframe elegido
Y el API actualiza con los datos del nuevo timeframe
```
**Escenario 7: Crear alerta en zona ICT**
```gherkin
DADO que el usuario está viendo un elemento ICT
CUANDO hace click en "Crear alerta" desde el modal
ENTONCES se abre un formulario para crear una alerta:
- Precio de trigger (pre-rellenado)
- Tipo de alerta (email/push/SMS)
- Mensaje personalizado
CUANDO confirma
ENTONCES se crea la alerta
Y se muestra confirmación "Alerta creada para $90,100"
```
**Escenario 8: Comparar análisis entre timeframes**
```gherkin
DADO que el usuario está en ICT Analysis
CUANDO hace click en "Compare"
ENTONCES se abre una vista con dos charts lado a lado:
- Izquierda: timeframe actual (ej: 4H)
- Derecha: timeframe diferente (ej: 1D)
Y ambos muestran su análisis ICT correspondiente
Y se resaltan confluyencias entre timeframes
```
**Escenario 9: Backtesting de zona ICT**
```gherkin
DADO que el usuario está viendo un Order Block o FVG
CUANDO hace click en "Backtest This"
ENTONCES se abre un análisis histórico mostrando:
- Cuántas veces el precio tocó esta zona en el pasado
- Cuántas veces resultó en reversión
- Ganancia promedio si se hubiera operado en esta zona
- Tasa de éxito (%)
- Gráfico histórico de touch points
```
## Criterios Adicionales
- [ ] El análisis debe cargar en menos de 1.5 segundos
- [ ] Debe soportar todos los timeframes (1m, 5m, 15m, 1h, 4h, 1d, 1w)
- [ ] Debe recalcularse automáticamente cada nueva vela
- [ ] Los colores deben ser customizables por tema (light/dark)
- [ ] Bullish elements en verde/azul, Bearish en rojo/naranja
- [ ] Responsive en tablets y mobile (scrollable chart)
- [ ] Performance: máximo 50 elementos ICT dibujados simultáneamente
- [ ] Debe funcionar sin valores reales de market data si es necesario (mock data)
---
## Tareas Técnicas
**Backend (FastAPI - ml-engine):**
- [ ] BE-ML-016: Crear endpoint GET /api/ml/ict/:symbol
- [ ] BE-ML-017: Implementar análisis de Liquidity Zones
- [ ] BE-ML-018: Implementar detección de Fair Value Gaps
- [ ] BE-ML-019: Implementar detección de Order Blocks
- [ ] BE-ML-020: Implementar cálculo de Points of Interest
- [ ] BE-ML-021: Implementar score/strength para cada elemento
- [ ] BE-ML-022: Endpoint GET /api/ml/ict/:symbol/compare (compare timeframes)
- [ ] BE-ML-023: Implementar caching de análisis ICT
**Python ML Service:**
- [ ] ML-ICT-001: Desarrollar módulo ICT detector
- [ ] ML-ICT-002: Algoritmo de identificación de Liquidity Zones
- [ ] ML-ICT-003: Algoritmo de detección de FVGs
- [ ] ML-ICT-004: Algoritmo de detección de Order Blocks
- [ ] ML-ICT-005: Algoritmo de cálculo de POI (Points of Interest)
- [ ] ML-ICT-006: Validación y backtesting de elementos ICT
- [ ] ML-ICT-007: Tests unitarios de detección
**Frontend (React):**
- [ ] FE-ML-035: Crear componente `ICTAnalysis.tsx`
- [ ] FE-ML-036: Crear componente `ICTChart.tsx` (integración lightweight-charts)
- [ ] FE-ML-037: Crear componente `ICTControls.tsx` (filtros y toggles)
- [ ] FE-ML-038: Crear componente `ICTSidebar.tsx` (listado de elementos)
- [ ] FE-ML-039: Crear componente `LiquidityZoneModal.tsx`
- [ ] FE-ML-040: Crear componente `FVGModal.tsx`
- [ ] FE-ML-041: Crear componente `OrderBlockModal.tsx`
- [ ] FE-ML-042: Crear componente `POIModal.tsx`
- [ ] FE-ML-043: Crear componente `ComparisonChart.tsx`
- [ ] FE-ML-044: Crear componente `BacktestModal.tsx`
- [ ] FE-ML-045: Implementar dibujado en lightweight-charts
- [ ] FE-ML-046: Implementar state management (Zustand) para ICT data
- [ ] FE-ML-047: Implementar tooltips interactivos
- [ ] FE-ML-048: Implementar colores customizables por tema
**Tests:**
- [ ] TEST-ML-016: Test detección de Liquidity Zones
- [ ] TEST-ML-017: Test detección de FVGs
- [ ] TEST-ML-018: Test detección de Order Blocks
- [ ] TEST-ML-019: Test E2E de análisis completo
- [ ] TEST-ML-020: Test de performance (<1.5s load)
**Documentación:**
- [ ] DOC-ICT-001: Guía de análisis ICT en la plataforma
- [ ] DOC-ICT-002: Explicación de cada elemento ICT
- [ ] DOC-ICT-003: Cómo interpretar las métricas
---
## Dependencias
**Depende de:**
- [ ] RF-ML-001: Integración de datos de mercado (OHLCV)
- [ ] US-ML-001: Ver chart de trading
- [ ] US-ML-002: Ver señal en chart
- [ ] OQI-003: Trading Charts (infraestructura base)
**Bloquea:**
- [ ] US-ML-010: Alertas ICT
- [ ] US-ML-011: Backtesting de estrategia ICT
---
## Notas Técnicas
**Endpoints involucrados:**
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | /api/ml/ict/:symbol | Obtener análisis ICT para símbolo |
| GET | /api/ml/ict/:symbol/timeframe/:tf | Análisis ICT por timeframe |
| GET | /api/ml/ict/:symbol/compare | Comparar análisis entre TFs |
| POST | /api/ml/ict/:symbol/backtest | Backtesting de zona ICT |
| GET | /api/alerts/:symbol/ict | Obtener alertas ICT activas |
**Query Parameters - ICT Analysis:**
```
GET /api/ml/ict/BTCUSDT?
timeframe=4h&
include=liquidity_zones,fvgs,order_blocks,poi&
threshold=medium&
bias=bullish
```
**Response esperado:**
```typescript
interface ICTAnalysisResponse {
symbol: string;
timeframe: string;
timestamp: string;
analysis: {
liquidity_zones: LiquidityZone[];
fair_value_gaps: FairValueGap[];
order_blocks: OrderBlock[];
points_of_interest: PointOfInterest[];
};
summary: {
total_elements: number;
bullish_elements: number;
bearish_elements: number;
strongest_level: number;
nearest_liquidity_up: number;
nearest_liquidity_down: number;
};
}
interface LiquidityZone {
id: string;
type: 'BUY' | 'SELL';
price_high: number;
price_low: number;
strength: number; // 0-100
formed_at: string;
touch_count: number;
probability_return: number; // 0-100
}
interface FairValueGap {
id: string;
type: 'BULLISH_BREAKER' | 'BEARISH_BREAKER' | 'CONTINUATION';
gap_high: number;
gap_low: number;
gap_size_pips: number;
gap_size_percent: number;
status: 'UNMITIGATED' | 'PARTIALLY_MITIGATED' | 'FULLY_MITIGATED';
formed_at: string;
probability_fill: number; // 0-100
estimated_fill_time: string; // ISO duration
}
interface OrderBlock {
id: string;
type: 'BULLISH' | 'BEARISH';
entry_high: number;
entry_low: number;
strength_score: number; // 1-10
power_percent: number; // 0-100
touch_count: number;
formed_at: string;
candle_formation: string;
next_target: number;
}
interface PointOfInterest {
id: string;
price: number;
type: 'SWING_HIGH' | 'SWING_LOW' | 'CONFLUENCE';
confluence_count: number;
reversal_probability: number; // 0-100
bounce_probability: number; // 0-100
elements: string[]; // IDs de elementos que confluyen
}
```
**Componentes UI principales:**
- `ICTAnalysis`: Container del análisis
- `ICTChart`: Canvas del chart con dibujado de elementos
- `ICTControls`: Controles de filtrado y display
- `ICTSidebar`: Listado de elementos detectados
- `ICTModals`: Familia de modales (Liquidity, FVG, OB, POI)
- `ComparisonChart`: Vista comparativa de timeframes
- `BacktestView`: Análisis histórico de una zona
**State Management (Zustand):**
```typescript
interface ICTStore {
ictData: ICTAnalysisResponse | null;
selectedElement: ICTElement | null;
timeframe: string;
visibleElements: {
liquidity_zones: boolean;
fvgs: boolean;
order_blocks: boolean;
poi: boolean;
};
bias: 'BULLISH' | 'BEARISH' | 'NEUTRAL';
threshold: 'LOW' | 'MEDIUM' | 'HIGH';
fetchICTAnalysis: (symbol: string, tf: string) => Promise<void>;
selectElement: (element: ICTElement) => void;
toggleElementType: (type: keyof visibleElements) => void;
setBias: (bias: string) => void;
setThreshold: (threshold: string) => void;
}
```
**Integración con Chart:**
- Usar series personalizada de lightweight-charts
- Plugins para dibujado de zonas y elementos
- Overlay layers para diferentes tipos de elementos
---
## Definition of Ready (DoR)
- [x] Historia claramente escrita (quién, qué, por qué)
- [x] Criterios de aceptación detallados (9 escenarios)
- [x] Story points estimados (5)
- [x] Dependencias identificadas
- [x] Sin bloqueadores
- [x] Diseño/mockup disponible
- [x] APIs especificadas
## Definition of Done (DoD)
- [ ] Código Python implementado (ICT detectors)
- [ ] Código TypeScript implementado (endpoints + frontend)
- [ ] Tests unitarios escritos y pasando (Python y TS)
- [ ] Tests E2E pasando
- [ ] Code review aprobado
- [ ] Documentación actualizada
- [ ] Backtesting validado (accuracy > 80%)
- [ ] Rendimiento verificado (<1.5s load)
- [ ] Responsive en mobile/tablet
- [ ] QA aprobado en staging
- [ ] Desplegado en producción
---
## Historial de Cambios
| Fecha | Cambio | Autor |
|-------|--------|-------|
| 2026-01-25 | Creación | Claude Code |
---
**Creada por:** Claude Code
**Fecha:** 2026-01-25
**Última actualización:** 2026-01-25

View File

@ -0,0 +1,448 @@
---
id: "US-ML-010"
title: "Scan Multi-Símbolo"
type: "User Story"
status: "Pending"
priority: "Media"
epic: "OQI-006"
project: "trading-platform"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-ML-010: Scan Multi-Símbolo
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | US-ML-010 |
| **Épica** | OQI-006 - Señales ML y Predicciones |
| **Módulo** | ml-signals |
| **Prioridad** | P2 (Media) |
| **Story Points** | 5 |
| **Sprint** | Por asignar |
| **Estado** | Pendiente |
| **Asignado a** | Por asignar |
---
## Historia de Usuario
**Como** trader/inversor,
**quiero** escanear múltiples símbolos simultáneamente en busca de señales de trading,
**para** encontrar las mejores oportunidades disponibles en el mercado de forma eficiente.
## Descripción Detallada
El usuario debe poder seleccionar una lista de símbolos (desde una lista predefinida, watchlist personal, o subir lista personalizada), ejecutar un escaneo que genere señales ML para todos ellos en paralelo, y visualizar los resultados filtrados y ordenados por confianza. El escaneo debe completarse en menos de 10 segundos para máximo 50 símbolos.
## Mockups/Wireframes
```
┌──────────────────────────────────────────────────────────────────┐
│ MULTI-SYMBOL SCAN │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Symbol Selection: │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ ▼ Select from: [Popular ▼] [My Watchlist ▼] [Custom ▼] │ │
│ │ │ │
│ │ ☑ BTCUSDT ☑ ETHUSDT ☑ BNBUSDT │ │
│ │ ☑ ADAUSDT ☑ XRPUSDT ☑ DOGEUSDT │ │
│ │ ☑ MATICUSDT ☑ SOLUSDT ☑ LINKUSDT │ │
│ │ │ │
│ │ [Clear All] [Select All] [Select: 9 symbols] │ │
│ │ │ │
│ │ Or upload CSV: [Choose File] upload-symbols.csv │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Filter & Sort: │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Signal Type: [All ▼] Action: [BUY ▼] Horizon: [All ▼] │ │
│ │ Min Confidence: [50% ▼] Sort by: [Confidence ▼] │ │
│ │ │ │
│ │ [🔄 Scan Now] [⏸️ Cancel] Scanning: 7/9 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ══════════════════════════════════════════════════════════════ │
│ │
│ SCAN RESULTS - 9 Symbols, 12 Signals Found │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Symbol Action Horizon Conf. Score Entry Status │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ BTCUSDT 🟢 BUY Scalping 85% 9.2/10 $89,400 ✅ Ready│ │
│ │ ETHUSDT 🟢 BUY Intraday 78% 8.8/10 $3,240 ✅ Ready│ │
│ │ BNBUSDT 🟢 BUY Swing 72% 8.1/10 $620 ✅ Ready│ │
│ │ ADAUSDT 🔴 SELL Intraday 68% 7.6/10 $1.05 ✅ Ready│ │
│ │ LINKUSDT 🟢 BUY Swing 65% 7.3/10 $28.50 ✅ Ready│ │
│ │ SOLUSDT 🔵 HOLD Position 58% 6.9/10 $190.50 ⚠️ Weak │ │
│ │ XRPUSDT 🔴 SELL Scalping 55% 6.2/10 $2.45 ⚠️ Weak │ │
│ │ MATICUSDT - - - - - - ❌ NoSig│ │
│ │ DOGEUSDT - - - - - - ❌ NoSig│ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ [View Details] [Add to Watchlist] [Export Results] │
│ │
│ SUMMARY │
│ ══════════════════════════════════════════════════════════════ │
│ Total Symbols Scanned: 9 │
│ Signals Found: 7 (77.8%) │
│ Strong Signals (>70%): 4 │
│ Weak Signals (50-70%): 3 │
│ Avg Confidence: 68.3% │
│ │
│ [Create Portfolio from BUY Signals] [Refresh Scan] │
│ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ SCAN PROGRESS [✕ Cancel] │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Scanning 9 symbols in parallel... │
│ │
│ ✅ BTCUSDT (2.1s) │
│ ✅ ETHUSDT (1.8s) │
│ ✅ BNBUSDT (1.5s) │
│ ⏳ ADAUSDT (Generating signal...) │
│ ⏳ XRPUSDT (Generating signal...) │
│ ⏳ LINKUSDT (Analyzing indicators...) │
│ ⏳ SOLUSDT (Analyzing indicators...) │
│ ⏳ MATICUSDT (Analyzing indicators...) │
│ ⏳ DOGEUSDT (Analyzing indicators...) │
│ │
│ Completed: 3/9 • Elapsed: 5.2s • Est. time: ~7.8s │
│ ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 33% │
│ │
│ [View Real-time Feed] [Pause] [Cancel] │
│ │
└──────────────────────────────────────────────────────────────────┘
```
---
## Criterios de Aceptación
**Escenario 1: Seleccionar símbolos desde lista predefinida**
```gherkin
DADO que el usuario está en la pantalla Multi-Symbol Scan
CUANDO hace click en "Popular"
ENTONCES se muestran los 50 símbolos más populares/líquidos
Y puede seleccionar hasta 50 símbolos con checkboxes
Y se muestra el contador "Select: X symbols"
```
**Escenario 2: Usar watchlist personal**
```gherkin
DADO que el usuario tiene una watchlist guardada
CUANDO selecciona "My Watchlist"
ENTONCES se cargan automáticamente los símbolos de la watchlist
Y puede desseleccionar símbolos si lo desea
Y se mantiene la selección al cambiar de filtro
```
**Escenario 3: Subir lista personalizada en CSV**
```gherkin
DADO que el usuario está en Symbol Selection
CUANDO hace click en "Choose File" y selecciona un CSV
ENTONCES el sistema parsea el archivo (formato: 1 símbolo por línea)
Y agrega los símbolos a la selección
Y muestra cantidad de símbolos cargados (validando que sean correctos)
Y permite deseleccionar los que no desea
```
**Escenario 4: Ejecutar escaneo multi-símbolo**
```gherkin
DADO que el usuario ha seleccionado 9 símbolos
Y ha configurado filtros (tipo de señal, confianza mínima)
CUANDO hace click en "Scan Now"
ENTONCES inicia escaneo paralelo en todos los símbolos
Y muestra progreso en tiempo real (símbolos completados)
Y el escaneo completa en menos de 10 segundos para 50 símbolos
Y muestra "Scanning: 3/9" mientras se ejecuta
```
**Escenario 5: Ver resultados en tabla**
```gherkin
DADO que el escaneo se ha completado
CUANDO se muestran los resultados
ENTONCES se visualiza tabla con columnas:
- Símbolo
- Acción (BUY/SELL/HOLD)
- Horizonte
- Confianza %
- Score (0-10)
- Precio de entrada
- Estado (✅ Ready / ⚠️ Weak / ❌ No Signal)
Y cada fila es clickeable para ver detalles completos
```
**Escenario 6: Filtrar resultados por confianza**
```gherkin
DADO que se muestran los resultados del escaneo
CUANDO selecciona "Min Confidence: 70%"
ENTONCES se muestran solo señales con confianza >= 70%
Y se actualiza el contador "7 of 12 signals"
Y el resumen se recalcula solo para señales filtradas
```
**Escenario 7: Filtrar por tipo de señal**
```gherkin
DADO que se muestran los resultados
CUANDO selecciona "Action: BUY"
ENTONCES muestra solo señales de compra
Y se pueden combinar filtros (ej: Action=BUY AND Horizon=Scalping)
```
**Escenario 8: Ordenar por confianza**
```gherkin
DADO que se muestran resultados
CUANDO hace click en "Sort by: Confidence" (descendente)
ENTONCES la tabla se ordena con señales más confiables primero
Y se puede invertir el orden (ascendente/descendente)
Y se pueden ordenar también por Score, Símbolo, etc.
```
**Escenario 9: Exportar resultados**
```gherkin
DADO que se muestran los resultados del escaneo
CUANDO hace click en "Export Results"
ENTONCES descarga archivo CSV con:
- Symbol, Action, Horizon, Confidence, Score, Entry Price
- Nombre: "scan-results-2026-01-25-09-30.csv"
```
**Escenario 10: Crear portfolio desde resultados**
```gherkin
DADO que se muestran resultados del escaneo
CUANDO hace click en "Create Portfolio from BUY Signals"
ENTONCES se abre modal para crear nuevo portfolio
Y se preseleccionan automáticamente todos los BUY signals
Y el usuario puede ajustar pesos y confirmar creación
```
## Criterios Adicionales
- [ ] El escaneo debe soportar máximo 50 símbolos simultáneamente
- [ ] El tiempo máximo debe ser menor a 10 segundos
- [ ] Los resultados deben mostrarse ordenados por confianza descendente
- [ ] El CSV debe ser válido y con header
- [ ] Debe mostrar progreso en tiempo real durante el escaneo
- [ ] Debe manejar símbolos inválidos (ignorarlos o marcar con error)
- [ ] La tabla debe ser responsive en móvil
- [ ] Los filtros deben ser combinables
---
## Tareas Técnicas
**Backend:**
- [ ] BE-ML-020: Crear endpoint POST /api/ml/scan
- [ ] BE-ML-021: Implementar worker para escaneo paralelo (queue-based)
- [ ] BE-ML-022: Validar símbolos de entrada
- [ ] BE-ML-023: Parsear CSV de símbolos
- [ ] BE-ML-024: Implementar filtros (action, horizon, confidence_min)
- [ ] BE-ML-025: Generar respuesta con resultados ordenados
- [ ] BE-ML-026: Implementar export a CSV
**Frontend:**
- [ ] FE-ML-040: Crear componente `MultiSymbolScan.tsx`
- [ ] FE-ML-041: Crear componente `SymbolSelector.tsx`
- [ ] FE-ML-042: Crear componente `ScanFilters.tsx`
- [ ] FE-ML-043: Crear componente `ScanResults.tsx`
- [ ] FE-ML-044: Crear componente `ScanProgress.tsx`
- [ ] FE-ML-045: Implementar upload de CSV
- [ ] FE-ML-046: Implementar tabla con sorting y filtros
- [ ] FE-ML-047: Implementar export a CSV
- [ ] FE-ML-048: Integración con TanStack Query (react-query)
- [ ] FE-ML-049: Real-time progress updates (WebSocket/SSE)
**ML Engine:**
- [ ] ML-020: Optimizar generación de señales para múltiples símbolos
- [ ] ML-021: Implementar ejecución paralela de análisis
- [ ] ML-022: Cachear indicadores técnicos por símbolo
**Tests:**
- [ ] TEST-ML-020: Test de validación de símbolos
- [ ] TEST-ML-021: Test de parseo CSV
- [ ] TEST-ML-022: Test de escaneo paralelo (timeout, errores)
- [ ] TEST-ML-023: Test de filtrado y ordenamiento
- [ ] TEST-ML-024: Test E2E completo del multi-scan
---
## Dependencias
**Depende de:**
- [ ] US-ML-002: Ver señal - Estado: Pendiente
- [ ] RF-ML-001: Generación de señales ML
- [ ] Infrastructure: Worker queue (Bull/RabbitMQ)
**Bloquea:**
- [ ] US-ML-011: Alertas de señales (requiere resultados del scan)
- [ ] US-ML-012: Portfolio builder (requiere scan multi-símbolo)
---
## Notas Técnicas
**Endpoints involucrados:**
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| POST | /api/ml/scan | Ejecutar escaneo multi-símbolo |
| GET | /api/ml/scan/:scanId/progress | Obtener progreso en tiempo real |
| GET | /api/ml/scan/:scanId/results | Obtener resultados del escaneo |
| GET | /api/ml/scan/:scanId/export.csv | Exportar resultados a CSV |
| GET | /api/symbols/popular | Lista de símbolos populares |
| GET | /api/watchlists/:id/symbols | Símbolos de watchlist |
**Request esperado:**
```typescript
interface MultiSymbolScanRequest {
symbols: string[]; // Array de símbolos (ej: ['BTCUSDT', 'ETHUSDT'])
filters: {
signal_type?: 'BUY' | 'SELL' | 'HOLD' | 'ALL';
horizon?: string;
confidence_min?: number; // 0-100
action?: 'BUY' | 'SELL';
};
sort_by?: 'confidence' | 'score' | 'symbol';
sort_order?: 'asc' | 'desc';
}
```
**Response esperado:**
```typescript
interface MultiSymbolScanResponse {
scan_id: string;
status: 'completed' | 'in_progress' | 'failed';
timestamp: string;
symbols_scanned: number;
signals_found: number;
results: SignalResult[];
summary: {
total_symbols: number;
signals_found: number;
strong_signals: number; // confidence >= 70%
weak_signals: number; // 50% <= confidence < 70%
avg_confidence: number;
};
execution_time_ms: number;
}
interface SignalResult {
symbol: string;
action: 'BUY' | 'SELL' | 'HOLD' | null;
horizon?: string;
confidence?: number;
score?: number;
entry_price?: number;
status: 'ready' | 'weak' | 'no_signal' | 'error';
error_message?: string;
}
```
**CSV Upload Parser:**
```typescript
// Soporta formatos:
// 1. Un símbolo por línea (simple)
BTCUSDT
ETHUSDT
BNBUSDT
// 2. CSV con header
Symbol,Exchange,Type
BTCUSDT,BINANCE,SPOT
ETHUSDT,BINANCE,SPOT
```
**Componentes UI:**
- `MultiSymbolScan`: Container principal
- `SymbolSelector`: Selector de símbolos con pestañas
- `SymbolListPicker`: Selector desde lista predefinida
- `WatchlistPicker`: Selector desde watchlist personal
- `CSVUploader`: Componente de upload de CSV
- `ScanFilters`: Filtros de escaneo
- `ScanResults`: Tabla de resultados
- `ScanProgress`: Modal de progreso en tiempo real
- `ResultsActions`: Acciones sobre resultados (export, create portfolio)
**Estado (Zustand):**
```typescript
interface MultiSymbolScanStore {
selectedSymbols: string[];
scanResults: SignalResult[];
scanProgress: {
total: number;
completed: number;
currentSymbol: string;
};
filters: ScanFilters;
isScanning: boolean;
sortBy: 'confidence' | 'score' | 'symbol';
sortOrder: 'asc' | 'desc';
setSelectedSymbols: (symbols: string[]) => void;
startScan: () => Promise<void>;
updateProgress: (progress: ScanProgress) => void;
updateFilters: (filters: Partial<ScanFilters>) => void;
setSortBy: (field: string, order: 'asc' | 'desc') => void;
exportToCSV: () => void;
}
```
**Real-time Progress:**
- Usar WebSocket o SSE para enviar actualizaciones de progreso
- Endpoint: `/api/ml/scan/:scanId/progress` con streaming
- O usar polling cada 500ms si WebSocket no disponible
**Performance Targets:**
- 50 símbolos scanned: < 10 segundos
- 20 símbolos scanned: < 5 segundos
- 10 símbolos scanned: < 3 segundos
---
## Definition of Ready (DoR)
- [x] Historia claramente escrita (quién, qué, por qué)
- [x] Criterios de aceptación definidos
- [x] Story points estimados
- [x] Dependencias identificadas
- [x] Diseño/mockup disponible
- [x] Targets de performance definidos
- [x] Formatos de datos especificados
## Definition of Done (DoD)
- [ ] Código implementado según criterios
- [ ] Tests unitarios escritos y pasando
- [ ] Tests E2E pasando
- [ ] Code review aprobado
- [ ] Documentación actualizada
- [ ] QA aprobado en staging
- [ ] Escaneo paralelo funciona correctamente
- [ ] Real-time progress updates funcionan
- [ ] CSV upload y export validan correctamente
- [ ] Filtros y ordenamiento funcionan
- [ ] Performance meets targets (< 10s para 50 símbolos)
- [ ] Manejo de errores robusto (símbolos inválidos, timeouts)
- [ ] Responsive en móvil
- [ ] Desplegado en producción
---
## Historial de Cambios
| Fecha | Cambio | Autor |
|-------|--------|-------|
| 2026-01-25 | Creación | Requirements-Analyst |
---
**Creada por:** Requirements-Analyst
**Fecha:** 2026-01-25
**Última actualización:** 2026-01-25

View File

@ -0,0 +1,357 @@
---
id: "US-LLM-011"
title: "Ejecutar Trade desde Chat"
type: "User Story"
status: "Pending"
priority: "Alta"
epic: "OQI-007"
project: "trading-platform"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-LLM-011: Ejecutar Trade desde Chat
**Épica:** OQI-007 - LLM Strategy Agent
**Sprint:** TBD
**Story Points:** 5
**Prioridad:** P0 - Alta
---
## Historia de Usuario
**Como** usuario Pro o Premium con capacidad de trading real
**Quiero** ejecutar trades directamente desde el chat con el asistente AI mediante comandos naturales
**Para** operar en los mercados rápidamente sin cambiar de interfaz
---
## Criterios de Aceptación
### AC-1: Interpretar comandos de trading
```gherkin
Given soy usuario Pro/Premium
And tengo acceso a trading real
When digo frases como "Vende 50 acciones de AAPL" o "Compra Bitcoin a $43,000"
Then el agente interpreta correctamente:
- Acción (compra/venta)
- Símbolo del activo
- Cantidad
- Tipo de orden (mercado/límite)
- Precio (si es límite)
And valida que la orden sea válida
```
### AC-2: Mostrar preview de la orden
```gherkin
Given el agente interpreta un comando de trading
When prepara la orden
Then muestra un resumen detallado:
- Símbolo y nombre del activo
- Acción (BUY/SELL)
- Cantidad de unidades
- Tipo de orden (market/limit)
- Precio unitario estimado
- Costo/ingresos totales
- Comisiones estimadas
- Impacto en el portafolio
And NO ejecuta la orden automáticamente
```
### AC-3: Requerir confirmación explícita
```gherkin
Given el agente muestra el preview de la orden
When el usuario revisa los detalles
Then el agente pide confirmación explícita:
- "¿Confirmas esta orden?" o similar
- Botones/acciones claras (Confirmar/Cancelar)
And SOLO ejecuta si el usuario confirma
And permite cancelar en cualquier momento
```
### AC-4: Validar límites de riesgo
```gherkin
Given quiero ejecutar una orden
When el agente prepara la orden
Then valida:
- Saldo disponible suficiente
- Límite de exposición por activo
- Límite de pérdida diaria
- Límite de apalancamiento
And si hay violación:
- Informa qué límite se excede
- Muestra valores actuales vs permitidos
- NO permite ejecutar
```
### AC-5: Ejecutar y retornar feedback
```gherkin
Given el usuario confirma la orden
When se ejecuta correctamente
Then muestra confirmación con:
- ID de la orden
- Status (filled/pending)
- Símbolo y precio ejecutado
- Cantidad y costo final
- Timestamp exacto
- Posición actualizada en el activo
And registra en el historial del chat
```
### AC-6: Manejo de errores
```gherkin
Given intento ejecutar una orden
When ocurre error (conexión, mercado cerrado, etc.)
Then el agente:
- Informa el tipo de error
- Explica por qué no se ejecutó
- Sugiere alternativas (ej: orden pendiente)
- NO procesa parcialmente la orden
```
### AC-7: Restricción por plan
```gherkin
Given soy usuario Free o con trading deshabilitado
When intento ejecutar una orden
Then el agente:
- Rechaza la orden
- Explica que requiere plan Pro/Premium
- Muestra opción de upgrade
- NO ejecuta ninguna orden
```
---
## Flujo de Confirmación
```markdown
## Confirmar Orden 📊
**Acción:** VENTA
**Símbolo:** AAPL - Apple Inc.
**Cantidad:** 50 acciones
**Tipo:** Market Order
**Precio actual:** $185.32
**Costo total:** ~$9,266.00
**Comisión:** ~$9.27
**Neto:** ~$9,256.73
**Tu portafolio:**
- Posición actual: 100 acciones @ $184.50
- Posición después: 50 acciones
---
⚠️ Esta es una orden REAL de trading
¿Confirmas esta orden?
[✅ Confirmar] [❌ Cancelar]
```
---
## Respuesta Post-Ejecución
```markdown
## Orden Ejecutada ✅
**ID:** ORD-20260125-001234
**Status:** Filled (Completada)
**Símbolo:** AAPL
**Acción:** VENTA
**Cantidad:** 50 acciones
**Precio:** $185.31
**Total:** $9,265.50
**Comisión:** $9.27
**Neto:** $9,256.23
**Timestamp:** 15:45:32 ET
**Posición Actualizada:**
- AAPL: 50 acciones @ $185.31 (promedio)
- Valor: $9,265.50
- Variación: +2.5% hoy
Registro guardado en tu historial.
```
---
## Respuesta con Error
```markdown
## Error al Ejecutar ❌
**Razón:** Mercado cerrado (Cierre: 16:00 ET)
La orden no pudo ejecutarse porque el mercado de NYSE está cerrado.
**Alternativas:**
- Crear orden pendiente para la apertura mañana
- Intentar en mercados abiertos (premarket a las 04:00 ET)
- Esperar a mañana a las 09:30 ET
¿Qué prefieres?
[Orden Pendiente] [Otra acción] [Cancelar]
```
---
## API Endpoint
### POST `/api/llm/execute-trade`
**Headers:**
```
Authorization: Bearer {token}
Content-Type: application/json
```
**Request Body:**
```json
{
"sessionId": "chat-session-12345",
"interpretation": {
"action": "BUY|SELL",
"symbol": "AAPL",
"quantity": 50,
"orderType": "market|limit",
"limitPrice": null,
"timeInForce": "DAY|GTC"
},
"userId": "user-uuid",
"confirmedAt": "2026-01-25T15:45:32Z"
}
```
**Response (Success):**
```json
{
"success": true,
"order": {
"orderId": "ORD-20260125-001234",
"status": "filled",
"symbol": "AAPL",
"action": "SELL",
"quantity": 50,
"executedPrice": 185.31,
"totalValue": 9265.50,
"commission": 9.27,
"netValue": 9256.23,
"executedAt": "2026-01-25T15:45:32Z"
},
"message": "Orden ejecutada exitosamente"
}
```
**Response (Error):**
```json
{
"success": false,
"error": {
"code": "MARKET_CLOSED",
"message": "El mercado está cerrado",
"details": "NYSE cierra a las 16:00 ET"
},
"alternatives": [
{
"type": "pending_order",
"description": "Crear orden pendiente para apertura"
}
]
}
```
---
## Notas Técnicas
- **Tool:** `execute_trade` (en el LLM Agent)
- **Servicio:** Trading API Backend (puerto 3080)
- **Confirmación:** OBLIGATORIA antes de ejecutar
- **Validación:** Límites de riesgo, saldo, mercado abierto
- **Logging:** Todas las órdenes registradas con timestamp
- **Rate limit:** 20 órdenes/minuto por usuario
- **Timeout:** 30 segundos para confirmación
- **Rollback:** Si falla ejecución, reversión de cambios
---
## Flujo Técnico
```mermaid
graph TD
A["Usuario: 'Vende 50 AAPL'"] -->|Chat Input| B["LLM Agent"]
B -->|NLU| C["Interpretar Comando"]
C -->|Validar Sintaxis| D{¿Válido?}
D -->|No| E["Error: Comando inválido"]
D -->|Sí| F["Preparar Preview"]
F -->|GET /api/market/price| G["Obtener precio actual"]
G -->|GET /api/portfolio/position| H["Obtener posición actual"]
H -->|Calcular| I["Preparar detalles orden"]
I -->|Mostrar| J["Preview en chat"]
J -->|Usuario revisa| K{¿Confirma?}
K -->|Cancela| L["Cancelado"]
K -->|Confirma| M["POST /api/llm/execute-trade"]
M -->|Validar riesgos| N{¿Límites OK?}
N -->|No| O["Error: Límite excedido"]
N -->|Sí| P["Ejecutar orden"]
P -->|Trading System| Q["Orden procesada"]
Q -->|Response| R["Mostrar confirmación"]
R -->|Actualizar portafolio| S["Feedback final"]
```
---
## Criterios de Aceptación Técnica
- [ ] Interpretar al menos 10 variantes de comandos
- [ ] Validar todos los campos obligatorios
- [ ] Conectar con Trading API backend
- [ ] Mostrar preview antes de ejecutar
- [ ] Requerir confirmación explícita
- [ ] Validar límites de riesgo
- [ ] Ejecutar orden correctamente
- [ ] Mostrar confirmación con detalles
- [ ] Registrar en historial
- [ ] Manejo robusto de errores
- [ ] Tests unitarios (80%+ coverage)
- [ ] Tests E2E del flujo completo
- [ ] QA aprobado
---
## Dependencias
- RF-LLM-005: Herramienta Trading Execution
- RF-LLM-006: Interpretación NLU avanzada
- ET-LLM-005: Arquitectura Tools
- OQI-001: Autenticación y autorización
- OQI-003: Paper Trading System
- REC-BACKEND-001: Trading API
---
## Definición de Done
- [ ] Endpoint `/api/llm/execute-trade` implementado
- [ ] LLM Agent puede interpretar comandos
- [ ] Preview de orden funcionando
- [ ] Confirmación obligatoria
- [ ] Validación de límites de riesgo
- [ ] Ejecución de orden
- [ ] Feedback post-ejecución
- [ ] Manejo de errores
- [ ] Restricción por plan
- [ ] Tests unitarios
- [ ] Tests E2E
- [ ] QA aprobado
- [ ] Documentación actualizada
---
*Historia de usuario - Sistema NEXUS*
*Trading Platform*

View File

@ -0,0 +1,656 @@
# ET-PFM-008: Especificación Frontend - Módulo Portfolio Manager
**Módulo:** OQI-008 Portfolio Manager
**Documento:** ET-PFM-008
**Estado:** A IMPLEMENTAR
**Versión:** 1.0.0
**Fecha de Creación:** 2026-01-25
**Última Actualización:** 2026-01-25
---
## 📋 Resumen Ejecutivo
Este documento especifica la arquitectura, estructura de componentes y flujos de interfaz de usuario para el módulo Portfolio Manager en la plataforma de trading. **Este es un diseño a implementar que no cuenta actualmente con código base.**
El módulo proporciona funcionalidades de visualización, análisis y gestión de portafolios de inversión, incluyendo posiciones, métricas de riesgo, pruebas de estrés y generación de reportes.
---
## 🎯 Objetivos del Frontend
1. Proporcionar visualización clara y en tiempo real del estado del portafolio
2. Facilitar análisis de riesgo mediante métricas consolidadas
3. Permitir simulaciones de rebalanceo de posiciones
4. Generar reportes analíticos exportables
5. Integrar datos de múltiples fuentes de mercado
---
## 📄 Páginas Propuestas
### 1. PortfolioPage
**Ruta:** `/portfolio`
**Descripción:** Página principal de gestión del portafolio
**Responsabilidades:**
- Mostrar resumen ejecutivo del portafolio
- Listar posiciones activas
- Mostrar indicadores clave de desempeño (KPIs)
- Permitir filtrado y búsqueda de posiciones
- Facilitar acceso a rebalanceo
**Estructura:**
```
PortfolioPage
├── PortfolioSummaryCard
├── PerformanceChart
├── PositionsTable
│ ├── Filtros
│ └── Paginación
└── Acciones (Rebalancear, Exportar)
```
**Datos Requeridos:**
- Valor total del portafolio
- Rentabilidad YTD
- Rentabilidad acumulada
- Composición por activo
- Posiciones individuales con métricas
---
### 2. StressTestPage
**Ruta:** `/portfolio/stress-tests`
**Descripción:** Página para ejecución y análisis de pruebas de estrés
**Responsabilidades:**
- Crear nuevas pruebas de estrés
- Ejecutar escenarios predefinidos
- Visualizar resultados de stress tests
- Comparar múltiples escenarios
- Exportar análisis de sensibilidad
**Estructura:**
```
StressTestPage
├── ScenarioSelector
├── SimulationControls
├── RiskMetricsPanel
├── ResultsVisualization
│ ├── ImpactChart
│ └── SensitivityTable
└── ExportOptions
```
**Datos Requeridos:**
- Escenarios disponibles
- Parámetros de simulación
- Resultados de ejecución
- Metricas de sensibilidad
---
### 3. ReportsPage
**Ruta:** `/portfolio/reports`
**Descripción:** Página de generación y consulta de reportes analíticos
**Responsabilidades:**
- Listar reportes generados
- Crear nuevos reportes personalizados
- Visualizar reportes en tiempo real
- Descargar reportes en múltiples formatos
- Programar generación automática de reportes
**Estructura:**
```
ReportsPage
├── ReportsList
│ └── ReportFilters
├── ReportGenerator
│ ├── ParameterSelector
│ └── FormatSelector
├── ReportViewer
│ ├── PaginationControls
│ └── ExportOptions
└── ScheduleManager
```
**Datos Requeridos:**
- Lista de reportes disponibles
- Historico de reportes generados
- Parámetros configurables
- Formato de salida (PDF, Excel, CSV)
---
## 🧩 Componentes Propuestos
### 1. PortfolioSummaryCard
**Tipo:** Componente Presentacional
**Ubicación:** `src/components/portfolio/PortfolioSummaryCard.vue`
**Props:**
```typescript
interface PortfolioSummaryProps {
totalValue: number;
ytdReturn: number;
cumulativeReturn: number;
currency: string;
lastUpdated: Date;
isLoading?: boolean;
}
```
**Funcionalidades:**
- Mostrar valor total del portafolio
- Indicadores de rentabilidad (YTD, acumulada)
- Tendencia visual (arriba/abajo)
- Moneda de referencia
- Timestamp de actualización
- Estado de carga
**Emits:**
- `refresh`: Solicitar actualización de datos
---
### 2. PositionsTable
**Tipo:** Componente Presentacional
**Ubicación:** `src/components/portfolio/PositionsTable.vue`
**Props:**
```typescript
interface PositionsTableProps {
positions: Position[];
loading?: boolean;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
pageSize?: number;
currentPage?: number;
}
interface Position {
id: string;
symbol: string;
name: string;
quantity: number;
entryPrice: number;
currentPrice: number;
currentValue: number;
percentageChange: number;
percentageOfPortfolio: number;
sector?: string;
lastUpdated: Date;
}
```
**Funcionalidades:**
- Visualización de tabla de posiciones
- Ordenamiento por columnas
- Paginación configurable
- Filtrado por sector/tipo
- Búsqueda por símbolo o nombre
- Indicadores visuales de desempeño
- Acciones por fila (detalles, vender, rebalancear)
**Emits:**
- `sort`: Cambio de ordenamiento
- `page-change`: Cambio de página
- `position-selected`: Selección de posición
- `position-action`: Acción sobre posición
---
### 3. PerformanceChart
**Tipo:** Componente Presentacional
**Ubicación:** `src/components/portfolio/PerformanceChart.vue`
**Props:**
```typescript
interface PerformanceChartProps {
data: PerformanceData[];
timeframe?: 'D' | 'W' | 'M' | 'Y' | 'ALL';
currency?: string;
showComparison?: boolean;
isLoading?: boolean;
}
interface PerformanceData {
date: Date;
value: number;
return: number;
benchmark?: number;
}
```
**Funcionalidades:**
- Gráfico de línea del desempeño del portafolio
- Múltiples plazos (Día, Semana, Mes, Año, Todo)
- Comparación con benchmark
- Visualización de retorno absoluto y porcentual
- Interactividad con tooltips
- Exportación como imagen
**Emits:**
- `timeframe-change`: Cambio de período
- `range-select`: Selección de rango personalizado
---
### 4. RiskMetricsPanel
**Tipo:** Componente Presentacional
**Ubicación:** `src/components/portfolio/RiskMetricsPanel.vue`
**Props:**
```typescript
interface RiskMetricsPanelProps {
metrics: RiskMetrics;
isLoading?: boolean;
}
interface RiskMetrics {
volatility: number; // Volatilidad anualizada
sharpeRatio: number; // Ratio de Sharpe
sortinoRatio: number; // Ratio de Sortino
valueAtRisk: number; // VaR 95%
expectedShortfall: number; // CVaR (Expected Shortfall)
beta: number; // Beta respecto a benchmark
correlation: number; // Correlación con benchmark
maxDrawdown: number; // Máxima caída histórica
diversificationRatio: number; // Ratio de diversificación
}
```
**Funcionalidades:**
- Visualización de métricas de riesgo clave
- Indicadores de riesgo (bajo/medio/alto)
- Comparación con benchmarks
- Explicación de métricas (tooltips)
- Gráficos de sensibilidad
- Histórico de evolución de métricas
**Emits:**
- `metric-selected`: Selección de métrica para análisis profundo
- `learn-more`: Solicitud de explicación de métrica
---
### 5. RebalanceModal
**Tipo:** Componente Modal
**Ubicación:** `src/components/portfolio/RebalanceModal.vue`
**Props:**
```typescript
interface RebalanceModalProps {
visible: boolean;
portfolio: Portfolio;
targetAllocation: AllocationTarget[];
currentAllocation: AllocationCurrent[];
constraints?: RebalanceConstraints;
}
interface AllocationTarget {
assetType: string;
targetPercentage: number;
minPercentage?: number;
maxPercentage?: number;
}
interface RebalanceConstraints {
maxTransactionCost?: number;
minTradeSize?: number;
excludeAssets?: string[];
allowNewPositions?: boolean;
}
```
**Funcionalidades:**
- Mostrar asignación actual vs. objetivo
- Calcular transacciones necesarias
- Permitir selección de restricciones
- Vista previa de cambios
- Estimación de costos de transacción
- Confirmación antes de ejecutar
- Historial de rebalanceos
**Emits:**
- `close`: Cierre del modal
- `confirm`: Confirmación de rebalanceo
- `cancel`: Cancelación de operación
- `preview`: Solicitud de vista previa
---
## 🗂️ Estructura de Store
### portfolioStore
**Ubicación:** `src/stores/portfolioStore.ts`
**Estado:**
```typescript
interface PortfolioState {
portfolio: Portfolio | null;
positions: Position[];
selectedPosition: Position | null;
performanceData: PerformanceData[];
riskMetrics: RiskMetrics | null;
stressTestResults: StressTestResult[] | null;
reports: Report[];
loading: {
portfolio: boolean;
positions: boolean;
riskMetrics: boolean;
stressTest: boolean;
reports: boolean;
};
filters: {
sector?: string;
minValue?: number;
maxValue?: number;
searchTerm?: string;
};
error: string | null;
}
interface Portfolio {
id: string;
name: string;
totalValue: number;
ytdReturn: number;
cumulativeReturn: number;
currency: string;
positions: Position[];
lastUpdated: Date;
}
```
**Acciones Principales:**
```typescript
// Portafolio
fetchPortfolio(portfolioId: string): Promise<Portfolio>
updatePortfolio(portfolioId: string, data: Partial<Portfolio>): Promise<Portfolio>
selectPosition(position: Position): void
clearSelection(): void
// Posiciones
fetchPositions(portfolioId: string): Promise<Position[]>
updatePosition(positionId: string, data: Partial<Position>): Promise<Position>
deletePosition(positionId: string): Promise<void>
addPosition(position: Position): Promise<Position>
// Desempeño
fetchPerformanceData(portfolioId: string, timeframe: string): Promise<PerformanceData[]>
// Métricas de Riesgo
fetchRiskMetrics(portfolioId: string): Promise<RiskMetrics>
// Pruebas de Estrés
executeStressTest(portfolioId: string, scenario: StressScenario): Promise<StressTestResult>
fetchStressTestResults(portfolioId: string): Promise<StressTestResult[]>
// Rebalanceo
calculateRebalance(portfolioId: string, targets: AllocationTarget[]): Promise<RebalancePlan>
executeRebalance(portfolioId: string, plan: RebalancePlan): Promise<RebalanceResult>
// Reportes
fetchReports(portfolioId: string): Promise<Report[]>
generateReport(portfolioId: string, config: ReportConfig): Promise<Report>
exportReport(reportId: string, format: 'pdf' | 'excel' | 'csv'): Promise<Blob>
// Filtros
setFilter(filterName: string, value: any): void
clearFilters(): void
```
**Getters:**
```typescript
getPortfolioValue(): number
getTotalReturn(): number
getPositionCount(): number
getFilteredPositions(): Position[]
getTopPerformer(): Position | null
getTopLoser(): Position | null
getRiskLevel(): 'low' | 'medium' | 'high'
```
---
## 🔄 Flujos de Datos
### Flujo 1: Carga Inicial de Portafolio
```
PortfolioPage Montada
[Dispatch] fetchPortfolio()
API Backend (GET /api/portfolio/{id})
[Commit] setPortfolio()
PortfolioSummaryCard actualizado
PositionsTable actualizado
```
### Flujo 2: Búsqueda y Filtrado
```
Usuario escribe en SearchInput
[Dispatch] setFilter('searchTerm', value)
Computed getFilteredPositions()
PositionsTable re-renderiza
```
### Flujo 3: Ejecución de Stress Test
```
Usuario selecciona escenario
[Dispatch] executeStressTest(scenario)
API Backend (POST /api/portfolio/stress-test)
[Commit] setStressTestResults()
RiskMetricsPanel actualizado
ResultsVisualization mostrada
```
### Flujo 4: Rebalanceo
```
Usuario abre RebalanceModal
[Dispatch] calculateRebalance(targets)
API Backend (POST /api/portfolio/calculate-rebalance)
Modal muestra vista previa
Usuario confirma
[Dispatch] executeRebalance(plan)
API Backend (POST /api/portfolio/execute-rebalance)
[Dispatch] fetchPortfolio() para refrescar
```
---
## 🎨 Estilos y Temas
### Principios de Diseño
- **Diseño Responsivo:** Compatible con desktop, tablet y mobile
- **Accesibilidad:** WCAG 2.1 AA como mínimo
- **Consistencia:** Uso de design system corporativo
- **Rendimiento:** Carga y animaciones fluidas
### Componentes de UI Requeridos
- Cards para resumen de métricas
- Tablas con ordenamiento y paginación
- Gráficos interactivos (Chart.js o Echarts)
- Modals para acciones confirmables
- Alerts y notificaciones Toast
- Loaders y spinners
- Iconografía consistente
---
## 📊 Integraciones Externas
### APIs Backend Requeridas
| Endpoint | Método | Descripción |
|----------|--------|-------------|
| `/api/portfolio/{id}` | GET | Obtener datos del portafolio |
| `/api/portfolio/{id}` | PUT | Actualizar portafolio |
| `/api/portfolio/{id}/positions` | GET | Listar posiciones |
| `/api/portfolio/{id}/positions` | POST | Crear posición |
| `/api/portfolio/position/{id}` | PUT | Actualizar posición |
| `/api/portfolio/position/{id}` | DELETE | Eliminar posición |
| `/api/portfolio/{id}/performance` | GET | Obtener datos de desempeño |
| `/api/portfolio/{id}/risk-metrics` | GET | Calcular métricas de riesgo |
| `/api/portfolio/stress-test` | POST | Ejecutar prueba de estrés |
| `/api/portfolio/{id}/rebalance/calculate` | POST | Calcular plan de rebalanceo |
| `/api/portfolio/{id}/rebalance/execute` | POST | Ejecutar rebalanceo |
| `/api/portfolio/{id}/reports` | GET | Listar reportes |
| `/api/portfolio/report/generate` | POST | Generar reporte |
| `/api/portfolio/report/{id}/export` | GET | Exportar reporte |
### Servicios Externos
- **Market Data Provider:** Para precios en tiempo real
- **Benchmark Data:** Índices de referencia (S&P 500, etc.)
- **Reporting Engine:** Generación de reportes complejos
---
## ⚙️ Configuración y Constantes
### Variables de Entorno
```env
VITE_PORTFOLIO_API_BASE_URL=http://localhost:3000/api
VITE_CHART_LIBRARY=echarts|chart.js
VITE_REPORT_FORMAT_DEFAULT=pdf
VITE_AUTO_REFRESH_INTERVAL=30000
VITE_MAX_POSITIONS_DISPLAY=50
```
### Constantes de Aplicación
```typescript
const CURRENCY_SYMBOLS: Record<string, string> = {
USD: '$',
EUR: '€',
COP: '$',
};
const TIMEFRAMES = ['D', 'W', 'M', 'Y', 'ALL'] as const;
const RISK_LEVELS = {
low: { min: 0, max: 0.08 },
medium: { min: 0.08, max: 0.15 },
high: { min: 0.15, max: Infinity },
};
const STRESS_SCENARIOS = [
{ id: 'market-crash', label: 'Caída de Mercado (-10%)', intensity: -0.1 },
{ id: 'rate-shock', label: 'Choque de Tasas (+2%)', intensity: 0.02 },
{ id: 'geopolitical', label: 'Evento Geopolítico', intensity: -0.05 },
];
```
---
## 📱 Responsive Design
### Breakpoints
- **Mobile:** < 640px
- **Tablet:** 640px - 1024px
- **Desktop:** > 1024px
### Ajustes por Pantalla
| Elemento | Mobile | Tablet | Desktop |
|----------|--------|--------|---------|
| PortfolioSummaryCard | Apilado | 2 columnas | 4 columnas |
| PositionsTable | Horizontal scroll | Scroll limitado | Completo |
| PerformanceChart | Altura reducida | Altura media | Altura completa |
| RiskMetricsPanel | 1 columna | 2 columnas | 3 columnas |
---
## 🔒 Seguridad
- **Autenticación:** Bearer token en headers
- **Validación Frontend:** Validación de input antes de envío
- **HTTPS Obligatorio:** En producción
- **CORS:** Configuración restrictiva
- **Rate Limiting:** Control de llamadas a API
---
## 📝 Notas de Implementación
### Estado Actual
**Este documento describe un diseño que aún no ha sido implementado.** No existe código base en el repositorio para estos componentes.
### Próximos Pasos
1. Crear estructura de directorios de componentes
2. Implementar store de Pinia con acciones básicas
3. Desarrollar componentes en orden de dependencia
4. Integrar con APIs backend
5. Implementar pruebas unitarias
6. Realizar pruebas de integración
7. Optimizar rendimiento
### Consideraciones Técnicas
- **Framework:** Vue 3 (Composition API recomendada)
- **State Management:** Pinia
- **Gráficos:** Echarts o Chart.js según disponibilidad
- **Validación:** Vee-validate
- **Estilos:** TailwindCSS o SCSS
- **Pruebas:** Vitest + Vue Test Utils
---
## 📚 Referencias Relacionadas
- OQI-008 Portfolio Manager - Especificación General
- ET-PFM-001-backend.md - Especificación Backend
- ET-PFM-002-database.md - Especificación Base de Datos
- Arquitectura Trading Platform
---
## ✅ Control de Cambios
| Versión | Fecha | Autor | Cambios |
|---------|-------|-------|---------|
| 1.0.0 | 2026-01-25 | Sistema | Especificación inicial |
---
**Estado:** A IMPLEMENTAR | **Prioridad:** Alta | **Dependencias:** Backend Portfolio Manager (OQI-008)

View File

@ -0,0 +1,154 @@
---
id: "US-PFM-013"
title: "Alerta de Rebalanceo"
type: "User Story"
status: "Pending"
priority: "Media"
epic: "OQI-008"
project: "trading-platform"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-PFM-013: Alerta de Rebalanceo
**Épica:** OQI-008 - Portfolio Manager
**Story Points:** 5 | **Prioridad:** P2
---
## Historia de Usuario
**Como** inversor
**Quiero** recibir alertas cuando mi portafolio se desvíe de la asignación objetivo
**Para** mantener mi estrategia de inversión y rebalancear cuando sea necesario
---
## Criterios de Aceptación
```gherkin
Scenario: Configurar umbral de desviación
Given soy usuario Pro/Premium
And estoy en la sección de Alertas
When configuro un umbral de desviación (ej: 5%)
Then el sistema guarda la configuración
And veo el umbral configurado en mi dashboard
Scenario: Recibir alerta cuando se excede el umbral
Given tengo un umbral configurado de 5%
And mi asignación objetivo es 60% acciones / 40% bonos
When mi portafolio alcanza 65% acciones / 35% bonos
Then recibo notificación push
And recibo notificación email
And veo badge de alerta en el dashboard
Scenario: Ver desviación actual del portafolio
Given estoy en la sección de Alertas
When consulto mi portafolio
Then veo tabla con cada clase de activo
And cada fila muestra: asignación objetivo, asignación actual, desviación %
And las desviaciones > umbral se resaltan en rojo
Scenario: Recibir sugerencias de rebalanceo
Given mi portafolio está fuera de balance
When visualizo la desviación
Then veo sugerencias automáticas de rebalanceo
And cada sugerencia muestra: qué vender, qué comprar, montos
And puedo ejecutar rebalanceo desde la sugerencia (1-click)
Scenario: Configurar canales de notificación
Given estoy en configuración de alertas
When selecciono canales (push, email, SMS)
Then el sistema respeta mis preferencias
And solo recibo en canales habilitados
```
---
## Dependencias
- RF-PFM-007.1, RF-PFM-007.2, RF-PFM-007.3
- ET-PFM-007
- US-PFM-009 (Asignación objetivo)
---
## API Endpoints
### POST /api/portfolio/alerts
**Configurar umbral de alerta**
```json
{
"userId": "uuid",
"threshold": 5.0,
"channels": ["push", "email"],
"enabled": true
}
```
**Response:** 201 Created
### GET /api/portfolio/deviation
**Obtener desviación actual del portafolio**
```json
{
"userId": "uuid",
"timestamp": "2026-01-25T10:30:00Z",
"assets": [
{
"assetClass": "stocks",
"targetAllocation": 60.0,
"currentAllocation": 65.2,
"deviation": 5.2,
"status": "alert"
},
{
"assetClass": "bonds",
"targetAllocation": 40.0,
"currentAllocation": 34.8,
"deviation": -5.2,
"status": "alert"
}
],
"isBalanced": false,
"suggestions": [
{
"action": "sell",
"assetClass": "stocks",
"amount": 500.00
},
{
"action": "buy",
"assetClass": "bonds",
"amount": 500.00
}
]
}
```
---
## Elementos de UI/UX
1. **Card de Alertas en Dashboard**
- Mostrar estado: ✓ Balanceado / ⚠ Fuera de balance
- Badge rojo si hay desviación > umbral
- Botón "Configurar"
2. **Modal de Configuración**
- Input slider: umbral 1-10%
- Checkboxes: canales de notificación
- Botón Guardar
3. **Página de Desviación**
- Tabla con desgloses por activo
- Gráfico de dona: objetivo vs actual
- Sugerencias de rebalanceo con botón "Ejecutar"
4. **Notificaciones**
- Push: "Tu portafolio se desvió 5.2% de tu objetivo. Rebalancear"
- Email: Detalles completos + link a dashboard
---
*Historia de usuario - Sistema NEXUS*

View File

@ -0,0 +1,177 @@
---
id: "US-PFM-014"
title: "Generar Reporte PDF"
type: "User Story"
status: "Ready"
priority: "Alta"
epic: "OQI-008"
project: "trading-platform"
story_points: 5
created_date: "2026-01-25"
updated_date: "2026-01-25"
---
# US-PFM-014: Generar Reporte PDF
**Épica:** OQI-008 - Portfolio Manager
**Story Points:** 5 | **Prioridad:** P0
---
## Historia de Usuario
**Como** inversor
**Quiero** generar reportes PDF de mi portafolio
**Para** análisis offline o compartir con asesores financieros
---
## Criterios de Aceptación
```gherkin
Scenario: Seleccionar período de reporte
Given estoy en la sección de reportes del portafolio
And tengo datos de inversión disponibles
When selecciono un rango de fechas
Then puedo elegir período predeterminado (mensual, trimestral, anual)
And puedo ingresar fechas personalizadas
And el período es validado contra datos disponibles
Scenario: Generar reporte con gráficos
Given seleccioné un período válido
When solicito generar reporte PDF
Then el documento incluye gráficos de:
- Evolución del valor del portafolio (línea temporal)
- Distribución por activos (pie chart)
- Comparativo portafolio vs benchmark
- Retorno acumulado vs rentabilidad mensual (barras)
Scenario: Incluir métricas de rendimiento
Given el reporte está siendo generado
When se incluyen métricas de rendimiento
Then veo en el documento:
- Rentabilidad total (%)
- Rentabilidad anualizada
- Volatilidad
- Ratio de Sharpe
- Máxima pérdida acumulada (drawdown)
- Ratio ganancia/pérdida
Scenario: Detalle de posiciones
Given el reporte incluye posiciones
When se genera la sección de posiciones
Then veo tabla con:
- Código/Ticker del activo
- Cantidad de unidades
- Precio de compra/Precio actual
- Valor actual en portafolio
- Rendimiento (% y valor absoluto)
- Fecha de compra
Scenario: Descargar reporte
Given el reporte PDF está listo
When hago clic en "Descargar"
Then el archivo se descarga como: Portfolio_[fecha_inicio]_[fecha_fin]_[timestamp].pdf
And el formato PDF es optimizado (tamaño <5MB)
Scenario: Enviar reporte por email
Given el reporte PDF está listo
When hago clic en "Enviar por Email"
And ingreso dirección(es) de correo
Then el PDF se envía a los destinatarios
And recibo confirmación de envío
And el destinatario recibe el correo con adjunto
Scenario: Reporte multi-cuenta
Given tengo múltiples cuentas/portafolios
When selecciono la opción "Consolidado"
Then el reporte muestra:
- Resumen general
- Desglose por cada cuenta
- Distribución consolidada
- Rentabilidades combinadas
```
---
## API Endpoint
### POST /api/portfolio/reports/pdf
**Request:**
```json
{
"portfolioId": "uuid",
"startDate": "2026-01-01",
"endDate": "2026-01-25",
"includeGraphs": true,
"includeMetrics": true,
"includePositions": true,
"benchmark": "SPX",
"downloadFormat": "pdf",
"sendEmail": {
"enabled": false,
"recipients": []
},
"consolidated": false
}
```
**Response (200):**
```json
{
"id": "report_uuid",
"status": "generated",
"downloadUrl": "/api/reports/download/report_uuid",
"emailStatus": "pending|sent|failed",
"generatedAt": "2026-01-25T10:30:00Z",
"fileName": "Portfolio_2026-01-01_2026-01-25_20260125103000.pdf"
}
```
**Response (202 - Async):**
```json
{
"jobId": "job_uuid",
"status": "processing",
"estimatedTime": "30s",
"checkUrl": "/api/portfolio/reports/pdf/status/job_uuid"
}
```
---
## Dependencias
- RF-PFM-007: Cálculo de métricas de rendimiento
- RF-PFM-008: Integración con servicio de reportes
- RF-PFM-009: Generación de gráficos embebidos en PDF
- ET-PFM-007: Entidad ReportPDF
- US-PFM-012: Reporte Fiscal (complementario)
---
## Notas Técnicas
- Usar librería `pdfkit` o `puppeteer` para generación
- Gráficos embebidos con `chart.js` o `lightweight-charts`
- Queue asíncrona para reportes grandes (>500MB portafolio)
- Implementar retry automático en fallos de email
- Almacenar reportes 30 días máximo
- Validar tamaño de portafolio antes de generar
---
## Aceptación
- [ ] Endpoint POST creado y documentado
- [ ] Generación de PDF con gráficos funcional
- [ ] Descarga de archivos validada
- [ ] Envío por email implementado
- [ ] Tests unitarios y de integración
- [ ] Documentación en Swagger
- [ ] Manual de usuario actualizado
---
*Historia de usuario - Sistema NEXUS*

View File

@ -0,0 +1,633 @@
# ET-MKT-003: Especificación Frontend - Módulo Marketplace
**Documento:** ET-MKT-003-frontend.md
**Proyecto:** Trading Platform - OQI-009-Marketplace
**Versión:** 1.0.0
**Estado:** A IMPLEMENTAR
**Última Actualización:** 2026-01-25
---
## 1. Descripción General
Este documento define la especificación de la capa frontend para el módulo Marketplace (OQI-009) del sistema Trading Platform. El módulo permite a usuarios explorar, comparar y adquirir productos financieros digitales (Signal Packs, sesiones de asesoramiento y complementos de visualización).
### Nota Importante
**Esta especificación describe un diseño a implementar. No existe código frontend actual para este módulo.** Las páginas y componentes listados representan la propuesta de arquitectura que será desarrollada en futuras iteraciones.
### Productos Soportados
- **Signal Packs**: Paquetes de señales de trading pre-configuradas
- **Advisory Sessions**: Sesiones de asesoramiento con expertos
- **Visualization Addons**: Complementos avanzados de visualización de mercados
---
## 2. Arquitectura Frontend
### 2.1 Stack Tecnológico
```
Framework: React 18.x
Lenguaje: TypeScript 5.x
Estilos: Tailwind CSS + CSS Modules
Gestión Estado: Redux Toolkit
HTTP Client: Axios
Componentes UI: Headless UI / Radix UI
Testing: Jest + React Testing Library
```
### 2.2 Patrones Arquitectónicos
- **Componentes Funcionales:** Todos los componentes deben ser funcionales con hooks
- **Estructura por Features:** Organización en carpetas por feature (pages, components)
- **Custom Hooks:** Lógica reutilizable extraída en hooks personalizados
- **Context API:** Para estados compartidos entre componentes distantes
- **Lazy Loading:** Carga diferida de componentes con React.lazy()
---
## 3. Estructura de Directorios
```
src/
├── features/
│ └── marketplace/
│ ├── pages/
│ │ ├── MarketplacePage/
│ │ ├── ProductDetailPage/
│ │ ├── SignalPacksPage/
│ │ └── AdvisoryPage/
│ ├── components/
│ │ ├── ProductCard/
│ │ ├── SignalPackCard/
│ │ ├── AdvisorCard/
│ │ ├── BookingModal/
│ │ ├── FilterBar/
│ │ ├── ProductGallery/
│ │ └── ReviewSection/
│ ├── hooks/
│ │ ├── useMarketplaceFilters.ts
│ │ ├── useProductCart.ts
│ │ └── useAdvisorBooking.ts
│ ├── services/
│ │ ├── marketplaceApi.ts
│ │ ├── productApi.ts
│ │ └── advisoryApi.ts
│ ├── types/
│ │ └── marketplace.types.ts
│ ├── store/
│ │ └── marketplaceSlice.ts
│ └── styles/
│ └── marketplace.module.css
```
---
## 4. Páginas Propuestas
### 4.1 MarketplacePage
**Ruta:** `/marketplace`
**Responsabilidad:** Landing principal del marketplace con vista general de todos los productos
#### Características:
- Hero section con introducción al marketplace
- Buscador global de productos
- Filtros por categoría (Signal Packs, Advisory, Addons)
- Grid de productos destacados
- Testimonios de usuarios
- Llamadas a la acción (CTA)
#### Responsive Design:
- Desktop: Grid 4 columnas
- Tablet: Grid 2 columnas
- Mobile: Grid 1 columna
---
### 4.2 ProductDetailPage
**Ruta:** `/marketplace/product/:productId`
**Responsabilidad:** Vista detallada de un producto individual
#### Contenido Esperado:
- Galería de imágenes/screenshots
- Nombre, descripción y precio
- Especificaciones técnicas
- Comparativa con productos similares
- Sección de reviews y ratings
- Botón de compra/carrito
- Información del vendedor
- FAQ relacionadas
#### Datos a Cargar:
- Detalles del producto (API GET `/api/products/:id`)
- Reviews (API GET `/api/products/:id/reviews`)
- Productos relacionados (API GET `/api/products/:id/related`)
---
### 4.3 SignalPacksPage
**Ruta:** `/marketplace/signal-packs`
**Responsabilidad:** Página especializada para Signal Packs con funcionalidades específicas
#### Características:
- Filtros avanzados (tipo de señal, precisión, timeframe)
- Comparador de paquetes
- Gráfico de performance histórico
- Tabla de estadísticas en tiempo real
- Demos interactivos
- Botón "Probar Gratis" y "Comprar Ahora"
#### Componentes Específicos:
- `SignalPackCard` (extendido)
- `PerformanceChart`
- `ComparisonTable`
- `LiveStatisticsWidget`
---
### 4.4 AdvisoryPage
**Ruta:** `/marketplace/advisory`
**Responsabilidad:** Página para sesiones de asesoramiento con expertos
#### Características:
- Directorio de asesores con filtros
- Calendarios de disponibilidad
- Precios por tipo de sesión
- Credenciales y especialidades de asesores
- Sistema de booking integrado
- Historial de sesiones del usuario
- Funcionalidad de reseñas post-sesión
#### Integración Modal:
- Modal de booking (`BookingModal`) se dispara desde tarjetas de asesores
- Confirmación y pago dentro del modal
---
## 5. Componentes Propuestos
### 5.1 ProductCard
**Ubicación:** `components/ProductCard/`
```typescript
interface ProductCardProps {
product: Product;
onViewDetails: (productId: string) => void;
onAddToCart?: (product: Product) => void;
variant?: 'default' | 'compact' | 'featured';
}
```
**Elementos:**
- Imagen de portada
- Nombre del producto
- Rating (estrellas + número de reviews)
- Precio y descuento (si aplica)
- Descripción breve (2-3 líneas)
- Etiquetas (categoría, trending)
- Botones de acción (Ver detalles, Agregar al carrito)
**Estados:**
- Default: Producto disponible
- Loading: Cargando datos
- Disabled: Producto no disponible
- Favorited: Producto agregado a favoritos
---
### 5.2 SignalPackCard
**Ubicación:** `components/SignalPackCard/`
**Extends:** ProductCard (con extensiones específicas)
```typescript
interface SignalPackCardProps extends ProductCardProps {
winRate: number;
totalSignals: number;
avgReturnPerSignal: number;
lastSignalDate: Date;
difficultyLevel: 'beginner' | 'intermediate' | 'advanced';
}
```
**Elementos Adicionales:**
- Badge de dificultad
- Win rate en porcentaje
- Total de señales generadas
- Retorno promedio por señal
- Fecha de última señal
- Gráfico mini de performance (sparkline)
---
### 5.3 AdvisorCard
**Ubicación:** `components/AdvisorCard/`
```typescript
interface AdvisorCardProps {
advisor: Advisor;
onBookSession: (advisorId: string) => void;
}
```
**Elementos:**
- Foto de perfil
- Nombre y especialidad
- Rating y número de sesiones completadas
- Descripción breve
- Certificaciones y credenciales (badges)
- Precio por hora/sesión
- Disponibilidad (horarios)
- Botón "Reservar Ahora"
- Link a perfil completo
---
### 5.4 BookingModal
**Ubicación:** `components/BookingModal/`
```typescript
interface BookingModalProps {
advisor: Advisor;
isOpen: boolean;
onClose: () => void;
onConfirm: (booking: BookingRequest) => Promise<void>;
}
```
**Flujo:**
1. **Selección de Sesión**: Tipo y duración
2. **Calendario**: Seleccionar fecha/hora disponible
3. **Detalles Personales**: Confirmar información del usuario
4. **Resumen de Pago**: Mostrar total y método de pago
5. **Confirmación**: Enviar reserva y mostrar confirmación
**Validaciones:**
- Fecha/hora no pueden ser pasadas
- Usuario debe estar autenticado
- Validar disponibilidad en tiempo real
- Procesar pago antes de confirmar
---
### 5.5 Componentes Auxiliares
#### FilterBar
**Ubicación:** `components/FilterBar/`
**Responsabilidad:** Filtros dinámicos reutilizables
```typescript
interface FilterBarProps {
filters: FilterDefinition[];
onApply: (appliedFilters: Record<string, any>) => void;
onReset: () => void;
}
```
#### ProductGallery
**Ubicación:** `components/ProductGallery/`
**Responsabilidad:** Galería de imágenes con zoom y thumbnails
#### ReviewSection
**Ubicación:** `components/ReviewSection/`
**Responsabilidad:** Mostrar y permitir crear nuevas reseñas
---
## 6. Flujos de Usuario Principales
### 6.1 Flujo: Explorar y Comprar Signal Pack
```
MarketplacePage
→ (filtrar/buscar)
→ SignalPacksPage
→ ProductDetailPage (Signal Pack)
→ Carrito
→ Checkout
```
### 6.2 Flujo: Reservar Sesión de Asesoramiento
```
MarketplacePage
→ AdvisoryPage
→ (filtrar asesores)
→ AdvisorCard
→ BookingModal (se abre)
→ Confirmación y Pago
→ Página de confirmación
```
### 6.3 Flujo: Ver Detalles de Complemento
```
MarketplacePage
→ ProductDetailPage (Addon)
→ Comparar con similares
→ Agregar al carrito
→ Checkout
```
---
## 7. Integración con API
### 7.1 Endpoints Consumidos
```
GET /api/marketplace/products # Listar productos con filtros
GET /api/marketplace/products/:id # Detalle de producto
GET /api/marketplace/products/:id/reviews
POST /api/marketplace/cart # Agregar al carrito
GET /api/marketplace/advisors # Listar asesores
POST /api/marketplace/bookings # Crear booking
GET /api/user/orders # Historial de compras
```
### 7.2 Servicios API (Custom Hooks)
```typescript
// marketplaceApi.ts
export const marketplaceApi = {
getProducts: (filters?: ProductFilters) => Promise<Product[]>,
getProductDetail: (id: string) => Promise<Product>,
getAdvisors: (filters?: AdvisorFilters) => Promise<Advisor[]>,
createBooking: (booking: BookingRequest) => Promise<BookingResponse>,
getReviews: (productId: string) => Promise<Review[]>,
submitReview: (review: ReviewSubmission) => Promise<Review>,
}
```
---
## 8. Estado Global (Redux)
### 8.1 Slices del Store
```typescript
// marketplaceSlice.ts
{
marketplace: {
products: Product[],
selectedProduct: Product | null,
advisors: Advisor[],
cart: CartItem[],
filters: {
category: string[],
priceRange: [number, number],
rating: number,
// ... más filtros
},
loading: boolean,
error: string | null,
}
}
```
### 8.2 Actions Principales
- `setProducts(products)`
- `setSelectedProduct(product)`
- `addToCart(product)`
- `removeFromCart(productId)`
- `updateFilters(filters)`
- `setLoading(boolean)`
---
## 9. Validaciones Frontend
### 9.1 Búsqueda y Filtros
- Campo de búsqueda: mínimo 3 caracteres
- Filtros deben reflejar datos del backend
- Debounce en búsqueda (300ms)
### 9.2 Booking de Sesiones
- Fecha no puede ser en el pasado
- Hora debe coincidir con disponibilidad del asesor
- Usuario debe estar autenticado
- Validar saldo/método de pago
### 9.3 Carrito
- Validar cantidad disponible
- Evitar agregar mismo producto dos veces (aumentar cantidad)
- Mostrar total actualizado
### 9.4 Formularios
- Validación en tiempo real
- Mensajes de error claros
- Estados loading en botones de envío
---
## 10. Performance y Optimización
### 10.1 Técnicas
- **Code Splitting:** Lazy loading de páginas con React.lazy()
- **Memoization:** React.memo() para componentes puros
- **Image Optimization:** Optimizar imágenes, WebP, lazy loading
- **Virtualization:** Virtualizaciónlist para listas largas (si aplica)
- **Bundle Analysis:** Usar webpack-bundle-analyzer
### 10.2 Métricas Objetivo
- LCP (Largest Contentful Paint): < 2.5s
- FID (First Input Delay): < 100ms
- CLS (Cumulative Layout Shift): < 0.1
---
## 11. Accesibilidad (A11y)
### 11.1 Estándares
- WCAG 2.1 Nivel AA
- Navegación por teclado
- Contraste mínimo 4.5:1
- Labels explícitos en formularios
- ARIA labels donde sea necesario
### 11.2 Implementación
```typescript
// Ejemplo: Botón accesible
<button
aria-label="Agregar producto al carrito"
className="btn-primary"
onClick={handleAddToCart}
>
Agregar al Carrito
</button>
```
---
## 12. Testing
### 12.1 Cobertura Objetivo
- Unit Tests: 80% de componentes
- Integration Tests: Flujos principales
- E2E Tests: Casos de compra y booking
### 12.2 Ejemplos de Pruebas
```typescript
// ProductCard.test.tsx
describe('ProductCard', () => {
it('should render product information', () => {
const product = mockProduct();
render(<ProductCard product={product} onViewDetails={jest.fn()} />);
expect(screen.getByText(product.name)).toBeInTheDocument();
});
it('should call onViewDetails when clicked', () => {
const onViewDetails = jest.fn();
const product = mockProduct();
render(<ProductCard product={product} onViewDetails={onViewDetails} />);
fireEvent.click(screen.getByRole('button', { name: /ver detalles/i }));
expect(onViewDetails).toHaveBeenCalledWith(product.id);
});
});
```
---
## 13. Tipo de Datos Principales
### 13.1 Interfaces TypeScript
```typescript
// marketplace.types.ts
interface Product {
id: string;
name: string;
description: string;
price: number;
discount?: number;
category: 'signal_pack' | 'advisory' | 'addon';
rating: number;
reviewCount: number;
image: string;
images?: string[];
createdAt: Date;
updatedAt: Date;
}
interface SignalPack extends Product {
winRate: number;
totalSignals: number;
avgReturnPerSignal: number;
difficultyLevel: 'beginner' | 'intermediate' | 'advanced';
lastSignalDate: Date;
}
interface Advisor {
id: string;
name: string;
email: string;
photo: string;
specialty: string;
bio: string;
rating: number;
completedSessions: number;
pricePerHour: number;
certifications: Certification[];
availability: TimeSlot[];
}
interface BookingRequest {
advisorId: string;
userId: string;
sessionType: 'consultation' | 'strategy_review';
duration: 30 | 60 | 90; // minutos
scheduledDate: Date;
notes?: string;
}
interface Review {
id: string;
productId: string;
userId: string;
rating: number;
title: string;
comment: string;
createdAt: Date;
}
```
---
## 14. Responsive Design Breakpoints
```css
/* Tailwind / CSS */
Mobile: < 640px (sm)
Tablet: 640px+ (md)
Desktop: 1024px+ (lg)
Wide: 1280px+ (xl)
UltraWide: 1536px+ (2xl)
```
---
## 15. Roadmap de Implementación
### Fase 1: Estructura Base (Sprint 1-2)
- [ ] Setup proyecto React + TypeScript
- [ ] Crear estructura de directorios
- [ ] Implementar routing y layout base
- [ ] Configurar Redux store
### Fase 2: Componentes (Sprint 3-4)
- [ ] ProductCard, SignalPackCard, AdvisorCard
- [ ] FilterBar, ProductGallery
- [ ] BookingModal
### Fase 3: Páginas (Sprint 5-6)
- [ ] MarketplacePage
- [ ] ProductDetailPage
- [ ] SignalPacksPage
- [ ] AdvisoryPage
### Fase 4: Integraciones y Polish (Sprint 7-8)
- [ ] Consumir APIs
- [ ] Testing
- [ ] Optimización
- [ ] Despliegue
---
## 16. Referencias y Documentos Relacionados
- **ET-MKT-001-database.md**: Esquema de base de datos
- **ET-MKT-002-api.md**: Especificación de API REST
- **Guía de Componentes**: (a crear en futuro)
- **Guía de Testing**: (a crear en futuro)
---
## 17. Notas de Desarrollo
### Prácticas Recomendadas
1. Mantener componentes pequeños y enfocados
2. Usar TypeScript para toda la capa frontend
3. Escribir tests mientras se desarrolla
4. Revisar código antes de merge
5. Documentar componentes complejos
### Dependencias NPM Esperadas
```json
{
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@reduxjs/toolkit": "^1.9.x",
"react-redux": "^8.1.x",
"axios": "^1.4.x",
"tailwindcss": "^3.3.x",
"typescript": "^5.1.x"
}
```
---
## 18. Cambios Pendientes
Este documento será actualizado cuando:
- Se inicie implementación de componentes
- Se definan cambios en UX/UI
- Se agreguen nuevas funcionalidades
- Se identifiquen patrones de optimización
---
**Documento Generado:** 2026-01-25
**Próxima Revisión:** Tras completar Fase 1 de implementación
**Estado:** BORRADOR - A IMPLEMENTAR

View File

@ -0,0 +1,48 @@
# TASK-2026-01-25-FRONTEND-ANALYSIS
**Estado:** COMPLETADA
**Fecha:** 2026-01-25
**Tipo:** ANALYSIS
## Resumen
Analisis y documentacion detallada del frontend de trading-platform.
## Entregables Completados
### FASE 1: Inventarios (3/3)
- MASTER_INVENTORY.yml actualizado
- FRONTEND_INVENTORY.yml completado (48 componentes)
- BACKEND_INVENTORY.yml completado (trading + ML modules)
### FASE 2: Especificaciones Frontend (5/5)
- ET-AUTH-006-frontend.md (OQI-001)
- ET-ML-008-frontend.md (OQI-006)
- ET-LLM-007-frontend.md (OQI-007)
- ET-PFM-008-frontend.md (OQI-008)
- ET-MKT-003-frontend.md (OQI-009)
### FASE 3: Historias de Usuario (8 nuevas)
- US-AUTH-013, US-AUTH-014
- US-ML-008, US-ML-009, US-ML-010
- US-LLM-011
- US-PFM-013, US-PFM-014
### FASE 4: Coherencia API-Frontend
- API-FRONTEND-COVERAGE-MATRIX.md (85% cobertura)
- FILE-GENERATION-SPEC.md
### FASE 5: Dependencias
- DEPENDENCY-GRAPH.yml actualizado con epicas
## Metricas
| Metrica | Valor |
|---------|-------|
| Modulos con doc frontend | 10/10 (100%) |
| Cobertura API-Frontend | 85% |
| Historias de usuario nuevas | 8 |
| Archivos creados/modificados | 20+ |
---
*Completado: 2026-01-25 | Sistema: SIMCO v4.0.0*

View File

@ -6,8 +6,8 @@ created: "2026-01-24"
updated: "2026-01-24"
resumen:
total_tareas: 0
completadas: 0
total_tareas: 1
completadas: 1
en_progreso: 0
pendientes: 0
@ -15,9 +15,21 @@ formato_id:
patron: "TASK-{YYYY-MM-DD}-{NNN}"
ejemplo: "TASK-2026-01-24-001"
por_fecha: {}
por_fecha:
2026-01-25:
- id: TASK-2026-01-25-FRONTEND-ANALYSIS
titulo: "Analisis y Documentacion Frontend"
estado: COMPLETADA
tipo: ANALYSIS
tareas_activas: []
tareas_completadas:
- id: TASK-2026-01-25-FRONTEND-ANALYSIS
fecha_inicio: "2026-01-25"
fecha_fin: "2026-01-25"
entregables: 20+
instrucciones:
crear_tarea: |
1. Crear carpeta YYYY-MM-DD/ si no existe