# TRACEABILITY-MGN-010.yaml # Matriz de Trazabilidad - MGN-010: RRHH Básico # Fecha: 2025-11-24 # Versión: 1.0 module: id: MGN-010 name: "RRHH Básico" description: "Gestión de recursos humanos: empleados, departamentos, contratos, asistencias y ausencias" priority: P1 story_points: 29 status: Diseñado metadata: total_rf: 5 total_et_backend: 5 total_et_frontend: 5 total_tables: 6 total_tests: 100 coverage: 100% requirements: - rf_id: RF-MGN-010-001 rf_title: "Gestión de Empleados" rf_file: "requerimientos-funcionales/mgn-010/RF-MGN-010-001-gestión-de-empleados.md" priority: P1 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-010/ET-BACKEND-MGN-010-001-gestión-de-empleados.md" endpoints: - method: POST path: /api/v1/hr/employees description: "Crear nuevo empleado" - method: GET path: /api/v1/hr/employees description: "Listar todos los empleados" - method: GET path: /api/v1/hr/employees/:id description: "Obtener empleado por ID" - method: PUT path: /api/v1/hr/employees/:id description: "Actualizar empleado" - method: DELETE path: /api/v1/hr/employees/:id description: "Eliminar empleado (soft delete)" services: - name: "EmployeeService" file: "src/modules/hr/services/employee.service.ts" methods: - create - findAll - findOne - update - remove - validateBusinessRules controllers: - name: "EmployeeController" file: "src/modules/hr/controllers/employee.controller.ts" dtos: - name: "CreateEmployeeDto" file: "src/modules/hr/dto/create-employee.dto.ts" - name: "UpdateEmployeeDto" file: "src/modules/hr/dto/update-employee.dto.ts" - name: "EmployeeResponseDto" file: "src/modules/hr/dto/employee-response.dto.ts" - name: "FilterEmployeeDto" file: "src/modules/hr/dto/filter-employee.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-010/ET-FRONTEND-MGN-010-001-gestión-de-empleados.md" routes: - path: "/hr/employees" component: "EmployeesPage" - path: "/hr/employees/create" component: "CreateEmployeePage" - path: "/hr/employees/:id/edit" component: "EditEmployeePage" - path: "/hr/employees/:id" component: "ViewEmployeePage" components: - name: "EmployeesTable" file: "src/widgets/employees-table/ui/EmployeesTable.tsx" type: widget - name: "CreateEmployeeForm" file: "src/features/create-employee/ui/CreateEmployeeForm.tsx" type: feature - name: "EmployeeCard" file: "src/entities/employee/ui/EmployeeCard.tsx" type: entity - name: "EmployeePage" file: "src/pages/hr/EmployeePage.tsx" type: page api_client: - name: "employeeApi" file: "src/entities/employee/api/employee.api.ts" methods: - getAll - getById - create - update - delete state_management: - name: "useEmployeeStore" file: "src/entities/employee/model/employee.store.ts" type: zustand - name: "useEmployees" file: "src/entities/employee/api/employee.queries.ts" type: react-query database_tables: - schema: hr table: employees file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_employees_tenant_id - idx_employees_user_id - idx_employees_department_id - idx_employees_status rls_policy: tenant_isolation_employees tests: backend: unit_tests: - file: "src/modules/hr/services/employee.service.spec.ts" test_cases: - "should create employee with valid data" - "should link employee to user account" - "should validate unique employee number" - "should find all employees for tenant" - "should update employee successfully" integration_tests: - file: "test/hr/employee.controller.e2e-spec.ts" test_cases: - "POST /api/v1/hr/employees should create employee" - "GET /api/v1/hr/employees should return all employees" - "GET /api/v1/hr/employees/:id should return employee" - "PUT /api/v1/hr/employees/:id should update employee" - "DELETE /api/v1/hr/employees/:id should soft delete employee" - "should enforce tenant isolation" - "should require authentication" - "should check permissions" frontend: component_tests: - file: "src/widgets/employees-table/ui/EmployeesTable.test.tsx" test_cases: - "should render table with employees" - "should handle pagination" - "should filter by department" - file: "src/features/create-employee/ui/CreateEmployeeForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" - "should show error messages" e2e_tests: - file: "e2e/hr/employees.spec.ts" test_cases: - "should create employee successfully" - "should edit employee successfully" - "should delete employee with confirmation" - "should enforce permissions" acceptance_criteria: - id: AC-001 description: "Usuario puede crear empleados con datos personales y laborales" status: Pending test_reference: "test/hr/employee.controller.e2e-spec.ts:35" - id: AC-002 description: "Empleado puede vincularse a cuenta de usuario" status: Pending test_reference: "src/modules/hr/services/employee.service.spec.ts:72" - id: AC-003 description: "Número de empleado es único por tenant" status: Pending test_reference: "test/hr/employee.controller.e2e-spec.ts:108" business_rules: - id: RN-001 description: "Número de empleado debe ser único por tenant" implementation: "database-design/schemas/hr-schema-ddl.sql:CONSTRAINT uq_employees_number_tenant" test_reference: "src/modules/hr/services/employee.service.spec.ts:95" - id: RN-002 description: "Empleado puede vincularse a un usuario del sistema" implementation: "src/modules/hr/services/employee.service.ts:linkUser()" test_reference: "src/modules/hr/services/employee.service.spec.ts:122" - id: RN-003 description: "Fecha de ingreso no puede ser posterior a fecha actual" implementation: "src/modules/hr/dto/create-employee.dto.ts:@MaxDate(today)" test_reference: "src/modules/hr/services/employee.service.spec.ts:148" dependencies: rf_dependencies: - RF-MGN-001-003 module_dependencies: - MGN-001 external_dependencies: - name: "@nestjs/common" version: "^10.0.0" - name: "ant-design" version: "^5.0.0" - rf_id: RF-MGN-010-002 rf_title: "Departamentos y Puestos" rf_file: "requerimientos-funcionales/mgn-010/RF-MGN-010-002-departamentos-y-puestos.md" priority: P1 story_points: 3 et_backend: file: "especificaciones-tecnicas/backend/mgn-010/ET-BACKEND-MGN-010-002-departamentos-y-puestos.md" endpoints: - method: POST path: /api/v1/hr/departments description: "Crear nuevo departamento" - method: GET path: /api/v1/hr/departments description: "Listar todos los departamentos" - method: GET path: /api/v1/hr/departments/:id description: "Obtener departamento por ID" - method: PUT path: /api/v1/hr/departments/:id description: "Actualizar departamento" - method: DELETE path: /api/v1/hr/departments/:id description: "Eliminar departamento (soft delete)" services: - name: "DepartmentService" file: "src/modules/hr/services/department.service.ts" methods: - create - findAll - findOne - update - remove - validateBusinessRules controllers: - name: "DepartmentController" file: "src/modules/hr/controllers/department.controller.ts" dtos: - name: "CreateDepartmentDto" file: "src/modules/hr/dto/create-department.dto.ts" - name: "UpdateDepartmentDto" file: "src/modules/hr/dto/update-department.dto.ts" - name: "DepartmentResponseDto" file: "src/modules/hr/dto/department-response.dto.ts" - name: "FilterDepartmentDto" file: "src/modules/hr/dto/filter-department.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-010/ET-FRONTEND-MGN-010-002-departamentos-y-puestos.md" routes: - path: "/hr/departments" component: "DepartmentsPage" - path: "/hr/departments/create" component: "CreateDepartmentPage" - path: "/hr/departments/:id/edit" component: "EditDepartmentPage" - path: "/hr/departments/:id" component: "ViewDepartmentPage" components: - name: "DepartmentsTable" file: "src/widgets/departments-table/ui/DepartmentsTable.tsx" type: widget - name: "CreateDepartmentForm" file: "src/features/create-department/ui/CreateDepartmentForm.tsx" type: feature - name: "DepartmentCard" file: "src/entities/department/ui/DepartmentCard.tsx" type: entity - name: "DepartmentPage" file: "src/pages/hr/DepartmentPage.tsx" type: page api_client: - name: "departmentApi" file: "src/entities/department/api/department.api.ts" methods: - getAll - getById - create - update - delete state_management: - name: "useDepartmentStore" file: "src/entities/department/model/department.store.ts" type: zustand - name: "useDepartments" file: "src/entities/department/api/department.queries.ts" type: react-query database_tables: - schema: hr table: departments file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_departments_tenant_id - idx_departments_parent_id rls_policy: tenant_isolation_departments - schema: hr table: jobs file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_jobs_tenant_id - idx_jobs_department_id rls_policy: tenant_isolation_jobs tests: backend: unit_tests: - file: "src/modules/hr/services/department.service.spec.ts" test_cases: - "should create department with valid data" - "should support hierarchical departments" - "should create job positions in department" - "should find all departments for tenant" - "should update department successfully" integration_tests: - file: "test/hr/department.controller.e2e-spec.ts" test_cases: - "POST /api/v1/hr/departments should create department" - "GET /api/v1/hr/departments should return all departments" - "GET /api/v1/hr/departments/:id should return department" - "PUT /api/v1/hr/departments/:id should update department" - "DELETE /api/v1/hr/departments/:id should soft delete department" - "should enforce tenant isolation" - "should require authentication" - "should check permissions" frontend: component_tests: - file: "src/widgets/departments-table/ui/DepartmentsTable.test.tsx" test_cases: - "should render table with departments" - "should show hierarchy tree" - "should call delete on button click" - file: "src/features/create-department/ui/CreateDepartmentForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" - "should show error messages" e2e_tests: - file: "e2e/hr/departments.spec.ts" test_cases: - "should create department successfully" - "should create sub-department" - "should delete department with confirmation" - "should enforce permissions" acceptance_criteria: - id: AC-001 description: "Usuario puede crear departamentos con estructura jerárquica" status: Pending test_reference: "test/hr/department.controller.e2e-spec.ts:38" - id: AC-002 description: "Cada departamento puede tener múltiples puestos de trabajo" status: Pending test_reference: "src/modules/hr/services/department.service.spec.ts:75" - id: AC-003 description: "Departamento con empleados no puede ser eliminado" status: Pending test_reference: "test/hr/department.controller.e2e-spec.ts:112" business_rules: - id: RN-001 description: "Nombre de departamento debe ser único por tenant" implementation: "database-design/schemas/hr-schema-ddl.sql:CONSTRAINT uq_departments_name_tenant" test_reference: "src/modules/hr/services/department.service.spec.ts:98" - id: RN-002 description: "Departamento puede tener departamentos hijos (jerarquía)" implementation: "database-design/schemas/hr-schema-ddl.sql:parent_id column" test_reference: "src/modules/hr/services/department.service.spec.ts:125" - id: RN-003 description: "No se puede eliminar departamento con empleados asignados" implementation: "src/modules/hr/services/department.service.ts:remove()" test_reference: "src/modules/hr/services/department.service.spec.ts:152" dependencies: rf_dependencies: [] module_dependencies: - MGN-001 external_dependencies: - name: "@nestjs/common" version: "^10.0.0" - rf_id: RF-MGN-010-003 rf_title: "Contratos Laborales" rf_file: "requerimientos-funcionales/mgn-010/RF-MGN-010-003-contratos-laborales.md" priority: P1 story_points: 5 et_backend: file: "especificaciones-tecnicas/backend/mgn-010/ET-BACKEND-MGN-010-003-contratos-laborales.md" endpoints: - method: POST path: /api/v1/hr/contracts description: "Crear nuevo contrato" - method: GET path: /api/v1/hr/contracts description: "Listar todos los contratos" - method: GET path: /api/v1/hr/contracts/:id description: "Obtener contrato por ID" - method: PUT path: /api/v1/hr/contracts/:id description: "Actualizar contrato" - method: POST path: /api/v1/hr/contracts/:id/terminate description: "Terminar contrato" services: - name: "ContractService" file: "src/modules/hr/services/contract.service.ts" methods: - create - findAll - findOne - update - terminate - validateBusinessRules controllers: - name: "ContractController" file: "src/modules/hr/controllers/contract.controller.ts" dtos: - name: "CreateContractDto" file: "src/modules/hr/dto/create-contract.dto.ts" - name: "UpdateContractDto" file: "src/modules/hr/dto/update-contract.dto.ts" - name: "ContractResponseDto" file: "src/modules/hr/dto/contract-response.dto.ts" - name: "TerminateContractDto" file: "src/modules/hr/dto/terminate-contract.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-010/ET-FRONTEND-MGN-010-003-contratos-laborales.md" routes: - path: "/hr/contracts" component: "ContractsPage" - path: "/hr/contracts/create" component: "CreateContractPage" - path: "/hr/contracts/:id/edit" component: "EditContractPage" - path: "/hr/contracts/:id" component: "ViewContractPage" components: - name: "ContractsTable" file: "src/widgets/contracts-table/ui/ContractsTable.tsx" type: widget - name: "CreateContractForm" file: "src/features/create-contract/ui/CreateContractForm.tsx" type: feature - name: "ContractCard" file: "src/entities/contract/ui/ContractCard.tsx" type: entity - name: "ContractPage" file: "src/pages/hr/ContractPage.tsx" type: page api_client: - name: "contractApi" file: "src/entities/contract/api/contract.api.ts" methods: - getAll - getById - create - update - terminate state_management: - name: "useContractStore" file: "src/entities/contract/model/contract.store.ts" type: zustand - name: "useContracts" file: "src/entities/contract/api/contract.queries.ts" type: react-query database_tables: - schema: hr table: contracts file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_contracts_tenant_id - idx_contracts_employee_id - idx_contracts_status - idx_contracts_end_date rls_policy: tenant_isolation_contracts tests: backend: unit_tests: - file: "src/modules/hr/services/contract.service.spec.ts" test_cases: - "should create contract with valid data" - "should validate date range consistency" - "should terminate contract with reason" - "should find all contracts for tenant" - "should update contract successfully" integration_tests: - file: "test/hr/contract.controller.e2e-spec.ts" test_cases: - "POST /api/v1/hr/contracts should create contract" - "GET /api/v1/hr/contracts should return all contracts" - "GET /api/v1/hr/contracts/:id should return contract" - "PUT /api/v1/hr/contracts/:id should update contract" - "POST /api/v1/hr/contracts/:id/terminate should terminate contract" - "should enforce tenant isolation" - "should require authentication" - "should check permissions" frontend: component_tests: - file: "src/widgets/contracts-table/ui/ContractsTable.test.tsx" test_cases: - "should render table with contracts" - "should filter by status" - "should show expiring contracts" - file: "src/features/create-contract/ui/CreateContractForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" - "should show error messages" e2e_tests: - file: "e2e/hr/contracts.spec.ts" test_cases: - "should create contract successfully" - "should terminate contract with reason" - "should show expiring contract alerts" - "should enforce permissions" acceptance_criteria: - id: AC-001 description: "Usuario puede crear contratos con tipo, fecha inicio y fin" status: Pending test_reference: "test/hr/contract.controller.e2e-spec.ts:42" - id: AC-002 description: "Sistema alerta sobre contratos próximos a vencer" status: Pending test_reference: "src/modules/hr/services/contract.service.spec.ts:78" - id: AC-003 description: "Contrato terminado registra fecha y razón" status: Pending test_reference: "test/hr/contract.controller.e2e-spec.ts:115" business_rules: - id: RN-001 description: "Fecha de fin debe ser posterior a fecha de inicio" implementation: "src/modules/hr/dto/create-contract.dto.ts:@IsDateAfter('start_date')" test_reference: "src/modules/hr/services/contract.service.spec.ts:102" - id: RN-002 description: "Empleado solo puede tener un contrato activo a la vez" implementation: "src/modules/hr/services/contract.service.ts:validateActiveContract()" test_reference: "src/modules/hr/services/contract.service.spec.ts:128" - id: RN-003 description: "Alerta si contrato vence en menos de 30 días" implementation: "src/modules/hr/services/contract.service.ts:checkExpiringContracts()" test_reference: "src/modules/hr/services/contract.service.spec.ts:155" dependencies: rf_dependencies: - RF-MGN-010-001 module_dependencies: - MGN-001 - MGN-014 external_dependencies: - name: "@nestjs/schedule" version: "^4.0.0" - rf_id: RF-MGN-010-004 rf_title: "Asistencias (Check-in/Check-out)" rf_file: "requerimientos-funcionales/mgn-010/RF-MGN-010-004-asistencias-check-in-check-out.md" priority: P1 story_points: 5 et_backend: file: "especificaciones-tecnicas/backend/mgn-010/ET-BACKEND-MGN-010-004-asistencias-check-in-check-out.md" endpoints: - method: POST path: /api/v1/hr/attendances/check-in description: "Registrar entrada (check-in)" - method: POST path: /api/v1/hr/attendances/check-out description: "Registrar salida (check-out)" - method: GET path: /api/v1/hr/attendances description: "Listar asistencias" - method: GET path: /api/v1/hr/attendances/:id description: "Obtener asistencia por ID" - method: GET path: /api/v1/hr/attendances/report description: "Reporte de asistencias" services: - name: "AttendanceService" file: "src/modules/hr/services/attendance.service.ts" methods: - checkIn - checkOut - findAll - findOne - getReport - validateBusinessRules controllers: - name: "AttendanceController" file: "src/modules/hr/controllers/attendance.controller.ts" dtos: - name: "CheckInDto" file: "src/modules/hr/dto/check-in.dto.ts" - name: "CheckOutDto" file: "src/modules/hr/dto/check-out.dto.ts" - name: "AttendanceResponseDto" file: "src/modules/hr/dto/attendance-response.dto.ts" - name: "AttendanceReportDto" file: "src/modules/hr/dto/attendance-report.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-010/ET-FRONTEND-MGN-010-004-asistencias-check-in-check-out.md" routes: - path: "/hr/attendances" component: "AttendancesPage" - path: "/hr/attendances/report" component: "AttendanceReportPage" components: - name: "AttendanceWidget" file: "src/widgets/attendance-widget/ui/AttendanceWidget.tsx" type: widget - name: "CheckInButton" file: "src/features/check-in/ui/CheckInButton.tsx" type: feature - name: "AttendanceTable" file: "src/entities/attendance/ui/AttendanceTable.tsx" type: entity - name: "AttendancePage" file: "src/pages/hr/AttendancePage.tsx" type: page api_client: - name: "attendanceApi" file: "src/entities/attendance/api/attendance.api.ts" methods: - checkIn - checkOut - getAll - getById - getReport state_management: - name: "useAttendanceStore" file: "src/entities/attendance/model/attendance.store.ts" type: zustand - name: "useAttendances" file: "src/entities/attendance/api/attendance.queries.ts" type: react-query database_tables: - schema: hr table: attendances file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE indices: - idx_attendances_tenant_id - idx_attendances_employee_id - idx_attendances_check_in - idx_attendances_check_out rls_policy: tenant_isolation_attendances tests: backend: unit_tests: - file: "src/modules/hr/services/attendance.service.spec.ts" test_cases: - "should register check-in successfully" - "should register check-out with duration calculation" - "should prevent double check-in" - "should generate attendance report" - "should calculate total hours worked" integration_tests: - file: "test/hr/attendance.controller.e2e-spec.ts" test_cases: - "POST /api/v1/hr/attendances/check-in should check in" - "POST /api/v1/hr/attendances/check-out should check out" - "GET /api/v1/hr/attendances should return attendances" - "GET /api/v1/hr/attendances/:id should return attendance" - "GET /api/v1/hr/attendances/report should return report" - "should enforce tenant isolation" - "should require authentication" - "should check permissions" frontend: component_tests: - file: "src/widgets/attendance-widget/ui/AttendanceWidget.test.tsx" test_cases: - "should show check-in button when not checked in" - "should show check-out button when checked in" - "should display current session duration" - file: "src/features/check-in/ui/CheckInButton.test.tsx" test_cases: - "should call check-in API" - "should show success message" - "should handle errors" e2e_tests: - file: "e2e/hr/attendances.spec.ts" test_cases: - "should check in successfully" - "should check out successfully" - "should view attendance report" - "should enforce permissions" acceptance_criteria: - id: AC-001 description: "Empleado puede registrar entrada y salida diaria" status: Pending test_reference: "test/hr/attendance.controller.e2e-spec.ts:45" - id: AC-002 description: "Sistema calcula automáticamente horas trabajadas" status: Pending test_reference: "src/modules/hr/services/attendance.service.spec.ts:82" - id: AC-003 description: "Reportes muestran asistencias por período y empleado" status: Pending test_reference: "test/hr/attendance.controller.e2e-spec.ts:118" business_rules: - id: RN-001 description: "Empleado no puede hacer check-in si ya tiene uno activo" implementation: "src/modules/hr/services/attendance.service.ts:validateCheckIn()" test_reference: "src/modules/hr/services/attendance.service.spec.ts:108" - id: RN-002 description: "Horas trabajadas = check-out - check-in" implementation: "src/modules/hr/services/attendance.service.ts:calculateDuration()" test_reference: "src/modules/hr/services/attendance.service.spec.ts:135" - id: RN-003 description: "Check-out debe ser posterior a check-in del mismo día" implementation: "src/modules/hr/services/attendance.service.ts:checkOut()" test_reference: "src/modules/hr/services/attendance.service.spec.ts:162" dependencies: rf_dependencies: - RF-MGN-010-001 module_dependencies: - MGN-001 external_dependencies: - name: "@nestjs/common" version: "^10.0.0" - name: "date-fns" version: "^2.30.0" - rf_id: RF-MGN-010-005 rf_title: "Ausencias y Permisos" rf_file: "requerimientos-funcionales/mgn-010/RF-MGN-010-005-ausencias-y-permisos.md" priority: P1 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-010/ET-BACKEND-MGN-010-005-ausencias-y-permisos.md" endpoints: - method: POST path: /api/v1/hr/leaves description: "Solicitar ausencia/permiso" - method: GET path: /api/v1/hr/leaves description: "Listar ausencias" - method: GET path: /api/v1/hr/leaves/:id description: "Obtener ausencia por ID" - method: POST path: /api/v1/hr/leaves/:id/approve description: "Aprobar ausencia" - method: POST path: /api/v1/hr/leaves/:id/reject description: "Rechazar ausencia" services: - name: "LeaveService" file: "src/modules/hr/services/leave.service.ts" methods: - create - findAll - findOne - approve - reject - validateBusinessRules controllers: - name: "LeaveController" file: "src/modules/hr/controllers/leave.controller.ts" dtos: - name: "CreateLeaveDto" file: "src/modules/hr/dto/create-leave.dto.ts" - name: "LeaveResponseDto" file: "src/modules/hr/dto/leave-response.dto.ts" - name: "ApproveLeaveDto" file: "src/modules/hr/dto/approve-leave.dto.ts" - name: "RejectLeaveDto" file: "src/modules/hr/dto/reject-leave.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-010/ET-FRONTEND-MGN-010-005-ausencias-y-permisos.md" routes: - path: "/hr/leaves" component: "LeavesPage" - path: "/hr/leaves/request" component: "RequestLeavePage" - path: "/hr/leaves/:id" component: "ViewLeavePage" components: - name: "LeavesTable" file: "src/widgets/leaves-table/ui/LeavesTable.tsx" type: widget - name: "RequestLeaveForm" file: "src/features/request-leave/ui/RequestLeaveForm.tsx" type: feature - name: "LeaveCard" file: "src/entities/leave/ui/LeaveCard.tsx" type: entity - name: "LeavePage" file: "src/pages/hr/LeavePage.tsx" type: page api_client: - name: "leaveApi" file: "src/entities/leave/api/leave.api.ts" methods: - getAll - getById - request - approve - reject state_management: - name: "useLeaveStore" file: "src/entities/leave/model/leave.store.ts" type: zustand - name: "useLeaves" file: "src/entities/leave/api/leave.queries.ts" type: react-query database_tables: - schema: hr table: leaves file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_leaves_tenant_id - idx_leaves_employee_id - idx_leaves_status - idx_leaves_date_from rls_policy: tenant_isolation_leaves - schema: hr table: leave_types file: "database-design/schemas/hr-schema-ddl.sql" operations: - SELECT indices: - idx_leave_types_tenant_id rls_policy: tenant_isolation_leave_types tests: backend: unit_tests: - file: "src/modules/hr/services/leave.service.spec.ts" test_cases: - "should create leave request successfully" - "should validate leave balance before approval" - "should approve leave request" - "should reject leave request with reason" - "should check overlapping leave requests" integration_tests: - file: "test/hr/leave.controller.e2e-spec.ts" test_cases: - "POST /api/v1/hr/leaves should request leave" - "GET /api/v1/hr/leaves should return leaves" - "GET /api/v1/hr/leaves/:id should return leave" - "POST /api/v1/hr/leaves/:id/approve should approve" - "POST /api/v1/hr/leaves/:id/reject should reject" - "should enforce tenant isolation" - "should require authentication" - "should check permissions" frontend: component_tests: - file: "src/widgets/leaves-table/ui/LeavesTable.test.tsx" test_cases: - "should render table with leaves" - "should filter by status" - "should show pending approvals" - file: "src/features/request-leave/ui/RequestLeaveForm.test.tsx" test_cases: - "should validate date range" - "should submit valid form" - "should show balance warning" e2e_tests: - file: "e2e/hr/leaves.spec.ts" test_cases: - "should request leave successfully" - "should approve leave as manager" - "should reject leave with reason" - "should enforce permissions" acceptance_criteria: - id: AC-001 description: "Empleado puede solicitar ausencias con fecha y tipo" status: Pending test_reference: "test/hr/leave.controller.e2e-spec.ts:48" - id: AC-002 description: "Manager puede aprobar o rechazar solicitudes" status: Pending test_reference: "src/modules/hr/services/leave.service.spec.ts:85" - id: AC-003 description: "Sistema valida balance de días disponibles" status: Pending test_reference: "test/hr/leave.controller.e2e-spec.ts:122" business_rules: - id: RN-001 description: "Fecha de fin debe ser posterior o igual a fecha de inicio" implementation: "src/modules/hr/dto/create-leave.dto.ts:@IsDateAfterOrEqual('date_from')" test_reference: "src/modules/hr/services/leave.service.spec.ts:112" - id: RN-002 description: "Sistema valida que empleado tenga días disponibles" implementation: "src/modules/hr/services/leave.service.ts:validateBalance()" test_reference: "src/modules/hr/services/leave.service.spec.ts:138" - id: RN-003 description: "No se permiten solicitudes de ausencia superpuestas" implementation: "src/modules/hr/services/leave.service.ts:checkOverlap()" test_reference: "src/modules/hr/services/leave.service.spec.ts:165" dependencies: rf_dependencies: - RF-MGN-010-001 module_dependencies: - MGN-001 - MGN-014 external_dependencies: - name: "@nestjs/common" version: "^10.0.0" - name: "date-fns" version: "^2.30.0" coverage: rf_to_et_backend: 100% rf_to_et_frontend: 100% rf_to_database: 100% rf_to_tests: 100% backend_tests: 100% frontend_tests: 100% statistics: total_endpoints: 25 total_components: 20 total_tables: 6 total_test_cases: 100 estimated_duration_sprints: 2