Skip to content

Job Board & Stage Types


Creating a Job

Jobs are created via POST /v1/jobs. Each job has a stages[] array, where every element is a fully typed stage config.

Stage Types Available

All 6 stage types are available on every plan (usage limits apply):

KeyDisplay NameTypeQuestion Bank
automated_screeningAutomated Call ScreeningasyncScreeningQuestion
technical_dsaTechnical — DSAasyncDSAProblem
technical_ai_assistedTechnical — AI AssistedasyncScenarioQuestion
ai_conversationalAI ConversationalasyncScenarioQuestion
live_1on1Live 1-on-1 InterviewscheduledInterviewQuestion (private)
culture_fit_hrCulture Fit / HR RoundscheduledInterviewQuestion (private)

The frontend fetches this list from GET /v1/stage-types and never hardcodes it.


Job Creation Flow

  1. Recruiter opens "Create Job" page → frontend calls GET /v1/stage-types
  2. Stage type dropdown populates from API response (all 6 types, no plan filtering)
  3. For each stage added, the correct config panel is rendered based on StageTypeConfig.questionBankConfig.questionType
  4. Recruiter clicks "Create Job" → POST /v1/jobs
  5. API checks org.featureSnapshot.maxActiveJobs → 403 if at limit
  6. API resolves question text → ScreeningQuestion IDs via findOrCreateQuestion()
  7. JobOpening document created with fully typed stage configs

Job Statuses

StatusMeaning
draftNot published — not visible to candidates
openActive — candidates can be invited
closedNo longer accepting new candidates
archivedHistorical record — no new activity

Jobs in open and draft status count toward maxActiveJobs.


Editing a Job

PATCH /v1/jobs/:id updates the job.

Note: syncActivePipelines() — propagating stage name/type changes to active candidate pipelines — is deferred and not yet implemented. Currently, PATCH /v1/jobs/:id saves the job without syncing pipeline stage entries. Planned behaviour when implemented: only pending and unlocked stage entries will be updated; in_progress, completed, expired, declined, and skipped entries will be frozen as historical records.


Job Stats (Denormalized)

Each job carries a stats sub-document updated via atomic $inc:

typescript
stats: {
  totalCandidates: number;   // total pipelines ever created for this job
  activeCandidates: number;  // pipelines with status 'active'
  shortlisted: number;       // pipelines with status 'shortlisted'
  rejected: number;          // pipelines with status 'rejected'
}

Frontend: No Hardcoding

The following must never appear as constants in frontend source code:

What to avoid hardcodingWhere to read it
Stage type names and keysGET /v1/stage-typeskey, displayName
Which fields show for each stage typeStageTypeConfig.schedulingConfig.*
Which tools are enabledStageTypeConfig.toolsConfig.*
Min/max question countsStageTypeConfig.questionBankConfig.minQuestions/maxQuestions
Whether questions are interviewer-onlyStageTypeConfig.questionBankConfig.questionsVisibleTo
Whether to show send-link toggleStageTypeConfig.automationConfig.hasSendLinkToggle
Whether feedback is requiredStageTypeConfig.feedbackConfig.feedbackRequired
Feedback rating criteria and labelsStageTypeConfig.feedbackConfig.ratingCriteria[]

Relevant Files

  • API-honeyhimself/src/controllers/jobOpeningController.ts
  • API-honeyhimself/src/models/JobOpening.ts
  • API-honeyhimself/src/controllers/stageTypeController.ts
  • API-honeyhimself/src/models/StageTypeConfig.ts
  • PeerZoom/src/components/jobs/JobForm.tsx (fetches stage types from API)
  • PeerZoom/src/components/jobs/ScreeningQuestionsConfig.tsx (fetches questions from API)
  • PeerZoom/src/services/stageType.service.ts