trading-platform/docs/02-definicion-modulos/OQI-001-fundamentos-auth/historias-usuario/US-AUTH-008-phone-sms.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
Changes include:
- Updated architecture documentation
- Enhanced module definitions (OQI-001 to OQI-008)
- ML integration documentation updates
- Trading strategies documentation
- Orchestration and inventory updates
- Docker configuration updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:33:35 -06:00

17 KiB

id title type status priority epic story_points created_date updated_date
US-AUTH-008 Autenticacion con SMS (Twilio) User Story To Do Alta OQI-001 5 2025-12-05 2026-01-04

US-AUTH-008: Autenticación con SMS (Twilio)

Version: 1.0.0 Fecha: 2025-12-05 Estado: Pendiente Story Points: 5 Prioridad: P1 (Alta) Épica: OQI-001


Historia de Usuario

Como usuario de OrbiQuant Quiero poder registrarme e iniciar sesión usando mi número de teléfono y un código SMS Para tener un acceso rápido sin necesidad de recordar contraseñas


Criterios de Aceptación

AC-001: Formulario de teléfono

Dado que estoy en la página de registro/login Cuando selecciono la opción de teléfono Entonces debería ver:

  • Selector de país con banderas (+1, +52, +34, etc.)
  • Campo para número de teléfono
  • Formato visual según el país seleccionado
  • Botón "Enviar código"

AC-002: Validación de número

Dado que ingreso un número de teléfono Cuando el número no es válido para el país seleccionado Entonces debería ver un mensaje de error Y el botón "Enviar código" debería estar deshabilitado

AC-003: Envío de código SMS

Dado que ingresé un número válido Cuando hago click en "Enviar código" Entonces debería:

  1. Ver un mensaje "Enviando código..."
  2. Recibir un SMS con un código de 6 dígitos
  3. Ver pantalla de verificación de código
  4. El código debería expirar en 10 minutos

AC-004: Formato del SMS

Dado que solicité un código Cuando recibo el SMS Entonces debería tener el formato:

Tu código de OrbiQuant es: 123456

Válido por 10 minutos.
No compartas este código.

AC-005: Ingreso de código

Dado que recibí el código por SMS Cuando ingreso el código en la app Entonces debería:

  • Autoformatear con espacios (123 456)
  • Auto-enviar al completar 6 dígitos
  • Validar el código en tiempo real

AC-006: Código correcto - Primer registro

Dado que es mi primera vez usando este número Cuando ingreso el código correcto Entonces debería:

  1. Ver formulario para completar perfil (nombre, apellido, email opcional)
  2. Crear mi cuenta
  3. Recibir un JWT token
  4. Ser redirigido al dashboard

AC-007: Código correcto - Login existente

Dado que ya tengo una cuenta con este número Cuando ingreso el código correcto Entonces debería:

  1. Iniciar sesión automáticamente
  2. Recibir un JWT token
  3. Ser redirigido al dashboard

AC-008: Código incorrecto

Dado que ingreso un código incorrecto Cuando envío el código Entonces debería:

  • Ver mensaje "Código incorrecto"
  • Poder intentar nuevamente
  • Después de 3 intentos fallidos, invalidar el código
  • Poder solicitar un nuevo código

AC-009: Código expirado

Dado que pasaron más de 10 minutos desde el envío Cuando intento usar el código Entonces debería ver mensaje "Código expirado" Y debería poder solicitar un nuevo código

AC-010: Reenvío de código

Dado que no recibí el código o expiró Cuando hago click en "Reenviar código" Entonces debería:

  • Esperar 60 segundos antes de permitir reenvío
  • Ver contador regresivo "Reenviar en 59s..."
  • Recibir un nuevo código (el anterior se invalida)

AC-011: Rate limiting

Dado que solicité 5 códigos en 1 hora Cuando intento solicitar otro Entonces debería ver mensaje:

  • "Demasiados intentos. Intenta en 1 hora"

AC-012: Número ya registrado con email

Dado que mi número ya está vinculado a una cuenta de email Cuando completo la verificación SMS Entonces debería iniciar sesión en esa cuenta Y tener ambos métodos de autenticación disponibles


Mockup

