Skip to main content

Overview

The Applicant Tracking System (HR-09) covers the full hiring lifecycle — from a published job posting through a candidate’s public application, interviews and scorecards, an offer, and the hire that creates the employee record. Open it from HR → Recruiting (ATS).
ATS recruiting hub

Job postings

Create a posting linked to an open position, then Publish it. Only published postings are reachable from the public careers page.
ATS job postings
Publishing a posting transitions it from draft to published and stamps published_at — the start of the time-to-fill clock used by analytics.

The public careers page

Each published posting has a public, unauthenticated careers URL at /careers/:postingId. Candidates view the role and apply without an account; the application is created server-side and the candidate sees an on-screen confirmation.
Public careers and apply page
Public applications are accepted through a service-role edge function with per-IP rate limiting; a candidate record is found-or-created by email and a duplicate application to the same posting is collapsed into the existing one.

The application pipeline

Applications progress through stages — applied → screening → interview → offer → hired (or rejected/withdrawn). Recruiters screen, advance, and manage candidates from the pipeline.
ATS application pipeline

Interviews & scorecards

Schedule interviews from an application and capture structured feedback — per-competency ratings (overall, technical, communication, cultural fit, problem solving) plus an overall recommendation (strong_yes … strong_no). Feedback is attributed to the interviewing employee and aggregated for the hiring manager.

Offers — sending and accepting

Offers move through draft → pending approval → approved → sent → accepted. From a sent offer, the Accept Offer action records the candidate’s acceptance and performs the hire.
Offer detail with the Accept Offer action
Accepting an offer is idempotent: it creates exactly one employee record (with its platform identity) and one hire transition, marks the application hired, and emits the hr_employee_hired event that drives HR-03 onboarding, IT-08 provisioning, and PF-10 notifications. Re-accepting the same offer is a safe no-op.

Candidate self-service from the portal

Candidates can review, accept, or decline their own offers from the candidate portal — the self-service counterpart to the recruiter Accept Offer action. After a recruiter sends an offer, the candidate sees a My Offers link on their portal dashboard at /hr/candidate-portal/offers, opens an individual offer at /hr/candidate-portal/offers/:offerId, and confirms an Accept or Decline in a dialog. The portal only surfaces offers in sent, accepted, rejected, expired, or withdrawn status — internal drafts and pending-approval offers are never exposed. Accepting from the portal runs the same idempotent hire pipeline as the admin action and emits hr_employee_hired. Declining transitions the offer to rejected, stamps responded_at, and mirrors the decline onto the linked application.
The portal uses a candidate-scoped JWT (not Supabase Auth), and every request is enforced against the offer’s owning candidate_id + organization_id. A candidate cannot view or act on another candidate’s offer.

Analytics

Time to fill

Measures the days from a posting’s published_at to a hire’s hired_at, with breakdowns and a target benchmark.
Time to fill analytics

EEO reporting

Aggregates applicant-pool and hired-candidate demographics with adverse-impact analysis and data-completeness. EEO data is stored in a restricted table readable only by compliance/admin roles.
EEO reporting analytics

Permissions