# RF-USER-003: Cambio de Email

## Identificacion

| Campo | Valor |
|-------|-------|
| **ID** | RF-USER-003 |
| **Modulo** | MGN-002 |
| **Nombre Modulo** | Users - Gestion de Usuarios |
| **Prioridad** | P1 |
| **Complejidad** | Media |
| **Estado** | Aprobado |
| **Autor** | System |
| **Fecha** | 2025-12-05 |

---

## Descripcion

El sistema debe permitir a los usuarios cambiar su direccion de email de forma segura, requiriendo verificacion del nuevo email antes de completar el cambio. Este proceso protege contra cambios no autorizados y mantiene la integridad de las comunicaciones.

### Contexto de Negocio

El cambio de email es sensible porque:
- El email es el identificador principal de login
- Se usa para recuperacion de password
- Se usa para notificaciones importantes
- Debe ser verificado antes del cambio efectivo

---

## Criterios de Aceptacion

- [x] **CA-001:** El usuario debe poder solicitar cambio de email
- [x] **CA-002:** El sistema debe enviar verificacion al NUEVO email
- [x] **CA-003:** El cambio no se aplica hasta verificar el nuevo email
- [x] **CA-004:** El sistema debe validar que el nuevo email no exista en el tenant
- [x] **CA-005:** El token de verificacion expira en 24 horas
- [x] **CA-006:** El sistema debe notificar al email ANTERIOR sobre el cambio
- [x] **CA-007:** El usuario debe confirmar con su password actual
- [x] **CA-008:** Despues del cambio, todas las sesiones se invalidan

### Ejemplos de Verificacion

```gherkin
Scenario: Solicitar cambio de email
  Given un usuario con email "viejo@empresa.com"
  When solicita cambiar a "nuevo@empresa.com"
  And confirma con su password actual
  Then el sistema valida que "nuevo@empresa.com" no existe
  And genera token de verificacion
  And envia email de verificacion a "nuevo@empresa.com"
  And el email actual permanece sin cambios
  And responde con status 200

Scenario: Verificar nuevo email
  Given una solicitud de cambio pendiente
  And un token de verificacion valido
  When el usuario hace clic en el link de verificacion
  Then el sistema actualiza el email del usuario
  And invalida todas las sesiones activas
  And envia notificacion al email anterior
  And redirige al login

Scenario: Token de verificacion expirado
  Given un token de verificacion de mas de 24 horas
  When el usuario intenta usarlo
  Then el sistema responde con error
  And el mensaje es "Token expirado, solicita nuevo cambio"

Scenario: Nuevo email ya existe
  Given un email "existente@empresa.com" ya registrado
  When un usuario intenta cambiar a ese email
  Then el sistema responde con status 409
  And el mensaje es "Email no disponible"
```

---

## Reglas de Negocio

| ID | Regla | Validacion |
|----|-------|------------|
| RN-001 | Requiere password actual para solicitar cambio | Verificacion bcrypt |
| RN-002 | Nuevo email debe ser unico en tenant | UNIQUE constraint |
| RN-003 | Token de verificacion expira en 24 horas | expires_at check |
| RN-004 | Solo una solicitud activa a la vez | Invalidar anteriores |
| RN-005 | Notificar al email anterior | Email de seguridad |
| RN-006 | Logout-all despues del cambio | Revocar tokens |
| RN-007 | Nuevo email formato valido | Regex validation |

### Flujo de Cambio de Email

```
┌─────────────────────────────────────────────────────────────────┐
│ 1. Usuario solicita cambio                                       │
│    POST /api/v1/users/me/email/request-change                   │
│    Body: { newEmail, currentPassword }                          │
└───────────────────────────┬─────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ 2. Validaciones                                                  │
│    - Password correcto                                           │
│    - Nuevo email formato valido                                  │
│    - Nuevo email no existe en tenant                            │
│    - No hay solicitud pendiente                                  │
└───────────────────────────┬─────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ 3. Crear solicitud                                               │
│    - Guardar en email_change_requests                           │
│    - Generar token (32 bytes, hex)                              │
│    - expires_at = now + 24 hours                                │
└───────────────────────────┬─────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ 4. Enviar email de verificacion                                  │
│    To: nuevo@email.com                                           │
│    Link: /verify-email-change?token={token}                     │
└───────────────────────────┬─────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ 5. Usuario hace clic en link                                     │
│    GET /api/v1/users/email/verify-change?token={token}          │
└───────────────────────────┬─────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ 6. Aplicar cambio                                                │
│    - Actualizar users.email                                      │
│    - Marcar solicitud como completada                           │
│    - Invalidar todas las sesiones                               │
│    - Enviar notificacion al email anterior                      │
└───────────────────────────┬─────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ 7. Redirigir al login                                            │
│    - Usuario debe iniciar sesion con nuevo email                │
└─────────────────────────────────────────────────────────────────┘
```

---

## Impacto en Capas

### Database

| Elemento | Accion | Descripcion |
|----------|--------|-------------|
| Tabla | crear | `email_change_requests` |
| Columna | - | `id` UUID PK |
| Columna | - | `user_id` UUID FK |
| Columna | - | `tenant_id` UUID FK |
| Columna | - | `current_email` VARCHAR(255) |
| Columna | - | `new_email` VARCHAR(255) |
| Columna | - | `token_hash` VARCHAR(255) |
| Columna | - | `expires_at` TIMESTAMPTZ |
| Columna | - | `completed_at` TIMESTAMPTZ |
| Columna | - | `created_at` TIMESTAMPTZ |
| Indice | crear | `idx_email_change_user` |

