Vite · Supabase · Claude · Git · Vercel
How to build your own stack, stop depending on a screen generator — and turn localhost into an edge case hunter.
Wellington Mota — Product Engineering
Where we start
None of this is a knock on the product. It's the price of an environment that decides things for you — and the bill arrives the day you need to decide.
The trade
Three pieces you swap independently. None of them owns your project — each solves one problem and gets out of the way.
And a fourth piece, the most important and the cheapest: your browser, open on localhost.
Git keeps the history. Vercel publishes. None of these five things charges you for looking at the same screen again.
Anatomy
Every layer has public docs, a competing alternative and an exit door. That's what separates architecture from a subscription.
The dev server
Vite serves your project's files straight to the browser, without bundling anything first. The server is up in milliseconds and you work on port 5173.
HMR swaps only the component that changed — no page reload. What you typed in the form is still there. The modal is still open. Step three of the wizard is still on step three.
npm run build outputs static HTML, CSS and JS. That's what Vercel publishes.The data
Database
Postgres. Tables, relations, SQL. You open the editor and see the data — not an abstraction of it.
Auth
Email and password, magic link, Google, GitHub. The session arrives already resolved in the client.
RLS
The rule of who sees what lives in the database, not in an if in the frontend.
Storage
Image and file uploads, under the same permission rules.
Realtime
The table changes, the screen changes. Useful for shared lists and notifications.
Local
supabase start runs the whole database in Docker on your machine. No internet needed.
Running the database locally is what closes the loop in Act II: you seed absurd data on purpose — a 74-character name, an order with no items, a user with no photo — and watch what the interface does.
The builder
Button.tsx already exists and that your spacing scale goes by 4.npm run dev, reads the error in the terminal, applies the fix and runs again. The error doesn't turn into an apology — it turns into a line of code.localhost:5173 in the browser, takes a screenshot, measures the element that overflowed, resizes to 320px and does it again.git diff before accepting.The difference between asking for a screen and asking for a fix: the second requires the tool to see the current state. Only something with the repository and the browser can.
The undo
It's the piece designers postpone the most and need the most. Working with AI, Git stops being developer bureaucracy and becomes a safety net: if the last round made everything worse, one line takes you back.
# before the first screen, not after git init git add -A && git commit -m "scaffold" # one experiment per branch git switch -c feat/editorial-home # didn't work out? the whole experiment disappears: git switch main
.env.local and node_modules stay out. The Supabase key never goes to GitHub.Day one
# 1. the project npm create vite@latest my-app -- --template react-ts cd my-app && npm install && git init # 2. style and data npm install @supabase/supabase-js npm install -D tailwindcss @tailwindcss/vite # 3. the database, on your machine npx supabase init && npx supabase start # 4. the loop starts here npm run dev → http://localhost:5173
After that, claude in the same directory. It now sees everything above.
The local Supabase key shows up in the output of supabase start. It goes into .env.local with the VITE_ prefix — without it, Vite won't expose the variable.
Six lines. None of them is irreversible, none of them charges per run, and the result is yours before it exists.
Never touched a terminal?
claude. From here you stop typing commands and start asking. Claude CodeEvery command on the previous slide is something you can type — and never have to. The six lines become one sentence.
Prompts to steal
Topography
my-app/ ├─ CLAUDE.md ├─ .env.local ├─ vercel.json ├─ src/ │ ├─ tokens.css │ ├─ components/ │ ├─ routes/ │ │ └─ hunt/ │ └─ lib/supabase.ts └─ supabase/ └─ migrations/
The contract
You write the rules once. Every future session starts with them on the table. It's a design system written in prose — and it's the piece a designer writes better than a developer.
Without this file, every conversation starts from scratch and every component invents a new gray.
# CLAUDE.md ## Visual - Every color comes from src/tokens.css. A literal hex in a component is a bug. - Spacing on the 4px scale only. - Display face: serif. Body: Inter. ## Components - One file per component. - Every new component gets a case in src/routes/hunt/ before it ships. ## Forms - Label always visible. Never placeholder-only. - Error below the field + aria-describedby. - Submit locks on the second click. ## House rules - Never install a UI library without asking. - Small commits, messages in the imperative.
The method
CLAUDE.md doesn't cover. "An order card with photo, status and amount. Follows the tokens."Step 3 is yours, and it's the only one you can't outsource: it's judgment. The rest of the architecture exists to make that step fast and cheap.
Act I scorecard
| Screen generator | Your own stack | |
|---|---|---|
| Where it runs | On their server | On your machine, on localhost |
| The error | A summary in natural language | The stack trace, in your terminal |
| Tokens | Approximated inside generated CSS | One file, imported by everything |
| Database | Abstracted behind a panel | Postgres, with SQL and migrations |
| History | A list of prompts | Git — readable, reversible, yours |
| Publishing | Their button, their domain | Vercel: a preview per branch, your domain |
| Cost to iterate | Per prompt | Saving the file |
| Ceiling | Exists, and you find it late | Yours |
The real prize isn't any single row — it's that no company sits between you and your work. Every piece is swappable, every file lives on your machine, and if a tool disappears or doubles its price, you walk away owning everything you built.
Act II — Edge Case Hunter
The other eighty are the situations nobody designed: the 74-character name, the network that dropped mid-submit, the empty list on first login, the server error on a field that was already correct.
You don't find these in Figma. You find them in the browser — and that's why Act I exists.
Taxonomy
Data
Empty. One. Many. Too long. Emoji and accents. Zero. Negative. Null. Right-to-left text.
State
Idle. Loading. Saving. Success. Error. Disabled. Read-only. Partially filled.
Network
Slow. Offline. 500. Timeout. Responses arriving out of order. Session expiring midway.
Input
Paste. Browser autofill. Double-click on submit. Keyboard only. Browser back with a draft.
Environment
320px. 4K. Dark theme. Large system font. 200% zoom. Reduced motion.
Permission
Logged out. No access to that row. Viewer role. Suspended account. Someone else's data.
Six axes × eight states × three widths × two themes. Nobody clicks through that by hand. So we render all of it at once.
The tool
/hunt route inside the same project. Same CSS, same tokens, same fonts, same theme. The component there is the production component — not a copy.prefers-reduced-motion, and doesn't break at 320px.The harness
// src/routes/hunt/text-field.cases.ts export default defineCases(TextField, { base: { label: 'Name', value: 'Ana Prado' }, empty: { value: '' }, long: { value: 'Maria das Graças A. Sant\'Anna' }, unicode: { value: '🇧🇷 José Ávila 🌱' }, error: { error: 'Enter a name' }, errorLong: { error: 'An account with this name already…' }, pending: { pending: true }, disabled: { disabled: true }, })
// src/routes/hunt/index.tsx <CaseMatrix cases={cases} viewports={[320, 768, 1280]} themes={['light', 'dark']} /> // 8 cases × 3 widths × 2 themes // = 48 screens on one page
Each case is three lines. Writing the case is faster than opening the screen and reproducing the situation by hand — and it stays there forever.
What you see when you open the route
TextField · viewport 320 px · light theme · zoom 100%
The clipping in the long case doesn't show up in a Figma export. It shows up here, at 320px, in the third cell — and the two-line error pushes the button below the fold in the sixth.
Where it hurts most
josé+test@company.com.br Does your validation accept + and accents?onChange fire, or does the field stay "empty"?Twelve lines of cases. Twelve bugs that never reach the user — and none of them needed a QA person clicking.
The hunt
/hunt/text-field at 320px and tell me what overflows."git diff, you read it, you accept it. The case stays in the repository: next month, it'll still be testing.Its job is to find. Yours is to decide whether it's good.
Coda
/hunt for empty, long, error and pending. Without those, it doesn't exist.Ship
Vite's npm run build outputs static files. Vercel detects the project on its own, publishes to the CDN and hands back an address — in seconds, not in a meeting with infrastructure.
# the repository gh repo create my-app --private --source=. --push # connect and publish npm i -g vercel vercel link # the keys, per environment vercel env add VITE_SUPABASE_URL production vercel env add VITE_SUPABASE_ANON_KEY production vercel --prod
main becomes production on every push. If something broke, the previous deploy comes back in one click — Git's history and Vercel's history are the same history./index.html in vercel.json, or /hunt only works when you navigate to it from inside.Four steps
git init before the first screen. Vite + Tailwind + tokens.css + CLAUDE.md. One static screen, one branch, one Vercel preview to prove the whole path works.supabase start on your machine. One table, one read, one write. Email login. The first screen that changes depending on who's logged in./hunt route and the first eight cases for your text field. The first overflow found at 320px. The first fix you wouldn't have seen in Figma.vercel --prod. And the matrix covering the five components you use most.No step depends on learning everything. Each one delivers one thing that works and gets out of the way.
The links
End
Vite opens. Supabase opens. Git opens. The browser opens. And when you can open it, you can fix it — including the ninety-nine situations nobody designed.
Wellington Mota — Product Engineering