A war room for high-intent job applications. PrepFor.Me tailors your resume truthfully to each role, builds company-specific interview prep that compounds with every recap you log, and keeps you in charge — nothing is ever auto-submitted.
This repo is meant to be open source. A hosted instance (when it exists) can charge for the cloud model, storage, and ops. Self-hosting stays yours: run the same app locally against a local LLM (Ollama) or against your own API keys (Anthropic + OpenAI). Nothing in the product requires the hosted billing path.
Live: https://prep-for-me.vercel.app/ — pre-v1, a working CRUD skeleton.
| Doc | What's in it |
|---|---|
| PROJECT.md | The source of truth. What the product is, the moat, scope and non-scope, decisions, current state, open questions, version history. |
| TECHNICAL.md | Stack, hosting, environment, code layout, data model, migrations, deploy, and the gotchas that have already cost time. |
| AGENTS.md | Conventions and invariants for anyone — human or agent — changing this repo. |
React 18 + TypeScript, built with Vite. Supabase for Postgres, magic-link and Google
auth, and later Edge Functions. TanStack Query for server state, React Router for navigation. No
UI framework: inline style strings are parsed into React style objects by
src/css.ts, so oklch colors and gradients stay exactly as designed.
You need Docker (Docker Desktop, or Colima on a Mac) and the
Supabase CLI.
npm run dev alone is the UI — Postgres, auth, and AI live in other processes.
npm install
cp .env.example .env.development.local
# After `supabase start`, copy API URL + publishable key from `supabase status`
# into .env.development.local. Set VITE_AI_PROVIDER=edge to talk to functions.
supabase start # Docker stack: API :54321, Studio :54323, inbox :54324
npm run dev # http://localhost:5173 — use localhost, not 127.0.0.1The app boots without credentials — the landing page renders and the sign-in screen tells you what's missing — so a blank env file never crashes anything.
supabase start does not serve Edge Functions. Those are a second process; see
Running AI locally.
| Process | Command | Needed for |
|---|---|---|
| Docker VM | colima start / Docker Desktop |
local Supabase |
| Supabase stack | supabase start |
auth, DB, storage |
| Vite | npm run dev |
the web app |
| Functions | supabase functions serve --env-file … |
any real AI (analyze, tailor, prep chat) |
| Model backend | Ollama + bridge, or Anthropic via supabase/.env.local |
what the functions call |
- Create a project at supabase.com.
- Run every file in
supabase/migrations/in filename order, via the SQL editor orsupabase db push.0003_grants.sqlis not optional — without it the tables exist and every query still fails with42501(why). - Copy the project URL from Settings → API and the
sb_publishable_…key from Settings → API Keys into.env.development.local. Both are safe in the browser; row level security is what protects the data. - In Authentication → URL Configuration, set the Site URL to
http://localhost:5173and addhttp://localhost:5173/**to the redirect allow list, or magic links / OAuth will send you somewhere that isn't your dev server. - (Recommended) Google sign-in — see Sign-in with Google below.
- Sign in at
/login. The first sign-in creates your account, and a trigger seeds yourprofilesanduser_settingsrows.
The login screen offers Continue with Google, plus the
email magic link. You create the OAuth apps; Supabase holds the secrets (never VITE_).
1. Google Cloud Console → APIs & Services → Credentials → Create OAuth client ID (Web):
- Authorized JavaScript origins:
http://localhost:5173,https://prep-for-me.vercel.app - Authorized redirect URIs (both):
- Local:
http://127.0.0.1:54321/auth/v1/callback - Hosted:
https://<PROJECT_REF>.supabase.co/auth/v1/callback
- Local:
2. Hosted Supabase → Authentication → Providers → enable Google → paste client id + secret for each.
3. Local — add to supabase/.env (or .env.local loaded by the CLI; not the Vite
.env.local):
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_ID=...
SUPABASE_AUTH_EXTERNAL_GOOGLE_SECRET=...Then supabase stop && supabase start so GoTrue picks up [auth.external.*] from
supabase/config.toml.
Redirect allow-list must include ${origin}/app (already required for magic links).
Scripts:
npm run build # typecheck + production build to dist/
npm run preview # preview the production build
npm run typecheck # tsc --noEmitThe hosted product can bill for cloud inference. Locally you pick the backend.
Every generation call (analyze, rewrite, tailor, prep chat, ingest extraction)
goes through ${ANTHROPIC_BASE_URL}/v1/messages. Point that at Anthropic or at a
local Ollama bridge.
supabase start does not inject model keys. Serve functions yourself, from a
file that process reads — not a VITE_ variable (those are inlined into the
browser).
In .env.development.local:
VITE_AI_PROVIDER=edgeRestart Vite after changing it. Leave it mock (or unset) for labelled sample
output with no model at all.
Only one supabase functions serve at a time — a second one takes over the
shared runtime container. Stop the current serve, then start the env you want.
Bills your Anthropic/OpenAI accounts. Analysis is roughly $0.09–0.10 on Claude; embeddings for prep chat/ingest use OpenAI.
supabase/.env.local(gitignored):ANTHROPIC_API_KEY=sk-ant-… OPENAI_API_KEY=sk-… # optional: ANTHROPIC_MODEL=claude-haiku-4-5-20251001- With the stack up:
supabase functions serve --env-file supabase/.env.local
npm run devin another terminal. Each Analyze / Improve / Tailor / Ask press is an explicit spend.
Generation hits Ollama. Prep-source embeddings still need OpenAI unless you skip ingest/chat retrieval.
- Install Ollama and pull the strongest model that still
feels fast on your machine for the whole product — resume analysis, tailoring,
and prep chat, not only chat. What we used:
qwen2.5:7bon a MacBook Pro with 64GB (M1 Max), and the same tag on an M4 Max; resume parsing and the other AI surfaces stayed usable.ollama pull <your-model-tag>
- Copy
supabase/.env.ollama.exampletosupabase/.env.ollama. SetANTHROPIC_MODELto the Ollama tag. AddOPENAI_API_KEYif you want prep chat / ingest. - Bridge (translates Anthropic
/v1/messages→ Ollama OpenAI/v1/chat/completions). Leave this terminal open:deno run --allow-net --allow-env supabase/functions/_stub/ollama-bridge.ts
- Functions, pointed at the bridge (
host.docker.internal:8788):supabase functions serve --env-file supabase/.env.ollama
npm run dev. The functions sendANTHROPIC_MODEL; the bridge uses that tag. Don't override it in the shell with a tag you have not pulled.
The functions container cannot see localhost on your Mac; the bridge must bind
0.0.0.0:8788 on the host. If analysis dies with ECONNREFUSED on
host.docker.internal:8788, the bridge is not running.
More detail: TECHNICAL.md §4 and the shared-container gotcha in §10.
Discover's job-feed queries, Practice, and drag-and-drop on the kanban board. Each of these says so on screen instead of pretending. See PROJECT.md for what's planned and in what order.
A first version lives in extension/ — tailors your resume to
the job posting in the current tab and autofills the application, using this app's own
Supabase auth and Edge Functions. Real field-mapping so far covers Greenhouse plus a
label-matching fallback for other sites; LinkedIn, Workday, and Lever are not mapped
yet. See its own README for setup.