erp-core/docs/04-modelado/trazabilidad/TRACEABILITY-MGN-010.yaml

965 lines
36 KiB
YAML

# 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