# US-MGN-001-001-001: Login con Email y Contraseña

**RF Asociado:** [RF-MGN-001-001](../../02-modelado/requerimientos-funcionales/mgn-001/RF-MGN-001-001-autenticacion-usuarios.md)
**Módulo:** MGN-001 - Fundamentos
**Epic:** Autenticación y Seguridad
**Prioridad:** P0 (MVP)
**Story Points:** 5
**Sprint:** Sprint 1
**Estado:** Ready for Development
**Fecha:** 2025-11-24

---

## User Story

**Como** usuario del sistema (administrador, contador, vendedor, etc.),
**Quiero** autenticarme con mi email y contraseña,
**Para** acceder de forma segura a las funcionalidades del ERP según mi rol y permisos.

---

## Descripción Detallada

Esta user story cubre el flujo principal de autenticación del sistema ERP. El usuario ingresa sus credenciales (email + contraseña) y el sistema valida:
1. Que el email exista en el tenant correcto (multi-tenancy)
2. Que la contraseña sea correcta (bcrypt hash)
3. Que el usuario esté activo
4. Que el tenant esté activo

Si todo es válido, el sistema genera un JWT token con claims (user_id, tenant_id, roles, permissions) y lo retorna al frontend para ser almacenado y usado en requests subsiguientes.

---

## Criterios de Aceptación

### Escenario 1: Login exitoso con credenciales válidas
**Dado que** soy un usuario con cuenta activa en el tenant "acme-corp",
**Cuando** ingreso mi email "juan@acme.com" y contraseña correcta,
**Entonces** el sistema me autentica y retorna un JWT token válido que contiene mi user_id, tenant_id, roles y permissions.

### Escenario 2: Login fallido por credenciales inválidas
**Dado que** ingreso un email existente pero contraseña incorrecta,
**Cuando** intento hacer login,
**Entonces** el sistema retorna error 401 "Credenciales inválidas" e incrementa el contador de intentos fallidos en mi usuario.

### Escenario 3: Cuenta bloqueada por múltiples intentos fallidos
**Dado que** tengo 5 intentos fallidos previos en los últimos 30 minutos,
**Cuando** intento hacer login nuevamente,
**Entonces** el sistema retorna error 429 "Cuenta bloqueada temporalmente. Intente en X minutos" sin validar la contraseña.

### Escenario 4: Usuario inactivo
**Dado que** mi cuenta tiene status='inactive',
**Cuando** intento hacer login con credenciales correctas,
**Entonces** el sistema retorna error 403 "Cuenta inactiva. Contacte al administrador".

### Escenario 5: Tenant inactivo
**Dado que** el tenant tiene status='inactive',
**Cuando** cualquier usuario de ese tenant intenta hacer login,
**Entonces** el sistema retorna error 403 "Tenant suspendido. Contacte soporte".

### Escenario 6: Email no existe en el tenant
**Dado que** ingreso un email que no existe en el tenant actual,
**Cuando** intento hacer login,
**Entonces** el sistema retorna error 401 "Credenciales inválidas" (sin revelar si el email existe o no).

---

## Reglas de Negocio

- **RN-1:** Email debe ser único por tenant (no globalmente). Usuario "juan@acme.com" puede existir en tenant A y B sin conflicto.
- **RN-2:** Contraseña debe tener mínimo 8 caracteres, 1 mayúscula, 1 número, 1 carácter especial.
- **RN-3:** JWT expira en 8 horas. Refresh token expira en 30 días.
- **RN-4:** Máximo 5 intentos fallidos antes de bloqueo temporal de 30 minutos.
- **RN-5:** Contraseña debe hashearse con bcrypt (cost factor 12) antes de almacenar.
- **RN-6:** Después de login exitoso, failed_login_attempts se resetea a 0.

---

## Tareas Técnicas (Checklist de Implementación)

