Skip to content

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

  1. Add this spec as the admin workbench contract.
  2. Add shared UI primitives without changing behavior:
  3. AdminFamilyLanding
  4. AdminWorkbench
  5. OperationsDrawer
  6. AckSuppressControl placeholder or disabled shell
  7. Trim Lifecycle landing to family-dashboard scope.
  8. Implement Lifecycle Nodes workbench as the first validation surface.
  9. Implement Finance landing and Sessions workbench using the same primitives.
  10. 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}.