Skip to content

Architecture Overview

Last updated: 2026-02-27

TalentSync is a two-repo monorepo:

RepoStackRole
API-honeyhimself/Express + TypeScript, MongoDB/Mongoose, Firebase Admin, ZodREST API backend
PeerZoom/React + TypeScript, Vite, Axios, shadcn/uiRecruiter + candidate frontend

All routes are mounted under /v1/. The frontend reads VITE_SERVER_URL + '/v1' as the API base (set via VITE_SERVER_URL env var, consumed by auth.service.ts axios instance).


High-Level Entity Relationship

mermaid
erDiagram
    Plan ||--o{ Organization : "subscribed_to"
    Organization ||--o{ User : "has_members"
    Organization ||--o{ JobOpening : "owns"

    User ||--o{ JobOpening : "creates"

    StageTypeConfig ||--o{ JobOpening : "defines_stage_shapes"

    ScreeningQuestion ||--o{ JobOpening : "in_screeningConfig"
    DSAProblem        ||--o{ JobOpening : "in_dsaConfig"
    ScenarioQuestion  ||--o{ JobOpening : "in_aiTechnical_aiConversational"
    InterviewQuestion ||--o{ JobOpening : "in_live1on1_cultureFit"

    JobOpening ||--o{ CandidatePipeline : "tracks_candidates"
    Participant ||--o{ CandidatePipeline : "enrolled_in"

    CandidatePipeline ||--o{ Interview : "has_stage_sessions"
    JobOpening ||--o{ Interview : "conducted_for"
    Participant ||--o{ Interview : "attends"
    User ||--o{ Interview : "hosts"

    ScreeningQuestion ||--o{ Interview : "in_screeningResponses"
    DSAProblem        ||--o{ Interview : "in_dsaSubmissions"
    ScenarioQuestion  ||--o{ Interview : "in_aiResponses"

Core Design Principles

1. Backend Drives the UI

StageTypeConfig is a seeded MongoDB collection that tells the frontend what stage types exist, what tools they enable, and what fields they require. The frontend renders forms dynamically — there is no STAGE_TYPES array, no STAGE_FIELD_CONFIG object, and no hardcoded per-stage conditional logic in frontend code.

2. Per-Stage Polymorphic Configuration

Each stage in a JobOpening.stages[] array carries only the config relevant to its type:

  • automated_screeningscreeningConfig
  • technical_dsadsaConfig
  • technical_ai_assistedaiTechnicalConfig
  • ai_conversationalaiConversationalConfig
  • live_1on1live1on1Config
  • culture_fit_hrcultureFitConfig

Only one config block is populated per stage. All other blocks are absent (not null, not empty).

3. Unified Candidate Pipeline State

CandidatePipeline is the single source of truth for where a candidate stands in a job. One document per (jobOpeningId, participantId) pair. It contains two parallel status views:

  • Internal view — frank evaluation terms (pass, fail, shortlisted, rejected)
  • Candidate-facing view — deliberate, humane language (in_progress, advanced, not_selected)

The projection layer enforces the boundary at every API response.

4. Polymorphic Question Bank

Four separate collections, one per question domain:

CollectionStage TypesDistinctive fields
ScreeningQuestionautomated_screeningcategory, chipId, contentHash (dedup)
DSAProblemtechnical_dsatestCases[{isHidden}], starterCode, timeLimitMs
ScenarioQuestiontechnical_ai_assisted, ai_conversationalevaluationRubric, followUpGuide, scenarioType
InterviewQuestionlive_1on1, culture_fit_hrinterviewerHints, expectedAnswerGuide, questionsVisibleTo: interviewer_only

5. Org-Level Usage Gating

All 6 stage types are available on every plan. Monetization is volume-based:

LimitEnforced at
maxActiveJobsPOST /v1/jobs
maxCandidatesPerJobPOST /v1/interviews (first invite for a candidate)
maxInterviewsPerMonthPOST /v1/interviews

Limits are stored in Organization.featureSnapshot (snapshotted from the Plan doc) for fast reads without joins.

6. Privacy by Design

candidateProjection() strips all recruiter-internal fields before any candidate API response. Candidates see:

  • Their own submitted answers
  • A single candidateAggregateScore (0–100) per completed stage
  • Coarse-grained stage status (candidateStatus)
  • Their own global status (candidateFacingStatus)

Candidates never see: AI scores, AI analysis, recruiter notes, feedback, criteria scores, internal results, or audio recordings.


Twelve Collections at a Glance

CollectionPurpose
PlanSystem-seeded pricing tiers (free / starter / pro / enterprise)
OrganizationRecruiter team, billing unit, featureSnapshot
UserRecruiter accounts (Firebase auth)
ParticipantCandidate identity — recruiter-created, candidate-claimed
StageTypeConfigSystem-seeded — defines all 6 stage types and their UI shapes
ScreeningQuestionQuestion bank for automated screening rounds
DSAProblemCoding problems with hidden test cases for DSA rounds
ScenarioQuestionOpen-ended scenarios for AI-assisted rounds
InterviewQuestionPrivate question bank for live interview rounds
JobOpeningJob listings with typed per-stage configuration
CandidatePipelineSingle source of truth for candidate pipeline state per job
InterviewOne session per stage — holds all runtime data (responses, AI reports, feedback)

Deployment Shape

┌──────────────────────────────────────────────────────────┐
│  PeerZoom (React/Vite — Vercel or similar)               │
│  Recruiter dashboard + candidate-facing public pages      │
│  Public routes:                                          │
│    /candidate/screening (no auth — ?token= query param)  │
│    /candidate/decline/:token  (no auth — decline page)   │
│    /dsa/:token          (no auth — token-gated)          │
│    /ai-session/:token   (no auth — token-gated)          │
│    /lobby/:roomId       (no auth — meeting link)          │
│    /room/:roomId        (no auth — meeting link)          │
└──────────────────────────────────────────────────────────┘
                    │ HTTPS / WebSocket
┌──────────────────────────────────────────────────────────┐
│  API-honeyhimself (Express/TS — Railway or similar)       │
│  All routes under /v1/                                   │
│  Auth: Firebase Admin SDK JWT verification               │
│  Validation: Zod schemas (at controller level)           │
│  ORM: Mongoose                                           │
└──────────────────────────────────────────────────────────┘
         │ Mongoose                    │ Admin SDK
┌────────────────────┐    ┌───────────────────────────┐
│  MongoDB Atlas     │    │  Firebase Auth             │
│  12 collections    │    │  Shared by recruiters      │
│                    │    │  and candidates            │
└────────────────────┘    └───────────────────────────┘

File Conventions

  • Backend models: API-honeyhimself/src/models/
  • Backend controllers: API-honeyhimself/src/controllers/
  • Backend routes: API-honeyhimself/src/routes/ + routes/v1/index.ts (mount point)
  • Frontend services: PeerZoom/src/services/
  • Frontend job components: PeerZoom/src/components/jobs/
  • Path alias @/ maps to src/ in both repos
  • Backend scripts: run with npx tsx src/scripts/foo.ts (uses tsx, not ts-node)