Skip to content

Phase 0 — Foundation: Schema Rebuild & Seed Infrastructure

Goal: Replace existing models with the new schema. No user-visible features change. Existing functionality (anonymous meetings, auth, basic job CRUD) continues to work.


0.1 Backend — Delete Old Models, Create New Ones

Delete

  • src/models/Question.ts — replaced by ScreeningQuestion, DSAProblem, ScenarioQuestion, InterviewQuestion
  • Drop Question collection reference from jobOpeningController.ts (findOrCreateQuestion import)
  • Remove STAGE_TYPES string-comparison validation from jobOpeningController.ts

Create / Rewrite Models

FileActionNotes
src/models/Plan.tsCreateSee DB Design §Plan
src/models/Organization.tsCreateReplaces User.organizationName
src/models/User.tsRewriteRemove organizationName. Add organizationId: ObjectId
src/models/Participant.tsRewriteAdd authId? (sparse unique), userId?, preferences, stats sub-doc
src/models/StageTypeConfig.tsCreateDrives all frontend dropdowns
src/models/ScreeningQuestion.tsCreateNear-clone of old Question.ts + organizationId, tags
src/models/DSAProblem.tsCreateStub — not used until Phase 3
src/models/ScenarioQuestion.tsCreateStub — not used until Phase 4
src/models/InterviewQuestion.tsCreateUsed in Phase 1B (create now, use later)
src/models/JobOpening.tsRewriteReplace stages[].type (string) with stageTypeKey. Polymorphic stage configs. Add organizationId. Add stats sub-doc.
src/models/CandidatePipeline.tsCreateDual-status, stageProgression[], jobSnapshot
src/models/Interview.tsRewriteReplace isAutomated boolean with stageTypeKey. Add candidatePipelineId, stageId, organizationId, stageData polymorphic sub-doc

Auth Middleware Update

src/middleware/authMiddleware.ts: after resolving req.user from Firebase UID, also attach req.organizationId:

typescript
const org = await Organization.findOne({ 'members.userId': req.user._id });
req.organizationId = org?._id;

0.2 Backend — Seed Scripts

ScriptPurpose
src/scripts/seedPlans.tsInsert 4 Plan docs
src/scripts/seedStageTypes.tsInsert 6 StageTypeConfig docs
src/scripts/seedScreeningQuestions.tsReplace seedQuestions.ts — inserts 22 system questions
src/scripts/seedDevOrg.tsDev-only — create org for honey.singhroi@gmail.com (requires plans seeded first)
src/scripts/seedInterviewQuestions.ts~30 InterviewQuestion docs — deferred to Phase 1B, NOT in seed:all
json
"seed:plans": "npx tsx src/scripts/seedPlans.ts",
"seed:stage-types": "npx tsx src/scripts/seedStageTypes.ts",
"seed:screening-questions": "npx tsx src/scripts/seedScreeningQuestions.ts",
"seed:dev-org": "npx tsx src/scripts/seedDevOrg.ts",
"seed:all": "npx tsx src/scripts/seedAll.ts",
"seed:interview-questions": "npx tsx src/scripts/seedInterviewQuestions.ts"

seed:all runs via a master seedAll.ts script in dependency order: plans → stageTypes → screeningQuestions → devOrg.


0.3 Backend — StageTypeConfig API

GET /v1/stage-types
  • Auth: None (public endpoint)
  • Logic: StageTypeConfig.find({ isActive: true }).sort({ order: 1 })
  • Response: Array of full IStageTypeConfig documents

This is the single source of truth the frontend uses to render job creation and interview scheduling forms.


0.4 Backend — Organization Bootstrapping

For Phase 0, auto-create an Organization for every new recruiter who signs up:

typescript
// On recruiter registration:
const org = await Organization.create({
  name: user.name + "'s Workspace",
  planKey: 'free',
  featureSnapshot: computeFromPlan('free'),
  members: [{ userId: user._id, role: 'admin', joinedAt: new Date() }],
  billingEmail: user.email,
  isActive: true,
});
await User.findByIdAndUpdate(user._id, { organizationId: org._id });

0.5 Frontend — Remove All Hardcoded Stage Configs

FileChange
src/components/jobs/JobForm.tsxRemove STAGE_TYPES constant. On mount, call GET /v1/stage-types. Render stage type dropdown from API response.
src/components/interviews/ScheduleInterviewForm.tsxRemove STAGE_FIELD_CONFIG constant. Determine which fields to show from the selected stage's StageTypeConfig.schedulingConfig.
src/components/jobs/ScreeningQuestionsConfig.tsxKeep as-is (already fetches from API). Wire to new GET /v1/screening-questions endpoint.

Cache stage-types in a Context or React Query key — it doesn't change between org plan changes.


0.6 Frontend — stageType.service.ts

typescript
// src/services/stageType.service.ts
export const stageTypeApi = {
  getAll: () => axiosInstance.get<IStageTypeConfig[]>('/stage-types'),
};

Phase 0 — Acceptance Criteria

  • [ ] npm run seed:all runs cleanly with no errors
  • [ ] GET /v1/stage-types returns all 6 stage type documents regardless of plan
  • [ ] POST /v1/jobs accepts stageTypeKey (not free-text type) in each stage
  • [ ] Job creation returns 403 when org has reached featureSnapshot.maxActiveJobs limit
  • [ ] JobForm dropdown populates from API — no hardcoded STAGE_TYPES array remains in frontend
  • [ ] Existing anonymous meeting flow (/lobby/:roomId, /room/:roomId) unaffected