Actively Maintained Work

TalentScan

Next.js TypeScript PostgreSQL Aurora Prisma Redis Docker AWS ECS AWS Elasticache

Overview

Reviewing hundreds of resumes against a job description is slow, inconsistent, and easy to get wrong. TalentScan automates the first pass: recruiters paste in a job description, upload resumes in bulk or one at a time, and get back a ranked shortlist with match scores. The platform parses each upload, splits multi-resume PDFs into individual candidate profiles, and runs keyword matching against the JD, with fully adjustable weightings so recruiters can tune how much each skill or requirement matters before re-ranking on the fly. Built to handle real hiring volumes, with Redis caching the hot paths and Aurora PostgreSQL backing the candidate and scoring data.

What I built

  • Batch resume upload with automatic splitting and per-candidate profile creation
  • Job description parser that extracts and weights keywords for matching
  • Configurable weighting UI, recruiters adjust per-keyword importance and scores update live
  • Scored shortlist ranked by match percentage with per-keyword breakdown
  • Redis (Elasticache) caching for JD keyword sets and scoring results
  • Aurora PostgreSQL for candidate, JD, and scoring data with Prisma ORM
  • Deployed on AWS ECS with Docker, backed by Elasticache and Aurora

What I learned

  • Resume parsing strategies, handling varied PDF layouts and multi-resume documents reliably
  • Designing a flexible scoring model where weights are first-class and not baked into the algorithm
  • Using Redis effectively for caching computed scores and invalidating on weight changes
  • Aurora PostgreSQL on AWS, provisioning, connection pooling, and the differences from standard Postgres
  • Building UIs where user-tunable parameters feed back into live results without a full reload

Architecture

flowchart TD
    Recruiter([" Recruiter"])

    subgraph AWS["AWS ECS · Docker"]
        subgraph App["Next.js Application"]
            Upload["Resume Upload
(batch / single)"]
            Parser["Resume Parser
& Splitter"]
            JD["Job Description
Parser"]
            Scorer["Keyword Scoring
Engine"]
            UI["Shortlist UI
(live reranking)"]
        end

        Cache[("Redis
Elasticache")]
        DB[("Aurora PostgreSQL
(Prisma)")]
    end

    Recruiter -->|"upload resumes"| Upload
    Recruiter -->|"paste JD + set weights"| JD
    Upload --> Parser
    Parser -->|"candidate profiles"| DB
    JD -->|"keyword weights"| Cache
    DB --> Scorer
    Cache --> Scorer
    Scorer -->|"scored shortlist"| UI
    Recruiter -->|"adjust weights"| UI
    UI -->|"invalidate + rescore"| Cache