V3 Admin Workbench Model v1¶
Status:
- Draft baseline for V3 platform/admin page refactors.
- Normative for new or substantially changed /v3-prod/platform/* admin
surfaces after adoption.
Purpose: - Prevent admin pages from becoming long documentation pages with data embedded. - Give Lifecycle, Finance, IAM, Evidence, Config, and Ops one shared interaction model before Billing expands. - Define acknowledgement/suppression as a first-class product primitive so persistent failures remain auditable without dominating active queues.
Non-goals:
- This document does not define backend endpoint shapes. Any new API field,
mutation, or read model must still start in doc/api/openapi.draft.yaml.
- This document does not redesign user-facing workload launch flows.
- This document does not fully resolve global user/admin shell segregation.
Operator-mode rail and shell behavior remain governed by
doc/product/Product_Surface_IA_and_Role_Model_v1.md and should receive a
follow-up shell spec if the left rail changes.
1. Diagnosis¶
Current V3 admin pages often stack three different levels of information on one screen: - family-level summary; - sub-section navigation; - detailed operational records.
That produces 2-3 viewport scrolls before an operator reaches the actual working surface. The issue is editorial, not only visual. A page must choose one primary job: orient, scan, inspect, or act.
Rule: - Dashboards stay short. - Lists become workbenches. - Details become focused. - Operations move into drawers or explicit workflow pages.
2. Page-Family Taxonomy¶
Family Landing¶
Use for:
- /v3-prod/platform/ops
- /v3-prod/platform/lifecycle
- /v3-prod/platform/config
- /v3-prod/platform/evidence
- /v3-prod/platform/finance
- /v3-prod/platform/iam
Primary job: - Orient the operator and route them to the right workbench.
Allowed content: - Page header with primary CTAs. - KPI strip, normally 3-5 tiles. - One urgent queue or all-clear banner. - Pivot links to sub-pages. - Optional recent activity summary limited to 3-5 rows.
Disallowed content: - Full inventory tables. - Long workflow cards. - Multiple independent detail sections. - Permanent explanatory prose that repeats the UI.
Viewport rule: - A family landing should mostly fit in one desktop viewport. If it needs more than one scroll, it is probably carrying workbench or detail content.
Workbench¶
Use for: - node inventory; - payment sessions; - users; - audit/evidence rows; - workloads requiring admin action; - MAAS workflows; - ledger/reconciliation rows.
Primary job: - Scan, filter, select, compare, and act on records without losing list context.
Default layout: - Filter/search/header rail at top. - Dense list or table as the primary surface. - Selected-row detail panel on the right for desktop width. - Drawer fallback or route fallback for narrow screens.
Right-edge collision rule: - The selected-row detail panel owns the right side while browsing. - The operation drawer overlays the detail panel from the right when open. - The list/table remains visible behind the overlay on desktop. - Only one operation drawer may be open at a time. - Closing the drawer returns focus to the invoking row or operation button.
Drawer width:
- Desktop operation drawers use min-width: 480px.
- Drawer width should default to min(560px, 50vw).
- Drawers may grow to min(720px, 60vw) only for evidence-heavy operations.
- If content needs more than that, link to a focused workflow page instead.
Responsive fallback:
- Desktop workbench: >= 1280px, list/table plus right-side selected detail.
- Narrow workbench: < 1280px, list/table only.
- Selecting a row on narrow screens navigates to the focused detail route.
- Operation drawers on narrow screens render as full-screen sheets.
- Do not invent separate mobile-only information architecture.
Viewport rule: - Workbenches may scroll vertically in the list area, but they should not stack unrelated sections above and below the list.
Focused Detail¶
Use for: - one node; - one payment session; - one tenant/user; - one MAAS workflow; - one reconciliation run.
Primary job: - Inspect one resource deeply enough to decide the next operation.
Allowed content: - Header with status, identifiers, and operation entry point. - Overview section. - Activity/evidence section. - Related records as compact tables or pivots.
Default tabs:
- Overview
- Activity
Disallowed content: - More than two default tabs unless the resource is proven to need a permanent secondary mode. - Inline operation catalogs with long runbook prose.
Tab expansion test: - Additional tabs are allowed only when each tab has a distinct primary job and would still satisfy either workbench or focused-detail criteria on its own. - Do not create tabs only to hide overflow from an overgrown page. - If a tab primarily starts operations, move it to the operation drawer.
Operation Drawer¶
Use for: - privileged or consequential actions; - copy/download affordances; - workflow starts; - runbook links; - evidence pivots.
Primary job: - Keep action context close to the selected row/resource without turning the page body into an operations manual.
Drawer content order: - Selected resource identity. - Current status and blocking reason. - Primary safe operation. - Repair/retry operations. - Destructive operations. - Copy/download utilities. - Runbook and audit/evidence links.
3. Shared Primitive Contracts¶
These are product contracts. Actual TypeScript prop names may change, but the behavior should remain consistent.
AdminFamilyLanding¶
Required behavior: - Renders one family command surface. - Keeps high-priority action queue above pivots. - Uses pivot links for deeper surfaces instead of embedding them.
Suggested props:
type AdminFamilyLandingProps = {
eyebrow: string;
title: string;
primaryActions?: ReactNode;
kpis: AdminKpi[];
urgentQueue?: AdminQueueSummary;
pivots: AdminPivot[];
recentActivity?: AdminActivitySummary;
};
AdminWorkbench¶
Required behavior: - Owns filter/search state for one record family. - Shows a compact list/table and selected-row detail. - Preserves selection when filters refresh, unless the selected row disappears. - Supports responsive fallback to list + focused detail route. - Persists filters, sort, search, and selected row in URL query parameters. - Uses URL state as the source of truth so operator links are shareable and refresh-safe.
Suggested props:
type AdminWorkbenchProps<Row> = {
title: string;
filters: AdminFilter[];
rows: Row[];
selectedRowId?: string | null;
urlState: AdminWorkbenchUrlState;
onUrlStateChange: (next: AdminWorkbenchUrlState) => void;
rowKey: (row: Row) => string;
renderRow: (row: Row, state: RowState) => ReactNode;
renderDetail: (row: Row) => ReactNode;
emptyState: ReactNode;
operationDrawer?: OperationsDrawerConfig<Row>;
};
OperationsDrawer¶
Required behavior: - Opens from a row, detail header, or queue item. - Keeps the selected resource visible in the drawer header. - Groups operations by intent, not implementation subsystem. - Requires confirmation for destructive or privileged mutations. - Links to runbooks instead of rendering long procedure text inline.
Suggested operation groups: - Inspect - Repair - Retry - Schedule - Reconcile - Reimage - Refund - Suppress/Acknowledge - Retire/Delete
Drawer/detail interaction: - Drawers do not replace focused detail pages. - Drawers are for deciding and starting operations. - Focused detail pages are for inspection, evidence review, and deep links. - If drawer content needs more than one scroll on desktop, split it into a focused workflow page and link to it from the drawer.
AckSuppressControl¶
Required behavior: - Lets an operator reduce queue noise without deleting the underlying failure. - Shows whether an item is unacknowledged, acknowledged, suppressed, expired, or resurfaced. - Always leaves an audit trail. - Resurfaces automatically when the failure fingerprint changes.
Suggested props:
type AckSuppressControlProps = {
targetType: string;
targetId: string;
fingerprint: string;
state: "none" | "acknowledged" | "suppressed" | "expired" | "resurfaced";
expiresAt?: string | null;
reason?: string | null;
onAcknowledge: (input: AckInput) => Promise<void>;
onSuppress: (input: SuppressInput) => Promise<void>;
onClear: () => Promise<void>;
};
Authority rule:
- The backend owns fingerprint.
- Every ack-able read-model row must include a backend-emitted fingerprint.
- The UI never derives or normalizes fingerprints client-side.
- Suppression records persist the backend fingerprint that was acknowledged or
suppressed.
- Resurface compares the latest backend fingerprint to the persisted
fingerprint.
4. Acknowledgement And Suppression Model¶
Definitions¶
Acknowledgement: - Operator says "I have seen this and it is being handled." - The item may remain visible but should not count as urgent untriaged work.
Suppression: - Operator says "Do not count this as active queue pressure until the TTL expires or the fingerprint changes." - Used for test debris, intentionally abandoned workloads, known temporary external dependency failures, or planned maintenance.
Clear: - Operator removes acknowledgement/suppression manually.
Resurface: - System makes an acknowledged/suppressed item active again because the failure fingerprint changed, the target changed owner/scope, or the TTL expired.
Ack-able Targets¶
Initial target types:
- workload
- allocation
- node
- node_agent
- maas_workflow
- payment_session
- ledger_reconciliation
- webhook_delivery
- user_account
- tenant
Fingerprint¶
Every ack/suppression must be tied to a stable fingerprint, not only a row id.
Backend authority: - Fingerprints are emitted by the owning backend read model. - UI components treat fingerprints as opaque strings. - Fingerprint format examples below are illustrative, not UI construction rules.
Examples:
- allocation:release_failed:<reason_code>:<node_id>
- node_agent:offline:<node_id>:<agent_version>
- payment_session:expired_uncredited:<stripe_status>:<user_id>
- webhook_delivery:failed:<event_type>:<provider_event_id>
Resurface rules:
- If target_id is the same but fingerprint changes, show as active again.
- If the item moves from warning to error severity, show as active again.
- If expires_at passes, show as active again.
- If the underlying state resolves, hide from active queues but keep audit.
Scope¶
Supported scopes: - per item: one target and one fingerprint; - per class: same target type and fingerprint pattern; - per environment: allowed only for platform admins and time-limited.
Default: - per item.
Per-class suppression requires: - explicit reason; - TTL; - platform admin role; - audit entry.
TTL¶
Defaults: - acknowledgement: no TTL required, but recommended for transient items; - suppression: TTL required; - max suppression TTL should come from policy, not hardcoded UI logic.
Audit Requirements¶
Every mutation writes audit:
- actor;
- action: acknowledge, suppress, clear_suppression, resurface;
- target type/id;
- fingerprint;
- reason;
- TTL/expires_at;
- correlation_id.
Queue Semantics¶
Queue counts should distinguish:
- active: unacknowledged and unsuppressed;
- acknowledged: visible but not urgent;
- suppressed: hidden from default queue, visible behind filter;
- resurfaced: active again with prior suppression context.
Default queue filter: - show active and resurfaced; - hide suppressed; - optionally show acknowledged in a muted group.
State Transitions¶
Allowed transitions:
none
-> acknowledged
-> suppressed
acknowledged
-> acknowledged (reason/owner update)
-> suppressed
-> none (clear)
-> resurfaced (fingerprint/severity/scope change)
suppressed
-> suppressed (TTL/reason update)
-> none (clear)
-> expired (TTL elapsed)
-> resurfaced (fingerprint/severity/scope change)
expired
-> acknowledged
-> suppressed
-> none (clear after review)
resurfaced
-> acknowledged
-> suppressed
-> none (clear after review)
Rules:
- suppressed -> suppressed is allowed only as an explicit TTL/reason update.
- acknowledged -> acknowledged is allowed only as an explicit reason update.
- Resolving the underlying condition removes the item from active queues but
does not delete the acknowledgement/suppression audit history.
Backend Contract Reservation¶
Before enabling real acknowledgement/suppression mutations, add contracts and
persistence for:
- Table: admin_ack_suppressions
- Read-model fields on ack-able rows:
- ack_fingerprint
- ack_state
- ack_reason
- ack_expires_at
- ack_actor
- ack_updated_at
- ack_state is computed on read by comparing the persisted
ack_fingerprint to the current row fingerprint and ack_expires_at to the
current time. Do not store ack_state as the source of truth.
- Mutations:
- acknowledge target/fingerprint;
- suppress target/fingerprint with TTL;
- clear acknowledgement/suppression;
- backend/system resurface.
- Audit actions:
- acknowledge
- suppress
- clear_suppression
- resurface
- Sentinel/domain errors:
- ack_target_not_found
- ack_fingerprint_mismatch
- suppression_ttl_invalid
- ack_scope_not_allowed
Error codes returned over HTTP must still use the catalog in
doc/architecture/Error_Code_Catalog.md; add contract-safe codes there before
using them publicly.
5. Platform IA Map¶
Ops¶
Landing: - health, live incidents, cross-domain queues.
Workbenches: - incidents/signals; - service health; - runtime logs and telemetry pivots.
Lifecycle¶
Landing: - node lifecycle KPIs; - urgent lifecycle queue; - pivots to nodes, provisioning, agents, profiles.
Workbenches:
- /v3-prod/platform/lifecycle/nodes
- /v3-prod/platform/lifecycle/provisioning
- /v3-prod/platform/lifecycle/agents
- /v3-prod/platform/lifecycle/profiles
Focused details: - node detail; - onboarding workflow; - decommission/reimage workflow; - agent rollout/repair workflow.
Config¶
Landing: - setup posture and drift.
Workbenches/focused pages: - SKUs; - images; - quotas; - policies; - storage providers; - MAAS sites/profiles.
Evidence¶
Landing: - audit coverage, export readiness, recent privileged actions.
Workbenches: - audit log; - task/event evidence; - correlation search; - exports.
Finance¶
Landing: - revenue/balance/payment health; - urgent finance queue; - pivots to sessions, ledger, reconciliation, refunds.
Workbenches:
- /v3-prod/platform/finance/sessions
- /v3-prod/platform/finance/ledger
- /v3-prod/platform/finance/reconciliation
- /v3-prod/platform/finance/refunds
- /v3-prod/platform/finance/webhooks
Focused details: - payment session detail; - ledger account/user detail; - reconciliation run detail; - refund decision detail.
Runbooks¶
Runbook surface:
- /v3-prod/runbooks/{key} is the canonical in-product page for longer
procedures opened from operation drawers.
Placement:
- Runbooks are a support surface, not a fifth admin family.
- Platform family pages and drawers may deep-link to runbooks.
- Runbooks may link back to the relevant workbench or focused detail route.
- Runbooks are versioned documentation in doc/operations/runbooks/ or
doc/product/ and are owned by the domain that owns the operation.
Graduation rule:
- One sentence of non-obvious context: ContextHelp.
- First-use/no-data explanation: empty state.
- Decision-specific warning: confirmation dialog.
- Multi-step procedure or policy rationale: runbook.
IAM¶
Landing: - user/tenant/project access posture.
Workbenches: - users; - tenants; - roles; - service accounts; - entitlements.
6. Validation Surface 1: Lifecycle Nodes¶
Landing target:
- /v3-prod/platform/lifecycle
Landing content:
- 4 KPI tiles: active nodes, blocked nodes, active allocations, needs action.
- One lifecycle queue summary.
- Pivot bar: Nodes, Provisioning, Agents, Profiles.
- No full node table.
- No MAAS profile cards.
- No long intervention card grid.
- Needs action and queue counts must use the same default queue semantics as
Section 4: active plus resurfaced, excluding suppressed.
Nodes workbench target:
- /v3-prod/platform/lifecycle/nodes
Workbench behavior: - Left/list: nodes with status, occupancy, agent state, maintenance impact. - Right/detail: selected node overview, allocations summary, agent health, latest task/evidence. - Operation drawer: inspect, telemetry, cordon/drain, agent repair, certificate repair, reimage, retire. - AckSuppressControl applies to node-agent and lifecycle failures.
Focused node detail: - Keep for deep links and narrow screens. - Default tabs: Overview and Activity. - Operations open drawer from header. - Lifecycle Nodes must satisfy Section 9 success criteria before it is treated as a model-validating surface.
7. Validation Surface 2: Billing Sessions¶
Landing target:
- /v3-prod/platform/finance
Landing content:
- 4 KPI tiles: balance risk, pending payments, failed sessions, reconciliation
drift.
- One finance queue summary.
- Pivot bar: Sessions, Ledger, Reconciliation, Refunds, Webhooks.
- No full session table.
- No inline diagnostics dump by default.
- Failed sessions, reconciliation drift, and queue counts must use the same
default queue semantics as Section 4: active plus resurfaced, excluding
suppressed.
Sessions workbench target:
- /v3-prod/platform/finance/sessions
Workbench behavior: - Left/list: payment sessions with status, amount, user, age, provider status, correlation id. - Right/detail: selected session state, ledger linkage, Stripe/provider linkage, webhook evidence, user/account context. - Operation drawer: copy IDs, open diagnostics, retry reconciliation, mark reviewed, create refund workflow, suppress known test/provider noise. - AckSuppressControl applies to expired/uncredited sessions, failed webhooks, and reconciliation drift.
Focused payment session detail: - Used for deep links from audit, support, and finance queues. - Default tabs: Overview and Activity. - Billing Sessions must satisfy Section 9 success criteria before it is treated as a model-validating surface.
8. Implementation Sequence¶
- Add this spec as the admin workbench contract.
- Add shared UI primitives without changing behavior:
AdminFamilyLandingAdminWorkbenchOperationsDrawerAckSuppressControlplaceholder or disabled shell- Trim Lifecycle landing to family-dashboard scope.
- Implement Lifecycle Nodes workbench as the first validation surface.
- Implement Finance landing and Sessions workbench using the same primitives.
- Add backend ack/suppression contracts and persistence before enabling real suppression mutations.
Do not build Finance as another long page while Lifecycle is still carrying workbench/detail content inline.
9. Success Criteria¶
Family landings: - Median scroll depth under normal desktop data is less than 1.5 viewports. - No full inventory table renders on a family landing. - The first actionable queue item is visible without scrolling.
Workbenches: - Median time from landing on a workbench to opening the first operation drawer is under 30 seconds in operator testing. - Selecting a new row does not navigate away on desktop. - Narrow-screen row selection uses the focused detail route.
Queues: - At least 80% of visible queue items have a concrete primary action. - Suppressed items do not count toward default urgent counts. - Resurfaced items show prior acknowledgement/suppression context.
10. Design Rules¶
- One page, one primary job.
- If the operator is scanning many records, use a workbench.
- If the operator is deciding one action, use a drawer or focused detail.
- If prose explains the section, move it to
ContextHelp, empty state, confirmation, or runbook. - Queue pressure must be actionable. If a queue contains intentionally ignored failures, add acknowledgement/suppression before adding more queue surfaces.
- Every privileged action needs evidence and audit linkage visible from the operation drawer.
Pivot ceiling: - Family landings should show 3-5 primary pivots. - If a family needs more than 5 destinations, group them into a workbench index or secondary "More" menu. - Do not add a second horizontal tab row to solve pivot overflow.
11. Existing Surfaces To Trim¶
These are known violations of the model and should be queued for conversion:
- Lifecycle landing: remove the full node inventory table into
/v3-prod/platform/lifecycle/nodes.
- Lifecycle landing: move MAAS profile cards into
/v3-prod/platform/lifecycle/profiles or Config setup.
- Lifecycle landing: collapse intervention workflow grids into one queue summary
plus pivots.
- Finance landing: do not add full payment-session, ledger, reconciliation, or
webhook tables inline.
- Focused details: move long operation catalogs and procedure prose into
operation drawers and /v3-prod/runbooks/{key}.