// CASE STUDY · RESCUE

How we rescued a Lovable-built fintech MVP and scaled it to 20,000 users.

A founder shipped a working demo in a weekend. Six months later it had real users — and a production codebase that couldn't carry them.

ClientNDA — fintech startup
IndustryFintech · Payments
EngagementRescue Sprint → Embedded Team
Timeline6 weeks to stable v1
StackNext.js · Postgres · AWS
// OUTCOMES
−70%p95 API latency after the hot-path rewrite1,420 ms → 410 ms
20k+Active users supported on the new architecturefrom ~200 concurrent ceiling
0Critical vulnerabilities at handoff14 critical · 0 critical
6 wksFrom audit to a production-ready v1fixed-scope rescue sprint
// THE SITUATION

A demo that worked. A product that didn't.

The founder shipped a fintech MVP over a long weekend with an AI tool. It looked great in the pitch deck — sign up, link an account, run a simulated transfer. Investors liked it. So did the first few hundred users.

Then the curve bent up. A press hit pushed roughly two thousand sign-ups through the door in 48 hours and the app started timing out. Auth tokens leaked into client bundles. A single Postgres instance was doing all the work, including a few queries that didn't have indexes. The founder reached out the same week.

We want to be clear: AI tools are great at producing a demo. A demo is not the same problem as a production system, and treating it like one is how good ideas get hurt. The job in front of us wasn't to start over — it was to keep the product running while turning it into something that could grow.

// WHAT WE FOUND

The audit, before anything else.

We spent the first week reading the codebase, the infra, and a sample of production logs. No commits. The findings came back in a written diagnosis with a severity column the founder could share with their board.

  1. 01API keys and a session signing secret were inlined in the client JS bundle.Critical
  2. 02Auth middleware trusted a header the client could rewrite — full account takeover via a one-line request.Critical
  3. 03Zero automated tests. Every release was a manual click-through of the happy path.Critical
  4. 04N+1 queries on the transaction list — one round-trip per row, no pagination, no indexes.High
  5. 05Client-side state shared the same store as form drafts and auth, with no clear boundaries.High
  6. 06No structured logs, no error tracking, no alerting. Outages were noticed by users first.High
  7. 07Background work running on the request thread — heavy jobs were timing out user actions.Medium
// THE APPROACH

Harden in production. No big-bang rewrite.

The temptation in a project like this is to throw the code out and start clean. We pushed back on that. Users were already in the product, money was already moving, and a rewrite is the slowest way to add risk. Instead we agreed a sequence: stop the bleeding first, build a safety net, then refactor the hot paths under that net.

We worked in short, deployable increments — usually one to three a day — paired with the founder's two engineers so they could keep going after we left. Every change went out behind a feature flag with a documented rollback. Weekly demos in their office. No surprises.

Before

Demo-grade scaffolding

  • · secrets in client bundle
  • · no tests, no CI
  • · single DB, no indexes
  • · request-thread jobs
  • · no error tracking
After

Production-grade backbone

  • · secrets in KMS, rotated
  • · integration + e2e suites
  • · read replicas, indexed queries
  • · queued workers, idempotent
  • · structured logs + alerts
// WHAT WE BUILT

The fixes, in the order they shipped.

  1. Locked down auth and rotated every secret.

    Moved signing keys into AWS KMS, replaced the trusted-header middleware with signed sessions, and forced a full token rotation. Shipped behind a flag on day three.

  2. Added the test harness that should have been there.

    Integration tests around money-movement flows first, then a small Playwright suite on the critical UI paths. CI on every PR, with required green builds for production.

  3. Fixed the data layer.

    Indexed the transaction queries, introduced a read replica for list views, and paginated everything that returned more than a screen of rows. p95 on the busiest endpoint went from 1.4s to 410ms.

  4. Moved heavy work off the request thread.

    Queued the reconciliation and notification jobs through SQS with idempotency keys, retries, and a dead-letter queue. User actions stopped timing out the next morning.

  5. Gave the team eyes on production.

    Structured logs, error tracking, a small set of SLO-based alerts, and an on-call rotation that included us for the first six weeks. The team stopped finding out about outages from Twitter.

  6. Wrote the runbook and handed it back.

    A short, opinionated runbook for the three internal engineers: what to do when an alert fires, how to roll back, how to add a migration safely. We stayed on for two more months as an embedded team while they hired.

// THE OUTCOME

The product the demo was always trying to be.

Six weeks in, the codebase looked like a normal production system: tests, logs, alerts, code review, and a small set of boring decisions written down. The same product, the same UI, the same brand — running on a foundation that could actually carry it.

The platform now serves more than 20,000 active userson the same core architecture, with p95 latency steady around 410 ms and no critical-severity vulnerabilities at handoff. The founder's team has shipped two major features since without us in the room. That's the part we're proudest of.

They came in, read the codebase before saying a word, and shipped the first real fix on day three. Six weeks later we had a product instead of a panic.
Founder & CEOFintech startup · name withheld under NDA
// WHAT WE USED

The stack and the services applied.

Tech stack
Next.js 14TypeScriptNode.jsPostgres 15PrismaAWS · ECSAWS · KMSSQSCloudWatchSentryPlaywrightGitHub ActionsTerraform
// LET'S TALK

Have something that needs the same treatment?

Tell us where you are. We'll tell you the honest path forward — usually within a day.