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>
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, successuseNavigate()- 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/registerPasswordCheck()- 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, erroruseNavigate()- 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), erroruseEffect()- Llamada automática a verifyEmail() si token existeuseSearchParams()- 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:
- loading: Spinner "Verificando email..."
- success: CheckCircle icon + "Email Verificado" + link a Login
- no-token: Mail icon + instrucción para hacer clic en email
- 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, formDatauseEffect()- Validación de token en mountuseNavigate()- Redirección tras éxitouseSearchParams()- 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:
- form: Formulario de contraseña nueva
- success: CheckCircle + redirige a Login
- error: Error message + opción de reintentar
- 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, erroruseEffect()- Procesamiento automático de query paramsuseNavigate()- Redirección finaluseSearchParams()- 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 expiradaoauth_failed- Conexión fallida con proveedoroauth_error- Error genérico de autenticaciónmissing_code_verifier- Error de configuracióninvalid_provider- Proveedor no válido
Flujos:
- loading: Spinner "Completando autenticación..."
- success: CheckCircle + redirección a onboarding (nuevo) o returnUrl
- 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()- activeTabuseNavigate()- 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):
- Google - bg-white, botón grande
- Facebook - bg-[#1877F2], botón grande
- X (Twitter) - bg-black, ícono pequeño
- Apple - bg-black, ícono pequeño
- 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, otpExpiresAtuseNavigate()- 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 OTPhandleVerifyOTP()- Verifica códigohandleResendOTP()- 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, revokeAllLoadinguseEffect()- 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:
- loading: Spinner "Loading sessions..."
- no sessions: "No active sessions found" (vacío)
- with sessions:
- Cada sesión es un
<DeviceCard /> - Security tip: "If you see unrecognized device..."
- Cada sesión es un
- 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
- SocialLoginButtons: Soporta modo login y registro
- PhoneLoginForm: Integrado solo en Login (no en Register)
- DeviceCard: Utiliza funciones helper de authService para parsing
- SecuritySettings: Tabs 2FA y Password sin implementación completa
- Validación de Contraseña: Idéntica en Register y ResetPassword
- Flujo 2FA: Solo en Login (TOTP), SecuritySettings es placeholder
- 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