Infrastructure
How this site is built — and how you’d build it.
No platform team, no microservice sprawl. A small, boring, durable stack one person can hold in their head — plus the real commands, packages, and Claude Code prompts to stand one up yourself in an afternoon.
The stack
What’s actually running.
Six choices, each picked for what it does best — and each a click from its docs. The whole thing fits in one repo on one database.
Vite · React 19 · TypeScript · Tailwind v4. Static pages and hydrated apps from one build.
Vercel. Static output served off the filesystem; serverless functions only where they earn it.
The Anthropic API for product features — and Claude Code as the dev environment that built this.
Stripe for payments and subscriptions; web-push for notifications. Money never touches our servers.
Architecture
One repo, a handful of vendors.
The browser talks to the Vercel edge; the edge talks to Postgres (guarded by row-level security), Stripe, and Claude. No message bus, no service mesh, nothing to page anyone at 3am.
Data
One Postgres, held by the database itself.
Isolation isn’t enforced by careful application code — it’s enforced by Postgres. Row-Level Security pins every row to its owner, so a forgotten where clause can’t leak data. The calm version of multi-tenancy.
Without RLS
// one missed check anywhere and the castle fallsif (user.id !== note.owner) { throw new ForbiddenError();}Authorization lives in app code. Every endpoint has to remember.
With RLS
-- the database simply won't return the rowcreate policy "owners read their own notes" on notes for select using (owner = auth.uid());Authorization lives in Postgres. The app can’t leak what the DB won’t hand over.
Build it yourself
A site like this, from scratch.
The actual recipe — the same pattern behind every product here. Copy the snippets, follow the links. About fifteen minutes to a multi-page site on a real domain, backed by a real database that keeps each user’s data to themselves.
Scaffold a Vite app
One command gives you React + TypeScript with hot reload — your whole frontend toolchain.
npm create vite@latest my-site -- --template react-tscd my-sitenpm installnpm run devAdd Tailwind v4
Tailwind v4 is one Vite plugin now — no config file, no PostCSS. Define your theme in CSS with @theme.
npm install tailwindcss @tailwindcss/viteimport { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [react(), tailwindcss()]});@import "tailwindcss"; @theme { --color-ink-950: #09090b; --color-violet-600: #7c3aed; --font-display: "Plus Jakarta Sans", sans-serif;}Add data with Supabase + RLS
Install the client and wire it with env vars. The anon key is safe to ship to the browser — because RLS makes Postgres refuse any row that isn’t yours.
npm install @supabase/supabase-jsimport { createClient } from '@supabase/supabase-js'; export const supabase = createClient( import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY);create table notes ( id uuid primary key default gen_random_uuid(), owner uuid references auth.users default auth.uid(), body text, created_at timestamptz default now()); alter table notes enable row level security; create policy "owners manage their own notes" on notes for all using (owner = auth.uid()) with check (owner = auth.uid());Add an API route
Drop a function in /api. Validate input with zod so bad requests never reach your logic. Vercel turns the file into a serverless endpoint automatically.
import { z } from 'zod'; const Body = z.object({ email: z.string().email(), message: z.string().min(1) }); export async function POST(req: Request) { const parsed = Body.safeParse(await req.json()); if (!parsed.success) return Response.json({ error: 'bad input' }, { status: 400 }); // ...do the work return Response.json({ ok: true });}Deploy to Vercel
One CLI, one command for a preview URL, one flag to ship. Lock your security headers once, for every path, and never think about them again.
npm i -g vercelvercel # build + preview URLvercel --prod # ship it{ "buildCommand": "npm run build", "headers": [ { "source": "/(.*)", "headers": [ { "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-Content-Type-Options", "value": "nosniff" } ] } ]}Claude Code prompts
Or just describe it.
This whole site was built with Claude Code in the terminal. Here are real, copy-paste prompts that map to each step above — point Claude Code at an empty folder and let it scaffold, wire, and ship.
Scaffold a Vite + React + TypeScript app. Configure Tailwind v4 through the @tailwindcss/vite plugin and a dark theme using CSS @theme tokens for colors and fonts.
Add Supabase Google sign-in: a useAuth() hook with getSession + onAuthStateChange, a sign-in button, and logic that strips ?code= from the URL after the OAuth redirect.
Write a Postgres migration for a notes table (id, owner, body, created_at), enable row-level security, and add policies so a user can only read and write their own rows, keyed on auth.uid().
Create a Vercel serverless function at /api/contact that validates the JSON body with zod, returns 400 on bad input, and add the route plus strict security headers (CSP, HSTS, X-Frame-Options) to vercel.json.
Make this multi-page site crawlable: add a build step that renders each page to static HTML with renderToString and injects it into the built index.html, then hydrate on the client.
Set up a daily Vercel Cron that calls /api/digest at 8am, and give me a git-free deploy I can run by hand: build locally, then ship with `vercel --prod`.
Tip: keep a CLAUDE.md at the repo root describing your stack and conventions — Claude Code reads it on every run, so the output matches your house style.
Packages
What you’ll actually install.
The short list that does the heavy lifting — nothing exotic, all maintained, all in production here.
npm install @supabase/supabase-js @anthropic-ai/sdk zod motionnpm install -D @tailwindcss/vite tailwindcss viteThat’s the whole machine. Want to see where this pattern ends up, or build it with us? See what we do or join the studio.
