{"protocol":"clank-doc/1","frameworkVersion":"0.8.0","slug":"application-recipes","title":"Application recipes for humans and agents","description":"This guide is the shortest path from an application request to a readable Clank implementation.","group":{"id":"start","title":"Start with npm"},"url":"https://docs.clank.run/docs/application-recipes","source":"docs/application-recipes.md","headings":["Choose the shape first","Contract first build order","Forms","Reusable interaction logic","Agent semantics","CRUD and live collaboration","Commerce","Dashboard","Booking or wizard","Readability checklist","Verification checklist"],"tableOfContents":[{"id":"choose-the-shape-first","title":"Choose the shape first","level":2},{"id":"contract-first-build-order","title":"Contract-first build order","level":2},{"id":"forms","title":"Forms","level":2},{"id":"reusable-interaction-logic","title":"Reusable interaction logic","level":2},{"id":"agent-semantics","title":"Agent semantics","level":2},{"id":"crud-and-live-collaboration","title":"CRUD and live collaboration","level":2},{"id":"commerce","title":"Commerce","level":2},{"id":"dashboard","title":"Dashboard","level":2},{"id":"booking-or-wizard","title":"Booking or wizard","level":2},{"id":"readability-checklist","title":"Readability checklist","level":2},{"id":"verification-checklist","title":"Verification checklist","level":2}],"markdown":"# Application recipes for humans and agents\n\nThis guide is the shortest path from an application request to a readable Clank implementation.\n\n## Choose the shape first\n\n| Application need | Clank starting point |\n| --- | --- |\n| Static marketing or content | TSX, signals for small interactions, router only when multiple client routes add value |\n| Rich client application | TSX, `createRouter`, forms, headless UI state, resources |\n| CRUD product | `defineDatabase`, `defineBackend`, typed queries/mutations, live client |\n| Private user application | `defineAuth`, owned tables, `createClient`, `AuthGate` |\n| Agent-operable workflow | schemas, named actions, semantic native controls, explicit `agentAction` |\n| Deployable product | `clank create`, migrations, health endpoint, `clank deploy` |\n\nDo not add a backend to a page that has no server-owned state. Do not keep private or shared state only in browser signals.\n\n## Contract-first build order\n\nFor AI-generated applications, this order minimizes rewrites:\n\n1. Write the user journeys and data ownership rules.\n2. Define schemas for persisted data, form input, and agent actions.\n3. Define database tables and backend functions.\n4. Build shared semantic views.\n5. Add forms and interaction controllers.\n6. Add Tailwind classes after the HTML structure works.\n7. Add stable agent IDs to important actions.\n8. Test validation, keyboard use, narrow screens, auth isolation, and live updates.\n9. Add migrations and deployment configuration.\n\nRuntime schemas are the shared truth. TypeScript inference and JSON Schema both flow from them.\n\n## Forms\n\nPrefer one `createForm` controller per independently validated user task.\n\nGood:\n\n```ts\nconst profile = createForm({ /* profile fields */ });\nconst password = createForm({ /* password fields */ });\n```\n\nLess readable:\n\n```ts\nconst everySettingOnTheAccountPage = createForm({ /* unrelated sections */ });\n```\n\nUse native `label`, `input`, `select`, `textarea`, and `button` elements. Spread the field helper props, then add classes and application-specific attributes.\n\nRemote uniqueness, authorization, inventory, pricing, and other server-owned checks belong in the submission handler or backend—not in client-only validation.\n\n## Reusable interaction logic\n\n- Expandable content: `createDisclosure`.\n- Modal task: `createDialog`.\n- Section switching: `createTabs`.\n- Long tables or catalogs: `createPagination`.\n- Async data: `resource`.\n- Async side effect: `actionRunner` or a form submission.\n- Stable list identity: `<For each={items} by=\"id\">`.\n- Route-level async data: router `load`.\n\nKeep controllers beside the feature that owns them. A controller should have a specific ID such as `invite-member`, not `dialog-1`.\n\n## Agent semantics\n\nAgents already understand native controls when the HTML is accessible:\n\n```tsx\n<label for=\"email\">Work email</label>\n<input id=\"email\" name=\"email\" type=\"email\" />\n```\n\nAdd Clank metadata where native semantics cannot express the application capability:\n\n```tsx\n<button\n  agentId=\"archive-project\"\n  agentAction=\"projects.archive\"\n  agentLabel=\"Archive current project\"\n  intent=\"destructive-control\"\n>\n  Archive\n</button>\n```\n\nRules:\n\n- IDs must be deterministic and unique in the mounted surface.\n- Labels describe the action, not its color or position.\n- `agentAction` should match a discoverable server action when one exists.\n- Metadata never replaces authorization.\n- Password, file, and secret values must not be exposed through labels or state.\n\n## CRUD and live collaboration\n\nDefine the table:\n\n```ts\nconst schema = defineDatabase({\n  projects: defineTable({\n    name: s.string({ min: 1, max: 120 }),\n    status: s.enum([\"active\", \"archived\"]),\n  }).owned(),\n});\n```\n\nDefine inferred functions:\n\n```ts\nconst backend = defineBackend({ schema, auth }).functions(({ query, mutation }) => ({\n  projects: {\n    list: query({\n      args: {},\n      handler: ({ db }) => db.table(\"projects\").collect(),\n    }),\n    create: mutation({\n      args: { name: s.string({ min: 1, max: 120 }) },\n      handler: ({ db }, { name }) =>\n        db.table(\"projects\").insert({ name, status: \"active\" }),\n    }),\n  },\n}));\n```\n\nUse `client.live()` in the browser. The query cache reruns only when a committed change intersects its recorded dependencies, and every subscribed tab receives the new snapshot.\n\n## Commerce\n\nTypical composition:\n\n- signals/computed values for local filters and cart preview;\n- server-owned price and inventory validation at checkout;\n- `createDialog` for the cart or quick view;\n- `createForm` for address and payment-provider handoff;\n- named actions for add/remove/checkout where agents should operate the store;\n- owned order tables after authentication.\n\nSee `examples/commerce`.\n\n## Dashboard\n\nTypical composition:\n\n- `createTabs` for major workspace sections;\n- computed filtering plus `createPagination`;\n- semantic native table markup;\n- `createDialog` + `createForm` for create/edit flows;\n- live queries for operational data;\n- role checks in backend functions, not hidden buttons alone.\n\nSee `examples/dashboard`.\n\n## Booking or wizard\n\nUse one form per step when steps have independent validation. Keep selections such as a room or plan in a signal, then compute the summary and total.\n\nThe final backend mutation must recompute availability and price from server-owned data. Client totals are display state, not an authority.\n\nSee `examples/booking`.\n\n## Readability checklist\n\n- Feature names are domain names: `invite`, `checkout`, `selectedRoom`.\n- Components represent meaningful regions, not arbitrary visual fragments.\n- Event handlers are short and named when they contain business rules.\n- Validation schemas sit beside the workflow that consumes them.\n- Shared behavior uses a controller instead of repeated event-listener code.\n- Tailwind classes do not hide missing semantic HTML.\n- Comments explain security or lifecycle constraints, not obvious syntax.\n- Examples compile under strict TypeScript.\n\n## Verification checklist\n\nFor each generated application:\n\n- run strict TypeScript;\n- run unit tests for schemas and state transitions;\n- exercise every form's invalid and successful paths;\n- test keyboard dismissal/focus for dialogs;\n- inspect the semantic agent tree;\n- verify password/file values are absent;\n- test desktop and narrow viewport layouts;\n- check browser console and page errors;\n- for full-stack apps, test two users and two simultaneous tabs;\n- test deployment health failure and migration rollback before production.\n"}