Skip to main content
Fit4Life OS is a single Next.js application that serves several distinct experiences from one codebase and one database. This page is the maintainer’s map of how the pieces fit together.

One app, several experiences

The mock /app demo and the pitch decks are intentionally separate from /live. Only /live and /ops touch real customer PII, and only they are behind the auth gate.

Stack

  • Next.js 16 (App Router, React 19, Turbopack). Dynamic route params are async (params: Promise<{ id }>). See AGENTS.md, this Next.js has breaking changes vs. older versions.
  • Tailwind CSS v4 (@theme tokens in src/app/globals.css), TypeScript strict, @/*src/*.
  • Neon Postgres (@neondatabase/serverless), the source of truth for /live.
  • Upstash Redis (REST), SMS conversation store + automation flags; falls back to an in-memory Map when unconfigured.
  • Anthropic Claude: the SMS bot brain and the in-OS assistant.
  • Twilio: inbound/outbound SMS, routed through an A2P 10DLC Messaging Service.
  • Hosted on Vercel (auto-deploy from master).

The server-only boundary

Everything under src/lib/server/** is marked import "server-only" and must never be imported from a client component. Secrets are read only through src/lib/server/env.ts. Pure, client-safe analytics live in src/lib/live-data/compute.ts; the DB loaders live in src/lib/live-data/index.ts (React cache()’d, server-only).

Request flows

1

Inbound SMS

Twilio POSTs to /api/sms/webhook → signature is verified → the message is persisted up front → the bot brain (bot.ts) runs its tool loop against bot-tools.ts → a TwiML reply is returned synchronously. The bot answers customers via TwiML, so the only outbound sendSms path is the ops manual reply.
2

Ops manual reply / takeover

/live/inbox/api/ops/replysendSms() (routed through the Messaging Service when TWILIO_MESSAGING_SERVICE_SID is set). Sending auto-takes-over the thread.
3

OS screens

/live/* server components call the live-data loaders → Neon. Mutations go through gated, atomic API routes under /api/live/* and append an audit_events row.
4

Automation chain

reorder → sendInvoice (Clover adapter) → on payment (onInvoicePaid) → notify clinic/owner (Twilio) → optional Uber dispatch. Selection of stub vs. real provider happens only in adapters/index.ts.

Auth gate

A single shared password (OS_PASSWORD) gates /live and /ops. /login sets a signed httpOnly session cookie (OPS_SECRET signs it); src/proxy.ts (Next 16 “proxy” = middleware) plus server-side checks enforce it. The ops API also accepts Authorization: Bearer <OPS_SECRET>. The pitch and mock /app stay public.

Next: the data model

See every Postgres table and why analytics are derived, not stored.