333 lines
13 KiB
Markdown
333 lines
13 KiB
Markdown
# 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 | - | - | [ ] |
|