An AI resume builder with an LLM ATS-scoring engine that gives section-level feedback, pixel-perfect PDF export, OAuth and payments. One codebase serving two domains, with a full SEO engine underneath.
Most resumes die inside applicant tracking systems before a human ever reads them, and most resume tools only care about how the page looks. I wanted a builder that treats the ATS as a first-class audience: score the resume the way a parser sees it, tell the user exactly which section is weak and why, then let an LLM rewrite it with them.
It also had to work as a product for the Indian market ("banao" is Hindi for "make it"), which meant Razorpay payments, Google sign-in, and PDFs that come out identical to the on-screen preview every single time.
Structured editor over a JSON resume model with template rendering, so content and design stay cleanly separated.
Scores the resume and returns section-level feedback: which parts an ATS parses badly, which bullets are weak, and what to fix first.
One-click LLM rewriting of bullets and summaries, wired through an Anthropic-format endpoint with the raw resume as grounding context.
Puppeteer with @sparticuz/chromium running inside Vercel functions, producing pixel-perfect PDFs of the exact preview markup.
Auth.js v5 with Google OAuth plus email flows, and Razorpay for paid features. Verification and forgot-password emails via SMTP.
Server-component metadata, JSON-LD (Organization, WebSite, SoftwareApplication, FAQ), a 21-URL sitemap, 8 long-tail guides, and Search Console + Bing verification.
Everything runs inside one Next.js 16 app on Vercel: server components for SEO-critical pages, API routes for the AI and PDF services, Prisma over Postgres for persistence. Two domains point at the same deployment, with one canonical auth host so OAuth cookies never split across domains.
Stack: Next.js 16 (Turbopack), React, TypeScript, Prisma, PostgreSQL, Auth.js v5 (Google OAuth), Razorpay, Puppeteer + @sparticuz/chromium, DeepSeek LLM API, nodemailer, Vercel, GA4 + Search Console + Bing.
After the rebrand the app served on both the old domain and resumebanao.com, but the auth host was still pinned to the old one. Logging in from the new domain built sign-in and callback URLs on the other domain, CSRF and state cookies got lost across origins, and every login ended in error=Configuration. The fix was to make one domain the canonical auth host: repoint NEXTAUTH_URL, add the matching Google redirect URI, and let the other domain funnel into it. Cross-domain auth is a cookie problem before it is a code problem.
The ATS engine runs on DeepSeek's reasoning model, and reasoning models put a thinking block first in Anthropic-format responses. My parser read content[0].text, which was the hidden reasoning slot, so users got empty feedback with no error anywhere. The fix: find the first block with type:"text" instead of trusting position. Provider response shapes are part of your contract; test them per model, not per API.
Full Chrome does not fit in a Vercel function, so PDF export runs @sparticuz/chromium, a trimmed headless build, against the same markup as the live preview. Fonts, page sizing and cold-start behavior all needed tuning so the downloaded PDF matches the on-screen resume exactly, every time, within serverless memory and time limits.
The product started as ResumeKraft, and unsaved work lived in the browser under resumekraft_* localStorage keys. A clean rename would have silently wiped users' drafts. So the brand changed across 112 strings, layouts, legal pages and emails, while the storage keys deliberately stayed on the old names. Users saw a new product and kept every byte of their data.
The next/og ImageResponse route worked locally and returned an empty file on Vercel, which meant every social share card was blank. Rather than fight the edge runtime, I generated the OG image once, shipped it as a static PNG, and referenced it from metadata. Boring beats clever when the clever path fails silently.