Skip to content

v4.16 — Guided Product Tour

New here? We'll show you around — a skippable, replayable, never-blocking guided tour now covers the dashboard and every major surface, plus a lightweight spotlight that re-introduces new features to existing users.

Summary

Objectuve had grown deep — dashboard, streaks, AI Coach, goals, communities, achievements, an activity feed, allies — but nothing in the product actually introduced any of it. An orphaned tour component sat unused in communities/OnboardingTour.vue, its steps hardcoded to a single page and its anchor targets pointing at elements that no longer existed anywhere in the app. Discovery was entirely left to users stumbling onto features on their own.

v4.16 closes that gap with a reusable FeatureTour engine — a dimmed backdrop, an animated spotlight/coach-mark tooltip positioned via @floating-ui/dom, and centered intro/outro dialogs, all gated on useReducedMotion() and fully keyboard/focus-trap accessible — generalized from that orphaned component rather than rebuilt from scratch. Completion and dismissal state is server-authoritative, written into the existing UserDetail.data['feature_tours'] jsonb column with no migration required, so a tour a user finishes or skips on one device never re-fires on another.

Phase 1 shipped the MVP: the engine itself, plus a flagship 8-step first-run tour that fires once when a new user lands on the dashboard straight out of onboarding. Phase 2 extended the same, unchanged engine to five more surfaces — Goals, Coach, Communities, Achievements, and the Activity Feed — and added a "Tours" section to Settings where any of the six tours can be replayed on demand. Phase 3, a stretch layer that was completed rather than deferred, added a lighter-weight re-engagement mechanism for existing users: a version-aware "What's New" spotlight that surfaces at most one newly-shipped feature per session, plus an admin-only completion funnel so the team can finally measure whether any of this tour work is actually landing.

Every tour, across all three phases, is skippable, never destructively blocks the UI, and is replayable — a deliberate brand-philosophy constraint (no dark patterns) that shaped every design and engineering decision in the milestone, not an afterthought applied at review time.

Goal

Give users a comprehensive, polished, in-app feature tour that turns the app's now-deep functionality (dashboard, streaks, AI Coach, goals, communities/challenges, achievements, activity feed, allies) into something users can discover — not just something that exists. Deliver a reusable spotlight/coach-mark + intro-dialog FeatureTour engine with server-authoritative completion state, a flagship first-run dashboard tour that fires once after onboarding, contextual per-surface mini-tours with a Settings replay entry, and (stretch) a re-engagement "What's New" spotlight layer for existing users.

