← back to index

Admin dashboard restructure — audit

Source of truth: ~/joyos-labs/src/views/AdminView.vue (8,033 LOC). Last touched 2026-05-14 to add the Founding-Member badge grant UI.

TL;DR. One horizontally-scrolling bar holds 16 unrelated functions. Three of them (Members vs Users vs Invites) overlap. Several haven't been opened in months. The Stripe tab is the only one with sub-navigation, suggesting the rest are also too dense to fit at the top level. Mobile is essentially unusable — the tab strip becomes a 16-item horizontal scroll with no landmarks.

1. Current state — inventory

Every tab declared in AdminView.vue:48, in source order:

#LabelSlugPurposeComplexityRecent activity
1Overviewmembers4-stat-card summary (total users + per-tier counts). PWA-install metrics loaded here too.TinyStable
2FeedbackfeedbackFeedback inbox + the AI daemon status bar, agent config modal, deploy banner, feedback-detail editing.Huge (~2,000 LOC)Active — last touch 2026-05
3InvitesinvitesMagic-link invite list + bulk-grant tier UI.MediumStable
4StripestripeThree internal sub-tabs: Products / Agent / History. The only tab with its own nested navigation.LargeActive
5MembersusersSearch + filter the users table; inline tier edit; impersonation; badge grant.Large (~1,500 LOC)Active — 2026-05-14 badge grant
6FlagsflagsFeature-flag CRUD. Most flag editing happens via the per-nav-item cog now, so this is read-mostly.MediumStable
7EventseventsEvents table (founding-member hub call, etc.).SmallNew (2026-05-13)
8PairspairsConnection-Pair matching admin (legacy feature).MediumCold
9TrialstrialsActive trial sessions + grant-trial form.MediumStable
10BackupsbackupsBackup status display.TinyStable
11TierstiersTier-display configuration. Overlaps heavily with Stripe products.SmallCold
12NotesnotesMarkdown admin notes (built-in + user-created). Effectively a wiki page.MediumActive
13MediamediaR2 / MinIO media library.MediumStable
14ExperimentsexperimentsExperiment editor (Space Audit etc.) — also has its own route /app/admin/experiments.LargeActive
15IntegrationsintegrationsExternal integration config (Airtable, Resend, etc.).MediumStable
16PreviewspreviewsPR preview environments list — redirects from /app/admin/previews.SmallStable

Plus the standalone admin routes: /app/admin/tour, /app/admin/experiments[/:slug], /app/admin/storage-settings — discoverable today only by typing the URL.

2. Problems

Overcrowded primary nav

Redundant / overlapping concerns

Misnamed labels

Hidden admin surfaces

Mobile

Dashboard ≠ admin distinction is muddied

3. Principles applied to the restructure

  1. One noun per surface. If two tabs operate on the same noun (users, money, content), they collapse into one surface with sub-views.
  2. Frequency drives placement. The two tabs Kristin actually opens daily — Feedback and Members — get pole position. Tabs that haven't been touched in 30+ days get demoted.
  3. ≤ 7 top-level destinations. Anything beyond that nests one level deeper, behind a label that names the workflow.
  4. Workflow-first labels. "Grant a trial" is what an admin does; "Trials" is what the data is called. Labels should describe verbs where reasonable.
  5. Survives mobile. The structure must work in a vertical drawer, not just a horizontal strip.
  6. Search as escape hatch. When IA can't be perfect, ⌘K should reach any admin surface in two keystrokes.

4. Proposals

Three distinct restructures, varying along the axes of hierarchy, discovery mechanism, and mental model:

Proposal 1 — Grouped sidebar (4 collapsible sections)

"Stripe Dashboard for admin." Tabs become a left sub-nav, organized into 4 groups by domain. Familiar pattern, biggest visual change, lowest cognitive change.

