Skip to content
All articles

From AI prototype to production: the eight layers I add, in order

App builders like Lovable, Bolt or v0 get you a working product in days. Then real customers, payments and personal data arrive, and the prototype starts to feel fragile: a small change breaks checkout, nobody knows whether the backups work, and the AI that built it keeps rewriting things. The usual advice is a rewrite. I've taken two such prototypes to production without one. These are the layers I add, in this order, and why the order matters.

Updated 11 min read

1. Take stock in one afternoon

Export the code to GitHub if it isn't there yet, and write down what the app actually does: sign-up and login, payments, emails, file uploads, admin screens, scheduled jobs, AI calls. Mark everything that touches money or personal data. That list is your risk map, and it is usually shorter and clearer than people fear.

Then check where the secrets live. In generated apps they often end up in the frontend code, a shared .env file or a chat history with the AI builder. Look at the database too: which tables exist, which have no access policies, which columns hold personal data. The readiness check below turns this afternoon into a score, so you can see at a glance where to start and show progress later.

Tip from practice

Search the built JavaScript bundle for your service-role key or payment secret. If it's there, rotate it today, before anything else on this list.

Interactive

Is your AI-built app ready for production?

Tick what is already true. The gaps that are left are your to-do list, in order.

0/12 ready

Your next three steps

  1. Code lives in Git; changes go through pull requests
  2. No secret keys in the frontend; server keys only on the server
  3. Row-level security (or equivalent) on every table
Get a production-readiness review
All calculators and checklists

2. Separate staging and production

Two environments with their own database, their own keys and their own third-party accounts in test mode. Every change goes through staging first, database migrations included, and nothing reaches production that hasn't run there. With Supabase, a second project or branching gives you a staging database; on Vercel, preview deployments give every pull request its own URL to click through.

This single step removes most of the 'it broke on the live site' moments, because the AI builder and the developers now have a place to be wrong safely. Keep staging close to production: same configuration, same extensions, realistic but anonymized data. A staging environment that drifts becomes a place where everything works and nothing proves anything. The Supabase production checklist is a good companion here: it walks through the settings that differ between a hobby project and a live one, from network restrictions to email providers.

From prototype to production: every change goes through Git, CI and staging; backups prove themselves nightly; synthetic checks watch what customers do.
Delivery architecture from AI prototype to production: an AI app builder pushes to GitHub, CI runs tests and a migration dry run, changes go to staging and then production on Vercel with Supabase and row-level security, secrets come via OIDC, backups go to object storage with a nightly restore test, and synthetic checks monitor the live site.

3. Lock down who can read what

Generated code often trusts the browser: the frontend hides a button and assumes that's security. Production needs the database to enforce it, because anyone can call your API without your frontend. Turn on row-level security on every table, write policies per role, and repeat the critical checks in server-side functions. Broken access control has topped the OWASP Top 10 for years, and AI-built apps are no exception.

Then write one test per role that tries to read and write data it shouldn't: another organisation's invoices, an admin setting, a deleted user's records. These tests are cheap to write and priceless when the AI changes a policy without telling you. In one platform this meant policies on every table and a test suite that grew past a thousand files, and that suite is what lets the team keep shipping fast.

sql
-- Members only see invoices of their own organisation
alter table invoices enable row level security;

create policy "members read own org invoices"
  on invoices for select
  using (
    org_id in (
      select org_id from memberships
      where user_id = auth.uid()
    )
  );

Tip from practice

A policy you haven't tested is a guess. In your test suite, log in as each role and try to read another organisation's data; the test passes only if the database says no.

Advanced Row Level Security (RLS) Policies // Authorization Deep Dive, Supabase (YouTube). Loads from YouTube only after you click.

4. Backups you have restored

The hosting provider's backups are a start, not a plan. If the account is locked, the region has an outage or someone deletes the project, those backups go with it. Add encrypted dumps on a schedule, stored with a different provider, and restore one into a separate project every night with a check that the row counts match. Uploaded files need the same treatment: mirror them to a second object store.

The reliability pillars of the Azure and AWS Well-Architected Frameworks both ask the same uncomfortable question: when did you last test a restore? In the production platforms I run, the restore test runs every night, and it is the only reason I can say the backups work. A backup you have never restored is a hope, not a plan, and you don't want to find that out during an incident.