### Backend
- [ ] Crear endpoint: `POST /api/v1/auth/login`
- [ ] Implementar método: `AuthService.login(email, password, subdomain)`
- [ ] Implementar método: `AuthService.validateUser(email, password, tenantId)`
- [ ] Implementar método: `AuthService.generateTokens(user)`
- [ ] Crear DTO: `LoginDto` con validaciones @IsEmail, @IsString, @MinLength
- [ ] Crear DTO: `TokenResponseDto` (accessToken, refreshToken, expiresIn)
- [ ] Implementar validaciones de negocio (RN-1 a RN-6)
- [ ] Agregar unit tests para AuthService (8 test cases)
- [ ] Agregar integration tests para POST /auth/login (6 test cases)
- [ ] Documentar endpoint en Swagger con ejemplos y respuestas de error
- [ ] Implementar rate limiting con Redis (max 10 req/min por IP)
- [ ] Registrar intentos de login en auth.login_history

### Frontend
- [ ] Crear componente: `LoginForm.tsx`
- [ ] Crear página: `LoginPage.tsx`
- [ ] Implementar formulario con React Hook Form + Zod validation
- [ ] Crear API client: `authApi.login(email, password)`
- [ ] Implementar Zustand store: `useAuthStore` (setUser, setTokens, logout)
- [ ] Agregar feedback visual: loading spinner, success redirect, error messages
- [ ] Implementar "Recordar sesión" (localStorage vs sessionStorage)
- [ ] Agregar component tests para LoginForm (5 test cases)
- [ ] Agregar e2e test: "should login successfully with valid credentials" (Playwright)
- [ ] Implementar manejo de errores por código HTTP (401, 403, 429)

### Database
- [ ] Verificar tabla: `auth.users` (email, password_hash, status, failed_login_attempts, last_failed_login)
- [ ] Verificar tabla: `auth.tenants` (subdomain, status)
- [ ] Verificar tabla: `auth.login_history` (user_id, tenant_id, ip_address, user_agent, success, timestamp)
- [ ] Validar índice: `idx_users_email_tenant` para búsquedas rápidas
- [ ] Validar índice: `idx_login_history_timestamp` para auditoría
- [ ] Validar RLS policy: `tenant_isolation_users`

---

## Mockups / Wireframes

**Pantalla de Login:**
- Layout centrado con card de 400px de ancho
- Logo del ERP en la parte superior
- Formulario con 2 campos:
  - Email (input type="email", placeholder="usuario@empresa.com", autocomplete="email")
  - Contraseña (input type="password", con botón "mostrar/ocultar", autocomplete="current-password")
- Checkbox "Recordar sesión"
- Botón "Iniciar Sesión" (primary, full width, con loading state)
- Link "¿Olvidaste tu contraseña?" (redirige a reset password)
- Footer con versión del sistema y copyright

**Estados:**
- **Loading:** Botón con spinner "Iniciando sesión...", inputs deshabilitados
- **Success:** Redirect inmediato a /dashboard (sin mostrar mensaje)
- **Error:** Alert rojo con mensaje de error arriba del formulario, con icono de error
- **Locked:** Alert naranja "Cuenta bloqueada. Intente en X minutos" con countdown timer

---

## Casos de Prueba (Test Scenarios)

### Pruebas Funcionales
1. **TC-001: Login exitoso**
   - **Input:** email="admin@acme.com", password="Admin123!"
   - **Expected:** JWT token retornado, redirect a /dashboard, failed_attempts=0

2. **TC-002: Email inválido**
   - **Input:** email="notfound@acme.com", password="Admin123!"
   - **Expected:** Error 401 "Credenciales inválidas"

3. **TC-003: Contraseña incorrecta**
   - **Input:** email="admin@acme.com", password="WrongPass"
   - **Expected:** Error 401, failed_attempts incrementado, registro en login_history

4. **TC-004: Cuenta bloqueada**
   - **Input:** email con 5 failed_attempts en últimos 30 minutos
   - **Expected:** Error 429 "Cuenta bloqueada temporalmente"

