← All work

AI Rescue · Entrepreneur · 2025

Stitchwork

A two-sided marketplace for custom tailoring, built to an impressive demo with AI — and already taking real payments it wasn't ready to handle.

  • Next.js
  • PostgreSQL
  • Stripe
  • Vercel
$0
in mispaid payouts since the ledger rewrite
11 days
to a deploy the founder could safely change on her own
2
security issues found and closed before public launch

What we inherited

The founder had shipped a genuinely impressive demo: tailors could list services, customers could book and pay, money moved. She had raised a small pre-seed round on it. The problem was that it was already taking real money from real people, and the payment logic had been assembled across a dozen AI sessions with no consistent model of who was owed what.

What was broken

  • Payouts calculated from the order row at read time

    Change a price or refund an order and historical payouts silently changed with it. There was no durable record of what had actually been owed at the time.

  • Webhooks with no idempotency

    Payment provider retries are normal and expected behavior. Here, every retry created a duplicate payout record.

  • A server-side secret key inlined into client code

    It had been moved into a component during one AI session to make something work, and never moved back.

  • Three different ways to do the same thing

    Sessions spread over weeks left three data-fetching patterns and two auth patterns in one codebase. Each session had reinvented the conventions of the last, because it couldn't see them.

What we fixed

  1. 1

    Built an append-only ledger

    Money events are now recorded as immutable entries. Balances are derived from them, never edited in place. A past payout cannot change retroactively, which is the property the whole business rests on.

  2. 2

    Made every webhook idempotent

    Keyed on the provider's event ID, with a test that replays the same event twenty times and asserts exactly one payout results.

  3. 3

    Rotated the exposed key and moved all secrets server-side

    Plus a CI check that fails the build if a secret-shaped string appears in client-side code again.

  4. 4

    Picked one convention and converted the codebase to it

    Then documented it in the repository, so the next AI session — or the next developer — extends the existing pattern instead of inventing a fourth one.

Why AI code drifts

The pattern in this codebase wasn’t carelessness. It was structural, and it’s worth understanding if you’re building this way.

An AI session can only act on what it can see. Start a fresh session on a codebase with no documented conventions and no obvious structure, and the model will do something reasonable — but “reasonable” chosen independently, twelve times, produces twelve local optima that don’t compose. That’s how one application ends up with three data-fetching patterns, each of which works.

The fix isn’t to stop using AI. The founder is still building with it, faster than before. The fix was to give the codebase a shape that survives between sessions: documented conventions, a test suite that fails loudly when a pattern is violated, and clear module boundaries so a session only needs to hold one part in context at a time.

Good structure makes AI assistance dramatically more effective. It’s the same property that makes a codebase easy for a new human developer to join.

“They found a payments bug in the first afternoon that would have taken me six months and a lot of angry tailors to find on my own.”

[Client name], Founder, Stitchwork

Got something that looks like this?

Thirty minutes, no pitch. We'll tell you what it would actually take.

Book a free 30-min call

Rather not book a time? Send a message instead.