Admin Dashboard
The admin package is the Green Goods operator canvas. This page is the single UI contract for packages/admin.
Purpose
packages/adminowns canvas shell composition and admin-only workflows.@green-goods/sharedowns reusable UI primitives, shared config helpers, hooks, providers, stores, and Storybook-backed foundations.- If a pattern is reusable across admin surfaces, move it to shared instead of creating a package-local copy.
Canonical Routes
- Primary canvas surfaces:
/hub,/garden,/community,/actions - Hub canonical deep links:
/hub/work/:workId,/hub/work/submit,/hub/assess/create,/hub/certify/:assessmentId,/hub/certify/create,/hub/history/:historyEventId - Secondary garden flows:
/garden/create,/garden/impact/hypercerts/:hypercertId,/community/treasury/vault,/community/governance/strategies,/community/governance/signal-pool/:poolType - Team campaign flows:
/cookies,/cookies/deploy - Removed admin top-level routes intentionally fall through to the admin 404 unless they are listed in the redirect policy below.
Redirect Policy
- Canonical admin bookmarks stay inside the admin app:
/hub,/garden,/community,/actions, and their documented nested routes. - Public garden URLs redirect to the client app:
/gardens,/gardens/:gardenId, and/gardens/:gardenId/*map to the same path ongreengoods.app. - The admin SPA keeps a client-side fallback for public garden URLs so local and static preview environments match production redirects.
- Removed admin route families are not blanket-redirected. Add a specific destination here before preserving any legacy admin bookmark.
Shell Contract
CanvasLayoutis the canonical shell.- The shell is
AppBar + .workspace-canvas + MainSheet + NavigationBar. AppBaris the stickyz-sticky h-14context region withGardenChipon the left and search, notifications, settings, and profile controls on the right. The three global actions open theAdminSideSheet; settings and profile are desktop-only (on mobile those surfaces live in the Profile tab, and the bell remains).NavigationBaris navigation only. The canonical items areHub,Garden,Community, andActions(plus the mobile-only Profile tab).- Controlled Chrome is the admin material boundary: subtle liquid glass is permitted on NavigationBar/FAB only. The AppBar root stays transparent so the workspace canvas tone reads behind it. Route cards, forms, tables, lists, dense content, dialogs, and the account side sheet stay solid.
ConnectShellis the disconnected full-screen state with a centered connect prompt and no navigation.- Admin owns
CanvasLayout,AdminSideSheet,CommandPalette,AccountProfilePanel,AccountSettingsPanel,AccountSurface,ConnectShell, andPageHeader. - Account panels render
AccountProfilePanelandAccountSettingsPanelas separate contents of theAdminSideSheetaccount inspector (routed through the right-sheet registry).AccountSurfaceremains the route-level tabbed account surface for mobile profile navigation — tabs Account | Settings ("Account" is the mobile name for the desktop Profile sheet content; notifications never appear as a tab). - Shared owns
AppBar,NavigationBar,GardenChip,MainSheet,NotificationPanel, andSheetErrorBoundary. TheLeftSheet/RightSheet/BottomSheetrenderers are deleted — every workspace overlay usesAdminDialog(centered on desktop, with the variant-specific mobile geometry in the dialog contract); the three global AppBar surfaces are the oneAdminSideSheetexception.
Preferred Primitives
AppBarNavigationBarMainSheetGardenChipCommandPaletteAccountSettingsPanelConnectShellPageHeaderAdminBadgeAdminButtonAdminCardAdminCheckboxAdminDialogAdminFabAdminFilterChipAdminLinearProgressAdminListItemAdminSearchToolbarAdminSelectableCardAdminChoiceGroupAdminConfirmDialogAdminSideSheetAdminSortSelectAdminTabRailAdminTextFieldAdminTooltipAdminViewActions- Shared foundations where appropriate:
ListToolbar,SortSelect,Card,Alert,StatusBadge,FormField
Card And Selection Grammar
- Use
WorkbenchCardfor workbench records, action queue items, assessment queue items, and other records operators scan, compare, and act on in a grid or list. - Use
AdminCardfor compact modules, stats, settings, status panels, and supporting detail regions. - Use
AdminSelectableCardfor richer exclusive or multi-select choices where the option needs a title, description, icon, or metadata. - Use
AdminChoiceGroupfor compact single-select preferences and context switches inside dense panels. - Use
AdminTabRailfor route-local exclusive modes or tabs. - Use
AdminFilterChipfor compact toolbar filters. - Avoid adding new direct shared
Cardusage in admin route work unless the route is intentionally consuming an existing shared, non-admin surface.
Surface Primitives
.workspace-canvasis the default canvas workspace treatment..surface-sectioncreates a rounded full-width section wrapper..surface-insetcreates nested panels inside a section..surface-cardcreates interactive tiles.
Dialog Contract
- Admin dashboard modals use
AdminDialogfor form and command-palette surfaces andAdminConfirmDialogfor destructive or confirmation flows. AdminDialogrenders a centered M3 dialog on desktop. On mobile,standardworkspace action/detail surfaces andflowcreation surfaces render as full-width bottom sheets; compactconfirmandpalettedialogs stay inset.- Dialog actions belong in the pinned
actionsslot. Keep cancel, save, confirm, retry, and close controls outside the scrollable body. - Form and detail content scrolls inside the dialog body, not on the page behind the scrim.
- Every admin dialog must expose a visible surface above the scrim, a non-zero panel rect, accessible title and description wiring, a close or cancel affordance, reduced-motion-safe behavior, and visible pinned actions when there is something to commit or cancel.
- The command palette uses the
palettevariant ofAdminDialogso search behavior and keyboard navigation live inside the same admin modal contract. AdminDialogsizes follow a three-tier scale by action weight —smis reserved for confirm/alert dialogs,md(the default) hosts a simple single-purpose action (one form, one concern),lghosts richer single-view content (lists with per-item actions, multi-field or multi-column layouts).xl/2xltiers no longer exist. A guard test (packages/admin/src/__tests__/components/AdminDialogStandard.guard.test.ts) fails any consumer passing an out-of-scale size or an ad-hocmax-w-*override.- Full-surface action flows (Submit Work, Create Assessment, Create Hypercert) use the
flowvariant ofAdminDialogwithsize="lg"and the sharedADMIN_FLOW_DIALOG_CLASSsizing constant. Theflowvariant suppresses the structured header and inner padding so the sharedActionFlowShellowns the visible header + scrolling body + pinned footer; it stays a centered, scrim-backed modal on desktop and a full-width bottom sheet on mobile, not a fullscreen takeover. DialogShellremains available for shared or non-admin surfaces. Do not use it for admin dashboard dialogs.- The three global AppBar surfaces (Profile, Settings, Notifications) are the one side-sheet exception:
AdminSideSheetshares the dialog chrome (scrim, hairline header, close button,tone, instant-exit) with side-sheet geometry — right-docked within the canvas chrome bounds at ≥640px, and the compact inset bottom-sheet geometry below. Panels composeSheetBody/SheetFooterinside it (the shell adds no padding). Usage is locked toCanvasLayoutand the registry to the three content ids bypackages/admin/src/__tests__/components/AdminSideSheetStandard.guard.test.ts.
Dialog interior grammar
Every variant shares one chrome — the action-flow reference anatomy — so standard, confirm, and palette dialogs read as the same product as the flows:
- Chrome. Header is a hairline-bottom bar (
px-4 py-3 sm:px-6) with an optional inline icon, atext-lgsemibold Title Case title, and atext-smsentence-case description. The body is the scrollable region between header and footer. Theactionsslot renders as a pinned footer bar — hairline top border on--surface-raised(the same anatomySheetFootergives the flows).AdminDialogowns all of this; consumers never rebuild header or footer chrome. - One header, one footer. Interior content never repeats a heading the dialog header states (no
Card.Headerinside a dialog), and a non-flow dialog that passesactionsmust not also nest aSheetFooter. Both are guard-tested. - Footer Cancel exits the dialog. A footer
Cancelruns the same guarded close as the X / scrim / Escape (confirm-before-discard when the form is dirty), and is disabled only while a write is in flight — it is not a form-reset, and is not disabled just because the form is pristine (a disabled-when-clean Cancel reads as broken).Savestays disabled until the form is dirty and valid. - Body sections separate with
space-y-4/space-y-6; section eyebrows use thelabel-xs/label-mdutilities in sentence case — no ad-hocuppercase tracking-wide. A field label (the title that labels a control) is different: it routes throughFormField(stacked field) orAdminSettingRow(inline setting row), also sentence case — never thelabel-xs text-text-softeyebrow token, which reads smaller and greyer than the fields beside it. Label/value pairs render as one-line definition rows (label left intext-text-soft, value right), not stacked icon rows. - Two-column layouts are
lg-only, using the established grids (lg:grid-cols-[minmax(0,2fr)_minmax(18rem,1fr)]or the WorkDetail 3/2 split): form/primary content left, load-bearing preview/meta right.mdand mobile always collapse to one column. - Loading reserves final geometry. Skeletons match the rendered component's dimensions (the same card/row shapes in
skeleton-shimmer, or explicit min-heights); never swap "Loading…" text into a value slot. A dialog's first paint fixes its height for the data it awaits. - Empty states use the shared
EmptyState(icon + title + description) centered in the reserved region — never bare text stretched to fill. - Open-state pattern. Dialogs stay mounted with a controlled
open;{cond ? <Dialog isOpen /> : null}skips the exit animation (close flash) and is forbidden. Closes that can never animate (hidden tab) are handled centrally by AdminDialog's instant-exit + the CanvasLayout close safety net. - Tone. Every dialog passes the
toneof its mounting workspace (the portal escapes[data-tone]); accent and status color inside dialogs go through--tone-*/--m3-*indirection only, so the[data-theme="dark"]ladder controls dark variants centrally. The account inspector deliberately stays on the neutralhubtone (global chrome, not workspace content).
Admin Color Roles
--tone-actionis for filled action backgrounds. It uses deep steps so white text clears contrast in light and dark mode.--tone-on-actionis the text/icon color on filled action backgrounds.--tone-on-surface-accentis for colored text/icons on solid surfaces.--tone-focus-ringis the only focus-ring role. It resolves to action tone in light mode and on-surface accent in dark mode so keyboard focus remains visible.--m3-outlineis the control-grade boundary for fields, chips, and outlined buttons.--m3-outline-variantis a decorative hairline. Do not use it as the only boundary for a control.- Shared Canvas components consumed by admin cannot rely on arbitrary Tailwind utility classes authored in
packages/shared/src; admin does not scan that package for generated utilities. Use inline token styles or admin CSS overrides for shared Canvas color/layout behaviors that must render inside admin.
Canvas UI Heuristics
- Admin is an operator canvas. Use utility copy and operational hierarchy over marketing language.
- Default page sequence is
PageHeader, then the primary workspace, then any secondary inspector (AdminDialog, centered on desktop). - Start with layout and flow before introducing cards or elevated panels.
- Cards and elevated surfaces are for discrete records, action targets, and bounded interaction zones. They are not the default page structure.
- Prefer one dominant workspace surface per route and plain layout within it. Avoid nested stacks of rounded bordered panels.
- Avoid hero sections, decorative promo callouts, and decorative gradients behind routine product UI.
- Use route-tint atmosphere, transparent AppBar continuity, Controlled Chrome depth on Navigation/FAB, and high-contrast state accents to establish hierarchy without turning the UI into a promo surface.
- Use
/hubas the reference implementation for canvas composition and interaction density. bun run check:design-tokensenforces the material boundary: admin source must not add glass, backdrop blur, or decorative gradients outsidepackages/admin/src/index.cssandadmin-m3-overrides.css.- Route content, canvas tone changes, FAB menus, sheets, and interaction state use the admin motion role aliases (
--admin-motion-*) layered on top of the canonical--spring-*tokens.
Unified Canvas Route Contract
- Every primary route must answer one operator question, not three.
- The first viewport must show: route title, one short scope sentence, current garden context when applicable, one control row, and the first actionable content.
- Default page anatomy is
PageHeader-> one dominant workspace canvas -> optional secondary inspector (AdminDialog, centered on desktop, or a single rail). - Use one control grammar per route. Choose one of: stage tabs, view tabs, or a list toolbar. Do not stack multiple competing switchers and banners above the workspace.
- Use at most one strong CTA in the header. If a FAB exists for the route, the header should not duplicate the same creation action.
- View-level actions must flow through
ViewAction+AdminViewActionson desktop and the same action set throughuseViewActionsfor tablet/mobile FAB speed dial. Do not add duplicate inline edit buttons inside route bodies for the same action; contextual row actions are allowed when the row is the only discoverable setting control. - Summary metrics are optional and should appear only when they improve decisions. Cap summary strips at three items for operational routes.
- Prefer layout, rows, and sections over card mosaics. Use cards only for discrete records, bounded workflows, or detail modules that need separation.
- Default detail behavior is an inspector or secondary pane, not a new pile of inline cards.
- Use utility copy. Titles identify the workspace. Descriptions explain scope, freshness, or what the operator can do next.
- Keep imagery subordinate to status, title, and actions unless the operator is explicitly reviewing media itself.
- Reduced-motion support is mandatory. Stage changes, row selection, and sheet open/close must retain state clarity without relying on travel or spring lift.
- Route and tab changes should animate only the named route content group. AppBar, Navigation/FAB, and the canvas root stay visually stationary.
Admin Route Recipe
Use this as the default assembly order for a new or refreshed primary admin route:
- Start with
CanvasRouteFrameand the route header. The title names the workspace; the description states scope or freshness. - Put view-level actions in
AdminViewActionson desktop and the matchinguseViewActionsaction set for tablet/mobile FAB speed dial. - Choose one control grammar: stage tabs, view tabs, or a list toolbar. Do not stack tabs, banners, and competing switchers above the work area.
- Use
AdminSearchToolbar,AdminSortSelect,AdminFilterChip, andAdminTabRailfor search, sorting, filtering, and route-local modes. - Build one dominant workspace surface. Prefer rows, sections, and dense work areas over card mosaics.
- Use cards only for discrete records, bounded workflows, or detail modules that need separation.
- Open workspace action/detail flows in
AdminDialog; usevariant="flow"withsize="lg"andADMIN_FLOW_DIALOG_CLASSfor full-surface creation/commit flows. Desktop centers these dialogs; mobile presentsstandardandflowas full-width bottom sheets. - Use
AdminSideSheetonly for the three global AppBar surfaces: Profile, Settings, Notifications. - Keep loading, empty, disabled, and error states calm and operational. Empty states should preserve final geometry and explain the next action.
- Reject hero sections, promotional gallery framing, decorative gradients, ad-hoc dialog widths, nested card stacks, and glass outside Navigation/FAB chrome.
Route Roles
/hubis the primary canvas workspace. Its primary object is the Hub workbench with Work, Assess, Certify, and History modes./hubis the gold-standard canvas route for composition, depth, responsive adaptation, and tactile state behavior./hubdefaults to one dominant workbench surface under the stage rail. Detail, review, and read-only handoff flows open asAdminDialoginspectors (size="lg", workspace tone). Full-surface creation/commit flows (Submit Work, Create Assessment, Create Hypercert) open as anAdminDialog(variant="flow"+ADMIN_FLOW_DIALOG_CLASS) with a scrim — centered on desktop, full-width bottom sheet on mobile — hosting the sharedActionFlowShellgrammar (pinned header + scrolling body + pinned footer). They are never fullscreen takeovers or non-modal routes.- Read-only Hub deep links (
/hub/work/:workId,/hub/certify/:assessmentId,/hub/history/:historyEventId) areAdminDialoginspectors that render through the Hub controller and preserve shareablegardenAddressandsortquery state. Full-surface creation/commit deep links (/hub/work/submit,/hub/assess/create,/hub/certify/create) open the action-flow dialog (full-width bottom sheet on mobile), not inspector sheets. Hub mode belongs to the path, not aviewquery parameter. Certifystays visible for evaluator-only users as a read-only handoff state. Owner or operator authority unlocks mint actions./gardenis the situational overview of a single garden. Its primary object is health, activity, and impact state./communityis the operations workspace for membership, treasury, pools, and yield. Only one of those modes should dominate the canvas at a time./actionsis the action registry and lifecycle workspace. It should feel like a managed catalog, not a marketing gallery.
Route Smells To Reject
/hub: stage navigation should reflect real operating modes rather than placeholder pipelines./hub: header chrome should keep the first actionable queue content within immediate reach./garden: large summary card grids before the operator reaches the actual overview or impact workspace./garden: mixing overview, impact, and settings as visually equivalent tabs without clearly changing page mode./community: a stat strip plus tab switcher plus contextual CTA banner plus card stack before the user reaches the active mode./community: treating treasury, members, pools, and yield as one blended page instead of four focused operational modes./actions: image-led card galleries that make the route read like a promotional browse surface instead of an admin registry./actions: filters that change presentation but never establish a clear “default management view” for scanning and editing records.
Page Families
- List pages:
PageHeader + ListToolbar + filters/sort + loading/empty/error + results - Detail and workbench pages:
PageHeaderor garden hero plus main/rail composition - Operational pages:
PageHeader + stage/tabs + primary workspace + optional inspector
Migration Rules
DashboardLayout,Sidebar, andHeaderare legacy references, not starting points for new work.- Do not add admin-local primitive shims such as
components/ui. - Do not add admin-local config helpers when the behavior belongs beside shared React Query or other shared config.
- Do not introduce package-local
utils/for logic that should live in shared. - Keep reusable components consumed through the
@green-goods/sharedbarrel.