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
Ejemplos de Verificacion
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
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<string, any>;
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 |
- |
- |
[ ] |