trading-platform/orchestration/analisis/OQI-001-ANALISIS-COMPONENTES.md
Adrian Flores Cortes 76b0ced338 [TASK-002] docs: Auditoria comprehensiva frontend trading-platform
Analisis exhaustivo CAPVED de 9 epics (OQI-001 a OQI-009) con:
- 48 documentos generados (~19,000 lineas)
- 122+ componentes analizados
- 113 endpoints API mapeados
- 30 gaps criticos identificados
- Roadmap de implementacion (2,457h esfuerzo)
- 9 subagentes en paralelo (2.5-3h vs 20h)

Hallazgos principales:
- 38% completitud promedio
- 10 gaps bloqueantes (P0)
- OQI-009 (MT4) 0% funcional
- OQI-005 (Pagos) PCI-DSS non-compliant
- Test coverage <10%

Entregables:
- EXECUTIVE-SUMMARY.md (reporte ejecutivo)
- 02-ANALISIS.md (consolidado 9 epics)
- 48 docs tecnicos por epic (componentes, APIs, gaps)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 12:57:14 -06:00

17 KiB

OQI-001: Análisis de Componentes - Fundamentos-Auth

Módulo: OQI-001 (fundamentos-auth) Ruta: apps/frontend/src/modules/auth/ Progreso: 70% Fecha: 2026-01-25 Status: ANÁLISIS COMPLETO


COMPONENTES - TABLA CONSOLIDADA

Componente Función Props Hooks Estados Eventos
Login.tsx Página principal de inicio de sesión con métodos email/teléfono none useState, useNavigate loginMethod, showPassword, isLoading, error, formData, requiresTwoFactor handleEmailLogin()
Register.tsx Página de registro de nueva cuenta con validación de contraseña none useState, useNavigate showPassword, isLoading, error, success, formData handleRegister(), PasswordCheck() componente
ForgotPassword.tsx Página para solicitar recuperación de contraseña none useState email, isLoading, submitted, error handleSubmit()
VerifyEmail.tsx Página de verificación de email con token none useState, useEffect, useSearchParams status, error, token (query param) verifyEmail() - llamada automática
ResetPassword.tsx Página para establecer nueva contraseña con token none useState, useEffect, useSearchParams, useNavigate showPassword, isLoading, status, error, formData, token (query param) handleSubmit(), PasswordCheck() componente
AuthCallback.tsx Página callback para OAuth y manejo de tokens none useState, useEffect, useNavigate, useSearchParams status, error, accessToken, refreshToken, isNewUser, returnUrl (query params) getErrorMessage(), redirección automática
SecuritySettings.tsx Página principal de configuración de seguridad con tabs none useState, useNavigate activeTab Cambio de tabs, navegación
SocialLoginButtons Componente de botones OAuth (Google, Facebook, X, Apple, GitHub) mode?: 'login' | 'register' useState isLoading (por provider) handleSocialLogin()
PhoneLoginForm Componente de formulario de login por teléfono (WhatsApp/SMS) none useState, useNavigate step, channel, isLoading, error, formData, otpExpiresAt handleSendOTP(), handleVerifyOTP(), handleResendOTP()
SessionsList Componente que lista sesiones activas del usuario none useState, useEffect (custom Zustand store) sessions, loading, error, revoking (Set), showRevokeAllConfirm fetchSessions(), revokeSession(), revokeAllSessions(), handleRevokeAll()
DeviceCard Componente que renderiza una tarjeta individual de sesión/dispositivo { session: ActiveSession, isRevoking: boolean, onRevoke: (sessionId) => Promise<void> } useState showConfirm handleRevoke(), toggle confirmación

PÁGINAS (7 Total)

1. Login.tsx

Ubicación: /pages/Login.tsx Líneas: 1-230

Función Principal: Página de inicio de sesión con soporte para email/contraseña, teléfono (SMS/WhatsApp), y OAuth social.

Props: Ninguno (componente página)

Hooks Utilizados:

  • useState() - Gestión de estado local (loginMethod, showPassword, isLoading, error, formData, requiresTwoFactor)
  • useNavigate() - Navegación programática tras login exitoso

Estados Principales:

loginMethod: 'email' | 'phone'
showPassword: boolean
isLoading: boolean
error: string | null
formData: {
  email: string
  password: string
  rememberMe: boolean
  totpCode: string
}
requiresTwoFactor: boolean

Eventos/Métodos:

  • handleEmailLogin() - POST /api/v1/auth/login
    • Soporta 2FA (TOTP)
    • Guarda tokens en localStorage
    • Redirige a /dashboard

