ShipVeryFastShipVeryFast
Documentation

Architecture overview

ShipVeryFast is a standard Next.js 15 App Router app with no proprietary magic. Every concern lives in a predictable place, and each external service sits behind a thin, typed layer you can read in one file. This page is the mental model. Once you have it, you always know which file to open.

The layers

Requests flow top to bottom. Each layer has one job, so logic never leaks into your pages.

Browser
  -> middleware.ts        auth redirects, CSRF checks, rate limiting, security logging
  -> app/                 routes: pages, layouts and API route handlers
       -> libs/           the service layer: auth, stripe, supabase, mailer, ai, config
            -> models/    Zod schemas validate every shape in and out
                 -> supabase/  Postgres with Row Level Security

The request lifecycle

Every request hits middleware.ts first. It redirects unauthenticated users away from protected routes, verifies the CSRF token on mutating API calls, applies the right rate limiter, and logs security events. Only then does the route handler in app/ run.

A typical API route validates its body with a Zod schema, checks the NextAuth session, calls into a libs/ service, and returns a consistent JSON shape. The service is the only thing that talks to the outside world (Stripe, Supabase, Mailgun, an LLM provider).

Where everything lives

  • app/, routes and API handlers. UI under route folders, server logic under app/api/.
  • libs/, the service layer. One file per concern: auth.ts, stripe.ts, supabase.ts, mailer.ts, ai/, config.ts, csrf.ts, rateLimiter.ts, securityLogger.ts.
  • models/, Zod schemas and types shared by routes and services.
  • supabase/migrations/, the database schema as SQL.
  • middleware.ts, the cross-cutting gate every request passes through.

Read config first

libs/config.ts validates every environment variable with Zod at startup. It is the fastest way to see exactly what the app expects and which services are optional.

Graceful degradation

A fresh clone boots with no external services configured. Auth falls back to Google OAuth plus terminal magic links, the AI assistant shows only the providers whose keys are present, and Stripe and Mailgun stay dormant until you wire them. You add capability by adding env vars, not by editing code.