Recruitment
Job vacancies and applications — staff-published postings, guest applicants, and a map-driven review state machine that strips PII from its audit trail.
The recruitment half of the application module: staff post job vacancies, guests apply, staff move applications through a review pipeline. Same module, different rules — most notably, job applications reuse the APPLICATION permission resource (there is no separate JOB_APPLICATION resource) while vacancies get their own JOB_VACANCY.
Vacancies
job_vacancy (@TenantScoped): title, description, optional department/campus, requirements/responsibilities, employmentType (full_time / part_time / contract), a deadline, status (draft → published → closed), and an aiInterviewEnabled flag.
- Staff CRUD is
@RequireUserType(STAFF)+ per-actionJOB_VACANCYpermissions, campus-scoped on list, all audited. - The "public" listing (
GET job-vacancies) is authenticated guests, not anonymous —@RequireUserType(GUEST), filtered topublished, ordered by deadline. There are no truly public routes in this module.
Job applications
job_application is not tenant-scoped — it has no schoolId; it snapshots campusId from its vacancy so staff list permissions can scope it. It carries personalInfo jsonb (name/contact/address), optional qualifications/experience, a cover letter, a stored CV (cvFileId), review fields (reviewedBy/At, rejectionReason), and isPrioritized — AI-screened applications sort first in the staff list.
Guest flow: create a draft (prefilled from the guest profile), update while draft, submit (requires a CV and a strict address — addressLine1 + country) → pending, or withdraw. Staff see everything except other people's drafts unless they filter for them explicitly.
The review state machine
Staff advance applications with PATCH :id/status, and the allowed moves live in a literal transition map — extend the map, not the handler:
Every status change stamps reviewedBy/reviewedAt and best-effort emails the applicant (APPLICATION_STATUS, campus-aware).
Audit snapshots strip PII
Job-application audit entries record metadata only — no personalInfo, cover letter, qualifications, or CV reference. Recruitment data is the most PII-dense in the system; keep the snapshot allowlist that way.