Integración: Utiliza <SocialLoginButtons /> y <PhoneLoginForm />


2. Register.tsx

Ubicación: /pages/Register.tsx Líneas: 1-258

Función Principal: Registro de nuevos usuarios con validación robusta de contraseña.

Props: Ninguno

Hooks Utilizados:

  • useState() - Estado del formulario, loading, error, success
  • useNavigate() - Redirección tras registro exitoso

Estados Principales:

showPassword: boolean
isLoading: boolean
error: string | null
success: boolean
formData: {
  firstName: string
  lastName: string
  email: string
  password: string
  confirmPassword: string
  acceptTerms: boolean
}

// Password validation
passwordChecks: {
  length: boolean (8 caracteres)
  uppercase: boolean (/[A-Z]/)
  lowercase: boolean (/[a-z]/)
  number: boolean (/[0-9]/)
  special: boolean (/[!@#$%^&*(),.?":{}|<>]/)
  match: boolean (password === confirmPassword)
}

Eventos/Métodos:

  • handleRegister() - POST /api/v1/auth/register
  • PasswordCheck() - Componente interno para mostrar requerimientos

Validaciones:

  • 5 requerimientos de contraseña (8+, mayúscula, minúscula, número, especial)
  • Confirmación de contraseña
  • Aceptación de términos

Integración: Utiliza <SocialLoginButtons mode="register" />


3. ForgotPassword.tsx

Ubicación: /pages/ForgotPassword.tsx Líneas: 1-119

Función Principal: Solicitud de recuperación de contraseña por email.

Props: Ninguno

Hooks Utilizados:

  • useState() - Email, isLoading, submitted, error
  • useNavigate() - Navegación

Estados Principales:

email: string
isLoading: boolean
submitted: boolean
error: string | null

Eventos/Métodos:

  • handleSubmit() - POST /api/v1/auth/forgot-password
  • Mensaje genérico (privacidad): "Si existe cuenta... recibirás enlace"

4. VerifyEmail.tsx

Ubicación: /pages/VerifyEmail.tsx Líneas: 1-98

Función Principal: Verificar email del usuario mediante token de verificación.

Props: Ninguno

Hooks Utilizados:

  • useState() - Status (loading|success|error|no-token), error
  • useEffect() - Llamada automática a verifyEmail() si token existe
  • useSearchParams() - Obtención del token (?token=xxx)

Estados Principales:

status: 'loading' | 'success' | 'error' | 'no-token'
error: string | null
token: string | null (query param)

Eventos/Métodos:

  • verifyEmail(token) - POST /api/v1/auth/verify-email
  • Ejecutado automáticamente en useEffect

Flujos UI:

  1. loading: Spinner "Verificando email..."
  2. success: CheckCircle icon + "Email Verificado" + link a Login
  3. no-token: Mail icon + instrucción para hacer clic en email
  4. error: XCircle icon + mensaje de error + botones de intento

5. ResetPassword.tsx

Ubicación: /pages/ResetPassword.tsx Líneas: 1-210

Función Principal: Establecer nueva contraseña con token de recuperación.

Props: Ninguno

Hooks Utilizados:

  • useState() - Contraseñas, loading, status, error, formData
  • useEffect() - Validación de token en mount
  • useNavigate() - Redirección tras éxito
  • useSearchParams() - Obtención de token

Estados Principales:

showPassword: boolean
isLoading: boolean
status: 'form' | 'success' | 'error' | 'no-token'
error: string | null
formData: {
  password: string
  confirmPassword: string
}
token: string | null

Eventos/Métodos:

  • handleSubmit() - POST /api/v1/auth/reset-password
  • Validación igual a Register (5 requerimientos)

Flujos UI:

  1. form: Formulario de contraseña nueva
  2. success: CheckCircle + redirige a Login
  3. error: Error message + opción de reintentar
  4. no-token: Token inválido/expirado

6. AuthCallback.tsx

Ubicación: /pages/AuthCallback.tsx Líneas: 1-96

Función Principal: Callback para OAuth y manejo de tokens post-autenticación.

Props: Ninguno

Hooks Utilizados:

  • useState() - Status, error
  • useEffect() - Procesamiento automático de query params
  • useNavigate() - Redirección final
  • useSearchParams() - Obtención de tokens y parámetros

Query Params Esperados:

?accessToken=xxx
&refreshToken=xxx
&isNewUser=true|false
&error=error_code
&returnUrl=/dashboard (default)

Errores Soportados:

  • invalid_state - Sesión expirada
  • oauth_failed - Conexión fallida con proveedor
  • oauth_error - Error genérico de autenticación
  • missing_code_verifier - Error de configuración
  • invalid_provider - Proveedor no válido

Flujos:

  1. loading: Spinner "Completando autenticación..."
  2. success: CheckCircle + redirección a onboarding (nuevo) o returnUrl
  3. error: XCircle + mensaje + botón "Volver a Iniciar Sesión"

7. SecuritySettings.tsx

Ubicación: /pages/SecuritySettings.tsx Líneas: 1-274

Función Principal: Panel principal de configuración de seguridad con 3 tabs: sesiones, contraseña, 2FA.

Props: Ninguno

Hooks Utilizados:

  • useState() - activeTab
  • useNavigate() - Navegación hacia atrás
  • Custom SVG icons (BackIcon, ShieldIcon, KeyIcon, LockIcon, DevicesIcon)

States Principales:

activeTab: 'sessions' | 'password' | 'two-factor'

Tabs Contenidos:

Tab Contenido Features
sessions Renderiza <SessionsList /> Listado y revocación de sesiones
password Formulario de cambio de contraseña 3 inputs (actual, nueva, confirmar) - SIN IMPLEMENTAR
two-factor Opciones 2FA Authenticator App y SMS - SIN IMPLEMENTAR (botones Setup)

Observaciones:

  • Tab password: Formulario básico sin handler
  • Tab two-factor: UI completa pero botones "Setup" sin funcionalidad
  • Integración con SessionsList component

COMPONENTES (4 Total)

1. SocialLoginButtons.tsx

Ubicación: /components/SocialLoginButtons.tsx Líneas: 1-129

Función Principal: Botones OAuth para login/registro social.

Props:

interface SocialLoginButtonsProps {
  mode?: 'login' | 'register'  // Default: 'login'
}

Hooks Utilizados:

  • useState() - isLoading por provider

Estados:

isLoading: string | null  // Provider ID siendo procesado

Providers Soportados (5):

  1. Google - bg-white, botón grande
  2. Facebook - bg-[#1877F2], botón grande
  3. X (Twitter) - bg-black, ícono pequeño
  4. Apple - bg-black, ícono pequeño
  5. GitHub - bg-[#24292e], ícono pequeño

Eventos:

  • handleSocialLogin(provider) - GET /api/v1/auth/{provider}?returnUrl=...
  • Redirige a data.data.authUrl (URL de OAuth del proveedor)

Estructura UI:

[Google | Facebook]  (grid 2 cols)
[X | Apple | GitHub] (flex horizontal, iconos)

2. PhoneLoginForm.tsx

Ubicación: /components/PhoneLoginForm.tsx Líneas: 1-264

Función Principal: Formulario de login por teléfono con OTP (SMS/WhatsApp).

Props: Ninguno

Hooks Utilizados:

  • useState() - step, channel, isLoading, error, formData, otpExpiresAt
  • useNavigate() - Redirección tras verificación

Estados:

step: 'phone' | 'otp'
channel: 'whatsapp' | 'sms'
isLoading: boolean
error: string | null
formData: {
  countryCode: string  // Default: '52' (Mexico)
  phoneNumber: string
  otpCode: string
}
otpExpiresAt: Date | null

Códigos de País Soportados (9):

País Código Flag
México 52 MX
USA 1 US
Colombia 57 CO
Argentina 54 AR
Chile 56 CL
Perú 51 PE
Ecuador 593 EC
Venezuela 58 VE
España 34 ES

Flujo de Dos Pasos:

PASO 1: Phone

  • Seleccionar canal (WhatsApp/SMS)
  • Seleccionar código de país
  • Ingresar número
  • POST /api/v1/auth/phone/send-otp

PASO 2: OTP

  • Mostrar número enmascarado (+52 55 1234 5678)
  • Input de 6 dígitos
  • POST /api/v1/auth/phone/verify-otp
  • Almacena tokens en localStorage
  • Redirige a /dashboard

Validaciones:

  • Número mínimo 8 dígitos
  • OTP exactamente 6 dígitos

Eventos:

  • handleSendOTP() - Envía OTP
  • handleVerifyOTP() - Verifica código
  • handleResendOTP() - Reenvía código

3. SessionsList.tsx

Ubicación: /components/SessionsList.tsx Líneas: 1-196

Función Principal: Listado de sesiones activas con opciones de revocación.

Props: Ninguno

Hooks Utilizados:

  • useState() - showRevokeAllConfirm, revokeAllLoading
  • useEffect() - fetchSessions en mount
  • Custom Zustand store: useSessionsStore()

Zustand Store Actions:

const {
  sessions: ActiveSession[]
  loading: boolean
  error: string | null
  revoking: Set<string>
  fetchSessions: () => Promise<void>
  revokeSession: (sessionId: string) => Promise<void>
  revokeAllSessions: () => Promise<void>
  clearError: () => void
} = useSessionsStore()

Estados Locales:

showRevokeAllConfirm: boolean
revokeAllLoading: boolean

Lógica Principal:

  • Ordena sesiones: actual primero, luego por lastActiveAt DESC
  • Muestra contador: "N active sessions across your devices"
  • Botón "Sign Out All Devices" si hay sesiones distintas a la actual
  • Renderiza <DeviceCard /> para cada sesión

UI Estados:

  1. loading: Spinner "Loading sessions..."
  2. no sessions: "No active sessions found" (vacío)
  3. with sessions:
    • Cada sesión es un <DeviceCard />
    • Security tip: "If you see unrecognized device..."
  4. error: Mensaje de error con botón cerrar

Evento:

  • handleRevokeAll() - POST /api/v1/auth/logout-all
    • Requiere confirmación
    • Limpia localStorage y redirige a /login

4. DeviceCard.tsx

Ubicación: /components/DeviceCard.tsx Líneas: 1-194

Función Principal: Tarjeta individual de sesión/dispositivo con información y botón de revocación.

Props:

interface DeviceCardProps {
  session: ActiveSession
  isRevoking: boolean
  onRevoke: (sessionId: string) => Promise<void>
}

Hooks Utilizados:

  • useState() - showConfirm
  • Custom functions: authService.parseUserAgent(), authService.formatRelativeTime()

Estados:

showConfirm: boolean

Información Mostrada:

Campo Origen Formato
Browser + OS userAgent (parsed) "Chrome on Windows 10/11"
Device Type userAgent (parsed) Desktop/Mobile/Tablet icon
IP Address session.ipAddress "10.0.0.1" o "Unknown IP"
Last Active session.lastActiveAt Relative time: "2 mins ago"
Session Created session.createdAt "1/25/2026, 3:30:45 PM"
Current Status session.isCurrent Badge verde "Current"

Device Type Icons (4):

  • Desktop - Monitor icon
  • Mobile - Phone icon
  • Tablet - Tablet icon
  • Unknown - Question mark icon

User Agent Parsing:

parseUserAgent(userAgent): {
  type: 'desktop' | 'mobile' | 'tablet' | 'unknown'
  os: string ('Windows 10/11', 'macOS', 'iOS', 'Android', etc)
  browser: string ('Chrome', 'Safari', 'Firefox', 'Edge', etc)
}

Styling:

  • Sesión actual: Fondo verde emergente, borde verde
  • Otras sesiones: Fondo gris-oscuro, borde gris

Botón Revocación:

  • Sesión actual: "Log Out" (gris)
  • Otras sesiones: "Revoke" (rojo)
  • Toggle de confirmación: "Confirm" / "Cancel"

Evento:

  • handleRevoke() - Llama a onRevoke(sessionId)
  • Para sesión actual: Logout + redirección a /login

RESUMEN ESTADÍSTICO

Métrica Cantidad
Páginas 7
Componentes 4
Total de archivos 11
Líneas de código (total) ~2,200
Hooks React utilizados useState, useEffect, useNavigate, useSearchParams
State Management Zustand (SessionsList) + localStorage + useState
APIs consumidas 14+ endpoints
Validaciones Contraseña robusta, Email, Teléfono, Tokens
Social Providers 5 (Google, Facebook, X, Apple, GitHub)
Métodos 2FA TOTP (Login), SMS (PhoneLoginForm), Authenticator (TODO)
Dispositivos soportados Desktop, Mobile, Tablet
Idioma Español (es)

REFERENCIAS INTERNAS

  • Auth Service: /services/auth.service.ts - API client y utilidades
  • Sessions Store: /stores/sessionsStore.ts - Estado global de sesiones (Zustand)
  • Auth Types: /types/auth.types.ts - Definiciones TypeScript

NOTAS IMPORTANTES

  1. SocialLoginButtons: Soporta modo login y registro
  2. PhoneLoginForm: Integrado solo en Login (no en Register)
  3. DeviceCard: Utiliza funciones helper de authService para parsing
  4. SecuritySettings: Tabs 2FA y Password sin implementación completa
  5. Validación de Contraseña: Idéntica en Register y ResetPassword
  6. Flujo 2FA: Solo en Login (TOTP), SecuritySettings es placeholder
  7. Locales: Mensajes en español, variables de environment para URLs

Análisis completado: 2026-01-25 Módulo OQI-001 (fundamentos-auth) - 70% implementación