Matthew Whyte
Back to work
2025Solo · Design, Product, Engineering

Resume Builder

A focused, ATS-first resume builder for product managers targeting top companies. Outputs a one-page PDF with a true text layer — no images, no tables, no graphics — so applicant tracking systems parse every word.

Stack
Next.js · Prisma + Postgres · @react-pdf/renderer · Claude API · Vercel
Links
Live demoGitHub

The problem

Most resume builders optimize for "looks pretty." That's the wrong target for PMs applying to Anthropic, Apple, Stripe, or Meta. Those resumes are scanned by an ATS first, a recruiter second, and a hiring manager third — and the prettiest templates (two columns, sidebars, icons, color blocks) are exactly the ones ATS systems fail to parse. PMs end up rewriting from scratch in Google Docs to undo the design. I wanted a builder where the default output is already what a top-company recruiter expects to see.

What I built

A web app where PMs sign in, write their experience once, and export a one-page PDF that's been deliberately stripped to maximize ATS parse rate: black-and-white only, single column, no images, no tables, real text layer. Four templates (Classic Harvard-style, Modern, Compact, Executive) keep the layout choices safe by construction. Sections are PM-tuned — experience, internships, projects, education, skills split into Product / Technical / Tools / Other, plus certifications and awards. An optional AI bullet enhancer uses your own Anthropic API key to rewrite rough notes into metric-driven PM bullets.

Three product decisions

Decision one — ATS-first instead of visually distinctive

I could have built another beautiful resume tool with two-column layouts and personality. I rejected that. The user isn't choosing between my resume and a plain one — they're choosing between getting parsed and getting filtered out before a human sees the file. Every template is single-column, every output is black-and-white, every line of text is a real glyph rather than rendered art. The tradeoff: the output looks intentionally plain. That's the point — the resume is plain so the bullets can do the work.

Decision two — Bring-your-own API key for the AI enhancer

The AI bullet rewriter could have been a paid feature behind a managed API key. I rejected that. Running a backend that proxies Claude calls means I'd need billing, abuse protection, and a paid plan to stay solvent — friction I didn't want on a portfolio project. Users paste their own Anthropic key, it lives in their browser's localStorage, and the cost stays at zero. The tradeoff: a real user has to go get an API key before they can use the best feature. For the PM audience I'm targeting, that's a low bar.

Decision three — PM-tuned sections, not a generic resume schema

Most resume builders give you Experience, Education, Skills, and a freeform "Additional" section. PMs have a more specific shape: internships are their own section early-career, projects matter (especially for PMs pivoting in), and "skills" is really four buckets — product (discovery, prioritization), technical (SQL, APIs), tools (Jira, Figma), and other. I baked those distinctions into the schema instead of leaving them to the user. The tradeoff: the tool is less useful to non-PMs, which is fine. The audience is the constraint, not the surface area.

What I'd do differently

Test against real ATS scanners. I optimized for ATS-safety based on best practices — single column, no tables, real text — but I didn't actually run generated PDFs through Workday, Greenhouse, or Lever to confirm. The hypothesis is sound but unvalidated, and the whole pitch of the product depends on it being true. A v1.1 should pipe five generated resumes through real ATS parsers and publish the parse-rate scores on the landing page.

Make accounts optional, not the default. I assumed PMs iterate on resumes over weeks and want accounts. That's true for some, but a chunk of users would prefer a stateless "fill form, get PDF, leave" path — fewer steps to value, no email required. A stronger v1 would have been localStorage by default with sign-in as an upgrade if you want sync. I added friction before I'd earned it.

Instrument the AI enhancer. The most useful signal of bullet quality is "did the user keep the rewritten version or revert it?" I didn't track that. Without it, I can't iterate on the system prompt — I'm trusting that Claude's output is good rather than measuring it. A simple revert/keep toggle would have given me the feedback loop I needed to actually improve the rewriter over time.