TLDR: For a demo, the backend is a liability. Kill it entirely. Hardcode the data, gate it behind a guest toggle, ship.

The Setup

I was racing to get a KOL (key opinion leader, think medical industry influencer) relationship CRM I'd built for a client onto TestFlight (Apple's app beta channel) in time for a real demo.

The app lives on top of Supabase (my Postgres backend).

Everything connects. Everything should be fine, right?

What I Chased First

I did what felt responsible: I hardened the live path.

Fixed the Supabase publishable key format. Made all DB-nullable fields optional so the Swift decoder stopped silently eating records. Added await on server confirmation before dismissing forms so saves actually stuck.

Four commits deep. Real bugs, real fixes.

And still wrong.

The Wall

Here's the thing nobody says out loud: even a bulletproof live backend is the wrong architecture for a demo.

A TestFlight build that requires the demo recipient to have a real account, real data, and a live Supabase connection is a ticking clock.

What happens when the internet is flaky at the conference?

What happens when you hand the phone to someone and their session token is stale?

What happens when there's just nothing in the database yet?

You know what happens. The demo dies. On a blank screen. In front of the exact person you needed to impress.

The Fix

One file: DemoData.swift.

Guest mode. Zero Supabase contact. Hardcoded sample KOLs, hardcoded relationship history, hardcoded activity feeds — all in memory, all instantaneous, all exactly what I wanted them to see.

A single toggle at the login screen: "Continue as Guest."

That's it. No network call. No auth. No failure mode.

I regenerated the Xcode project to include the file, pushed, triggered the Xcode Cloud build, and it was on TestFlight the same afternoon.

Why This Generalizes

I'd used the same instinct on the web side — a real estate analytics demo for an investment client was built as a pure static snapshot: no DB at all.

The pattern is always the same:

  • Gate it explicitly — a "Guest" or "Demo" button, not a hidden URL
  • Hardcode the data — pick the best-looking, most representative snapshot and freeze it
  • Make the demo state visible — the user knows they're in demo mode; no pretending it's live
  • Touch zero network — latency is unpredictable; memory is not

The demo mode isn't a dumbed-down version of the app. It's the most reliable version of the app, by design.

Why This Matters to Me

I spent four commits making the live Supabase path airtight before realizing I was solving the wrong problem.

The backend being correct doesn't matter if the demo context makes it unreachable.

A demo isn't a product review — it's a controlled experience. You own every variable. Take that seriously and eliminate the ones you can't.

P.S. The guest mode commit message I left myself: "zero Supabase contact." That's the spec. Write it on the wall.