Case study · Flagship build
LiveOCLA — Online Coach Launch Academy
A complete app that unifies a whole online coaching business — zero to launched.
- Next.js
- Supabase
- Claude API
- Vercel
- ~100 hrs
- Built solo
- 4
- Modules
- 6
- Operating tools
- 12
- AI endpoints
Most online fitness coaches start with no system: no clear niche, no content plan, no repeatable way to find and sign clients. OCLA takes a coach through that whole journey — four guided modules that build their niche, content, offer and outreach from scratch — then hands them the tools to actually run the business day to day. AI helps at every step, and an assistant is one click away on every page. It's a real, live product, not a demo.
Inside the app






The problem
Two hard problems sit on top of each other here. The first is product: a coach's journey from zero to a running business is a dozen connected decisions — niche, content, offer, pricing, outreach, delivery — and most tools only solve one slice. The second is reliability: the moment you put AI on every feature, you inherit its failure modes. Models drift, invent data, and time out. A portfolio demo can hide that; a live app coaches pay for cannot.
The goal was one coherent system that takes a coach all the way through, where the AI is genuinely dependable — and where the business plumbing around it (sign-ups, trials, billing state) holds together against a third-party platform that doesn't give you the hooks you'd want.
Under the hood
How it's actually built. The plain version is above — everything from here down is the technical detail, for anyone who wants to see how the pieces fit.
What it actually does
Seven surfaces. A four-module curriculum that the coach completes in order, then six tools that unlock to run the business — plus an AI helper on every page that knows where the user is and what they've saved.
The curriculum
- Module 1 — Niche & Ideal Clientdefines who they help and the outcome; AI writes a promise statement + deep client insights
- Module 2 — Social & ContentInstagram bio, four content pillars, and a 32-idea content bank
- Module 3 — Offer Creationmaps the client journey, builds program pillars, names it, sets pricing tiers
- Module 4 — DMs & Call Offera call-booking offer + a poll-style cold-DM opener
The tools to run it
- Content Plannerweekly post planning from the content bank — AI writes captions + format-specific content (scripts, carousels, overlays)
- DM Supportreal-time AI guidance through a live DM conversation, two reply options at each step
- KPI Trackerdaily outreach + ad metrics, a booking→taken→converted funnel, rolling rates
- Client Huba light CRM — MRR, min-term alerts, a per-client week-by-week journey tracker
- Ad PlannerMeta ad copy (primary text, talking-head script, B-roll overlays) from the user's own data
- Website Generatorready-to-paste copy for an 8-section sales page, drawn from a saved coach profile
The four engineering problems worth talking about
The interesting work wasn't the screens — it was making a multi-tenant, AI-heavy app behave in production. Four decisions carried most of the weight.
Designing around a platform that won't tell you what happened
The community platform tells the app when someone joins a paid trial — but never tells it when that trial turns into a real subscription, or when someone cancels or a payment fails. So the app had to figure out its own access rules safely.
Sign-ups come from a Skool community, whose Zapier integration exposes only two events — “Answered Membership Questions” and “New Paid Member.” There's no trial-converted, cancellation, or payment-failed event, and Stripe Express was locked. So access can't be read straight from billing.
The answer is a subscription state machine on the approved-emails table — invited → trial → paid → overdue / cancelled / revoked. A “New Paid Member” webhook (/api/zapier/skool-join) opens a 7-day trial row; feature access is gated by trial day (Module 1 from day 1, Module 2 from day 5, the rest on paid); and from day 7 the app infersconversion — Skool would have removed the member if the auto-charge failed, so continued membership is the signal. A daily Vercel cron drives the trial clock, and admin override buttons are the deliberate manual fallback for the states the platform never reports. It's integration architecture designed around real, missing hooks — not the happy path.
Keeping AI dependable in production
Putting AI on every feature means inheriting every way AI goes wrong — it drifts, repeats itself, or times out. The app is built so none of that reaches the user.
Generation is split into small, per-section endpoints (12 in total) rather than one giant call — that keeps each request inside Vercel's limit (every AI route sets maxDuration = 60 and each fetch carries a 60-second AbortSignal.timeout). Where a screen needs many pieces at once — the eight-section website generator, the ad planner — they fan out in parallel with Promise.allSettled, so one failed section never sinks the rest.
The subtle one is drift. When a user regenerates their client insights, the prompt first strips their previous answers out of the context — otherwise the model anchors to the old wording and returns lightly-reworded variations instead of fresh thinking (especially damaging after a user redoes their niche). Every AI endpoint is also rate-limited (200 requests/hour/user via Upstash Redis, failing open in local dev) to keep a runaway loop from burning the API budget.
Every user sees only their own data
It's one app serving many separate coaches. Each only ever sees their own clients, content, and numbers — enforced at the database, not just the screen.
Isolation is enforced with row-level securityin Postgres, so the boundary lives in the database rather than hopeful checks in the UI. Privileged work (admin actions, the cron) runs through a server-only service-role client that's never exposed to the browser. Even the support “log in as this user” feature is done safely — the admin mints a server-side magic link and POSTs the token in the request body (never in a URL that could leak) to land in the user's session.
Built to be edited safely
A tool people use daily has to feel instant and never lose work — even on a flaky connection or a fast double-click.
Edits are optimistic with rollback— the change shows immediately and reverts only if the save fails. Autosave treats local state as the source of truth so a slow response can't clobber newer typing, and a per-resource AbortController cancels an in-flight save when a newer one starts, killing out-of-order races. Schema changes ship as additive, numbered migrations (001–019) so live user data is never reshaped from under them, and finished module work exports to polished PDF and DOCX.
The other half — the community it plugs into
OCLA isn't just the app. About a third of the build (~50 hours) went into the paired Skool community that sells and onboards it — the go-to-market half of the same product. The two are wired together: when someone joins the paid community, Skool fires a Zap that hits /api/zapier/skool-join, which provisions their trial in the app automatically — no manual approval step. A daily trial-pulse cron then emails a digest (via Resend) so onboarding stays on top of where each new member is in their trial. Designing the product and the funnel that feeds it is the whole-system thinking the rest of this portfolio is about.
Why it's built this way
The throughline is probabilistic where it should be, deterministic where it must be. The model writes and reasons; code owns anything where being slightly wrong isn't acceptable — access rules, money state, data isolation.
And nearly every hard decision was designing around a real constraintrather than an ideal one: Skool exposes two events, so the app infers the rest; Vercel caps execution at 60 seconds, so generation is split and parallelised; billing state isn't readable, so a state machine plus manual overrides covers the gap. That's the real work of building software — making the pieces flow together given what the real systems will and won't do.
Where it is now
OCLA is live in production with paying users.Since moving into building AI software full-time I've moved it to maintenance-only — kept running for its users, infrastructure trimmed to lower-cost tiers, fully backed up — and it now serves as the centrepiece of this portfolio. It's the most complete answer I have to “can you build and ship a real, AI-native system end to end?” — so it's the one I point to first.
Want the full walkthrough?
It's a private, login-gated app — but I'll happily give you a live tour and talk through any part of the architecture.

