LLD

AI-Powered Recruitment Automation System

Low-Level Design Document (LLD)

📘 Table of Contents

  1. System Overview
  2. Module Breakdown
  3. API Design
  4. Database Design
  5. Business Workflow
  6. AI Integration Points
  7. System Architecture

1. System Overview

1.1 🎯 Purpose

Automate the recruitment pipeline from resume ingestion to candidate ranking using NLP-based parsing, vector embeddings, and AI-powered re-ranking.


1.2 ⚙️ Key Capabilities

  • Incremental Resume Ingestion: Fetch new resumes from Gmail on schedule
  • Automated Resume Parsing: Extract structured data (skills, experience, education, contact)
  • Semantic Matching: Use embeddings to find similar candidates to job descriptions
  • AI Re-Ranking: Re-rank top candidates using GPT-4o-mini for better precision
  • Dashboard: HR views ranked candidates with explainability

1.3 🧰 Technology Stack

Layer Technology
Frontend React.js + Tailwind CSS
Backend Node.js + Express.js
Database PostgreSQL 15+ with pgvector extension
AI/ML OpenAI GPT-4o-mini
Embeddings OpenAI text-embedding-3-small
Email Integration Gmail API with OAuth 2.0
Scheduler node-cron

2. Module Breakdown

Module 1: Gmail Module

Responsibility: Email integration and resume fetching

Functions:

  • Authenticate with Gmail API using OAuth 2.0
  • Fetch emails with attachments based on filters (date, keywords, labels)
  • Download resume attachments (PDF, DOCX)
  • Track last fetch timestamp for incremental processing

Key Operations:

  • fetchNewEmails(afterDate, filters) → Returns array of email objects with attachments
  • downloadAttachment(messageId, attachmentId) → Returns file buffer
  • getLastFetchTime(jobId) → Returns timestamp of last successful fetch

External Dependencies: Gmail API, Google OAuth 2.0


Module 2: Resume Parser Module

Responsibility: Extract structured data from resume text

Parsing Strategy: Rule-based NLP with regex patterns

