Onboarding And Teaching Surfaces
This runbook covers welcome, Block Party practice, sidebar tips, billing gates, and the rule that at most one onboarding card or modal is on screen at a time. Keyboard shortcut bindings themselves live in Shortcuts.
Teaching surfaces and their coordinator are documented in Frontend Runtime Flow.
Scope
Use this guide to validate:
- only one onboarding card or modal at a time (
RootShellsurface priority) - the billing gate and checkout celebration hiding lower-priority prompts
- the welcome flow with the mouse (every control responds to clicks)
- opt-in Block Party practice (
?play=1, command palette, welcome footer) - sidebar tip mute and five-minute rotation
- palette Next time, press … teaching (see Shortcuts scenario 25)
The sidebar tip and the ? legend are not onboarding cards and may appear
alongside a card when the coordinator allows it.
Do not use this guide for full shortcut parity (see shortcuts.md) or auth
flows (see auth.md).
Setup
- Start the app with
bun run dev:web(anonymous IndexedDB is enough for most scenarios). - Use a fresh browser profile or clear cookies and local storage unless a scenario needs persisted flags.
- Use a desktop viewport (onboarding overlays are skipped on mobile OSes).
Helpful storage keys:
compass.onboarding.has-seen-welcomecompass.onboarding.welcome-exit(which welcome CTA closed the modal)compass.onboarding.has-seen-shortcut-showcasecompass.onboarding.shortcut-showcase-outcome(finishedorskipped)compass.onboarding.first-event-donecompass.shortcuts.tips-muted(STORAGE_KEYS.SHORTCUT_TIPS_MUTED)compass.pointer-hint.dismissed-permanently(STORAGE_KEYS.POINTER_HINT_DISMISSED_PERMANENTLY)
Automated coverage: e2e/onboarding/welcome-mouse.spec.ts,
e2e/onboarding/shortcut-showcase.spec.ts,
e2e/onboarding/billing-gate-hides-prompts.spec.ts, and
e2e/billing/signup-trial-step.spec.ts.
Scenario 1: One Surface At A Time
UX
RootShell owns an ordered list of teaching surfaces. Only the highest-priority
surface that wants the screen is mounted. Lower surfaces wait their turn.
Priority (highest first): billing gate, checkout celebration, welcome modal,
Shortcut Showcase, welcome guide, connect-calendar prompt, first-event prompt,
palette PointerHint. While ?auth=trial keeps the signup trial step open,
RootShell suppresses the billing gate and calendar onboarding so Checkout
owns the screen (same app-lock behavior as the gate).
Steps
- Open
/weekas a first-time anonymous visitor. - Confirm the welcome dialog is visible.
- Dismiss welcome with Explore without an account.
- Open the command palette and start Play Block Party.
- While Block Party is open, confirm no first-event card stacks on top.
Expected Results
- Step 2: only the welcome dialog is an onboarding card; no connect-calendar or first-event card appears underneath.
- Step 5: the practice region is the sole onboarding card; the first-event complementary card stays hidden until practice closes.
Scenario 2: Billing Gate Hides Prompts
UX
When the signed-in account cannot write (awaiting_checkout, expired, or
canceled), the billing gate owns the screen. Welcome, practice, connect
calendar, first-event, sidebar teaching copy, and palette PointerHint do
not appear above or beside the gate.
Steps
- Sign in on an account that is read-only with status
awaiting_checkout(or use the e2e mock inbilling-gate-hides-prompts.spec.ts). - Clear welcome and showcase flags so a fresh visitor would normally see them.
- Load
/week. - Optionally append
?play=1and reload.
Expected Results
- The Finish starting your trial billing dialog is visible (or the subscribe variant for expired/canceled accounts).
- No welcome dialog, Block Party region, connect-calendar prompt, or first-event card is present.
?play=1does not open Block Party while the gate is up.
Scenario 3: Welcome Flow With The Mouse
UX
Every welcome control works with the mouse. No screen refuses clicks or shows "No clicks allowed".
Steps
- Open
/weekin a fresh profile. - Click Get started for free.
- Expand each FAQ row by clicking its question button.
- Click Next, then click Practice the shortcuts in the footer.
- On Block Party, click Start practicing.
Expected Results
- Each click advances or toggles state; focus and
aria-expandedupdate on FAQ rows. - Block Party opens from the footer link without requiring keyboard shortcuts.
- Covered by
e2e/onboarding/welcome-mouse.spec.ts.
Scenario 4: Block Party Is Opt-In
UX
Block Party does not auto-start when welcome closes or after signup. Entry
points are the welcome footer link, ?play=1, and the command palette
(Play Block Party).
Steps
- Fresh profile on
/week; complete welcome with Explore without an account. - Confirm Block Party is closed.
- Open
/week?play=1. - Open the command palette and run Play Block Party after closing practice.
Expected Results
- Step 2: no Shortcut practice region.
- Step 3: Block Party how-to card opens;
play=is stripped from the URL. - Step 4: practice reopens from the palette.
- Covered by
e2e/onboarding/shortcut-showcase.spec.ts.
Scenario 5: Sidebar Tip Mute
UX
The sidebar status bar rotates shortcut tips every five minutes for most
levels. Newcomer browsers (level 1) re-rank tips every 60 seconds and
prefer tips that match pointer intents detected this session
(rankShortcutHints + detectedIntents()).
Hide tips on the tip mutes sidebar tips, palette pills, and pointer-intent
pills via compass.shortcuts.tips-muted. The command palette exposes Hide
shortcut tips / Show shortcut tips.
Steps
- Load
/weekafter welcome and showcase flags are set (signed-in or explore-without-account with sample events). - Open the sidebar if collapsed; note the tip in the status bar.
- Click Hide tips on the tip (or Tab to it and press Enter).
- Open the command palette, run Create event, and confirm no Next time, press … pill appears.
- Click an event card and confirm no pointer-intent pill appears either.
- Open the palette and run Show shortcut tips.
- Run Create event again and click an event card; confirm pills return.
Expected Results
- Step 3: the sidebar tip disappears and stays hidden after reload.
- Steps 4–5: no palette or pointer
PointerHintpill while muted. - Step 7: pills return after tips are shown again.
- Newcomer cadence and skip keys persist in localStorage only (no server sync).
Scenario 6: Trial Step After Signup
UX
On hosted billing, email or OAuth signup finishes with a read-only account in
awaiting_checkout, then the auth modal shows the Start your 7-day free
trial step: charge-date copy and embedded Checkout (trial_period_days: 7).
Closing the step without paying opens Finish starting your trial
(BillingGateModal) with Add card. Completing Checkout runs anonymous event migration once billing becomes writable.
Steps
- On staging (or
e2e/billing/signup-trial-step.spec.tsmocks), sign up a fresh hosted account with billing enforcement on, or open/week?auth=trialwhile signed in withawaiting_checkout. - Confirm the trial step dialog title and the sentence that the card will not be charged until a date seven days out.
- Press Escape (or Back) to leave Checkout without paying.
- Confirm the billing gate dialog Finish starting your trial is visible.
- Optional on staging: complete Checkout with a test card, wait for the celebration, and confirm writes succeed and local-only events synced.
Expected Results
- Step 2: only the trial step auth dialog is a full-screen lock; calendar onboarding cards stay hidden.
- Step 4: gate copy matches Finish starting your trial.
- Step 5: status becomes
trialingwith a Stripe subscription id; anonymous IndexedDB events migrate once (seecomplete-checkout-session.ts). - Covered by
e2e/billing/signup-trial-step.spec.tsfor steps 1 to 4.