Admin ├── People │ ├── Overview (was: Overview) │ ├── Members (was: Members + impersonate) │ ├── Invites (was: Invites) │ └── Trials (was: Trials + grant) ├── Money │ ├── Billing (was: Stripe→Products + Tiers, merged) │ ├── Billing agent (was: Stripe→Agent) │ └── History (was: Stripe→History) ├── Content │ ├── Feedback (was: Feedback) │ ├── Experiments (was: Experiments + /admin/experiments) │ ├── Events (was: Events) │ ├── Media (was: Media) │ └── Notes (was: Notes) └── Operations ├── Feature flags (was: Flags) ├── Integrations (was: Integrations) ├── PR previews (was: Previews + /admin/previews) ├── Storage (NEW surfaced: was hidden /admin/storage-settings) ├── Tour editor (NEW surfaced: was hidden /admin/tour) ├── Pairs (was: Pairs — demoted) └── Backups (was: Backups — demoted)

Pros

16→4 top-level groups. Familiar SaaS pattern. Surfaces previously-hidden admin routes. Mobile-friendly (sections collapse cleanly).

Cons

Two clicks to reach anything. Doesn't address the "I want to grant trial X for user Y" cross-tab workflow.

Risks

Grouping is opinionated — Notes could equally belong in Operations. Easy to argue forever.

View mockup →

Proposal 2 — Command palette + recents

The 16 tabs collapse to one surface called "All admin." ⌘K reaches anything in two keystrokes; a left-rail of recents covers the 80% case.

Admin (single page) ├── Recents (auto: last 5 surfaces visited) ├── Pinned (user-pinnable from any surface) └── All admin (grid of 16 surfaces, alphabetized, with last-visited + last-edited meta) Global: ⌘K opens a command palette that searches: · surface names (Feedback, Members, Flags …) · destructive verbs (Grant trial, Impersonate, Purge cache) · entity lookup (user email → opens user-detail directly)

Pros

Future-proof (17th tab is free). Two keystrokes beats two clicks for power users. Recents = de-facto frequency-based nav without curation. Verb-search is the killer feature.

Cons

Discovery via search means new admins need onboarding. No visual hierarchy = no domain landmarks. Requires building a real palette component.

Risks

Kristin doesn't share Ethan's keyboard-first reflex; she may bounce off the empty-state palette.

View mockup →

Proposal 3 — Role-based home cards

The admin landing is three role cards — Member success, Money & growth, Build & operate — each showing live counts and the 2-3 actions that role actually performs. Existing tabs survive as drill-downs.

Admin home ├── Member success [card] │ · 14 unread feedback → Feedback │ · 3 trials expiring → Trials │ · 2 invites pending → Invites │ [Open inbox] [Grant trial] [View members] │ ├── Money & growth [card] │ · 2 webhooks failed → Stripe history │ · 1 product unsynced → Stripe products │ [Edit pricing] [Run webhook backfill] │ └── Build & operate [card] · Last deploy: 12m ago → Previews · 1 feature flag draft → Flags [Open flag editor] [View deploys] [Run backup] Drill-down: each card links to the same existing tabs, but framed around the work, not the data.

Pros

Landing answers "what needs my attention right now?" not "where do I click?" — strongest fit with the dashboard-central-hub philosophy. Surfaces underused tabs by showing live counters. Same nav structure, new entry point.

Cons

Requires live data fetches on the admin landing. Role boundaries blur (whose job is the failed webhook?). Existing tab strip likely still needed as a fallback.

Risks

"Role" doesn't map cleanly when there are only 2 admins. May feel like extra ceremony for someone who knows exactly what tab they want.

View mockup →

5. Recommendation

The least-risky path is Proposal 1 (grouped sidebar) — it preserves every existing surface, demotes nothing destructively, and matches a pattern Kristin sees daily in Stripe / GitHub / Linear.

The highest-leverage path is Proposal 3 (role cards) — it directly addresses the dashboard-as-hub philosophy Ethan reinforced last week, and replaces "did I check the right tab?" with "what needs me right now?"

A reasonable ship sequence is Proposal 1 first (a structural cleanup that ships in days), then Proposal 3's role-card landing added on top as a richer admin home that drills into the new grouped sidebar.

Reply with which direction resonates and I'll cut a real PR.