Ryan Alexander Black
← All work

Case study · Flagship build

Live

OCLA — 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
Live at ocla.thefitnessstall.com · login-gated (private)

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.

Skool communitypaid member joinsZapier webhook/api/zapier/skool-joinprovisions 7-day trialcreates trial rowOCLA — Next.js 16 · App Router · Vercel7 surfaces · multi-tenant · AI helper on every pageFoundation BuilderContent PlannerDM SupportKPI TrackerClient HubAd PlannerWebsite GeneratorAI Helper12 AI endpoints · maxDuration 60s · parallel fan-out (Promise.allSettled)Claude Sonnet 4generation + chatUpstash Redis200 req/hr rate limitSupabasePostgres · Auth · RLSAI callsrate limitdata · RLSVercel Cron — dailytrial-pulseResendtrial digest emaildrives trial clock
How the pieces fit — the app, its data, the AI layer, and the community-to-app flow.

Inside the app

Foundation Builder — the 4-module curriculum
Foundation Builder — the 4-module curriculum
Content Planner — weekly posts
Content Planner — weekly posts
DM Support — live AI reply guidance
DM Support — live AI reply guidance
KPI Tracker — outreach + ads funnel
KPI Tracker — outreach + ads funnel
Client Hub — CRM + MRR
Client Hub — CRM + MRR
Ad Planner — Meta campaign copy
Ad Planner — Meta campaign copy

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.

Next.js 16 (App Router)React 19TypeScriptSupabase — Postgres + Auth + RLSClaude Sonnet 4 (Anthropic SDK)Upstash RedisResendVercel — hosting + cronRechartsreact-pdf + docx

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.

01

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.

02

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.

03

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.

04

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.

See other work