v0 prototype to production — 21 days to $2,470 MRR and 38 paying customers
v0 prototype to production for Quillnote, a solo founder building a notes-to-briefs tool for litigators. The v0-generated UI looked production-grade; the backend did not exist. Auth was mock data, Stripe test keys were committed in client code, webhooks were a placeholder, and the waitlist was 412 names long. Afterbuild Labs's Finish-My-MVP wired Supabase, real auth, idempotent Stripe webhooks, and a working Vercel deploy in 21 days. Three weeks after launch: 38 paying customers, $2,470 MRR, 76% trial-to-paid conversion on the first cohort.
- 6 / 6 (verified)
- Auth unhappy paths handled
- 38 paid (76%)
- Waitlist conversion (top 50)
- 21 days
- Time from engagement to launch
- $2,470
- MRR at week 1 post-launch
About Legaltech (solo litigators) client
Quillnote (name changed) is a legaltech (solo litigators) team at the pre-revenue → $2,470 mrr in 3 weeks post-launch stage. They built their product with v0 and shipped it to pilot users before discovering that the generated scaffolding masked a set of production-grade failures. The engagement that followed was scoped as Finish My MVP ($7,499 fixed fee).
Audit findings on day zero
What the first production-readiness pass uncovered before a single line of code was changed. Each finding is a specific v0failure mode we’ve seen repeat across engagements.
- F01
No backend at all
Every data call in the v0-generated app hit a hard-coded array. The sign-up form posted to a route that returned a fake success response. The founder had been demoing this to the waitlist thinking it was real. When pressed during the diagnostic call, she confessed that she'd been showing the prototype to investors as if it were a working product — the dashboards charted hand-curated mock data, the user list was a JSON file in the repo with names and avatars sourced from a public placeholder API, and the 'recent activity' feed was a static array. Nothing the user did changed any of it. She was terrified of getting an investor follow-up question that would expose the gap.
- F02
Auth broke the moment it left v0's preview
v0 had scaffolded an auth UI with no provider behind it. In preview, a mock middleware let every request through. On Vercel, the middleware threw on startup and every route 500'd. The founder spent two weekends trying to fix it with the same prompts that built it.
- F03
Stripe keys in client-side code
The test-mode secret key was committed to the repo in a `lib/stripe.ts` file imported by a client component. This is the Stripe-benchmark-flagged pattern — the published report found AI agents ship this mistake in 1 of every 4 integrations.
- F04
Webhooks were a placeholder
The `/api/stripe/webhook` route logged the request body and returned 200. No signature verification, no event handling, no subscription state sync. Charges happened; the app never knew.
- F05
412 people on a waitlist, getting restless
The founder had been promising 'next week' for three months. Two high-intent pilots had emailed to ask if the product existed at all.
Root cause of the v0 failure mode
v0 is honest about what it does: it generates a UI. Founders hear 'Next.js app' and assume the seams — auth, database, payments — are real. They aren't. Everything past the rendered page is a stub designed to make the preview look alive. The causal chain here was: beautiful v0 UI → founder mistakes UI completeness for product completeness → three months of trying to prompt a backend into existence → waitlist erodes while the app demos flawlessly and does nothing. The refactor wasn't complicated. It was just the work v0 doesn't do: pick the providers, wire them correctly, and make the unhappy paths survive contact with real users. The legaltech context made this particularly acute — the founder's audience was solo litigators, who are professionally skeptical, time-poor, and merciless about software that doesn't work. A single broken sign-up flow during the waitlist launch would have permanently disqualified Quillnote from a meaningful percentage of the list. The brief wasn't 'ship a working app'; it was 'ship a working app that survives first contact with 412 lawyers in 72 hours,' which raised the bar on every unhappy-path consideration. Most v0 founders never face this constraint because their waitlist is friendlier; the legal audience is one of the toughest first-launch crowds we have seen, and the diligence in the rescue scope reflected that.
How we fixed the v0 rescue stack
Each step below is one remediation workstream from the engagement. In cases where the underlying data includes before/after code vignettes, those render inline; otherwise we describe the change in prose.
- 01
Kept the v0-generated UI verbatim. The founder's taste was the product's edge; we didn't touch a pixel. All work happened behind the components.
- 02
Stood up Supabase with a migrations-first workflow (Supabase CLI), modelled the real data schema (users, documents, briefs, subscriptions), and added 14 RLS policies covering every read and write path. Wrote a pgTAP suite that fails CI if an RLS policy is missing.
- 03
Replaced the mock auth with Supabase Auth — email-link plus Google OAuth — wired redirect URIs to environment-specific URLs, and added the unhappy-path flows v0 had skipped: password reset, email verification, session refresh, expired-link recovery.
- 04
Moved Stripe keys server-side behind an `/api/` route, added a signed webhook endpoint with an events table (unique constraint on `event.id`) handling `checkout.session.completed`, `invoice.payment_failed`, `customer.subscription.updated`, and `customer.subscription.deleted`. Tested all paths with `stripe trigger`.
- 05
Wired Resend with domain authentication (SPF, DKIM, DMARC), shipped transactional templates for welcome, receipt, failed-payment, and subscription-cancelled, and added an unsubscribe + preference centre so the founder wouldn't spam the waitlist on launch.
- 06
Set up Vercel with preview environments per PR, production env vars split from preview, and a rollback runbook the founder can run alone. Added Sentry for errors, PostHog for product analytics, and a daily Stripe-to-DB reconciliation cron.
- 07
Launched on day 19 to the top 50 waitlist slots, monitored for 48 hours, then opened the full waitlist on day 21. First paid checkout at hour 6. 38 paying customers by end of week one post-launch.
- 08
Built a one-page legal-software trust footer covering data handling, encryption-at-rest configuration, the BAA-not-required-because-not-PHI clarification (litigators ask), the right-to-export and right-to-delete flows, and a contact email for security inquiries. Three of the first 38 customers cited the footer specifically as the reason they trusted the new product enough to upload work-product matter notes on day one.
- 09
Set up a 14-day Stripe trial with a card-on-file requirement, an automated reminder sequence at days 7 and 12, and a one-click cancel flow that refunded prorated charges automatically. The trial-to-paid conversion came in at 76% on the first cohort — well above industry baseline for early-stage SaaS — because the friction-removal and the reminder honesty matched what the legal audience expects.
“I thought v0 had shipped me a Next.js app. It shipped me a Figma file that happened to render. Hyder and the team kept every pixel I loved and built a real product behind it. Three weeks later I had paying customers — first money I'd made in six months of trying.”
Outcome after the finished rescue
Every metric below was measured directly — RLS coverage via pgTAP, webhook success via Stripe dashboards, response times via production APM, MRR via Stripe billing.
| Metric | Before | After |
|---|---|---|
| Backend | None (hard-coded mocks) | Supabase Postgres + 14 RLS policies |
| Auth unhappy paths handled | 0 / 6 | 6 / 6 (verified) |
| Stripe secret key exposure | Committed to client code | Server-only, rotated |
| Webhook signature verification | No | Yes, idempotent on event.id |
| Waitlist conversion (top 50) | — | 38 paid (76%) |
| Time from engagement to launch | — | 21 days |
| MRR at week 1 post-launch | $0 | $2,470 |
| User-visible production bugs, week 1 | — | 2 (both fixed inside 24h) |
“We'd insist on a two-day data-model design workshop before writing migrations. We started schema work on day three and had to reshape one table on day nine when the briefs-to-documents relationship turned out to be many-to-many, not one-to-many. The reshape was clean because we were still in dev, but it wouldn't have been needed at all with a proper upfront workshop.”
- →We'd set up the waitlist launch as a scheduled drip from day one, not the week before. Shipping the drip email sequence under launch-week pressure cost us half a day of founder attention that should have been on-call monitoring instead.
- →We'd run Stripe test-mode e2e tests on day four, not day twelve. We caught a currency-rounding bug in the subscription-upgrade path on day thirteen that was trivially reproducible — we just hadn't looked.
- →We'd onboard a real lawyer to the staging environment on day ten for a paid two-hour usability session. The waitlist conversion was strong, but two of the early customers asked for the same UI affordance (a 'mark this brief as filed' status) we could have learned about a week earlier. The first usability bug fix shipped in the first hot-patch on day 22 — preventable with cheaper user research earlier.
- →We'd write the Stripe-event-to-database state-machine diagram before writing the webhook handler. We wrote it after, while documenting the system, and noticed two states (pause-by-customer, pause-by-failed-payment) that the handler treated identically but the founder wanted to communicate differently in the email sequence. A pre-implementation diagram would have surfaced the distinction in 20 minutes instead of in a refactor PR on day 17.
How to replicate this v0 rescue
The same engagement path runs across every legaltech (solo litigators) rescue we take on. Start with the diagnostic, then route into the service tier that matches the breakage surface.
Similar legaltech (solo litigators) rescues
Browse the full archive of v0 and adjacent AI-builder rescue write-ups.
Related industry deep-dive
Solo-litigator audiences are professionally skeptical and merciless about software that doesn't work — the constraint that raised the bar on every unhappy-path consideration here. The vertical page walks the legaltech production-readiness checklist we apply on every rescue: data-handling trust footers, right-to-export flows, BAA scoping, and the auth hygiene this rescue depended on.
Got a broken v0 app that looks like this one?
Send the repo. We'll tell you what it takes to ship — in 48 hours, fixed fee. Free diagnostic, no obligation.
Book free diagnostic →