Paso 1: Ingreso de teléfono
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│          🌟 Ingresa con tu número de teléfono              │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Número de teléfono                                   │   │
│  │ ┌────────┐ ┌──────────────────────────────────────┐ │   │
│  │ │ 🇺🇸 +1 ▾│ │ (555) 123-4567                       │ │   │
│  │ └────────┘ └──────────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │               Enviar código                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ─────────────────── O continúa con ───────────────────    │
│                                                             │
│  [Email] [Google] [Facebook] [Apple]                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Paso 2: Verificación de código
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│          📱 Ingresa el código que enviamos                 │
│                                                             │
│  Enviamos un código a +1 (555) 123-4567                    │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                      │   │
│  │         ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐        │   │
│  │         │ 1 │ │ 2 │ │ 3 │ │ 4 │ │ 5 │ │ 6 │        │   │
│  │         └───┘ └───┘ └───┘ └───┘ └───┘ └───┘        │   │
│  │                                                      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ¿No recibiste el código?                                  │
│  Reenviar código (disponible en 58s)                       │
│                                                             │
│  ← Cambiar número                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Paso 3: Completar perfil (solo registro nuevo)
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│          🎉 ¡Bienvenido! Completa tu perfil                │
│                                                             │
│  ┌────────────────────────┐ ┌────────────────────────┐     │
│  │ Nombre                 │ │ Apellido               │     │
│  │ ┌──────────────────┐  │ │ ┌──────────────────┐   │     │
│  │ │ Juan             │  │ │ │ Pérez            │   │     │
│  │ └──────────────────┘  │ │ └──────────────────┘   │     │
│  └────────────────────────┘ └────────────────────────┘     │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Email (opcional)                                     │   │
│  │ ┌─────────────────────────────────────────────────┐ │   │
│  │ │ juan@email.com                                   │ │   │
│  │ └─────────────────────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ☑ Acepto los Términos de Servicio                         │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │               Crear mi cuenta                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Tareas Técnicas

Database (DB)

  • Agregar campos a tabla users:
    ALTER TABLE users ADD COLUMN phone_number VARCHAR(20) UNIQUE;
    ALTER TABLE users ADD COLUMN phone_verified_at TIMESTAMP;
    ALTER TABLE users ADD COLUMN phone_country_code VARCHAR(5);
    
  • Tabla phone_verification_codes:
    CREATE TABLE phone_verification_codes (
      id UUID PRIMARY KEY,
      phone_number VARCHAR(20) NOT NULL,
      code VARCHAR(6) NOT NULL,
      attempts INT DEFAULT 0,
      expires_at TIMESTAMP NOT NULL,
      used_at TIMESTAMP,
      created_at TIMESTAMP DEFAULT NOW(),
      INDEX idx_phone_expires (phone_number, expires_at)
    );
    
  • Tabla phone_rate_limits:
    CREATE TABLE phone_rate_limits (
      id UUID PRIMARY KEY,
      phone_number VARCHAR(20) NOT NULL,
      ip_address VARCHAR(45),
      attempts INT DEFAULT 1,
      window_start TIMESTAMP DEFAULT NOW(),
      created_at TIMESTAMP DEFAULT NOW(),
      INDEX idx_phone_window (phone_number, window_start)
    );
    

Backend (BE)

  • Configurar cuenta de Twilio
  • Obtener Account SID y Auth Token
  • Configurar Twilio Phone Number
  • Endpoint POST /api/v1/auth/phone/send-code
    • Validar número con libphonenumber
    • Rate limiting (5 códigos / hora)
    • Generar código aleatorio de 6 dígitos
    • Guardar en DB con expiración
    • Enviar SMS via Twilio
  • Endpoint POST /api/v1/auth/phone/verify-code
    • Validar código
    • Verificar no expirado
    • Verificar intentos < 3
    • Crear o actualizar usuario
    • Generar JWT token
  • Endpoint POST /api/v1/auth/phone/resend-code
    • Invalidar código anterior
    • Generar nuevo código
    • Verificar cooldown de 60s
  • Service TwilioSMSService
    • sendVerificationCode()
    • verifyCode()
    • formatPhoneNumber()
  • Librería: twilio SDK
  • Librería: libphonenumber-js para validación
  • Tests unitarios (12 casos)
  • Tests de integración con mock de Twilio

