{"protocol":"clank-doc/1","frameworkVersion":"0.13.0","slug":"admin-studio","title":"Generated admin studio","description":"Clank can derive a secure, server rendered operations surface from an application blueprint. The studio shows the selected entity schemas, the records visible to the signed in account, and the same typed create, update, and delete controls ","group":{"id":"agents","title":"Agents and generation"},"url":"https://docs.clank.run/docs/admin-studio","source":"docs/admin-studio.md","headings":["Enable it","What is generated","Authorization model","Agent access","Generated contract checks"],"tableOfContents":[{"id":"enable-it","title":"Enable it","level":2},{"id":"what-is-generated","title":"What is generated","level":2},{"id":"authorization-model","title":"Authorization model","level":2},{"id":"agent-access","title":"Agent access","level":2},{"id":"generated-contract-checks","title":"Generated contract checks","level":2}],"markdown":"# Generated admin studio\n\nClank can derive a secure, server-rendered operations surface from an application blueprint. The\nstudio shows the selected entity schemas, the records visible to the signed-in account, and the\nsame typed create, update, and delete controls used by the product UI.\n\nThis is an application admin surface, not a database superuser. Opening it never bypasses a query,\nmutation, role, ownership rule, validation schema, or optimistic concurrency check.\n\n## Enable it\n\nAn app with an `owner` or `admin` role receives a studio automatically:\n\n```ts\nexport default {\n  auth: {\n    roles: {\n      owner: {\n        description: \"Application administrator.\",\n        permissions: [\"tasks.*\"],\n      },\n      member: {\n        description: \"Application member.\",\n        permissions: [\"tasks.read\", \"tasks.write\"],\n      },\n    },\n  },\n  // entities, routes, and actions...\n} satisfies import(\"@clank.run/framework/blueprint\").AppBlueprintInput;\n```\n\nThe default URL is `/__clank/studio`. Only the inferred `owner` and `admin` roles can open it.\nSet `admin: false` to omit the route and all generated studio code.\n\nUse an explicit contract when the app uses a different privileged role, needs a smaller data\nsurface, or should be read-only:\n\n```ts\nexport default {\n  auth: {\n    roles: {\n      operator: {\n        description: \"Operates the application.\",\n        permissions: [\"tasks.*\", \"projects.read\"],\n      },\n      member: {\n        description: \"Uses the application.\",\n        permissions: [\"tasks.read\", \"tasks.write\"],\n      },\n    },\n  },\n  admin: {\n    path: \"/operations\",\n    roles: [\"operator\"],\n    entities: [\"projects\", \"tasks\"],\n    allowMutations: false,\n  },\n  // entities, routes, and actions...\n} satisfies import(\"@clank.run/framework/blueprint\").AppBlueprintInput;\n```\n\n`roles` must name existing application roles. It is required when neither `owner` nor `admin`\nexists. `entities` must name existing entities and defaults to every entity. `allowMutations`\ndefaults to `true`.\n\nThe path is static. `/__clank/studio` is the only studio path allowed inside Clank's reserved\nnamespace; choose an ordinary application path for a custom URL.\n\n## What is generated\n\nThe studio is generated into the application's normal `src/view.tsx`, `src/app.tsx`, and\n`src/server.tsx` files. It provides:\n\n- server-rendered schema, ownership, update-mode, record-count, and field information;\n- browser hydration without replacing the server-rendered document;\n- live updates for realtime entities and ordinary post-mutation refresh for other entities;\n- responsive entity forms and lists built from the blueprint field contract;\n- a server-rendered, newest-first revision timeline for every selected entity;\n- role-checked restores that add a new version instead of rewriting history;\n- role-filtered links and controls; and\n- a direct link to the app-local Agent access inbox.\n\nThere is no separate admin API. A generated control references the same typed backend function as\nthe corresponding product control. That function is also the action described by the app's MCP\nmanifest. Generated contract tests fail when a rendered control and that backend/MCP contract\ndrift apart.\n\n## Authorization model\n\nAuthorization is enforced in layers:\n\n1. The server checks the studio route role before loading data or rendering the page.\n2. The hydrated UI repeats the role check before showing navigation or studio content.\n3. Each query and mutation checks its own backend action role.\n4. Owned tables constrain records to the authenticated owner.\n5. Mutations validate inputs and expected document versions inside a transaction.\n\nThe generated `<entity>.history` query and `<entity>.restore` mutation use the studio roles and are\nalso documented MCP tools. History refreshes after every browser mutation, and the server renders\nthe initial timeline before hydration. A restore sends the exact database revision/sequence plus\nthe current document version (or `null` for a deleted document), so two administrators cannot\nsilently overwrite each other. `allowMutations: false` keeps the timeline but omits restore controls.\n\nThe backend is authoritative. For example, an `owner` allowed into the studio still cannot invoke\nan action declared only for `member`. A user-owned entity count is the number visible to the\ncurrent user, not a global database total. This makes the studio safe by construction, but it also\nmeans broader operational access must be modeled deliberately in the action and ownership\ncontracts. Clank does not manufacture a hidden bypass.\n\n`allowMutations: false` removes mutation controls from the studio. It does not change actions used\nelsewhere in the product or by an authorized MCP client. Restrict those separately with action\nroles and agent grant scopes.\n\n## Agent access\n\nEvery generated app retains its own OAuth-protected MCP endpoint. The studio's **Agent access**\nlink opens `/__clank/oauth/access`, where the signed-in user can inspect, reduce, or revoke their\napplication-bound agent grants. The studio itself does not issue tokens or expose secrets.\n\nAn agent changing a blueprint should treat `admin.roles`, `admin.entities`, backend action roles,\nand ownership as one reviewable security boundary. Run `clank plan` to inspect the normalized\nstudio route and `npm test` to verify SSR, ownership isolation, and UI-to-MCP action parity before\ndeploying.\n\n## Generated contract checks\n\nThe application-owned test suite:\n\n- server-renders the studio using an allowed fixture role;\n- proves the studio route is part of the deterministic plan;\n- verifies every mutable studio control resolves to a current typed server action;\n- compares those actions with the no-store backend/MCP manifest; and\n- excludes read-only studio panels from required mutation-control coverage.\n\nUse `npm test` for the generated application and `npm run deploy:check` before upload. Neither\ncommand needs production data or credentials.\n"}