ML Engine Updates: - Updated BTCUSD with Polygon API data (2024-2025): 215,699 new records - Re-trained all ML models: Attention (R²: 0.223), Base, Metamodel (87.3% confidence) - Backtest results: +176.71R profit with aggressive_filter strategy Documentation Consolidation: - Created docs/99-analisis/_MAP.md index with 13 new analysis documents - Consolidated inventories: removed duplicates from orchestration/inventarios/ - Updated ML_INVENTORY.yml with BTCUSD metrics and training results - Added execution reports: FASE11-BTCUSD, correction issues, alignment validation Architecture & Integration: - Updated all module documentation with NEXUS v3.4 frontmatter - Fixed _MAP.md indexes across all folders - Updated orchestration plans and traces Files: 229 changed, 5064 insertions(+), 1872 deletions(-) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
340 lines
11 KiB
Markdown
340 lines
11 KiB
Markdown
---
|
|
id: "RF-AUTH-003"
|
|
title: "Autenticacion por Telefono"
|
|
type: "Requirement"
|
|
status: "Done"
|
|
priority: "Alta"
|
|
module: "auth"
|
|
epic: "OQI-001"
|
|
version: "1.0"
|
|
created_date: "2025-12-05"
|
|
updated_date: "2026-01-04"
|
|
---
|
|
|
|
# RF-AUTH-003: Autenticación por Teléfono
|
|
|
|
**Version:** 1.0.0
|
|
**Fecha:** 2025-12-05
|
|
**Estado:** ✅ Implementado
|
|
**Prioridad:** P1 (Alta)
|
|
**Épica:** [OQI-001](../_MAP.md)
|
|
|
|
---
|
|
|
|
## Descripción
|
|
|
|
El sistema debe permitir a los usuarios autenticarse mediante número de teléfono usando OTP (One-Time Password) enviado por SMS o WhatsApp, facilitando el acceso a usuarios que prefieren no usar email o redes sociales.
|
|
|
|
---
|
|
|
|
## Objetivo de Negocio
|
|
|
|
- Ampliar opciones de autenticación para mercado LATAM
|
|
- Reducir fricción para usuarios móviles
|
|
- WhatsApp tiene alta penetración en México y LATAM
|
|
- Proporcionar alternativa sin necesidad de recordar contraseña
|
|
|
|
---
|
|
|
|
## Requisitos Funcionales
|
|
|
|
### RF-AUTH-003.1: Envío de OTP
|
|
|
|
**DEBE:**
|
|
1. Aceptar número de teléfono con código de país
|
|
2. Validar formato E.164 (+52XXXXXXXXXX)
|
|
3. Permitir selección de canal (SMS o WhatsApp)
|
|
4. Generar OTP de 6 dígitos
|
|
5. Almacenar OTP con TTL de 5 minutos
|
|
6. Enviar OTP via Twilio
|
|
7. Limitar envíos por número (3 cada 15 min)
|
|
|
|
### RF-AUTH-003.2: Verificación de OTP
|
|
|
|
**DEBE:**
|
|
1. Aceptar número de teléfono y OTP
|
|
2. Validar OTP contra almacenado
|
|
3. Invalidar OTP después de uso
|
|
4. Máximo 3 intentos por OTP
|
|
5. Crear o actualizar usuario
|
|
6. Generar tokens JWT
|
|
|
|
### RF-AUTH-003.3: Vinculación de Teléfono
|
|
|
|
**DEBE:**
|
|
1. Permitir agregar teléfono a cuenta existente
|
|
2. Verificar teléfono con OTP
|
|
3. Marcar teléfono como verificado
|
|
4. Un teléfono solo puede estar en una cuenta
|
|
|
|
---
|
|
|
|
## Canales Soportados
|
|
|
|
| Canal | Proveedor | Costo* | Velocidad |
|
|
|-------|-----------|--------|-----------|
|
|
| SMS | Twilio | $0.05 USD | 5-30 seg |
|
|
| WhatsApp | Twilio | $0.005 USD | 1-5 seg |
|
|
|
|
*Costos aproximados por mensaje en México
|
|
|
|
---
|
|
|
|
## Formato de Número
|
|
|
|
### Validación
|
|
|
|
```typescript
|
|
// Formato E.164
|
|
const phoneRegex = /^\+[1-9]\d{1,14}$/;
|
|
|
|
// Ejemplos válidos:
|
|
// +525512345678 (México)
|
|
// +5491123456789 (Argentina)
|
|
// +573001234567 (Colombia)
|
|
```
|
|
|
|
### Normalización
|
|
|
|
```typescript
|
|
function normalizePhone(phone: string): string {
|
|
// Remover espacios, guiones, paréntesis
|
|
return phone.replace(/[\s\-\(\)]/g, '');
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Flujo de Autenticación
|
|
|
|
```
|
|
Usuario Frontend Backend Twilio
|
|
│ │ │ │
|
|
│─── Ingresa teléfono ────▶│ │ │
|
|
│ +525512345678 │ │ │
|
|
│ Selecciona: WhatsApp │ │ │
|
|
│ │ │ │
|
|
│ │─── POST /auth/phone/send─▶ │
|
|
│ │ { phone, channel } │ │
|
|
│ │ │ │
|
|
│ │ │─── Check rate limit ───│
|
|
│ │ │ │
|
|
│ │ │─── Generate OTP ───────│
|
|
│ │ │ (6 digits) │
|
|
│ │ │ │
|
|
│ │ │─── Store in Redis ─────│
|
|
│ │ │ TTL: 5 min │
|
|
│ │ │ │
|
|
│ │ │─── Send via Twilio ───▶│
|
|
│ │ │ │
|
|
│ │ │◀── Message sent ───────│
|
|
│ │ │ │
|
|
│ │◀── 200 OK ───────────────│ │
|
|
│ │ { message, expires } │ │
|
|
│ │ │ │
|
|
│◀── "Código enviado" ─────│ │ │
|
|
│ │ │ │
|
|
│═══ Recibe WhatsApp ══════════════════════════════════════════════════════════│
|
|
│ "Tu código: 123456" │ │ │
|
|
│ │ │ │
|
|
│─── Ingresa 123456 ──────▶│ │ │
|
|
│ │ │ │
|
|
│ │─── POST /auth/phone/verify │
|
|
│ │ { phone, code } │ │
|
|
│ │ │ │
|
|
│ │ │─── Validate OTP ───────│
|
|
│ │ │ │
|
|
│ │ │─── Find/Create user ───│
|
|
│ │ │ │
|
|
│ │ │─── Generate JWT ───────│
|
|
│ │ │ │
|
|
│ │◀── 200 OK ───────────────│ │
|
|
│ │ { tokens, user } │ │
|
|
│ │ │ │
|
|
│◀── Dashboard ────────────│ │ │
|
|
```
|
|
|
|
---
|
|
|
|
## Generación de OTP
|
|
|
|
```typescript
|
|
function generateOTP(): string {
|
|
// 6 dígitos numéricos
|
|
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
}
|
|
```
|
|
|
|
### Almacenamiento en Redis
|
|
|
|
```typescript
|
|
// Key pattern
|
|
const key = `otp:${phone}`;
|
|
|
|
// Value structure
|
|
{
|
|
"code": "123456",
|
|
"attempts": 0,
|
|
"channel": "whatsapp",
|
|
"createdAt": "2025-12-05T10:00:00Z"
|
|
}
|
|
|
|
// TTL: 5 minutos
|
|
await redis.setEx(key, 300, JSON.stringify(otpData));
|
|
```
|
|
|
|
---
|
|
|
|
## Mensajes de OTP
|
|
|
|
### SMS
|
|
|
|
```
|
|
Trading Platform: Tu código de verificación es 123456. Expira en 5 minutos.
|
|
```
|
|
|
|
### WhatsApp
|
|
|
|
```
|
|
🔐 *Trading Platform*
|
|
|
|
Tu código de verificación es: *123456*
|
|
|
|
Este código expira en 5 minutos.
|
|
No compartas este código con nadie.
|
|
```
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
### Por Número de Teléfono
|
|
|
|
| Período | Límite | Acción |
|
|
|---------|--------|--------|
|
|
| 15 min | 3 envíos | Bloqueo temporal |
|
|
| 1 hora | 5 envíos | Bloqueo 1 hora |
|
|
| 24 horas | 10 envíos | Bloqueo 24 horas |
|
|
|
|
### Por IP
|
|
|
|
| Período | Límite | Acción |
|
|
|---------|--------|--------|
|
|
| 15 min | 10 envíos | Bloqueo temporal |
|
|
| 1 hora | 20 envíos | Bloqueo 1 hora |
|
|
|
|
---
|
|
|
|
## Manejo de Errores
|
|
|
|
| Error | Código | Mensaje Usuario |
|
|
|-------|--------|-----------------|
|
|
| Teléfono inválido | 400 | Formato de teléfono inválido |
|
|
| Rate limit | 429 | Demasiados intentos, espera X minutos |
|
|
| OTP inválido | 401 | Código incorrecto |
|
|
| OTP expirado | 401 | Código expirado, solicita uno nuevo |
|
|
| Twilio error | 502 | Error al enviar mensaje, intenta de nuevo |
|
|
| Canal no soportado | 400 | Canal de envío no soportado |
|
|
|
|
---
|
|
|
|
## Integración Twilio
|
|
|
|
### Configuración
|
|
|
|
```env
|
|
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
TWILIO_PHONE_NUMBER=+15555555555
|
|
TWILIO_WHATSAPP_NUMBER=+14155238886
|
|
```
|
|
|
|
### Envío SMS
|
|
|
|
```typescript
|
|
await twilioClient.messages.create({
|
|
body: `Trading Platform: Tu código es ${otp}. Expira en 5 min.`,
|
|
from: process.env.TWILIO_PHONE_NUMBER,
|
|
to: phone,
|
|
});
|
|
```
|
|
|
|
### Envío WhatsApp
|
|
|
|
```typescript
|
|
await twilioClient.messages.create({
|
|
body: `🔐 *Trading Platform*\n\nTu código es: *${otp}*\n\nExpira en 5 minutos.`,
|
|
from: `whatsapp:${process.env.TWILIO_WHATSAPP_NUMBER}`,
|
|
to: `whatsapp:${phone}`,
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Reglas de Negocio
|
|
|
|
### RN-001: Teléfono Existente
|
|
|
|
Si el teléfono ya está registrado:
|
|
1. Enviar OTP al número
|
|
2. Al verificar, crear sesión con cuenta existente
|
|
3. No crear cuenta nueva
|
|
|
|
### RN-002: Teléfono Nuevo
|
|
|
|
Si el teléfono no está registrado:
|
|
1. Crear cuenta nueva con teléfono como identificador
|
|
2. Solicitar email posteriormente (opcional)
|
|
3. Asignar rol `investor` por defecto
|
|
|
|
### RN-003: Sin Email
|
|
|
|
Cuentas creadas solo con teléfono:
|
|
1. Pueden operar normalmente
|
|
2. Se les solicita email para ciertas funciones (inversión real)
|
|
3. Pueden agregar email después
|
|
|
|
---
|
|
|
|
## Consideraciones de Seguridad
|
|
|
|
### Prevención de Abuso
|
|
|
|
1. **Rate limiting agresivo** por número e IP
|
|
2. **CAPTCHA** después de 2 intentos fallidos
|
|
3. **Bloqueo progresivo** de números sospechosos
|
|
4. **Monitoreo** de patrones de abuso
|
|
|
|
### Protección de Datos
|
|
|
|
1. **No almacenar** OTPs en logs
|
|
2. **Encriptar** números de teléfono en BD
|
|
3. **Audit log** de todos los envíos
|
|
4. **Eliminar** OTPs después de verificación
|
|
|
|
---
|
|
|
|
## Criterios de Aceptación
|
|
|
|
- [ ] Usuario puede solicitar OTP por SMS
|
|
- [ ] Usuario puede solicitar OTP por WhatsApp
|
|
- [ ] OTP se recibe en menos de 30 segundos
|
|
- [ ] OTP expira después de 5 minutos
|
|
- [ ] Usuario puede verificar OTP correctamente
|
|
- [ ] Usuario bloqueado después de 3 intentos fallidos
|
|
- [ ] Rate limiting funciona correctamente
|
|
- [ ] Usuario existente puede hacer login con teléfono
|
|
- [ ] Usuario nuevo puede registrarse con teléfono
|
|
- [ ] Teléfono se puede vincular a cuenta existente
|
|
|
|
---
|
|
|
|
## Especificación Técnica Relacionada
|
|
|
|
- [ET-AUTH-004: API Endpoints](../especificaciones/ET-AUTH-004-api.md)
|
|
|
|
## Historias de Usuario Relacionadas
|
|
|
|
- [US-AUTH-008: Login con SMS](../historias-usuario/US-AUTH-008-phone-sms.md)
|
|
- [US-AUTH-009: Login con WhatsApp](../historias-usuario/US-AUTH-009-phone-whatsapp.md)
|