# US-MGN001-001: Login con Email y Password ## Identificacion | Campo | Valor | |-------|-------| | **ID** | US-MGN001-001 | | **Modulo** | MGN-001 Auth | | **Sprint** | Sprint 1 | | **Prioridad** | P0 - Critica | | **Story Points** | 8 | | **Estado** | Ready | | **Autor** | System | | **Fecha** | 2025-12-05 | --- ## Historia de Usuario **Como** usuario del sistema ERP **Quiero** poder iniciar sesion con mi email y contraseña **Para** acceder a las funcionalidades del sistema de forma segura --- ## Descripcion El usuario necesita un mecanismo seguro para autenticarse en el sistema utilizando sus credenciales (email y contraseña). Al autenticarse exitosamente, recibira tokens JWT que le permitiran acceder a los recursos protegidos. ### Contexto - Primera interaccion del usuario con el sistema - Puerta de entrada a todas las funcionalidades - Base de la seguridad del sistema --- ## Criterios de Aceptacion ### Escenario 1: Login exitoso ```gherkin Given un usuario registrado con email "user@example.com" And password "SecurePass123!" And el usuario no esta bloqueado And el usuario esta activo When el usuario envia sus credenciales al endpoint /api/v1/auth/login Then el sistema responde con status 200 And el body contiene "accessToken" de tipo string And el body contiene "refreshToken" de tipo string And el body contiene "user" con id, email, firstName, lastName, roles And se establece cookie httpOnly "refresh_token" And se registra el login en session_history ``` ### Escenario 2: Login con email incorrecto ```gherkin Given un email "noexiste@example.com" que no existe en el sistema When el usuario intenta hacer login con ese email Then el sistema responde con status 401 And el mensaje es "Credenciales invalidas" And NO se revela que el email no existe And se registra el intento fallido en login_attempts ``` ### Escenario 3: Login con password incorrecto ```gherkin Given un usuario registrado con email "user@example.com" And el password correcto es "SecurePass123!" When el usuario intenta hacer login con password "wrongpassword" Then el sistema responde con status 401 And el mensaje es "Credenciales invalidas" And se incrementa failed_login_attempts del usuario And se registra el intento fallido en login_attempts ``` ### Escenario 4: Cuenta bloqueada por intentos fallidos ```gherkin Given un usuario con email "user@example.com" And el usuario tiene 5 intentos fallidos de login And el campo locked_until es una fecha futura When el usuario intenta hacer login con credenciales correctas Then el sistema responde con status 423 And el mensaje indica "Cuenta bloqueada" And se indica el tiempo restante de bloqueo ``` ### Escenario 5: Cuenta inactiva ```gherkin Given un usuario con email "inactive@example.com" And el campo is_active del usuario es false When el usuario intenta hacer login Then el sistema responde con status 403 And el mensaje es "Cuenta inactiva" ``` ### Escenario 6: Validacion de campos ```gherkin Given un request al endpoint de login When el email no es un email valido Then el sistema responde con status 400 And el mensaje indica "Email invalido" When el password tiene menos de 8 caracteres Then el sistema responde con status 400 And el mensaje indica "Password debe tener minimo 8 caracteres" When el email esta vacio Then el sistema responde con status 400 And el mensaje indica "Email es requerido" ``` ### Escenario 7: Desbloqueo automatico ```gherkin Given un usuario con cuenta bloqueada And el tiempo de bloqueo (30 minutos) ha pasado When el usuario intenta hacer login con credenciales correctas Then el sistema permite el login And resetea failed_login_attempts a 0 And limpia locked_until ``` --- ## Mockup / Wireframe ``` +------------------------------------------------------------------+ | ERP SUITE | | | | ╔═══════════════════════════╗ | | ║ INICIAR SESION ║ | | ╚═══════════════════════════╝ | | | | Correo electronico | | +---------------------------+ | | | user@example.com | | | +---------------------------+ | | | | Contraseña | | +---------------------------+ | | | •••••••••••• | [👁] | | +---------------------------+ | | | | [ ] Recordar sesion | | | | [===== INICIAR SESION =====] | | | | ¿Olvidaste tu contraseña? | | | +------------------------------------------------------------------+ Estados de UI: ┌─────────────────────────────────────────────────────────────────┐ │ Estado: Loading │ │ - Boton deshabilitado │ │ - Spinner visible en boton │ │ - Campos deshabilitados │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ Estado: Error │ │ - Toast rojo con mensaje de error │ │ - Campos con borde rojo si invalidos │ │ - Texto de ayuda debajo del campo │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ Estado: Bloqueado │ │ - Mensaje: "Cuenta bloqueada. Intenta en XX minutos" │ │ - Enlace a "¿Necesitas ayuda?" │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Notas Tecnicas ### API ```typescript // Request POST /api/v1/auth/login Content-Type: application/json X-Tenant-Id: optional-if-single-tenant { "email": "user@example.com", "password": "SecurePass123!" } // Response 200 { "accessToken": "eyJhbGciOiJSUzI1NiIs...", "refreshToken": "eyJhbGciOiJSUzI1NiIs...", "tokenType": "Bearer", "expiresIn": 900, "user": { "id": "uuid", "email": "user@example.com", "firstName": "John", "lastName": "Doe", "roles": ["admin"] } } // Set-Cookie: refresh_token=...; HttpOnly; Secure; SameSite=Strict; Max-Age=604800 ``` ### Validaciones | Campo | Regla | Mensaje Error | |-------|-------|---------------| | email | Required, IsEmail | "Email es requerido" / "Email invalido" | | password | Required, MinLength(8), MaxLength(128) | "Password es requerido" / "Password debe tener minimo 8 caracteres" | ### Seguridad - Bcrypt con salt rounds = 12 - Rate limiting: 10 requests/minuto por IP - No revelar si email existe - Tokens firmados con RS256 --- ## Definicion de Done - [ ] Endpoint POST /api/v1/auth/login implementado - [ ] Validaciones de DTO funcionando - [ ] Login exitoso retorna tokens JWT - [ ] Login fallido registra intento - [ ] Bloqueo despues de 5 intentos - [ ] Desbloqueo automatico despues de 30 min - [ ] Cookie httpOnly para refresh token - [ ] Registro en session_history - [ ] Tests unitarios (>80% coverage) - [ ] Tests e2e pasando - [ ] Documentacion Swagger actualizada - [ ] Code review aprobado --- ## Dependencias ### Requiere | Item | Descripcion | |------|-------------| | Tabla users | Con campos email, password_hash, is_active | | Tabla login_attempts | Para registro de intentos | | Tabla session_history | Para auditoria | | TokenService | Para generar tokens JWT | ### Bloquea | Item | Descripcion | |------|-------------| | US-MGN001-002 | Logout (necesita sesion) | | US-MGN001-003 | Refresh token (necesita login) | | Todas las features | Requieren autenticacion | --- ## Estimacion | Tarea | Horas | |-------|-------| | Backend: AuthService.login() | 4h | | Backend: Validaciones y errores | 2h | | Backend: Tests unitarios | 3h | | Frontend: LoginPage | 4h | | Frontend: authStore | 2h | | Frontend: Tests | 2h | | **Total** | **17h** | --- ## Referencias - [RF-AUTH-001](../../01-requerimientos/RF-auth/RF-AUTH-001.md) - Requerimiento funcional - [DDL-SPEC-core_auth](../../02-modelado/database-design/DDL-SPEC-core_auth.md) - Esquema BD - [ET-auth-backend](../../02-modelado/especificaciones-tecnicas/ET-auth-backend.md) - Spec tecnica --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | System | Creacion inicial |