Frontend (FE)

  • Componente PhoneAuth.tsx
  • Selector de país con banderas
  • Input de teléfono con formato automático
  • Componente CodeInput.tsx (6 dígitos)
  • Componente CompleteProfile.tsx
  • Validación con React Hook Form
  • Librería: react-phone-number-input
  • Contador regresivo para reenvío
  • Tests con React Testing Library

Testing (QA)

  • E2E: Registro con teléfono completo
  • E2E: Login con teléfono existente
  • E2E: Código incorrecto (3 intentos)
  • E2E: Código expirado
  • E2E: Reenvío de código
  • E2E: Rate limiting
  • Test de integración con Twilio Test Credentials
  • Test de seguridad: Brute force protection
  • Performance: Envío de SMS < 2s

Dependencias

  • Bloqueantes:

    • Cuenta de Twilio activa
    • Twilio Phone Number comprado
    • Presupuesto para SMS (aprox $0.0075 USD por SMS)
  • Deseables:

    • US-AUTH-001: Para vinculación de cuentas

Definition of Ready (DoR)

  • Cuenta de Twilio configurada
  • Twilio Phone Number asignado
  • Presupuesto aprobado para SMS
  • Mockups aprobados
  • API contract definido
  • Estrategia de rate limiting definida

Definition of Done (DoD)

  • Código implementado y revisado
  • Tests unitarios con 80%+ cobertura
  • Tests de integración pasando
  • Tests E2E implementados
  • Twilio configurado en todos los ambientes
  • Rate limiting implementado
  • Logs y monitoring de SMS
  • Costos monitoreados
  • Documentación actualizada
  • QA aprobado en staging
  • Deploy a producción exitoso

Notas Técnicas

Twilio SMS Flow

  1. Usuario ingresa número de teléfono
  2. Frontend valida formato
  3. Frontend llama POST /api/v1/auth/phone/send-code
  4. Backend valida número con libphonenumber
  5. Backend verifica rate limits
  6. Backend genera código aleatorio (6 dígitos)
  7. Backend guarda código en DB (expira en 10 min)
  8. Backend envía SMS via Twilio API
  9. Usuario recibe SMS e ingresa código
  10. Frontend llama POST /api/v1/auth/phone/verify-code
  11. Backend valida código
  12. Backend crea/actualiza usuario
  13. Backend genera JWT token

Environment Variables

TWILIO_ACCOUNT_SID=AC...
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_PHONE_NUMBER=+15551234567
TWILIO_VERIFY_SERVICE_SID=VA... # Opcional: usar Twilio Verify

Twilio API Usage

import twilio from 'twilio';

const client = twilio(accountSid, authToken);

// Enviar SMS
await client.messages.create({
  body: `Tu código de OrbiQuant es: ${code}\n\nVálido por 10 minutos.`,
  from: twilioPhoneNumber,
  to: userPhoneNumber
});

Phone Number Validation

import { parsePhoneNumber } from 'libphonenumber-js';

const phoneNumber = parsePhoneNumber(input, countryCode);
if (!phoneNumber || !phoneNumber.isValid()) {
  throw new Error('Invalid phone number');
}

Code Generation

// Generar código de 6 dígitos
const code = Math.floor(100000 + Math.random() * 900000).toString();

Rate Limiting Strategy

  • 5 códigos por número de teléfono por hora
  • 10 códigos por IP por hora
  • Cooldown de 60 segundos entre reenvíos
  • Máximo 3 intentos de verificación por código

Security Considerations

  • Códigos de 6 dígitos (1 millón de combinaciones)
  • Expiración de 10 minutos
  • Invalidar después de 3 intentos fallidos
  • Rate limiting estricto
  • Logs de todos los intentos
  • Validación de número en backend
  • No devolver información si el número existe o no

Cost Optimization

  • SMS en USA: ~$0.0075 USD
  • SMS internacional: $0.0075 - $0.10 USD
  • Usar Twilio Verify Service para mejor pricing
  • Implementar captcha para prevenir abuso
  • Alertas si se excede presupuesto mensual

Alternative: Twilio Verify Service

En lugar de manejar códigos manualmente, considerar usar Twilio Verify:

  • Manejo automático de códigos
  • Rate limiting incluido
  • Mejor pricing
  • Reenvíos automáticos
  • Múltiples canales (SMS, Voice, WhatsApp)

Requerimientos Relacionados

Especificaciones Relacionadas