Case Study

Building a Serverless AI Resume Analyzer

How Puter's per-user cost model and client-side PDF processing made it possible to build a fully serverless AI resume scorer — and why getting the prompt calibration right was the hardest engineering problem of the project.

Role

Solo Developer

Timeline

2 weeks

Type

Personal Project

Status

Shipped

Stack

React Router 7 · Puter.js · pdf.js · Zustand

Categories

5 scored

$0

Infrastructure cost

100%

Client-side processing

~5s

End-to-end analysis

Any LLM

Swappable AI model

01

The Problem

The Gap

  • Black-box scoring — Most resume tools give you a number with no explanation of how it was derived
  • False positives — Visually attractive resumes often score high even when ATS parsing would fail
  • Infrastructure cost — Running AI analysis at scale typically requires backend servers, queues, and storage — all expensive
  • Privacy concerns — Uploading a resume to an unknown server raises legitimate data handling questions

The Opportunity

  • Per-user quota — Puter's model means each user's AI usage is charged against their own account — zero marginal cost to the developer
  • Client-side PDF processing — pdf.js renders pages in the browser, so the resume never leaves the user's device
  • Transparent scoring — A well-designed prompt schema can return structured scores with category-level detail
  • Honest calibration — Prompt engineering can enforce realistic score distributions — preventing the inflation that makes most tools useless

02

How It Works

Three services, zero servers. Puter provides auth, file storage, and AI access — all scoped to the authenticated user. The browser handles PDF rendering. The result is a fully functional AI analyzer with no backend to maintain.

Application data flow

01 · Authentication

Puter OAuth

User authenticated — AI and storage quota scoped to their account

02 · User Inputs

Company Name

Job Title

Job Description

CV PDF

03 · Client-side Processing

pdf.js

Parses the PDF in-browser — extracts raw text and renders each page as a PNG at 4× scale. Nothing is uploaded to a server.

04 · State & Persistence

Zustand Store

Puter SDK wrapper — manages auth state, upload flow, and analysis results reactively

05 · AI Analysis

Prompt Builder

Combines TypeScript interface schema + company/role inputs + extracted PDF text into a calibrated system prompt

Puter AI Chat — GPT-5.2

Returns structured JSON matching the injected interface — score, ATS analysis, per-category feedback

Puter

KV Store → History View

Result JSON stored per application — user can browse all past analyses

06 · Output

Results View

Overall score, ATS panel, per-category accordion feedback

Scalability

Each user funds their own usage

Puter gives every authenticated user a free monthly quota — storage, compute, and AI credits. When a user runs an analysis, it draws from their quota, not the developer's.

This means the app scales to any number of users with zero marginal infrastructure cost. The $0/month figure isn't a temporary free tier — it's how the model works by design.

Puter usage dashboard — Free plan, 2.13 MB used, $0.50 AI quota consumed

A user's Puter dashboard after running several analyses — their quota, not yours

03

Prompt Calibration — The Hard Part

ATS Severity Classification

The key insight was building a two-tier severity taxonomy — distinguishing between issues that merely look bad and issues that actually break ATS parsing.

Minor issues — small penalty each

Weak action verbs
Missing keywords
Vague quantification
Overused phrases
Inconsistent tense
Soft skill padding

Major issues — 10–15pt penalty each

Spaced letters — e.g. "J A V A S C R I P T" — ATS reads as unknown characters
Detached dates — Floating in whitespace columns, parsed as unrelated text
Sidebar injection — Two-column layout splits tokens, breaks skill extraction
Garbled text — Decorative fonts or embedded images replacing actual text

Rule

2 or more MAJOR issues → overall score must fall below 50, regardless of content quality.

Score Scale

91–100

Precisely tailored

RESERVED for resumes written for this exact role

81–90

Strong

Well-structured, strong keyword density

66–80

Good

Clear structure, decent keyword match

51–65

Parseable but flawed

ATS can read it, notable issues present

31–50

Multiple problems

Structural failures hurt parsing

