erp-core/docs/01-fase-foundation/MGN-002-users/historias-usuario/US-MGN002-005.md

9.6 KiB

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

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

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

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

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

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

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

// 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

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