Skip to content

StageTypeConfig

This is the key to removing all hardcoding from the frontend.

StageTypeConfig is a system-seeded collection that defines all 6 stage types. The API exposes GET /v1/stage-types (returns all active types — no plan filtering) and the frontend renders all forms dynamically from this data.


Schema

typescript
interface IStageTypeConfig {
  _id: ObjectId;
  key: StageTypeKey;       // enum — see below
  displayName: string;     // e.g. "Automated Call Screening"
  description: string;
  icon: string;            // icon name for frontend

  // No plan gating on stage types — all types available on all plans.
  // Usage limits on Plan/Organization handle monetization.

  // Scheduling shape
  schedulingConfig: {
    type: 'async' | 'scheduled';
    requiresStartTime: boolean;
    requiresEndTime: boolean;
    hasExpiryDeadline: boolean;
    defaultDurationMinutes?: number;
  };

  // Which tools are enabled in the interview session
  toolsConfig: {
    whiteboard: boolean;
    ide: boolean;
    screenShare: boolean;
    audio: boolean;
    video: boolean;
    aiChatbot: boolean;
    webcamProctoring: boolean;
    voiceInterface: boolean;
  };

  // What question bank type this stage uses
  questionBankConfig: {
    questionType: QuestionType | null;  // null = no question bank (e.g. basic 1-on-1)
    minQuestions: number;
    maxQuestions: number;
    questionsVisibleTo: 'both' | 'interviewer_only';
  };

  // Automation / AI behavior
  automationConfig: {
    hasAiInterviewer: boolean;
    aiInterviewerMode: 'none' | 'qa_bot' | 'conversational' | 'coding_evaluator';
    hasSendLinkToggle: boolean;   // "send automated link vs. notify only"
  };

  // What feedback schema to apply post-stage
  feedbackConfig: {
    feedbackRequired: boolean;
    ratingCriteria: {
      key: string;
      label: string;
      maxScore: number;
    }[];
  };

  // When does a stage mark itself complete?
  // 'manual'              — recruiter always marks completion + unlocks next stage
  // 'auto_on_submission'  — stage auto-marks 'completed' once candidate submits.
  //                         Does NOT auto-unlock the next stage.
  // 'auto_on_deadline'    — stage is auto-marked 'expired' once deadline passes.
  progressionTrigger: 'manual' | 'auto_on_submission' | 'auto_on_deadline';

  order: number;     // display order in dropdowns
  isActive: boolean;
}

type StageTypeKey =
  | 'automated_screening'
  | 'technical_dsa'
  | 'technical_ai_assisted'
  | 'ai_conversational'
  | 'live_1on1'
  | 'culture_fit_hr';

type QuestionType = 'screening' | 'dsa' | 'scenario' | 'behavioral';

Indexes:

  • { key: 1 } — unique
  • { isActive: 1, order: 1 }

All 6 Stage Types

1. automated_screening

FieldValue
displayNameAutomated Call Screening
schedulingConfig.typeasync
requiresStartTimefalse
hasExpiryDeadlinefalse
toolsConfigvoiceInterface: true, all others false
questionBankConfig.questionTypescreening
minQuestions / maxQuestions2 / 10
questionsVisibleToboth
automationConfig.hasAiInterviewertrue
aiInterviewerModeqa_bot
hasSendLinkToggletrue
feedbackRequiredfalse
progressionTriggerauto_on_submission

2. technical_dsa

FieldValue
displayNameTechnical — DSA
schedulingConfig.typeasync
hasExpiryDeadlinetrue
toolsConfigide: true, webcamProctoring: true, aiChatbot: true
questionBankConfig.questionTypedsa
minQuestions / maxQuestions1 / 5
automationConfig.aiInterviewerModecoding_evaluator
feedbackRequiredfalse
progressionTriggerauto_on_deadline

3. technical_ai_assisted

FieldValue
displayNameTechnical — AI Assisted
schedulingConfig.typeasync
hasExpiryDeadlinetrue
toolsConfigwhiteboard: true, ide: true, audio: true, video: true, aiChatbot: true
questionBankConfig.questionTypescenario
minQuestions / maxQuestions1 / 3
automationConfig.hasAiInterviewertrue
aiInterviewerModeconversational
feedbackRequiredfalse
progressionTriggerauto_on_submission

4. ai_conversational

FieldValue
displayNameAI Conversational
schedulingConfig.typeasync
toolsConfigvoiceInterface: true, audio: true
questionBankConfig.questionTypescenario
automationConfig.hasAiInterviewertrue
aiInterviewerModeconversational
feedbackRequiredfalse
progressionTriggerauto_on_submission

5. live_1on1

FieldValue
displayNameLive 1-on-1 Interview
schedulingConfig.typescheduled
requiresStartTimetrue
requiresEndTimetrue
defaultDurationMinutes60
toolsConfigwhiteboard: true, ide: true, screenShare: true, audio: true, video: true, aiChatbot: true
questionBankConfig.questionTypebehavioral
minQuestions / maxQuestions0 / 30
questionsVisibleTointerviewer_only
automationConfig.hasAiInterviewerfalse
feedbackRequiredtrue
ratingCriteriaTechnical Depth, Problem Solving, Communication, Culture Fit (all max 5)
progressionTriggermanual

6. culture_fit_hr

FieldValue
displayNameCulture Fit / HR Round
schedulingConfig.typescheduled
requiresStartTimetrue
defaultDurationMinutes45
toolsConfigaudio: true, video: true
questionBankConfig.questionTypebehavioral
questionsVisibleTointerviewer_only
feedbackRequiredtrue
ratingCriteriaCommunication, Culture Fit, Motivation (all max 5)
progressionTriggermanual

Seed Script

src/scripts/seedStageTypes.ts — run via npm run seed:stage-types


What the Frontend Does with This Data

The frontend calls GET /v1/stage-types on app load (or job creation page mount) and caches the result in a React Query key or Context. It then uses the StageTypeConfig fields to:

StageTypeConfig fieldFrontend behavior
key, displayNameStage type dropdown options
schedulingConfig.requiresStartTimeShow/hide date + time pickers in schedule form
schedulingConfig.hasExpiryDeadlineShow/hide expiry field
schedulingConfig.type === 'async'Hide date/time pickers entirely for async stages
questionBankConfig.questionTypeWhich question picker panel to show
questionBankConfig.minQuestionsValidation hint ("min X questions required")
questionBankConfig.questionsVisibleTo === 'interviewer_only'Show "interviewer only" notice
automationConfig.hasSendLinkToggleShow "send automated link" toggle
feedbackConfig.feedbackRequiredShow "Feedback required" badge
feedbackConfig.ratingCriteria[]Render feedback form with dynamic criteria fields
toolsConfig.*Which tool panels to render in interview room

No hardcoding

The frontend must never have if (stageTypeKey === 'live_1on1') { showDatePicker() } style logic. All conditional rendering reads from the StageTypeConfig fields listed above.