Admin Dashboard — Design of Record (M27, #485)
These boards are the Al-approved (2026-08-15) design of record for milestone M27 — Admin Dashboard. The UI build slice (#486) implements these patterns and nothing beyond them.
Canonical Penpot study
The five patterns are reproduced as a version-controlled Penpot file on the self-hosted server:
- File:
Bloom Admin Dashboard — M27(project Bloom Dashboard) - URL: https://bloom-design.exe.xyz/#/workspace?team-id=15cab2bd-418a-81a7-8008-69cdbdab9f82&file-id=15cab2bd-418a-81a7-8008-7c4cd225d590&page-id=15cab2bd-418a-81a7-8008-7c4cd225d591
- One page, ten boards: each pattern as a desktop (1120px) and mobile (390px)
frame, faithful to
reference/admin-design-study.html(layout, palette, type scale, read-only banner, sort/filter whitelist, redaction cues). - A named Penpot snapshot ("M27 #485 — faithful reproduction of Al-approved boards (2026-08-15)") pins the delivered state.
Known limitation: the deployment's Penpot exporter service (headless Chromium) is unavailable (
/api/export→ 400), so PNG exports could not be produced from Penpot. The PNGs below are the approved renders of the same boards and serve as the previews of record.
The five patterns
| # | Pattern | Preview |
|---|---|---|
| 1 | Admin shell — nav (7 resources + Overview, counts from each resource's total), read-only banner, identity + role pill, self sign-out | ![]() |
| 2 | Resource list (Users) — only whitelisted sort/search/filter controls; › view affordance per row | ![]() |
| 3 | Record detail (User) — read-only fields + related panels cross-linked by user_id; actions limited to Copy ID / View raw JSON | ![]() |
| 4 | Overview — resource total tiles, grants-by-role, recent sessions; no fabricated metrics | ![]() |
| 5 | JSON inspector — the redaction contract made visible | ![]() |
All five at once: reference/admin-all-boards.png.
Full layout source: reference/admin-design-study.html.
The hard rule: no fake affordances
Every control in these frames maps 1:1 to what the M27-7 read-only resource
protocol (apps/api/src/bloom/domain/admin_resources.py,
apps/api/src/bloom/persistence/admin_resources.py) actually supports. The
admin surface is read-only in this slice — no create/edit/delete/bulk
controls exist anywhere, because the backend exposes no mutation routes.
The frames are bound to exactly this whitelist:
| Resource | Filters | Search | Sortable columns |
|---|---|---|---|
users | has_grant, created_since, created_until | email, name | email, created_at |
admin_grants | role | — | granted_at, role |
sessions | user_id, surface, active | — | created_at, expires_at |
oauth_identities | provider | provider, user_id | |
telegram_links | verified | — | created_at |
workspaces | — | user email | created_at, user_email |
global_credentials | user_id | name | provided_at, name |
jobs (M27-12) | kind, status | — | run_after, attempts |
outbound_messages (M27-12) | channel, kind, status, thread_id | — | created_at |
runtime_correlations (M27-12) | runtime, status | external id | created_at, updated_at |
projects (#488) | phase, lifecycle, owner_user_id | title, thread id | updated_at, title |
audit_log (M27-13) | actor_id, action, resource, resource_id, outcome, since, until | — | at |
Redaction is structural (fields absent from the read models cannot serialize):
- Session
idis an 8-character prefix — the raw 43-char cookie id never leaves the store. - Telegram link one-time
codeis omitted entirely. - Global credentials carry metadata only — there is no
valuefield. - Audit
before/aftersnapshots are redacted at append time (M27-3); the audit screens (M27-13) render them verbatim, read-only. - Job payloads (M27-12) render read-only, always: they are immutable
server-side (RCE-adjacent - they drive Claude Code execution on a worker VM).
The only job verbs are
retry/cancel(+ bulk cancel), and no verb accepts a payload - retry re-enqueues the stored payload byte-identically. - Outbound messages (M27-12) carry a truncated preview + content hash only - the full body was never stored (#216), so it has no field to leak from.
- Runtime correlations' free-form
metadatadict is omitted entirely (M27-12).
The JSON-inspector board exists to make this contract visible in the UI.
Forward-looking: forms standard for write slices
When later milestones add mutation routes, admin forms use the project
standard: shadcn Form + react-hook-form + zod. Nothing in the
current frames anticipates those routes.




