Skip to content

Recruitment

Overview

Recruitment handles the full candidate lifecycle — from pipeline configuration to applicant tracking, assessments, interviews, document verification, and automated hiring.

The module uses Eloquent Observers that react to model events to automate stage snapshots, pipeline configuration duplication, deposit initialization, notification dispatching, and hiring record creation.

Key Entities

EntityDescription
PipelineOrdered collection of stages defining the recruitment flow
StageA single step in the pipeline (Screening, Interview, etc.)
ApplicantA candidate tracked through pipeline stages
CandidateA person in the talent pool

Flowchart

Pipeline Configuration Flow

The following flowchart illustrates how an admin configures pipelines and stages for recruitment:

Applicant Review Flow

The following flowchart shows how an admin reviews and processes applicants:

Assessment Scoring Flow

The following flowchart shows the assessment input and review process:


Observer Flows

ApplicantObserver — Full Lifecycle Automation

The ApplicantObserver is the most complex observer — it handles code generation, pipeline snapshotting, stage advancement, hiring logic, and vacancy state synchronization across 6 different Eloquent events.

Explanation by event:

creating — Before the applicant is first saved:

  1. Generates a unique applicant code (prefix APP-) using Applicant::generateUniqueCode().
  2. Snapshots the current pipeline stages into a pipeline_stages JSON column — this freezes the stage configuration at the time of application so changes to the pipeline don't affect existing applicants.

created — After the applicant is saved:

  1. Calls InitializeApplicantDeposits to create any required deposit/fee records based on the pipeline configuration.

saving — Before every save (create and update):

  1. If linked to a candidate, syncs name, email, phone, and social_media from the candidate record.
  2. If stage_id changed:
    • Updates the pipeline_stages JSON snapshot — marks completed stages, sets the current stage, and sets remaining stages as pending.
    • If the new stage is the final stage in the pipeline, triggers the Hiring Logic: creates a User account, Employee record, Teacher record (if the vacancy title contains "teacher"), assigns the default role, and sends a HiringNotification.
    • Sets applicant status to done (final stage) or progress (intermediate stage).
  3. Always calls StageOrchestrator::enter() after handling stage logic.

saved — After every save:

  1. Calls SyncVacancyState to update the vacancy's recruitment state based on applicant progress.

updated — After an update:

  1. If stage_id changed, dispatches SendStageChangedNotification with the from/to stage names.

deleted — After deletion:

  1. Calls SyncVacancyState to recalculate vacancy state.

ApplicantDocumentObserver — Document Versioning

The ApplicantDocumentObserver manages document deduplication by generating a deterministic hash key:

Explanation:

  1. Documents flagged as is_current = true get a deterministic SHA1 hash based on owner_type|owner_id|document_type_id.
  2. This hash ensures that each owner can only have one "current" document of each type — uploading a new version replaces the previous one.
  3. Documents with is_current = false get current_key = null (archived/version history).

VacancyObserver — Pipeline Setup Automation

The VacancyObserver automates vacancy configuration when a vacancy is created or its pipeline changes:

Explanation:

created — When a new vacancy is created:

  1. Creates a VacancyState record with status pending.
  2. Calls duplicatePipelineSettings() which copies all stages, required documents, and required deposits from the master pipeline into per-vacancy PipelineRequiredItem records. This allows each vacancy to customize its requirements independently.

updated — When a vacancy is updated:

  1. If pipeline_id changed, deletes all old vacancy-specific stages and required items, then re-duplicates from the new pipeline.
  2. Logs a reminder to notify selected applicants.

DFD — Data Flow Diagram

Level 0 — Context Diagram

Level 1 — Applicant Processing


Activity Diagram — Applicant Lifecycle


Database

Key Tables

TableDescription
applicantsTracks candidate through stages — stage_id, status, score, pipeline_stages (JSON snapshot)
candidatesTalent pool — user_id, first_name, last_name, email
talent_interviewsInterview scheduling — scheduled_at, interviewer_id, status
talent_assessmentsTest scores — type (WRITTEN/INTERVIEW/MICRO), score
applicant_documentsFile uploads per stage — asset_id, current_key, status
applicant_depositsFee tracking per stage — amount, status
vacancy_statesVacancy status tracking — status, stage_id
pipeline_required_itemsPolymorphic requirements (docs, deposits) per stage/vacancy

Key Files

FilePurpose
app/Observers/Recruitment/ApplicantObserver.phpFull lifecycle — code gen, stage snapshot, hiring logic, notifications
app/Observers/Recruitment/ApplicantDocumentObserver.phpDocument versioning — SHA1 hash deduplication
app/Observers/Recruitment/VacancyObserver.phpPipeline setup — auto-duplicate stages, docs, deposits to vacancy
app/Jobs/Recruitment/SendStageChangedNotification.phpJob: notify on applicant stage change
app/Services/Recruitment/Deposits/InitializeApplicantDeposits.phpCreate deposit records on applicant creation
app/Services/Recruitment/VacancyState/SyncVacancyState.phpSync vacancy state based on applicants
app/Services/Platform/Pipeline/StageOrchestrator.phpStage entry triggers and contract auto-creation
app/Models/Recruitment/Applicant/Applicant.phpApplicant model — stage tracking, status, scoring
app/Models/Recruitment/Candidate/Candidate.phpCandidate talent pool
app/Models/Recruitment/TalentAssessment/TalentAssessment.phpAssessment scoring
app/Models/Recruitment/TalentInterview/TalentInterview.phpInterview scheduling
app/Models/Platform/Pipeline/Pipeline.phpPipeline definition
app/Models/Platform/Stage/Stage.phpStage definition with config
app/Filament/Resources/Applicants/Applicant CRUD + actions (advance, approve)