# RF-MGN-001-005: Reset de Contraseña

**Módulo:** MGN-001 - Fundamentos
**Prioridad:** P0 (MVP)
**Story Points:** 5
**Estado:** Definido
**Fecha:** 2025-11-23

## Descripción

El sistema debe permitir a los usuarios solicitar el reset de su contraseña cuando la olvidan. Se envía un token temporal por email que permite establecer una nueva contraseña.

## Actores

- **Actor Principal:** Usuario (olvidó contraseña)
- **Actores Secundarios:** Sistema de Email

## Precondiciones

1. Usuario debe tener cuenta activa
2. Sistema de email debe estar configurado
3. Tenant debe estar activo

## Flujo Principal

1. Usuario accede a página de login y selecciona "Olvidé mi contraseña"
2. Usuario ingresa su email
3. Sistema valida que email existe en el tenant actual
4. Sistema genera token único de reset (UUID) con expiración 24h
5. Sistema guarda token en auth.password_reset_tokens con expires_at
6. Sistema envía email con link: {app_url}/reset-password?token={token}
7. Usuario recibe email y hace clic en link
8. Sistema valida que token existe y no ha expirado
9. Usuario ingresa nueva contraseña (2 veces para confirmar)
10. Sistema valida política de contraseña
11. Sistema hashea nueva contraseña con bcrypt
12. Sistema actualiza auth.users.password_hash
13. Sistema marca token como usado (used_at = NOW())
14. Sistema invalida refresh tokens existentes (logout en otros dispositivos)
15. Sistema muestra mensaje: "Contraseña actualizada. Inicie sesión"

## Flujos Alternativos

### FA-1: Email No Encontrado
1. Si email no existe en tenant
2. Sistema NO revela que email no existe (seguridad)
3. Sistema muestra: "Si el email existe, recibirá instrucciones"
4. Sistema NO envía email

### FA-2: Token Expirado
1. Si token existe pero expires_at < NOW()
2. Sistema retorna error 400: "Token expirado. Solicite nuevo reset"

### FA-3: Token Inválido
1. Si token no existe en BD
2. Sistema retorna error 400: "Token inválido"

### FA-4: Token Ya Usado
1. Si token.used_at IS NOT NULL
2. Sistema retorna error 400: "Token ya fue utilizado. Solicite nuevo reset"

### FA-5: Contraseña Débil
1. Si nueva contraseña no cumple política
2. Sistema retorna error 400: "Contraseña debe tener 8+ caracteres, mayúscula, número, símbolo"

### FA-6: Múltiples Solicitudes de Reset
1. Usuario solicita múltiples tokens en corto tiempo
2. Sistema invalida tokens anteriores (solo último es válido)
3. Sistema aplica rate limiting (max 3 solicitudes por hora)

## Reglas de Negocio

- **RN-1:** Token de reset expira en 24 horas
- **RN-2:** Token solo puede usarse una vez
- **RN-3:** Nueva contraseña debe cumplir política de seguridad
- **RN-4:** Sistema NO revela si email existe o no (prevenir enumeración)
- **RN-5:** Múltiples solicitudes de reset invalidan tokens anteriores
- **RN-6:** Rate limiting: máximo 3 solicitudes por hora por IP
- **RN-7:** Reset de contraseña invalida refresh tokens existentes

## Criterios de Aceptación

- [ ] Usuario puede solicitar reset de contraseña con su email
- [ ] Sistema envía email con token de reset válido por 24h
- [ ] Usuario puede establecer nueva contraseña usando token
- [ ] Token expirado no permite reset
- [ ] Token solo puede usarse una vez
- [ ] Nueva contraseña debe cumplir política de seguridad
- [ ] Sistema NO revela si email existe (prevenir enumeración)
- [ ] Reset invalida sesiones activas en otros dispositivos
- [ ] Rate limiting previene abuso (max 3 solicitudes/hora)
- [ ] Link de reset tiene formato seguro (HTTPS, token complejo)

## Entidades Involucradas

- **Principales:**
  - auth.password_reset_tokens (token, user_id, expires_at, used_at)
  - auth.users (password_hash)
- **Relacionadas:**
  - auth.sessions (tokens a invalidar)

## Referencias

- [ALCANCE-POR-MODULO.md - MGN-001](../../01-definicion-modulos/ALCANCE-POR-MODULO.md#mgn-001-fundamentos)
- [Auth Domain Model](../domain-models/auth-domain.md)
- [Auth Schema DDL](../database-design/schemas/auth-schema-ddl.sql)
- [Gap Analysis MGN-001](../../01-definicion-modulos/gaps/GAP-ANALYSIS-MGN-001.md)

## Notas Técnicas

- **Patrón Odoo:** Similar a reset password en portal
- **Token:** UUID v4 (aleatorio, no predecible)
- **Expiración:** Cronjob limpia tokens expirados diariamente
- **Email Template:**
  ```
  Hola {{user.name}},

  Recibimos una solicitud para restablecer tu contraseña.

  Haz clic en el siguiente enlace para establecer una nueva contraseña:
  {{reset_link}}

  Este enlace expira en 24 horas.

  Si no solicitaste este cambio, ignora este email.
  ```
- **Seguridad:**
  - No revelar si email existe
  - Token largo (UUID = 36 caracteres)
  - HTTPS obligatorio en producción
  - Rate limiting por IP

## Dependencias

- **RF Dependientes:** RF-MGN-001-001 (Autenticación)
- **Bloqueante para:** Ninguno (funcionalidad independiente)
