LLD
AI-Powered Recruitment Automation System
Low-Level Design Document (LLD)
📘 Table of Contents
- System Overview
- Module Breakdown
- API Design
- Database Design
- Business Workflow
- AI Integration Points
- 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 attachmentsdownloadAttachment(messageId, attachmentId)→ Returns file buffergetLastFetchTime(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/DOCXparseResume(resumeText)→ Returns structured JSON objectvalidateParsedData(data)→ Returns boolean + error messagesnormalizeSkills(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 arraybatchGenerateEmbeddings(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 candidateIdfindSimilarCandidates(jdEmbedding, topK)-> Returns top-K candidate IDs by cosine similarityupdateCandidateScore(candidateId, score)-> Updates match scoregetCandidatesByJob(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 DBgetActiveJobs()-> Returns list of jobs with status='active'findTopCandidates(jobId, topK)-> Queries DB for top-K similar candidatescloseJob(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_embeddingcolumn
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 searchreRankWithAI(candidates, jdText)-> Returns re-ranked list with scores and reasoningcalculateFinalScore(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:
- Rank position (1-N)
- Fit score (0-1)
- 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 processinggetRankedCandidates(jobId)-> Orchestrates ranking workflowhandleDuplication(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