Skip to content

v4.15 — Dashboard Hierarchy — Standard & Detailed

One dashboard, two densities — the 1,570-line populated-dashboard monolith becomes a lean Standard default and an inline-expandable Detailed tier, with the Focus card stack untouched.

Summary

Before this milestone, Dashboard.vue's populated branch (Branch D — users with 3+ active goals) had grown to 1,570 lines and rendered CoachDockCard up to three times across duplicated, near-identical layouts. A permanently-0% stats tile sat in the prime slot for habit-heavy users (habit goals never flip completed, so they sit in the denominator but never the numerator of overallProgress), a Supporter upsell sat above today's actions, and SocialSection/ShowcasedAchievements competed with the dashboard's actual job instead of living on their own tabs.

This milestone replaced that single busy branch with one hierarchy — primary → secondary → tertiary — offered at two densities. Standard (the new default) collapses the tertiary layer (week shape, upcoming events, AI insight) behind a "More on your week" disclosure; Detailed expands it inline on both mobile and desktop. Existing full-mode users were backfilled to Detailed once, with a dismissible migration note, so nobody lost the density they'd chosen without being told where it went. Focus, the swipeable card-stack view, was explicitly out of scope and shipped unchanged. The habit-goal metric was fixed, SocialSection and ShowcasedAchievements were relocated to the Community and Achieve tabs with discovery hints, and the Supporter nudge was demoted out of the prime slot — all locked product calls from Josh at kickoff (OBJ-1719 §3), not open design questions.

