# 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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
interface SocialLoginButtonsProps {
  mode?: 'login' | 'register'  // Default: 'login'
}
```

**Hooks Utilizados:**
- `useState()` - isLoading por provider

**Estados:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
interface DeviceCardProps {
  session: ActiveSession
  isRevoking: boolean
  onRevoke: (sessionId: string) => Promise<void>
}
```

**Hooks Utilizados:**
- `useState()` - showConfirm
- Custom functions: `authService.parseUserAgent()`, `authService.formatRelativeTime()`

**Estados:**
```typescript
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:**
```typescript
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*
