# Recruiting Module

The Recruiting module (ATS — Applicant Tracking System) provides a full hiring pipeline management experience. It covers job offer creation and publishing, candidate pipeline tracking, and applicant screening.

## Screens

| Screen | Route | Description |
|---|---|---|
| **Offers list** | `/recruiting/offers` | Paginated list of all job offers with search and sorting |
| **New offer** | `/recruiting/offers/new` | Multi-step wizard to create a new job offer |
| **Job detail** | `/recruiting/offers/:id/detail` | Read-only summary of all sections of a job offer |
| **Edit job offer** | `/recruiting/offers/:id/edit` | Edit the General Config section of an existing job offer |
| **Offer detail** | `/recruiting/offers/:id` | Candidates table for a job, with pipeline stage filters |
| **Publish offer** | `/recruiting/offers/:id/publish` | Publish or manage job postings on external job boards |
| **Applicant detail** | `/recruiting/offers/:id/applicants/:applicantId` | Full applicant screening view with stage progression, files, and notes |

## Top-level structure

```
Recruiting/
├── index.tsx          # React Router setup (lazy-loaded routes + permission guards)
├── routes.ts          # Centralized route helpers (recruitingRoutes)
├── services.ts        # All API calls (Axios, /ats/admin base URL)
├── types.ts           # All shared TypeScript types and enums
├── queries.ts         # React Query key factories (jobKeys, applicantsKeys)
├── constants.ts       # Module-level configuration
├── utils.ts           # Shared helper functions
├── dateUtils.ts       # Date formatting utilities
│
├── utils/
│   └── form.ts        # requiredLabel / optionalLabel helpers for form field labels
│
├── hooks/
│   └── useUploadFile.ts   # Generic file upload hook — accepts uploadService as param
│
├── Offers/            # Job offer management — see Offers/README.md
├── Applicants/        # Cross-offer applicants list (shell — not yet fully active)
└── components/        # Shared UI components used across the module
```

## Key patterns

### State management
All server state is managed via **React Query** (`react-query`). Query keys are defined in `queries.ts` using factory functions (e.g. `jobKeys.detail(id)`). Mutations invalidate the relevant query keys on success.

### API layer
All API calls live in `services.ts`. The base URL is `/ats/admin`. Functions follow the naming convention `verb + Resource` (e.g. `createJob`, `getJobDetailApplicants`, `deleteApplicationStageNote`).

### Routing
Routes are defined as nested React Router objects in `index.tsx`. All routes are lazy-loaded via `lazyRetry` and wrapped with `PermissionsGuard` using `ROUTE_PERMISSIONS.ATS`. Route path helpers are centralised in `routes.ts` via the `recruitingRoutes` object.

### i18n
All user-facing strings use the `useLokaliseTranslation` hook. The primary namespace is `ats`.

### Theming
Pages that require the HuGo design system theme wrap their content with `useHuGoTheme()` and `useHideHeader()`.

## Permissions

The entire module is gated behind `ROUTE_PERMISSIONS.ATS`. Individual screens do not add further permission checks beyond that guard.

## Notable shared components

| Component | Location | Purpose |
|---|---|---|
| `SideStepper` | `components/SideStepper` | Step navigation sidebar used in the create wizard |
| `Footer` | `components/Footer` | Next / Back / Draft action bar for the wizard |
| `ModalUnsavedChanges` | `components/ModalUnsavedChanges` | Prompt before navigating away with unsaved changes |
| `StatusPill` | `components/StatusPill` | Job offer status badge |
| `JobsTable` | `components/JobsTable` | Infinite-scroll table used on the offers list |
| `ApplicantPersonalInfoForm` | `components/ApplicantPersonalInfoForm` | Candidate personal info form used when adding/editing a candidate. Uses `watch` + `trigger` to force async validation after phone autocomplete |
| `JobDetailsForm` | `components/JobDetailsForm` | Source + pipeline stage selector used in add/edit candidate drawers |
| `TitleWithCopyTooltip` | `components/TitleWithCopyTooltip` | Title with a copy-to-clipboard icon that appears on hover without layout shift |
| `CandidatesTableEmptyState` | `components/CandidatesTableEmptyState` | Empty state for candidates tables |
| `TableError` | `components/TableError` | Error state for tables |
| `TableNoInternetConnection` | `components/TableNoInternetConnection` | Offline state for tables |
| `TableSkeleton` | `components/TableSkeleton` | Loading skeleton for tables |
| `DetailSectionSummary` | `Offers/JobDetail/components/DetailSectionSummary` | Read-only card for key/value section data, supports nested subsections |
