# US-MGN002-005: Cambio de Email ## Identificacion | Campo | Valor | |-------|-------| | **ID** | US-MGN002-005 | | **Modulo** | MGN-002 Users | | **Sprint** | Sprint 3 | | **Prioridad** | P1 - Alta | | **Story Points** | 6 | | **Estado** | Ready | | **Autor** | System | | **Fecha** | 2025-12-06 | | **RF Asociado** | RF-USER-003 | --- ## Historia de Usuario **Como** usuario autenticado del sistema **Quiero** poder cambiar mi direccion de email de forma segura **Para** mantener mi cuenta actualizada y proteger el acceso a mi informacion --- ## Descripcion El usuario necesita un proceso seguro para cambiar su email registrado. El sistema debe verificar la identidad del usuario con su password actual y validar la propiedad del nuevo email antes de aplicar el cambio. Esto protege contra cambios no autorizados. ### Contexto - El email es el identificador principal de login - Se usa para recuperacion de password y notificaciones - Requiere doble verificacion por seguridad (password + email) - Todas las sesiones se invalidan despues del cambio --- ## Criterios de Aceptacion ### Escenario 1: Solicitar cambio de email exitosamente ```gherkin Given un usuario autenticado con email "viejo@empresa.com" When solicita cambiar a "nuevo@empresa.com" And confirma con su password actual And el nuevo email no esta registrado Then el sistema 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 And el body contiene "expiresAt" con fecha +24h ``` ### Escenario 2: Verificar nuevo email ```gherkin Given un usuario con solicitud de cambio pendiente And un token de verificacion valido (< 24 horas) When hace clic en enlace 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 con mensaje de exito ``` ### Escenario 3: Nuevo email ya registrado ```gherkin Given un email "existente@empresa.com" ya en uso When un usuario intenta cambiar a ese email Then el sistema responde con status 409 And el mensaje es "Email no disponible" ``` ### Escenario 4: Password incorrecto ```gherkin Given un usuario autenticado When solicita cambio de email con password incorrecto Then el sistema responde con status 400 And el mensaje es "Password incorrecto" And no se crea solicitud de cambio ``` ### Escenario 5: Token de verificacion expirado ```gherkin Given un token de verificacion emitido hace mas de 24 horas When el usuario intenta usarlo Then el sistema responde con status 400 And el mensaje es "Token expirado, solicita nuevo cambio" ``` ### Escenario 6: Cancelar solicitud pendiente ```gherkin Given un usuario con cambio de email pendiente When solicita un nuevo cambio Then la solicitud anterior se invalida And se crea nueva solicitud con nuevo token ``` --- ## Mockup / Wireframe ``` Pagina: Mi Perfil - Seccion Email ┌──────────────────────────────────────────────────────────────────┐ │ Email actual: juan@empresa.com │ │ [Cambiar Email] │ └──────────────────────────────────────────────────────────────────┘ Modal: Cambiar Email ┌──────────────────────────────────────────────────────────────────┐ │ CAMBIAR EMAIL │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ Email actual juan@empresa.com (no editable) │ │ │ │ Nuevo email* [_______________________________] │ │ │ │ Confirmar password* [_______________________________] │ │ │ │ ⚠️ Se enviara un link de verificacion al nuevo email. │ │ Tu email no cambiara hasta que verifiques el enlace. │ │ Todas tus sesiones seran cerradas despues del cambio. │ │ │ │ [ Cancelar ] [ Enviar Verificacion ] │ └──────────────────────────────────────────────────────────────────┘ Pagina: Verificacion Exitosa ┌──────────────────────────────────────────────────────────────────┐ │ │ │ ✅ Email Actualizado │ │ │ │ Tu email ha sido cambiado a: nuevo@empresa.com │ │ │ │ Por seguridad, todas tus sesiones han sido cerradas. │ │ │ │ [ Ir al Login ] │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## Notas Tecnicas ### API Endpoints ```typescript // Solicitar cambio de email POST /api/v1/users/me/email/request-change { "newEmail": "nuevo@empresa.com", "currentPassword": "MiPasswordActual123!" } // Response 200 { "message": "Se ha enviado un email de verificacion a nuevo@empresa.com", "expiresAt": "2025-12-07T10:30:00Z" } // Response 400 - Password incorrecto { "statusCode": 400, "message": "Password incorrecto" } // Response 409 - Email existe { "statusCode": 409, "message": "Email no disponible" } // Verificar cambio de email 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" } ``` ### Permisos Requeridos | Accion | Permiso | |--------|---------| | Solicitar cambio | Autenticado (propio email) | | Verificar cambio | Token valido | ### Schema de Base de Datos ```sql CREATE TABLE core_users.email_change_requests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES core_users.users(id), tenant_id UUID NOT NULL REFERENCES core_tenants.tenants(id), current_email VARCHAR(255) NOT NULL, new_email VARCHAR(255) NOT NULL, token_hash VARCHAR(255) NOT NULL, expires_at TIMESTAMPTZ NOT NULL, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT uq_pending_email_change UNIQUE (user_id, completed_at) WHERE completed_at IS NULL ); CREATE INDEX idx_email_change_user ON core_users.email_change_requests(user_id); CREATE INDEX idx_email_change_token ON core_users.email_change_requests(token_hash); ``` --- ## Definicion de Done - [ ] Endpoint POST /api/v1/users/me/email/request-change implementado - [ ] Endpoint GET /api/v1/users/email/verify-change implementado - [ ] Tabla email_change_requests creada con RLS - [ ] Validacion de password actual - [ ] Validacion de email unico en tenant - [ ] Generacion de token seguro (32 bytes hex) - [ ] Envio de email de verificacion - [ ] Envio de notificacion al email anterior - [ ] Invalidacion de sesiones post-cambio - [ ] Frontend: ChangeEmailForm integrado en perfil - [ ] Frontend: Pagina de verificacion exitosa - [ ] Tests unitarios (>80% coverage) - [ ] Tests e2e pasando - [ ] Code review aprobado --- ## Dependencias | ID | Descripcion | |----|-------------| | RF-USER-001 | CRUD Usuarios (tabla users) | | RF-AUTH-001 | Login para autenticacion | | RF-AUTH-004 | Logout para invalidar sesiones | | EmailService | Para enviar verificacion | --- ## Estimacion | Tarea | Story Points | |-------|--------------| | Database: Tabla email_change_requests | 1 | | Backend: Endpoint request-change | 1.5 | | Backend: Endpoint verify-change | 1.5 | | Backend: Tests | 1 | | Frontend: ChangeEmailForm | 0.5 | | Frontend: Pagina verificacion | 0.5 | | **Total** | **6** | --- ## Reglas de Negocio | ID | Regla | Validacion | |----|-------|------------| | RN-001 | Requiere password actual | Verificacion bcrypt | | RN-002 | Nuevo email unico en tenant | UNIQUE constraint | | RN-003 | Token expira en 24 horas | expires_at check | | RN-004 | Una solicitud activa a la vez | Invalidar anteriores | | RN-005 | Notificar email anterior | Email de seguridad | | RN-006 | Logout-all post-cambio | Revocar tokens | | RN-007 | Formato email valido | Regex validation | --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-06 | System | Creacion inicial |