The five phases (UI-SPEC → decomposition → persistence → layout/relocate/flag → docs/rollout) shipped on the integration branch gsd/v4.15-dashboard-hierarchy between 2026-07-24 and 2026-07-25, and the dashboard_hierarchy PostHog flag was ramped to 100% and retired from code in Phase 5. The integration branch itself, however, sat unmerged to master for five days — the flag was live at 100% rollout the entire time, evaluating against code that only existed on the unlanded branch, so the feature was silently inert in production. Josh caught the gap by opening the app on 2026-07-30 and not seeing the feature. The missing master-promotion landed as a same-day hotfix (PR #1891, OBJ-1911) after reconciling 92 commits of drift, and a new CI guard (chore(guards): detect stranded milestone branches and reverse PostHog flag drift, #1894) now catches this failure mode — a milestone-complete flag at 100% rollout with no corresponding code on master — before it can happen silently again.

Goal

Restructure the populated dashboard (ionic_frontend/src/views/Dashboard.vue, a 1,570-line monolith whose Branch D competes with itself across ~15 surfaces) into one dashboard with two densities: a lean Standard default with a clear primary → secondary → tertiary hierarchy, and a Detailed density preference that expands the tertiary layer inline. Focus (the swipeable StreamlinedDashboard card stack) is unchanged. Today's action goes in the prime slot; noise (a permanently-0% stats row, an upsell above the fold, sections that belong on other tabs) is removed, demoted, or relocated. The dashboard-density preference is promoted server-side (UserDetail.data → GraphQL UserType), existing full-mode users migrate to Detailed, and the whole change ships behind a feature flag.

Scope — What Shipped

  • DashboardHierarchy.vue — the new Branch D, rendering Standard or Detailed density from one shared primary/secondary/tertiary composition instead of the old duplicated layout.
  • Four-branch decompositionDashboard.vue's empty / first-goal / sparse / populated branches extracted into standalone components (DashboardEmptyState, DashboardNewGoalState, DashboardSparseState, DashboardHierarchy) with zero visual diff proven by the existing spec suite passing unchanged.
  • Server-persisted density preferencestore_accessor :data, :dashboard_mode, :dashboard_density on rails_api's UserDetail, exposed on GraphQL UserType as dashboardPreferences { mode density }, mirroring the existing coaching-preferences pattern.
  • 4-option Settings control (Focus / Standard / Detailed / Auto) plus an in-context header mode chip / DashboardModeSwitcher for switching without opening Settings.
  • One-time full → Detailed backfill with a dismissible, server-acknowledged migration note (not localStorage) so the prompt doesn't reappear across devices.
  • Habit-goal metric fix for overallProgress/completedGoals, so a habit-heavy user no longer shows a structurally stuck 0%.
  • Relocations with discovery hintsSocialSection → Community tab, ShowcasedAchievements → Achieve tab — plus demotion of SupporterStreakNudge out of the prime slot and a one-interstitial-per-session cap.
  • dashboard_hierarchy PostHog flag — registered, ramped to 100%, and retired from code in Phase 5 once flag-off parity was reconfirmed; Branch D now renders unconditionally.
  • Docs reconciliationdocs/features/dashboard.md rewritten for the Focus / Standard / Detailed / Auto model and the new composition.

Phases

PhaseNameStatusPlansHighlights
1Dashboard hierarchy UI-SPEC (OBJ-1722)Shipped1Desi's design contract — Standard/Detailed wireframes per breakpoint, mobile tertiary home, 4-option Settings copy, migration-note copy, metric decision. Hard Josh sign-off gate before Phases 2–5 dispatched.
2Behavior-preserving decomposition (OBJ-1723)Shipped1Dashboard.vue's four branches extracted into components; zero visual/behavioral diff (#1769)
3Dashboard preference persistence (OBJ-1724)Shipped1UserDetail store_accessor + GraphQL UserType + Interaction::Base mutation (#1768)
4Standard/Detailed hierarchy + relocations + Settings + backfill (OBJ-1725)Shipped1Core UX change behind the flag — layout, 4-option control, relocations, metric fix, flag registration (#1776)
5Rollout + docs + cleanup (OBJ-1726 / OBJ-1747)Shipped1docs/features/dashboard.md reconciled (#1780); flag ramped to 100% and retired, dead legacy branch deleted (#1781)

Key Decisions

  • Hybrid, not three layouts. Standard default + Detailed density that expands the tertiary layer inline — one layout, two densities. Focus card stack stays untouched. Locked by Josh at kickoff (OBJ-1719 §3); a third separate layout was explicitly rejected.
  • Naming: Focus / Standard / Detailed / Auto — no "Pro." Supporter is the paid concept; a "Pro" dashboard tier would wrongly imply a paywall on a free-means-free app.
  • Migration is backfill, not silent loss. Existing full-mode users move to Detailed automatically, with a dismissible note explaining the change — nobody loses the density they chose without being told where it went.
  • Respect Over Revenue over conversion optimization. The Supporter upsell was demoted out of the prime slot as a PBC/dark-pattern requirement, not a preference — measured for conversion impact in PostHog, but not reverted on that basis alone.
  • Phase 5's flag-off parity gate used a documented substitute, not the planned screenshot-diff. Docker Desktop was unhealthy across two fix rounds, so capture-ui-evidence.mjs was unreachable. Roy accepted 102/102 Vitest pass against the unmodified base commit as substitute evidence, given the integration branch hadn't shipped to real users yet and the gated component itself was unchanged by the cleanup. Real screenshot-diff evidence was still owed before a master merge — see Tech Debt.
  • A stranded, fully-shipped integration branch is a distinct failure mode from an unfinished one. All five phases were complete and the flag was at 100% rollout for five days while the code sat on gsd/v4.15-dashboard-hierarchy, unmerged — monitoring said "live," production had nothing to render it, and nothing alerted on the gap. The fix wasn't just landing this milestone (PR #1891); it was adding a guard (#1894) that detects this specific pattern — a milestone-complete branch with its flag ramped but not merged — going forward.

Requirements Coverage

9 / 9 phase tasks satisfied, per the phase checklist in v4.15-dashboard-hierarchy-ROADMAP.md. This milestone has no standalone REQUIREMENTS.md or MILESTONE-AUDIT.md; the milestone ROADMAP is the requirement source, per this repo's convention for informal Multica-crew milestones.

TaskStatus
DH-UISPEC (Phase 1)Satisfied
DH-DECOMP (Phase 2)Satisfied
DH-PERSIST (Phase 3)Satisfied
DH-LAYOUT (Phase 4)Satisfied
DH-SETTINGS-MIGRATE (Phase 4)Satisfied
DH-RELOCATE-DEMOTE (Phase 4)Satisfied
DH-FLAG (Phase 4)Satisfied
DH-DOCS (Phase 5)Satisfied
DH-RAMP-CLEANUP (Phase 5)Satisfied

Outcomes

Users with 3+ active goals now see a dashboard tuned to how much they want on screen — Standard for a lean, do-today view, or Detailed for everything expanded — switchable from Settings or the header mode chip, with Focus unchanged as the streamlined alternative. Habit-heavy users no longer see a permanently-stuck 0% progress stat. The Supporter upsell no longer sits above today's actions, and Community/Achievements content lives on its own tabs with a discovery hint pointing the way. The dashboard_hierarchy flag is fully retired from code — Branch D renders unconditionally — and the stranded-branch guard added alongside the hotfix means a milestone can't again sit fully shipped-but-unmerged with its flag live in production.

Tech Debt

  • (Phase 5, OBJ-1747) Flag-off parity before the legacy-branch deletion was verified via a 102/102 Vitest substitute rather than the planned real screenshot-diff evidence (Docker Desktop was unhealthy in the execution sandbox). Residual visual risk was assessed as low but unverified at the time; the code has since shipped to master and to production without a reported regression.
  • (Post-ship) The dashboard_hierarchy PostHog flag still needs to be archived by a human with PostHog UI access — scripts/sync-posthog-feature-flags.mjs supports create/promote but not archive.
  • (Post-ship, fixed same-day) Hiding the header streak pill on the hierarchy layout (Phase 4) didn't wire an alternate entry point onto DashboardHero's day streak tile, dropping the stone-stack streak visual and the tap target that opened StreakDetailsModal for users on the new layout. Caught via user report on 2026-07-30 and restored the same day — see OBJ-1918 and docs/features/dashboard.md.
  • acb9ca09d — Land v4.15 Dashboard Hierarchy milestone onto master (PR #1891)
  • f50cc4dda / 9a50f2d45 — Phase 1: dashboard hierarchy UI-SPEC + amendments (Desi, OBJ-1722)
  • d0618bd63 — Phase 2: extract Dashboard.vue's four branches into components (PR #1769, OBJ-1723)
  • a18d1e30b — Phase 3: persist dashboard mode/density preferences (PR #1768, OBJ-1724)
  • 721ef8031 — Phase 4: Standard/Detailed hierarchy + relocations + Settings + backfill (PR #1776, OBJ-1725)
  • 01c1bf383 — Phase 5: reconcile dashboard.md to the Focus/Standard/Detailed/Auto model (PR #1780, OBJ-1726)
  • (Phase 5) [Codi] feat(dashboard): retire dashboard_hierarchy flag, delete dead branch — PR #1781, OBJ-1747
  • 35e2f9a5a — Post-ship guard: detect stranded milestone branches and reverse PostHog flag drift (PR #1894)

Last updated: 2026-07-30

Loading…