### Backend

| Elemento | Accion | Descripcion |
|----------|--------|-------------|
| Controller | agregar | `UsersController.requestEmailChange()` |
| Controller | agregar | `UsersController.verifyEmailChange()` |
| Method | crear | `UsersService.requestEmailChange()` |
| Method | crear | `UsersService.verifyEmailChange()` |
| DTO | crear | `RequestEmailChangeDto` |
| Entity | crear | `EmailChangeRequest` |
| Endpoint | crear | `POST /api/v1/users/me/email/request-change` |
| Endpoint | crear | `GET /api/v1/users/email/verify-change` |

### Frontend

| Elemento | Accion | Descripcion |
|----------|--------|-------------|
| Componente | crear | `ChangeEmailForm` |
| Pagina | crear | `VerifyEmailChangePage` |
| Modal | crear | `ConfirmPasswordModal` |

---

## Dependencias

### Depende de (Bloqueantes)

| ID | Requerimiento | Estado |
|----|---------------|--------|
| RF-USER-001 | CRUD Usuarios | Tabla users |
| RF-AUTH-004 | Logout | Para logout-all |

### Dependencias Externas

| Servicio | Descripcion |
|----------|-------------|
| Email Service | Envio de verificacion |

---

## Especificaciones Tecnicas

### Endpoint POST /api/v1/users/me/email/request-change

```typescript
// Request
{
  "newEmail": "nuevo@empresa.com",
  "currentPassword": "MiPasswordActual123!"
}

// Response 200
{
  "message": "Se ha enviado un email de verificacion a nuevo@empresa.com",
  "expiresAt": "2025-12-06T10:30:00Z"
}

// Response 400 - Password incorrecto
{
  "statusCode": 400,
  "message": "Password incorrecto"
}

// Response 409 - Email existe
{
  "statusCode": 409,
  "message": "Email no disponible"
}
```

### Endpoint GET /api/v1/users/email/verify-change

```typescript
// Request
GET /api/v1/users/email/verify-change?token=abc123...

// Response 200 (redirect)
// Redirect to: /login?emailChanged=true

// Response 400 - Token invalido
{
  "statusCode": 400,
  "message": "Token invalido o expirado"
}
```

### Template de Email - Verificacion

```html
Asunto: Verifica tu nuevo email - ERP Suite

<h2>Hola {{firstName}},</h2>

<p>Recibimos una solicitud para cambiar tu email de:</p>
<p><strong>{{currentEmail}}</strong> a <strong>{{newEmail}}</strong></p>

<p>Haz clic en el siguiente enlace para confirmar el cambio:</p>
<a href="{{verifyUrl}}">Verificar nuevo email</a>

<p><strong>Este enlace expira en 24 horas.</strong></p>

<p>Si no solicitaste este cambio, ignora este email y considera
cambiar tu password por seguridad.</p>
```

### Template de Email - Notificacion al Email Anterior

```html
Asunto: Tu email ha sido cambiado - ERP Suite

<h2>Hola {{firstName}},</h2>

<p>Te informamos que el email de tu cuenta ha sido cambiado.</p>

<p><strong>Email anterior:</strong> {{oldEmail}}</p>
<p><strong>Email nuevo:</strong> {{newEmail}}</p>
<p><strong>Fecha:</strong> {{changeDate}}</p>

<p>Si no realizaste este cambio, contacta inmediatamente a soporte.</p>
```

---

## Datos de Prueba

| Escenario | Entrada | Resultado |
|-----------|---------|-----------|
| Solicitud valida | newEmail, password correcto | 200, email enviado |
| Password incorrecto | password erroneo | 400, "Password incorrecto" |
| Email ya existe | email de otro usuario | 409, "Email no disponible" |
| Email invalido | "notanemail" | 400, "Email invalido" |
| Verificar token valido | token < 24h | 200, email cambiado |
| Token expirado | token > 24h | 400, "Token expirado" |
| Token ya usado | solicitud completada | 400, "Token ya utilizado" |

---

## Estimacion

| Capa | Story Points | Notas |
|------|--------------|-------|
| Database | 1 | Tabla email_change_requests |
| Backend | 3 | Endpoints, validaciones, emails |
| Frontend | 2 | Form y pagina verificacion |
| **Total** | **6** | |

---

## Notas Adicionales

- Considerar periodo de gracia donde se puede revertir el cambio
- Implementar notificacion push ademas de email
- Rate limiting en solicitudes (max 3 por dia)
- Log de todos los cambios de email para auditoria

---

## Historial de Cambios

| Version | Fecha | Autor | Cambios |
|---------|-------|-------|---------|
| 1.0 | 2025-12-05 | System | Creacion inicial |

---

## Aprobaciones

| Rol | Nombre | Fecha | Firma |
|-----|--------|-------|-------|
| Analista | System | 2025-12-05 | [x] |
| Tech Lead | - | - | [ ] |
| Product Owner | - | - | [ ] |
