# RF-USER-001: CRUD de Usuarios ## Identificacion | Campo | Valor | |-------|-------| | **ID** | RF-USER-001 | | **Modulo** | MGN-002 | | **Nombre Modulo** | Users - Gestion de Usuarios | | **Prioridad** | P0 | | **Complejidad** | Media | | **Estado** | Aprobado | | **Autor** | System | | **Fecha** | 2025-12-05 | --- ## Descripcion El sistema debe permitir la gestion completa del ciclo de vida de usuarios, incluyendo crear, leer, actualizar y eliminar (soft delete) usuarios dentro de un tenant. Solo usuarios con permisos administrativos pueden gestionar otros usuarios. ### Contexto de Negocio La gestion de usuarios es fundamental para: - Controlar quien accede al sistema - Asignar roles y permisos apropiados - Mantener registro de empleados/usuarios del tenant - Cumplir con politicas de seguridad y auditoria --- ## Criterios de Aceptacion - [x] **CA-001:** El sistema debe permitir crear usuarios con datos basicos (email, nombre, apellido) - [x] **CA-002:** El sistema debe generar password temporal o enviar invitacion por email - [x] **CA-003:** El sistema debe validar unicidad de email dentro del tenant - [x] **CA-004:** El sistema debe permitir listar usuarios con paginacion y filtros - [x] **CA-005:** El sistema debe permitir buscar usuarios por nombre, email o rol - [x] **CA-006:** El sistema debe permitir actualizar datos de usuario - [x] **CA-007:** El sistema debe implementar soft delete (no eliminar fisicamente) - [x] **CA-008:** El sistema debe permitir activar/desactivar usuarios - [x] **CA-009:** El sistema debe registrar quien creo/modifico cada usuario (auditoria) - [x] **CA-010:** Solo admins pueden crear/modificar/eliminar usuarios ### Ejemplos de Verificacion ```gherkin Scenario: Crear usuario exitosamente Given un administrador autenticado When crea un nuevo usuario con email "nuevo@empresa.com" And nombre "Juan" y apellido "Perez" Then el sistema crea el usuario con estado "pending_activation" And envia email de invitacion al usuario And registra created_by con el ID del admin And responde con status 201 Scenario: Crear usuario con email duplicado Given un usuario existente con email "existente@empresa.com" When un admin intenta crear otro usuario con el mismo email Then el sistema responde con status 409 And el mensaje es "El email ya esta registrado" Scenario: Listar usuarios con filtros Given 50 usuarios en el sistema When un admin solicita GET /api/v1/users?page=1&limit=10&role=admin Then el sistema retorna los primeros 10 usuarios con rol admin And incluye metadata de paginacion (total, pages, hasNext) Scenario: Soft delete de usuario Given un usuario activo con ID "user-123" When un admin elimina el usuario Then el campo deleted_at se establece con la fecha actual And el campo deleted_by se establece con el ID del admin And el usuario ya no aparece en listados normales And el usuario no puede hacer login ``` --- ## Reglas de Negocio | ID | Regla | Validacion | |----|-------|------------| | RN-001 | Email unico por tenant | UNIQUE(tenant_id, email) | | RN-002 | Email en formato valido | Regex validation | | RN-003 | Nombre y apellido requeridos | NOT NULL, min 2 chars | | RN-004 | Soft delete en lugar de hard delete | deleted_at NOT NULL | | RN-005 | Solo admins gestionan usuarios | RBAC permission check | | RN-006 | Usuario no puede eliminarse a si mismo | Validacion en backend | | RN-007 | Password temporal expira en 24 horas | Validacion en activacion | | RN-008 | Auditoria de cambios obligatoria | created_by, updated_by | ### Estados de Usuario ``` ┌─────────────────┐ │ CREATED │ │ (pending_activ) │ └────────┬────────┘ │ Usuario activa cuenta ▼ ┌─────────────┐ ┌─────────────────┐ ┌─────────────┐ │ LOCKED │◄────►│ ACTIVE │◄────►│ INACTIVE │ │ (bloqueado) │ │ (activo) │ │ (inactivo) │ └─────────────┘ └────────┬────────┘ └─────────────┘ │ Admin elimina ▼ ┌─────────────────┐ │ DELETED │ │ (soft delete) │ └─────────────────┘ ``` --- ## Impacto en Capas ### Database | Elemento | Accion | Descripcion | |----------|--------|-------------| | Schema | crear | `core_users` | | Tabla | crear | `users` - tabla principal | | Columna | - | `id` UUID PK | | Columna | - | `tenant_id` UUID FK | | Columna | - | `email` VARCHAR(255) | | Columna | - | `password_hash` VARCHAR(255) | | Columna | - | `first_name` VARCHAR(100) | | Columna | - | `last_name` VARCHAR(100) | | Columna | - | `phone` VARCHAR(20) | | Columna | - | `status` ENUM | | Columna | - | `is_active` BOOLEAN | | Columna | - | `email_verified_at` TIMESTAMPTZ | | Columna | - | `last_login_at` TIMESTAMPTZ | | Columna | - | `failed_login_attempts` INTEGER | | Columna | - | `locked_until` TIMESTAMPTZ | | Columna | - | `created_by` UUID FK | | Columna | - | `updated_by` UUID FK | | Columna | - | `deleted_at` TIMESTAMPTZ | | Columna | - | `deleted_by` UUID FK | | Indice | crear | `idx_users_tenant_email` UNIQUE | | Indice | crear | `idx_users_tenant_status` | ### Backend | Elemento | Accion | Descripcion | |----------|--------|-------------| | Controller | crear | `UsersController` | | Service | crear | `UsersService` | | Method | crear | `create()` | | Method | crear | `findAll()` | | Method | crear | `findOne()` | | Method | crear | `update()` | | Method | crear | `remove()` (soft delete) | | Method | crear | `activate()` | | Method | crear | `deactivate()` | | DTO | crear | `CreateUserDto` | | DTO | crear | `UpdateUserDto` | | DTO | crear | `UserResponseDto` | | DTO | crear | `UserListQueryDto` | | Guard | usar | `RolesGuard` | | Endpoint | crear | `POST /api/v1/users` | | Endpoint | crear | `GET /api/v1/users` | | Endpoint | crear | `GET /api/v1/users/:id` | | Endpoint | crear | `PATCH /api/v1/users/:id` | | Endpoint | crear | `DELETE /api/v1/users/:id` | ### Frontend | Elemento | Accion | Descripcion | |----------|--------|-------------| | Pagina | crear | `UsersListPage` | | Pagina | crear | `UserDetailPage` | | Pagina | crear | `UserCreatePage` | | Pagina | crear | `UserEditPage` | | Componente | crear | `UsersTable` | | Componente | crear | `UserForm` | | Componente | crear | `UserCard` | | Service | crear | `usersService` | | Store | crear | `usersStore` | --- ## Dependencias ### Depende de (Bloqueantes) | ID | Requerimiento | Estado | |----|---------------|--------| | RF-AUTH-001 | Login | Para autenticacion | | RF-AUTH-002 | JWT Tokens | Para autorizacion | ### Dependencias Relacionadas | ID | Requerimiento | Relacion | |----|---------------|----------| | RF-USER-002 | Perfil de usuario | Extiende datos de usuario | | RF-ROLE-001 | Asignacion de roles | Usa tabla users | --- ## Especificaciones Tecnicas ### Modelo de Datos Simplificado ```typescript interface User { id: string; tenantId: string; email: string; passwordHash: string; firstName: string; lastName: string; phone?: string; avatarUrl?: string; status: UserStatus; isActive: boolean; emailVerifiedAt?: Date; lastLoginAt?: Date; failedLoginAttempts: number; lockedUntil?: Date; metadata?: Record; createdAt: Date; createdBy?: string; updatedAt: Date; updatedBy?: string; deletedAt?: Date; deletedBy?: string; } enum UserStatus { PENDING_ACTIVATION = 'pending_activation', ACTIVE = 'active', INACTIVE = 'inactive', LOCKED = 'locked', } ``` ### Flujo de Creacion de Usuario ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. Admin envia POST /api/v1/users │ │ Body: { email, firstName, lastName, roleIds } │ └───────────────────────────┬─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 2. Validaciones │ │ - Email formato valido │ │ - Email no existe en tenant │ │ - Admin tiene permiso users:create │ └───────────────────────────┬─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 3. Crear usuario │ │ - status = 'pending_activation' │ │ - is_active = false │ │ - created_by = admin.id │ │ - Generar activation token │ └───────────────────────────┬─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 4. Asignar roles │ │ - Insertar en user_roles │ └───────────────────────────┬─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 5. Enviar email de invitacion │ │ - Link: /activate?token={activation_token} │ │ - Token expira en 24 horas │ └───────────────────────────┬─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 6. Responder con usuario creado │ │ - Status 201 │ │ - Body: UserResponseDto (sin password) │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Datos de Prueba | Escenario | Entrada | Resultado | |-----------|---------|-----------| | Crear usuario valido | email, firstName, lastName | 201, usuario creado | | Email duplicado | email existente | 409, "Email ya registrado" | | Email invalido | "notanemail" | 400, "Email invalido" | | Sin permiso | Usuario no admin | 403, "Permiso denegado" | | Listar usuarios | page=1, limit=10 | 200, lista paginada | | Buscar por email | search=john@ | 200, usuarios filtrados | | Actualizar usuario | PATCH con datos | 200, usuario actualizado | | Soft delete | DELETE /users/:id | 200, deleted_at set | | Eliminar a si mismo | DELETE propio ID | 400, "No puede eliminarse" | --- ## Estimacion | Capa | Story Points | Notas | |------|--------------|-------| | Database | 3 | Schema y tabla users | | Backend | 5 | CRUD completo con validaciones | | Frontend | 5 | 4 paginas, componentes, store | | **Total** | **13** | | --- ## Notas Adicionales - Implementar soft delete para mantener integridad referencial - El email de invitacion debe usar template personalizable - Considerar bulk import de usuarios via CSV - Implementar export de lista de usuarios - Los usuarios eliminados se pueden restaurar (admin) --- ## 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 | - | - | [ ] |