# 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
