DEV Community

Sophie F A
Sophie F A

Posted on

Where AI-Generated Full-Stack Code Silently Rots (and How Templates Cap the Damage)

TL;DR

  • AI-generated full-stack code does not fail on merge. It fails months later, at the seams between subsystems
  • Three recurring rot sites: missing auth boundary tests, decorative RLS policies, and Stripe webhooks that only handle checkout completion
  • The AI writes tests for the code it wrote, never for the gap it introduced
  • Templates cap the damage because their value is debugged code, not written code
  • Safe workflow: template for the seams, AI for the surface area, human-picked failure modes for every new route

Six months of shipping Next.js + Supabase + Stripe apps under a mixed workflow (some human-written, some AI-scaffolded from Claude and Cursor) has surfaced a repeatable pattern. The AI-generated code doesn't fail on merge. It fails in month three. And it fails in a specific place: the seams between subsystems that the AI never wrote a test for, because it never generated the test that would have caught its own gap.

This post is a field report on where the rot happens, and why starting from a template collapses most of the failure surface.

The three places AI-generated code rots

Auth boundary tests are always missing. Every Next.js + Supabase project I've reviewed that was generated top-to-bottom by an AI had tests. They were also generated by the AI. Every test verified that a signed-in user could read their own data. Zero tests verified that an anonymous user got a 401. Zero tests verified that user A couldn't read user B's data by manipulating the URL. The AI wrote the tests it thought about, which was the tests for the code it wrote.

RLS policies are decorative. Related to the above. AI will generate a create table users_data migration and skip enable row level security. If your dev environment uses the Supabase local stack, RLS is off by default on your custom tables. The auth policy is documentation, not enforcement, and the missing test never catches it.

Stripe webhooks fire on the wrong event, then no-op silently. The pattern the AI reaches for is if (event.type === 'checkout.session.completed'). That covers the most common flows and misses subscription upgrades, downgrades, cancellations, and dunning. The webhook is wired, the code is present, the user's subscription state drifts silently over weeks.

Why templates cap the damage

A template is not obsolete because AI can generate code. A template is a codebase that has already been debugged by a human against real production traffic. The value isn't the 200 lines the AI could regenerate in a minute. The value is the hours of debugging those 200 lines that someone already paid.

Concretely, the Applighter Next.js + Stripe + Supabase starter ships with:

  • All migrations enable RLS by default. Skip it explicitly if you don't want it; the default catches you if you forget.
  • A Stripe webhook handler that dispatches on the full event set (customer.subscription.updated, .deleted, invoice.payment_failed, etc.), not just checkout completion.
  • A test suite that verifies auth boundaries (anon requests, cross-user access attempts, expired sessions) before any happy-path tests.

You can still let AI generate the app on top. The template ensures the seams already have the tests the AI won't write for you.

How to use AI on top of a template safely

The workflow that has worked for us:

  1. Start from a template that has the seams solved.
  2. Let AI generate feature code: new routes, new components, new business logic.
  3. Do not let AI generate tests for the seams. It cannot see the failure mode it just introduced.
  4. Human-write a smoke test per new route: anon access, wrong-user access, malformed input. The AI can help you write the assertions, but you should be picking the failure modes.

The rule of thumb: AI generates the code it thought of. Humans think of the code the AI didn't.

Concluding thought

Most of the "AI-generated codebase failure" postmortems I read describe the same shape: everything worked, tests passed, then a specific class of user request revealed data leaking through a policy that was written but not enforced. This is not a Claude problem or a Cursor problem. It is a workflow problem. And the workflow fix is trivially available: start from a codebase where the seams are already solid, and use the AI to fill in the surface area on top.

Applighter's templates exist for this reason.

Where has AI-generated code rotted on you? Drop the failure mode in the comments.

Top comments (0)