From demo to product in 15 minutes
Start state: nothing. End state: a deployed client tracker that Claude can drive over MCP — built by reshaping the Mini CRM demo instead of writing a domain. The demo codegen generates the schema, backend, and multi-view page from a spec; your flags rename and reshape it at scaffold time, so the generated code is already YOUR domain.
1. Scaffold the reshaped demo
pnpm new my-crm --demo crm --table clients --labels "Client,Clients" \
--fields "+source:select:Lead source,-notes"
pnpm install
cd apps/my-crm && npx convex dev --once && pnpm exec tsc --noEmit
Expected scaffold output includes a demo line: "demo Mini CRM · clients (8 fields) + activities (5 fields) · sample data included". You renamed contacts → clients, added a source select field, and dropped notes — schema, backend, and page all follow. The demo picked the saas design, blue accent, and sidebar layout for you (override with the normal flags). tsc must exit clean.
Gotcha: --demo always builds a --type webapp on the react stack — passing --type website or --stack static is an error. And --table wants a camelCase identifier: clients works, my-clients does not.
2. Load the sample data
pnpm dev # inside apps/my-crm — http://localhost:52xx
Sign up, open Clients in the nav. The workspace is empty, so the page offers "Load sample data" — click it and six clients (Ada Lovelace through Margaret Hamilton) appear, pipeline stages and deal values included. Switch to the board view for the pipeline, stats for revenue, calendar for close dates. The Activities page (the demo's second entity) has its own three-row sample set.
Gotcha: the seed rows you loaded no longer carry notes values (the field is gone) but do NOT have source values either — sample data only covers the original spec fields; new fields start at their defaults.
3. Tour the generated code — it's the records pattern
- convex/schema.ts — a generated clients table block (userId + your 8 fields, indexed by_user) beside the shell tables, plus activities
- convex/clients.ts — listClients / createClients / updateClients / deleteClients shaped exactly like the standard per-user CRUD pattern (requireUserId first, ownership checks), plus the seedDemo mutation behind "Load sample data"
- convex/clientsShared.ts — STAGE_META and SOURCE_META select-option constants, one source of truth for backend and frontend
- src/features/crm/pages/ClientsPage.tsx — ONE generated CONFIG: EntityConfig (labels, titleKey, statusKey: stage, dateKey, amountKey, your fields) driving EntityViews/EntityDetail; registered in src/features/index.tsx
From here you edit like any hand-built domain: change the CONFIG, add a field to the schema + patchFields, run npx convex codegen && pnpm exec tsc --noEmit. Or, while still exploring, delete the app and re-scaffold with different --fields — scaffolding is cheap.
4. Connect Claude to it
The demo scaffolds with all features on (minus the example/records placeholders), so the mcp feature is already there: your app is an MCP server at <your Convex site URL>/mcp. Because the primary entity is now clients with a stage select, the generated tools are:
list_clients # the user's clients, newest first
create_client # takes { name }
set_client_stage # { id, value } — validated against lead/qualified/proposal/won/lost
list_activities / create_activity / set_activity_kind # the second entity
Add the server to Claude (see the Connect Claude tutorial for the full OAuth/API-key flow) and ask it to summarize your pipeline or move a deal to won — it works against the same per-user data you see in the browser.
5. Deploy
cd ../.. && pnpm deploy my-crm --json
Expected: Convex backend deploys first, the frontend lands on Cloudflare Pages, SITE_URL syncs to the real URL, and the final @geenius-mvp:result line carries the live url. Sign up on the deployed app, load the sample data, and you have a demo-able product.
What you built
- A renamed, reshaped two-entity CRM (clients + activities) with 8+ views, seed data, and a create/edit form — zero hand-written domain code
- An MCP server whose tools speak your domain language (list_clients, set_client_stage)
- The pattern for any product: pick the closest demo, reshape with --fields/--table/--labels, then evolve the generated code directly