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
- 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.
- 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.
- 03
Billing that can't double-charge
DodoPayments subscriptions with webhook signature validation and idempotent payment processing.
- 04
Multi-tenant with paid tiers
Per-user data isolation in PostgreSQL, with free and paid feature gating.
- 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