5. **TC-005: Usuario inactivo**
   - **Input:** email="inactive@acme.com", password="Admin123!"
   - **Expected:** Error 403 "Cuenta inactiva"

6. **TC-006: Tenant isolation**
   - **Input:** email="user@tenant-a.com" desde subdomain tenant-b
   - **Expected:** Error 401 (no encuentra usuario en tenant-b)

7. **TC-007: Reset de failed_attempts después de login exitoso**
   - **Input:** usuario con 3 failed_attempts previos hace login exitoso
   - **Expected:** failed_attempts resetea a 0

### Pruebas No Funcionales
1. **Performance:** Response time < 300ms (incluyendo bcrypt hash comparison)
2. **Seguridad:**
   - JWT firmado con secret seguro de 256+ bits
   - bcrypt con cost factor 12
   - Rate limiting: max 10 login attempts por IP/minuto
   - No revelar en errores si email existe o no
3. **Usabilidad:**
   - Foco automático en campo email al cargar
   - Enter en cualquier campo ejecuta submit
   - Tab navigation funciona correctamente

---

## Dependencias

- **User Stories bloqueantes:** Ninguna (es el punto de entrada del sistema)
- **Módulos requeridos:** Ninguno (es parte de MGN-001 Fundamentos)
- **Datos maestros necesarios:**
  - Tenant creado con subdomain configurado
  - Al menos 1 usuario con rol administrador creado (seed data)

---

## Notas de Implementación

- JWT secret debe estar en variable de entorno `JWT_SECRET` (nunca en código)
- Subdomain se obtiene del header `Host` o de query param `?tenant=xxx` (para desarrollo local)
- Implementar rate limiting con Redis: max 10 login attempts por IP/minuto
- Logging detallado de intentos de login (exitosos y fallidos) para auditoría y detección de ataques
- NUNCA retornar en el error si el email existe o no (previene user enumeration attacks)
- Considerar agregar CAPTCHA después de 3 intentos fallidos (Fase 2)
- Considerar 2FA/MFA opcional (Fase 2)

---

## Estimación Detallada

| Tarea | Estimación |
|-------|------------|
| Backend Development | 3 horas |
| Frontend Development | 3 horas |
| Testing (Unit + Integration + E2E) | 2 horas |
| Code Review | 1 hora |
| **TOTAL** | **9 horas** |

**Equivalente:** 5 Story Points

---

## Definition of Done (DoD)

- [ ] Código backend implementado según ET-BACKEND-MGN-001-001
- [ ] Código frontend implementado según ET-FRONTEND-MGN-001-001
- [ ] Unit tests escritos y pasando (cobertura > 80%)
- [ ] Integration tests escritos y pasando
- [ ] E2E test "should login successfully" pasando
- [ ] Code review completado y aprobado por Tech Lead
- [ ] Documentación Swagger actualizada con ejemplos
- [ ] Sin vulnerabilidades de seguridad (SonarQube green)
- [ ] Rate limiting configurado y testeado
- [ ] Merge a branch `develop` completado
- [ ] QA manual completado
- [ ] Product Owner ha validado flujo de login

---

## Referencias

- [RF-MGN-001-001: Autenticación de Usuarios](../../02-modelado/requerimientos-funcionales/mgn-001/RF-MGN-001-001-autenticacion-usuarios.md)
- [ET-BACKEND-MGN-001-001](../../02-modelado/especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-001-autenticacion-usuarios.md)
- [ET-FRONTEND-MGN-001-001](../../02-modelado/especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-001-autenticacion-usuarios.md)
- [TRACEABILITY-MGN-001.yaml](../../02-modelado/trazabilidad/TRACEABILITY-MGN-001.yaml)
- [Auth Schema DDL](../../02-modelado/database-design/schemas/auth-schema-ddl.sql)