0–30

Severely broken

ATS cannot reliably parse

// Injected verbatim into the system prompt

"Do NOT inflate scores.
 A visually attractive resume with broken text extraction
 is still a BAD ATS resume.
 Score 91–100 is RESERVED for resumes precisely
 tailored to this specific job description."

// TypeScript interface injected verbatim as schema documentation

interface AnalysisResult {
  overallScore: number;        // 0–100
  atsCompatibility: { score, issues, tips };
  categories: { toneAndStyle, content, structure, skills };
}

04

Visual Walkthrough

Resumer — Upload form with company, job title, job description, and PDF dropzone
Resumer — Results overview with sticky PDF viewer and score panel

The upload form and the results panel — score breakdown, ATS compatibility, and per-category feedback

Loading experience

Clean UX to keep the user engaged while the scan runs

AI analysis takes ~5 seconds end-to-end. Rather than showing a spinner, the processing state breaks the wait into four visible steps — PDF rendering, text extraction, AI analysis, and result compilation.

A live status message tells the user exactly what's happening at each stage, while the animation keeps the interface feeling alive during the wait.

Magnifying glass scanning animation — used during resume analysis step
Document loading animation — used during text extraction step

Honest feedback

Fair but unsparing when the resume earns it

A score that's always high is useless. The prompt calibration ensures the model penalises real structural problems — spaced letters, detached dates, multi-column layouts — that would genuinely break ATS parsing.

Some categories carry more weight than others — ATS compatibility in particular can override an otherwise decent resume. Every issue flagged comes with a concrete fix.

Resume Review — overall score 44/100 with Tone & Style 72, Content 68, Structure 30, Skills 75
ATS Score 38/100 — Needs Improvement with four actionable issues listed

05

Key Technical Decisions

PDF Processing

Client-side via pdf.js

Privacy was a first-class constraint: the resume should never leave the user's browser. pdf.js renders each page to a canvas at 4× scale, then converts to PNG for AI analysis. This also eliminates a backend upload pipeline entirely.

Tradeoff

Adds bundle weight. Mitigated with dynamic import — pdf.js only loads when the user submits a file.

State Management

Zustand wrapping Puter SDK

Zustand provides a clean, typed reactive interface over Puter's SDK calls. The store handles auth state, upload progress, analysis results, and error states — all with Redux DevTools support for debugging.

Tradeoff

A thin abstraction to maintain if Puter's SDK API changes, but the coupling is intentionally shallow.

AI Response Schema

TypeScript interface injected as prompt documentation

Injecting the TypeScript interface directly into the system prompt reliably constrains the model to return exactly the expected JSON structure. No post-processing or fallback parsing needed.

Tradeoff

More prompt tokens per request, but the consistency benefit far outweighs the marginal cost.

Unique IDs

crypto.randomUUID() for serverless ID generation

With no backend, there's no database sequence or UUID service. crypto.randomUUID() is collision-resistant and available in all modern browsers — sufficient for per-user session and file identification in Puter's KV store.

Tradeoff

None meaningful at this scale.

06

Reflection

What I Learned

The technical implementation took a day. Getting the scoring to behave honestly took the rest of the project.

  • Prompt iteration is engineering — it requires hypotheses, tests, and measurable outcomes, not intuition
  • Client-side processing is underrated — browser APIs are powerful enough for tasks most developers reflexively push to a server
  • Zustand + external SDK pattern is repeatable — clean abstraction over third-party state is worth the extra file

Results

Infrastructure cost

$0 / month

Puter's per-user model means the developer pays nothing at any scale

End-to-end processing

~5 seconds

PDF render + AI analysis + result display from submit to results

Privacy

Zero server exposure

Resume content never leaves the user's browser — processed entirely client-side

Resumer demonstrated that the combination of Puter's platform and modern browser APIs can eliminate entire infrastructure tiers. The project wasn't primarily about the AI feature — it was about proving that tailored prompt engineering, not backend complexity, is what makes AI-powered tools genuinely useful.