Scope — What Shipped

  • FeatureTour.vue + useFeatureTour.ts (ionic_frontend/src/components/tour/, ionic_frontend/src/composables/) — the reusable engine: backdrop, animated spotlight ring, coach-mark tooltip card (@floating-ui/dom-positioned with collision handling), centered intro/outro dialogs, step-progress dots, Skip/Back/Next/Done controls, focus-trap, useReducedMotion() gating throughout. Generalized from the orphaned communities/OnboardingTour.vue, not rebuilt.
  • storeFeatureTourState mutation + UserIdentity::StoreFeatureTourState interaction (rails_api/app/interactions/user_identity/) + featureTourStatus resolver on UserType — server-authoritative completion state in the existing UserDetail.data['feature_tours'] jsonb column, deep_merged so sibling keys (data['onboarding']) are never touched. No migration.
  • Flagship dashboard tour — an 8-step walkthrough (intro → streak → check-in → coach → today's actions → goals → nav → outro), firing exactly once at /dashboard?source=wizard, gated on the new feature_tour_enabled flag.
  • Five per-surface mini-tours — Goals, Coach, Communities, Achievements, Activity Feed — as step composables under ionic_frontend/src/composables/tours/, each auto-starting once behind feature_tour_enabled (Communities' ally-request step additionally gated on ally-request-flow-enabled).
  • Settings → Tours replayToursSettingsSection.vue + a canonical TOUR_REGISTRY (ionic_frontend/src/composables/tourRegistry.ts) lists all six tours with per-row completion status and a Start/Replay control, resetting the tour's persisted state (and its Apollo cache entry) on replay.
  • "What's New" re-engagement spotlightWhatsNewSpotlight.vue / WhatsNewWatcher.vue / useWhatsNew.ts, a lighter-weight, non-blocking callout (not the full FeatureTour overlay) — version-aware against a per-user "epoch," capped at one per session, gated on its own whats_new_enabled flag, persisted through the same feature_tours map keyed by feature id. WHATS_NEW_FEATURES ships empty by design — the mechanism is live but inert until a future feature opts in.
  • Admin-only tour completion funnelAdmin::ComputeTourFunnel (rails_api/app/interactions/admin/), exposed via Query.tourFunnelStats, require_admin!-gated — aggregates started/completed/dismissed/completion_rate per tour.
  • QA + a11y — Playwright smoke (dashboard tour + What's New spotlight), a reduced-motion/a11y audit across FeatureTour.vue and WhatsNewSpotlight.vue, and a watcher-test backfill for the four surfaces (Coach/Communities/Achievements/ActivityFeed) that Phase 2 had left uncovered.
  • Docs — new docs/features/feature-tour.md covering the architecture, persistence model, and every tour added across all three phases; docs/product/user-guide.md §16 (Tours); docs/features/onboarding-timeline.md Day-1 update; ionic_frontend/STYLE_GUIDE.md overlay pattern note; CHANGELOG.md and ionic_frontend/CHANGELOG.md entries.

Phases

PhaseNameStatusPlansHighlights
1Engine, persistence & flagship dashboard tourShipped1FeatureTour/useFeatureTour engine, server-authoritative persistence, 8-step dashboard tour — the MVP, ships value alone
2Full surface coverage + Settings replayShipped1Five more mini-tours on the unchanged Phase 1 engine, Settings "Tours" replay section; Roy caught a stale-cache replay no-op, fixed pre-merge
3Re-engagement "What's New" + analytics/polishShipped1Version-aware spotlight layer, admin completion funnel, QA/a11y sweep — stretch phase, completed rather than deferred

Key Decisions

  • Generalize the orphaned tour, don't rebuild (D-1) — communities/OnboardingTour.vue already had the right visual base (backdrop, spotlight, glass tooltip, progress dots, keyboard-accessible controls); its steps were just hardcoded to one page. Turning it into a props-driven engine reused proven, on-brand UI instead of starting over.
  • @floating-ui/dom for anchor positioning (D-2, Josh-approved) — replaces hardcoded 300px/400px position estimates with real viewport-collision handling, the single new frontend dependency this milestone introduced.
  • Server-authoritative completion state, not PostHog or localStorage (D-3) — PostHog is dev-disabled and best-effort; useDismissedActions's 30-day TTL is the wrong shape for a tour that should stay completed forever. UserDetail.data['feature_tours'] (existing jsonb, deep_merge) needed no migration and no new table.
  • Every tour is always skippable, never blocking, always replayable (D-4) — a brand-philosophy constraint, not a nice-to-have; it shaped the engine's control cluster, the Settings replay surface, and the What's New spotlight's non-blocking (halo/docked, not full-overlay) presentation.
  • What's New deliberately does not reuse the FeatureTour overlay — a re-engagement callout for an existing user browsing normally needs to be lighter-weight and non-blocking, unlike a first-run walkthrough. Same persistence and analytics plumbing, different UI treatment.
  • Phase 3 (stretch) completed, not deferred — flagged at kickoff as deferrable without stranding Phases 1–2; Orion recommended shipping it anyway since the funnel closes a "shipped a retention feature with no measurement" gap, and it landed in full.
  • .planning/ milestone artifacts must merge to master via their own PR before any milestone branch is deleted — the one durable process lesson from this milestone (see Tech Debt / near-miss below), now recorded for future milestones.

Requirements Coverage

14 / 14 requirements satisfied (per the Milestone Audit; this milestone has no standalone REQUIREMENTS.md — coverage is derived from the ROADMAP's own task checklist per this repo's planning convention).

CategoryCountStatus
Phase 1 (TOUR-BE-1, UISPEC-1, ENGINE-1, DASH-1, DOCS-1)5All satisfied
Phase 2 (TOUR-UISPEC-2, SURF-2, REPLAY-2, DOCS-2)4All satisfied
Phase 3 (TOUR-UISPEC-3, WHATSNEW-3, FUNNEL-3, QA-3, DOCS-3)5All satisfied

Full detail: v4.16-guided-product-tour-MILESTONE-AUDIT.md.

Outcomes

A new user finishing onboarding now sees a guided dashboard tour exactly once, pointing out their streak, check-in, Coach, today's actions, goals, and navigation. Any user can discover and take a mini-tour on Goals, Coach, Communities, Achievements, or the Activity Feed, and can replay any of the six tours at any time from Settings → Tours. An existing user on a new app version can see at most one dismissible "What's New" spotlight per session for a newly-shipped feature — live but currently inert, since no feature has opted into the registry yet. The team can now query an admin-only completion funnel to measure tour effectiveness, closing a "shipped a retention feature with no measurement" gap that existed through Phase 2.

Not yet true for any real user: no production tag has been cut for this milestone — it rides the next Wednesday release train, per the beta release cadence. All merges landed on master → staging only.

Tech Debt

  • (Phase 1, near-miss, resolved) The integration branch gsd/v4.16-guided-product-tour was deleted mid-Phase-1 before its planning docs (ROADMAP, UI-SPEC, mockups) had ever merged to master. They survived only in a dangling commit and were recovered and durably landed via a follow-up PR (OBJ-1785, #1809) before Phase 2 dispatch — no data was actually lost, but it's the reason every phase after Phase 1 cut its branch fresh off origin/master instead of reusing a milestone integration branch.
  • (Phase 2/3, open, non-blocking) The Capture UI Evidence CI gate only ever screenshots /dashboard — it never covered any of the five Phase 2 surfaces or the Phase 3 What's New spotlight, a pre-existing scope limit of scripts/capture-ui-evidence.mjs's default route list. Worth a standalone backlog item to extend UI-Evidence-Routes per-PR.
  • (Phase 3) ionic_frontend/CHANGELOG.md intentionally has no Phase 3 entry — WHATS_NEW_FEATURES ships empty and the funnel is admin-only, so nothing user-visible shipped from Phase 3 yet. Not a gap; will need an entry once the first feature opts into the What's New registry.
  • 4a0924eaf — docs(tour): document What's New spotlight + tour funnel, backfill in-app CHANGELOG (TOUR-DOCS-3, OBJ-1793) (#1821) — milestone-complete commit (master head at close)
  • 58712cd7e — [Codi] feat(tour): add per-surface mini-tours + Settings Tours replay (TOUR-SURF-2, TOUR-REPLAY-2, OBJ-1776) (#1812)
  • b1fc5207e — [Codi] feat(tour): add FeatureTour engine + flagship dashboard tour (TOUR-ENGINE-1, TOUR-DASH-1, OBJ-1775) (#1803)
  • 47f2f22f6 — [Codi] feat(tour): add feature-tour completion state (TOUR-BE-1, OBJ-1775) (#1802)

Last updated: 2026-07-27

Loading…