Case study · 2025

ScoreResume

AI resume scoring against a specific job description, with an async pipeline so LLM timeouts never fail a request.

Role
Solo founder and engineer
Scope
Built and run solo, with paying users
Platform
Web
paying users, zero paid marketing
25+
organic pageviews
18,000+
p95 & p99 API latency
< 150 ms
free users
300+

01 — Overview

ScoreResume scores a resume against the job it is meant for: ATS readiness, job fit and interview readiness, not a generic grade.

02 — The problem

Generic resume checkers give a generic score. A job seeker needs to know how this resume reads against this job, and an LLM call that times out can't be allowed to fail the request.

03 — Engineering decisions

  1. 01

    LLM calls never fail a request

    Scoring runs as queued jobs on BullMQ and Redis, with exponential backoff and a dead-letter queue, so a slow or failing model is retried in the background instead of erroring in front of the user.

  2. 02

    RAG for job fit

    Resume and job description are chunked and embedded with pgvector, and the relevant context is retrieved for multi-dimensional scoring with LangChain and Gemini.

  3. 03

    Billing that can't double-charge

    DodoPayments subscriptions with webhook signature validation and idempotent payment processing.

  4. 04

    Multi-tenant with paid tiers

    Per-user data isolation in PostgreSQL, with free and paid feature gating.

  5. 05

    Run like production

    Hetzner VPS with CI/CD, Cloudflare in front, Sentry and PostHog for errors and usage.

    99%+ uptime.

04 — Stack

App
Next.js, TypeScript
Data
PostgreSQL, Redis, BullMQ, pgvector
AI
LangChain, Gemini, RAG
Infra
Hetzner, Cloudflare, DodoPayments, Sentry, PostHog