Name Extraction: First line heuristics, capitalization patterns
Email Extraction: Regex pattern [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
Phone Extraction: Regex for various formats (+1-XXX-XXX-XXXX, (XXX) XXX-XXXX)
Skills Extraction: Keyword matching against predefined skill database
Experience Parsing: Section detection (keywords: "experience", "work history") + date parsing
Education Parsing: Section detection + degree/institution extraction

Functions:

  • extractText(fileBuffer, format) → Returns plain text from PDF/DOCX
  • parseResume(resumeText) → Returns structured JSON object
  • validateParsedData(data) → Returns boolean + error messages
  • normalizeSkills(skillArray) → Returns deduplicated, lowercase skills

Output Format (JSON):

{
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1-555-0123",
  "skills": ["javascript", "python", "sql"],
  "experience": [
    {
      "title": "Software Engineer",
      "company": "Tech Corp",
      "duration": "2020-2023",
      "description": "Built REST APIs..."
    }
  ],
  "education": [
    {
      "degree": "B.S. Computer Science",
      "institution": "MIT",
      "year": 2018
    }
  ],
  "total_experience_years": 5
}

Alternative AI Approach (Optional Enhancement)

Instead of rule-based parsing, use GPT-4o-mini with structured JSON output. The flow would be: extract plain text -> send it to GPT-4o-mini with a schema-enforced prompt -> receive structured JSON (name, email, phone, skills, experience, education, total years).

Pros:

  • Much higher accuracy across different resume formats and layouts
  • Handles inconsistent structures, missing sections, and varied wording
  • Reduces need for complex regex/heuristics

Cons:

  • Incur API usage costs
  • Slightly higher latency (~2–5 seconds per resume, depending on length)
  • Requires API reliability and internet access

Module 3: Embedding Module

Responsibility: Generate vector embeddings for semantic search

Embedding Strategy:

  • Use OpenAI text-embedding-3-small model (1536 dimensions)
  • Embed full resume text (truncated to 8000 chars if needed)
  • Embed JD text once per job creation
  • Store vectors in PostgreSQL pgvector columns

Functions:

  • generateEmbedding(text) -> Returns 1536-dimensional float array
  • batchGenerateEmbeddings(textArray) -> Returns array of vectors (for efficiency)
  • calculateCosineSimilarity(vec1, vec2) -> Returns similarity score (0-1)

Caching Strategy:

  • Cache JD embeddings in memory (job lifecycle)
  • Resume embeddings stored permanently in database

Module 4: Database Module

Responsibility: Data persistence and vector operations

Core Operations:

  • CRUD for all entities (users, jobs, candidates, communications)
  • Vector similarity search using pgvector
  • Transaction management for atomic operations
  • Query optimization with proper indexing

Key Functions:

  • storeCandidate(candidateData) -> Returns candidateId
  • findSimilarCandidates(jdEmbedding, topK) -> Returns top-K candidate IDs by cosine similarity
  • updateCandidateScore(candidateId, score) -> Updates match score
  • getCandidatesByJob(jobId, filters) -> Returns paginated candidate list

Vector Search Query (Conceptual):

  • Use pgvector's <=> operator for cosine distance
  • Order by 1 - (jd_embedding <=> resume_embedding) for similarity
  • Apply filters (status, score range) after vector search

Module 5: Job Description Module

Responsibility: JD lifecycle management and candidate retrieval

Functions:

  • createJob(jobData) -> Validates input, generates embedding, stores in DB
  • getActiveJobs() -> Returns list of jobs with status='active'
  • findTopCandidates(jobId, topK) -> Queries DB for top-K similar candidates
  • closeJob(jobId) -> Updates status, stops scheduled tasks

JD Processing Flow:

  • HR submits JD text via UI
  • Validate JD (length, required fields)
  • Generate embedding for JD text
  • Store job with embedding in database
  • Schedule resume ingestion task (cron)
  • Return job ID to frontend

Embedding Generation:

  • Extract key requirements from JD text
  • Generate single embedding vector (1536-dim)
  • Store in jobs.jd_embedding column

Module 6: Ranking Module

Responsibility: AI-powered re-ranking of top candidates

Two-Stage Ranking:

Stage 1: Vector Similarity (Fast)

  • Use pgvector to retrieve top-50 candidates by cosine similarity
  • Initial filter based on semantic matching
  • Execution time: <100ms

Stage 2: AI Re-Ranking (Precise)

  • Use GPT-4o-mini to re-rank top-50 -> top-10
  • Provide full context: JD text + parsed resume data
  • AI considers: skill match, experience relevance, education fit
  • Execution time: 2-3 seconds

Functions:

  • getTopKSimilar(jobId, k) -> Returns top-K candidates from vector search
  • reRankWithAI(candidates, jdText) -> Returns re-ranked list with scores and reasoning
  • calculateFinalScore(candidate, job) -> Combines vector similarity + AI score

AI Re-Ranking Prompt Structure:
System: You are an expert technical recruiter evaluating candidate fit.

Input:

  • Job Description: [JD text]
  • Candidates: [Array of parsed resume data]

Task:
Rank these candidates from best to worst fit. For each, provide:

  1. Rank position (1-N)
  2. Fit score (0-1)
  3. Brief reasoning (2-3 sentences)

Consider:

  • Skill alignment with required skills
  • Experience level match
  • Domain relevance
  • Education requirements

Output Format: JSON array ordered by rank

Scoring Algorithm:

  • Initial Vector Similarity: S_vec (from pgvector)
  • AI Re-Ranking Score: S_ai (from GPT-4o-mini)

Final Score: Final Score = 0.4 × S_vec + 0.6 × S_ai

Reasoning: Vector similarity provides broad semantic match, AI re-ranking adds nuanced understanding of requirements.


Module 7: Application Controller

Responsibility: Orchestrate workflow across modules

Core Workflows:

Resume Processing Workflow

  • Trigger: Cron job (every 4 hours)
  • Steps: Fetch emails → Extract text → Parse → Embed → Store

Candidate Ranking Workflow

  • Trigger: HR requests candidates for a job
  • Steps: Vector search → AI re-rank → Return ranked list

Deduplication Workflow

  • Trigger: Before storing new candidate
  • Steps: Hash resume text → Check DB → Skip if exists

Functions:

  • processNewResumes(jobId) -> Orchestrates resume processing
  • getRankedCandidates(jobId) -> Orchestrates ranking workflow
  • handleDuplication(resumeHash) -> Checks and logs duplicates

Error Handling:

  • Retry logic for API failures (3 attempts with exponential backoff)
  • Log all errors with context (job ID, resume ID, error message)
  • Continue processing remaining resumes on individual failures

Module 8: HR UI Module

Responsibility: Provide API endpoints for frontend dashboard

API Endpoints: Detailed in Section 3

Dashboard Views:

  • Job listing with candidate counts
  • Candidate pipeline (New, Contacted, Replied, Interviewed)
  • Candidate detail with parsed data and match score
  • Communication history per candidate