erp-core/docs/03-requerimientos/RF-auth/RF-AUTH-001.md

235 lines
8.4 KiB
Markdown

# RF-AUTH-001: Login con Email y Password
## Identificacion
| Campo | Valor |
|-------|-------|
| **ID** | RF-AUTH-001 |
| **Modulo** | MGN-001 |
| **Nombre Modulo** | Auth - Autenticacion |
| **Prioridad** | P0 |
| **Complejidad** | Media |
| **Estado** | Aprobado |
| **Autor** | System |
| **Fecha** | 2025-12-05 |
---
## Descripcion
El sistema debe permitir a los usuarios autenticarse utilizando su correo electronico y contraseña. Al autenticarse exitosamente, el sistema debe generar tokens JWT (access token y refresh token) que permitan al usuario acceder a los recursos protegidos del sistema.
### Contexto de Negocio
La autenticacion es la puerta de entrada al sistema ERP. Sin un mecanismo robusto de login, no es posible garantizar la seguridad de los datos ni el aislamiento multi-tenant. Este requerimiento es la base de toda la seguridad del sistema.
---
## Criterios de Aceptacion
- [x] **CA-001:** El sistema debe aceptar email y password como credenciales de login
- [x] **CA-002:** El sistema debe validar que el email exista en la base de datos
- [x] **CA-003:** El sistema debe verificar el password usando bcrypt
- [x] **CA-004:** El sistema debe generar un access token JWT con expiracion de 15 minutos
- [x] **CA-005:** El sistema debe generar un refresh token JWT con expiracion de 7 dias
- [x] **CA-006:** El sistema debe registrar el login en el historial de sesiones
- [x] **CA-007:** El sistema debe devolver error 401 si las credenciales son invalidas
- [x] **CA-008:** El sistema debe bloquear la cuenta despues de 5 intentos fallidos
### Ejemplos de Verificacion
```gherkin
Scenario: Login exitoso
Given un usuario registrado con email "user@example.com" y password "SecurePass123!"
When el usuario envia credenciales correctas al endpoint /api/v1/auth/login
Then el sistema responde con status 200
And el body contiene accessToken y refreshToken
And se registra el login en session_history
Scenario: Login fallido por password incorrecto
Given un usuario registrado con email "user@example.com"
When el usuario envia password incorrecto
Then el sistema responde con status 401
And el mensaje es "Credenciales invalidas"
And se incrementa el contador de intentos fallidos
Scenario: Cuenta bloqueada por intentos fallidos
Given un usuario con 5 intentos fallidos de login
When el usuario intenta hacer login nuevamente
Then el sistema responde con status 423
And el mensaje indica que la cuenta esta bloqueada
```
---
## Reglas de Negocio
| ID | Regla | Validacion |
|----|-------|------------|
| RN-001 | El email debe ser unico por tenant | Constraint UNIQUE(tenant_id, email) |
| RN-002 | El password debe tener minimo 8 caracteres | Validacion en DTO |
| RN-003 | El password debe incluir mayuscula, minuscula, numero | Regex validation |
| RN-004 | Maximo 5 intentos fallidos antes de bloqueo | Contador en BD |
| RN-005 | El bloqueo dura 30 minutos | Campo locked_until en users |
| RN-006 | Los tokens deben incluir tenant_id en el payload | JWT payload |
| RN-007 | El access token expira en 15 minutos | JWT exp claim |
| RN-008 | El refresh token expira en 7 dias | JWT exp claim |
### Excepciones
- Si el usuario tiene 2FA habilitado, el login genera un token temporal y requiere verificacion adicional
- Los superadmins pueden acceder a multiples tenants (tenant_id opcional en su caso)
---
## Impacto en Capas
### Database
| Elemento | Accion | Descripcion |
|----------|--------|-------------|
| Schema | usar | `core_auth` |
| Tabla | usar | `users` - verificar credenciales |
| Tabla | usar | `sessions` - registrar login |
| Tabla | crear | `login_attempts` - control de intentos |
| Columna | agregar | `users.failed_login_attempts` |
| Columna | agregar | `users.locked_until` |
| Indice | crear | `idx_users_email_tenant` |
### Backend
| Elemento | Accion | Descripcion |
|----------|--------|-------------|
| Service | crear | `AuthService.login()` |
| Service | crear | `TokenService.generateTokens()` |
| Controller | crear | `AuthController.login()` |
| DTO | crear | `LoginDto` |
| DTO | crear | `LoginResponseDto` |
| Endpoints | crear | `POST /api/v1/auth/login` |
| Guard | crear | `ThrottlerGuard` para rate limiting |
### Frontend
| Elemento | Accion | Descripcion |
|----------|--------|-------------|
| Pagina | crear | `LoginPage` |
| Componente | crear | `LoginForm` |
| Store | crear | `authStore` |
| Service | crear | `authService.login()` |
| Hook | crear | `useAuth` |
---
## Dependencias
### Depende de (Bloqueantes)
| ID | Requerimiento | Estado |
|----|---------------|--------|
| - | Ninguna (es el primer RF) | - |
### Dependencias Relacionadas (No bloqueantes)
| ID | Requerimiento | Relacion |
|----|---------------|----------|
| RF-AUTH-002 | JWT Tokens | Genera tokens |
| RF-AUTH-003 | Refresh Token | Genera refresh token |
| RF-AUTH-004 | Logout | Usa misma sesion |
---
## Mockups / Wireframes
### Pantalla de Login
```
+------------------------------------------------------------------+
| ERP SUITE |
+------------------------------------------------------------------+
| |
| +-------------------------+ |
| | INICIAR SESION | |
| +-------------------------+ |
| |
| Email: |
| +-------------------------+ |
| | user@example.com | |
| +-------------------------+ |
| |
| Password: |
| +-------------------------+ |
| | •••••••••••• | |
| +-------------------------+ |
| |
| [ ] Recordarme |
| |
| [ INICIAR SESION ] |
| |
| Olvidaste tu password? |
| |
+------------------------------------------------------------------+
```
### Estados de UI
| Estado | Comportamiento |
|--------|----------------|
| Loading | Boton deshabilitado, spinner visible |
| Error | Toast rojo con mensaje de error |
| Success | Redirect a dashboard |
| Blocked | Mensaje de cuenta bloqueada con tiempo restante |
---
## Datos de Prueba
### Escenarios
| Escenario | Datos Entrada | Resultado Esperado |
|-----------|---------------|-------------------|
| Happy path | email: "test@erp.com", password: "Test123!" | 200, tokens generados |
| Email no existe | email: "noexiste@erp.com" | 401, "Credenciales invalidas" |
| Password incorrecto | password: "wrongpass" | 401, "Credenciales invalidas" |
| Cuenta bloqueada | 5+ intentos fallidos | 423, "Cuenta bloqueada" |
| Email vacio | email: "" | 400, "Email es requerido" |
| Password muy corto | password: "123" | 400, "Password minimo 8 caracteres" |
---
## Estimacion
| Capa | Story Points | Notas |
|------|--------------|-------|
| Database | 2 | Tablas ya existen, solo columnas nuevas |
| Backend | 5 | Service, Controller, DTOs, Guards |
| Frontend | 3 | LoginPage, Form, Store |
| **Total** | **10** | |
---
## Notas Adicionales
- Usar bcrypt con salt rounds = 12 para hash de passwords
- Los tokens JWT deben firmarse con algoritmo RS256 (asymmetric)
- Implementar rate limiting: max 10 requests/minuto por IP
- Loguear todos los intentos de login (exitosos y fallidos) para auditoria
- Considerar implementar CAPTCHA despues de 3 intentos fallidos
---
## 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 | - | - | [ ] |