bash
# Nightly: dump, encrypt, ship to another provider, prove it restores
pg_dump "$PROD_DB_URL" --format=custom --file=prod.dump
age -r "$BACKUP_PUBKEY" -o prod.dump.age prod.dump
aws s3 cp prod.dump.age "s3://backups-offsite/$(date +%F)/" \
  --endpoint-url "$OFFSITE_S3_ENDPOINT"
pg_restore --clean --if-exists --no-owner -d "$RESTORE_TEST_DB_URL" prod.dump
psql "$RESTORE_TEST_DB_URL" -c "select count(*) from public.bookings;"

5. A release pipeline that can say no

Pull requests only, no direct pushes to main, not even for the AI. CI runs type checks, linting with a baseline that may only improve, unit tests, and a dry run of database migrations against staging before anything merges. A migration that fails on staging at 3 p.m. is a learning; the same migration failing on production at 3 a.m. is an incident.

After the merge, deploy only what changed and run a smoke test against the live site: can someone sign up, log in and reach checkout? If not, roll back automatically or with one click. Small, reversible steps add up faster than big careful ones: one platform shipped 3,025 merged pull requests in ten months this way, and the pipeline is what made that pace safe.

yaml
# .github/workflows/ci.yml (excerpt)
on: pull_request
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - uses: supabase/setup-cli@v1
      - run: npm ci
      - run: npm run typecheck && npm run lint && npm test
      - name: Migration dry run against staging
        run: supabase db push --dry-run --db-url "$STAGING_DB_URL"
        env:
          STAGING_DB_URL: ${{ secrets.STAGING_DB_URL }}

6. Monitor what customers actually do

CPU graphs don't tell you that nobody could book since lunch. The Google SRE book puts it simply: monitor the symptoms users feel, not just the causes. Add outside-in checks on the journeys that matter, sign-up, checkout and booking, every few minutes from outside your hosting, so you hear about a broken flow before a customer writes to you.

Then watch business states, not just technical ones. 'Payment succeeded but no booking was created' and 'no bookings in six hours on a weekday' are the alerts that catch the expensive bugs. On one platform that meant hourly probes on the booking funnel, a daily synthetic payment and a booking-drought alert. Alert on state changes only, open and resolved, so people keep reading the alerts instead of muting the channel.

Tip from practice

Run one synthetic payment a day through the real checkout in test mode. It catches broken webhooks long before a customer does.

7. Secrets and access without long-lived keys

Move secrets out of the code, out of chat histories and off people's laptops. Each environment gets its own secrets in the platform's secret store. CI authenticates to your cloud with OpenID Connect instead of stored keys, so there is no long-lived credential in GitHub that could leak. Service-role keys stay on the server and never reach the browser.

Access for people follows the same idea. Everyone gets their own account with the least rights they need, admins use multi-factor authentication, and access is removed the day someone leaves. Write it down in a one-page access matrix: who can deploy, who can read production data, who can change billing. It takes an hour, and it answers the first questions of every customer security questionnaire you'll ever receive. Review it every quarter; access that nobody looks at only ever grows.

8. Guardrails for the AI that keeps building

The coding agent that built the prototype will keep changing it, so give it rules, the same way you would onboard a new developer. A written instruction file in the repository says what it may and may not touch, which commands it must run before a pull request, and which areas always need a human: login, payments, deleting data, access policies.

Keep its pull requests small, and make it prove its work. A real-browser check of the main journeys before each release, a screenshot or test result in every pull request that changes a user flow, and a human approval for the sensitive areas. The agent keeps its speed; the pipeline, the tests and the review keep production safe. That combination is the whole point: you get the pace of an AI-built product with the reliability customers expect from a real one.

Tip from practice

Make the agent prove it: no pull request that touches a user journey merges without a browser test result or a screenshot attached.

Takeaway

Keep the speed of the prototype and add the safety of production in layers. You don't need a rewrite; you need these eight steps, in this order.

More articles

    Get in touch

    Tell me what you're building. I'll reply within 1–2 business days.

    Dominik Heinrich
    Company
    MADO Consulting

    Available worldwide, remote. On-site on request, depending on the country.

    I reply within 1–2 business days. Free slots: see the calendar

    Opens Calendly's booking calendar here. Loading it sends data to Calendly (see Impressum).