Billing, API keys, uploads, AI
billing
Stripe-ready plans. Locally it works out of the box: plan changes apply synchronously with no Stripe account. In real mode you set STRIPE_PRICE_PRO / STRIPE_PRICE_TEAM price ids and a Stripe webhook calls the internal setPlan mutation to finalize the change. On Supabase the feature owns src/features/billing.tsx plus the stripe-checkout and stripe-webhook Edge Functions.
api-keys
Programmatic access keys with correct hashing hygiene: the browser generates the key and its SHA-256 hash (the shell's generateApiKey util); only the hash and a short display prefix reach the server, so the full key exists exactly once — in the user's clipboard. Lookups go through an internal by_hash index; there is deliberately no public query that accepts a hash, so key owners cannot be enumerated. These keys are also the dev-tool auth for the mcp feature. On Supabase the feature adds the agent-api Edge Function as the external HTTP surface.
uploads
File uploads backed by the platform's storage: Convex file storage (convex/uploads.ts + src/features/uploads) or Supabase Storage (src/features/uploads.tsx). Upload, list, and delete, scoped per user.
ai
A Claude chat feature. The Anthropic API key lives server-side only — the browser never sees it. Set it on the backend:
# Convex (dev deployment, then prod):
npx convex env set ANTHROPIC_API_KEY sk-ant-...
npx convex env set ANTHROPIC_API_KEY sk-ant-... --prod
# Supabase:
supabase functions deploy ai-chat
supabase secrets set ANTHROPIC_API_KEY=sk-ant-...
On Convex the feature owns src/features/ai, convex/ai.ts and convex/aiNode.ts (the Node runtime action that calls Anthropic); on Supabase, src/features/ai.tsx plus the ai-chat Edge Function. Without the key the chat page renders and explains what to set.