15 KiB
Gap Card — S12 First Launch (Onboarding Step 1)
Screen S12 of the Waggle OS UX-refactor. PRD source of truth: §12.12 (Onboarding Flow, step 1 "First Launch - promise and privacy"), §13 Journey 1 step 2, §14.1 global states. Blueprint screen spec:
_blueprint_extracted.txt:365-372(PAGE 14, row 12). Mockup (directional only, PRD §24):Waggle_OS_Handoff_Assets/screen_12_first_launch.png. Execution model: in-place incremental refactor ofapps/web— KEEP the wizard shell, redesign the welcome step per PRD §20.2.
1. Screen & purpose
The very first thing a fresh-install user sees: a minimal promise + privacy reassurance splash before any setup. It is onboarding step 1 of the 7-step flow (PRD §12.12: First Launch → Who Are You → Tool Discovery → Memory Import → Memory Review → Workspace Creation → Home Cockpit).
Purpose (blueprint S12): "Minimal promise and privacy reassurance." Acceptance (blueprint S12): "No infrastructure overload before user intent" — i.e. no API-key/tier/model questions on this screen; only the brand promise, a privacy note, a language affordance, and a single Continue action.
Mockup content (directional): Waggle "W" logo + wordmark top-left; centered hero logo;
Welcome to Waggle; tagline Your work. Your memory. Your agents.; primary Continue →
button; a 4-dot progress indicator; footer-left privacy line ("Your data is private. Stored
locally."); footer-right language selector showing English (US).
2. Required states (PRD / Blueprint)
Blueprint S12 names exactly four states (_blueprint_extracted.txt:369-370), plus the PRD §14.1
global-state baseline that "every major screen must implement":
| State | Source | What it means on S12 |
|---|---|---|
| Fresh install | Blueprint S12 | Default: brand promise + privacy + Continue. The only state the current code renders. |
| Resumed setup | Blueprint S12 | User dismissed/closed mid-onboarding and returns; wizard re-opens at the saved step (not necessarily step 0). Resume should land on the persisted step, and First Launch should communicate "picking up where you left off" rather than re-greeting cold. |
| Offline | Blueprint S12 + PRD §14.1 | Sidecar unreachable. Screen must still render (it is pre-network) and must not block; surface a non-alarming offline indicator and keep Continue usable (downstream steps degrade, not this one). |
| Local-only | Blueprint S12 + PRD §6/§18.1 (local-first default) | Privacy promise must be truthful and visible: "your data is private / stored locally." This is the trust hook the whole onboarding leans on (PRD §12.12 acceptance: "Nothing imports without explicit review/approval"). |
| Interaction: Continue | Blueprint S12 | Advance to step 2 (Who Are You). |
| Interaction: Change language | Blueprint S12 + mockup | A language affordance. No i18n infra exists (see §3) — scope decision required (§9). |
| Interaction: View privacy note | Blueprint S12 + mockup | A privacy note / link, inline or expandable. |
PRD §14.1 also lists Loading / Error / Permission-denied as universal — for a pre-network welcome splash these collapse to: render immediately (no loading gate), and offline == the only "error-ish" state that matters here.
3. Current state in repo (exact files + what they do)
Disposition: rework (KEEP the wizard shell per PRD §20.2 "Onboarding wizard → simplify";
redesign the step-0 component and add the missing affordances).
The shell (KEEP)
apps/web/src/components/os/overlays/OnboardingWizard.tsx— full-screen early-return wizard (OnboardingWizard.tsx:399-576). Holds 8 steps (STEP_NAMES,:35):welcome / why-waggle / tier / memory-import / template / persona / api-key / ready. Step 0 auto-advances after 3 s (:136-141), Escape → Skip (:86-96), a top progress bar + step dots + Back + "Skip setup" chrome (:421-493). Rendered byDesktop.tsx:262-272when!onboardingState.completed. This shell is the reuse target.apps/web/src/hooks/useOnboarding.ts—OnboardingState(:10-19:completed, step, tier?, workspaceId?, apiKeySet?, templateId?, personaId?, tooltipsDismissed?), persisted tolocalStoragekeywaggle:onboarding(:21). Auto-completes for returning users via Tauri first-launch flag (:102-131) and a sidecargetWorkspaces().length > 0check (:139-176).?forceWizard=true(DEV) forces step 0 (:47-57). This is the "resumed setup" backbone —state.stepalready persists, so resume is half-built.
The screen itself (REWORK)
apps/web/src/components/os/overlays/onboarding/WelcomeStep.tsx— the current step-0 component (54 lines). Renders the Waggle logo, eyebrowYour AI Operating System,Welcome to the Hive, taglinePersistent memory. Workspace-native. Built for knowledge work., aContinue →button (:39-45) + "or click anywhere". Gaps vs S12: copy differs from mockup ("Welcome to the Hive" vs "Welcome to Waggle"; tagline differs); no privacy note, no language selector, no offline/local-only awareness. It is a pure presentational component (propsWelcomeStepProps=goToStep+onClickAnywhere,onboarding/types.ts:10-12).apps/web/src/components/os/overlays/onboarding/WhyWaggleStep.tsx(step 1, the current 2nd screen) carries the 3VALUE_PROPS(constants:111-115) + the "Skip — quick setup" escape hatch. Mentioned because the mockup's tagline-style promise overlaps WelcomeStep/WhyWaggle; the rework should not duplicate value-prop content across both.apps/web/src/components/os/overlays/onboarding/constants.ts—VALUE_PROPS(:111-115),fadeSlidemotion preset (:118-123),STEP_NAMES. ReusefadeSlidefor the rework.apps/web/src/components/os/overlays/onboarding/types.ts—WelcomeStepProps(:10-12).
Supporting state already present (REUSE)
apps/web/src/hooks/useOfflineStatus.ts—useOfflineStatus()returnsoffline:boolean(:36-99, 2-consecutive-failure tolerance). Backs the offline state. Already consumed byDesktop.tsx:112andStatusBar.tsx; thread it into the welcome step.- Privacy/local-only copy: no dedicated component exists, but the claim is true per PRD §6
("Local-first by default") / §18.1. EraseDataDialog / data-erase surfaces exist elsewhere
(
overlays/EraseDataDialog.tsx) but there is no reusable "privacy note" primitive — net-new small UI. - No i18n infrastructure — grep for
i18next | react-i18next | useTranslation | LanguageSelector | changeLanguage | navigator.languageoverapps/web/srcreturns 0 matches. All UI copy is hardcoded English. The mockup'sEnglish (US)selector has no backing system.
4. Frontend work
Reuse the wizard shell; rework step 0 into a proper First-Launch screen.
Components to create / rework
- REWORK
WelcomeStep.tsx(or rename toFirstLaunchStep.tsxkeeping the same step-0 slot)- Align copy to mockup:
Welcome to Waggle+ taglineYour work. Your memory. Your agents.(PRD §24: mockup is directional — keep current eyebrow/brand voice if it reads better, but the privacy promise + language + Continue affordances are required by blueprint, not optional). - Add privacy note (footer-left): short line ("Your data is private. Stored locally.") with
a "view privacy note" expand (inline
Popover/HoverCardfromcomponents/ui/, or a small details disclosure). Maps blueprint interaction "view privacy note" + state "local-only". - Add offline awareness: consume
useOfflineStatus(); when offline, show a subtle indicator (reuse the StatusBar offline visual language) and keep Continue enabled (this step is pre-network). - Add language affordance (footer-right): see §9 open question — recommended v1 = a static,
disabled-looking
English (US)chip (honest: only English ships) OR a minimal selector wired to a newOnboardingState.localethat only persists the choice. Do not build full i18n in this card's scope. - Keep the existing Continue (
goToStep(1)) + click-anywhere + autoFocus + keyboard-reachable button (WelcomeStep already satisfies WCAG 2.1.1/2.2.1 — preserve).
- Align copy to mockup:
- (Optional, recommended) reconsider the 3 s auto-advance (
OnboardingWizard.tsx:136-141). A privacy-reassurance screen that auto-dismisses in 3 s undercuts the "read the privacy note" intent. Rework: keep auto-advance only when no interaction, or drop it for S12. (Surgical change, oneuseEffect.) - "Resumed setup" copy hook — when
state.step > 0on mount (returning mid-flow), the shell already restores the step; ensure First Launch isn't re-shown cold. Minimal: the existingstate.steprestore (OnboardingWizard.tsx:39) already handles navigation; add a one-line "Welcome back — picking up where you left off" variant ifstate.stepwas persisted > 0. Low priority; the resume mechanic exists.
Reuse targets
- Shell:
OnboardingWizard.tsx(progress bar, dots, Skip, Back, AnimatePresence step swap). - Motion:
fadeSlide(constants.ts:118-123). - Offline:
useOfflineStatus(). - UI primitives:
components/ui/{button,popover,hover-card,badge}.tsx(shadcn set already present). - Brand assets:
assets/waggle-logo.{png,jpeg}(already imported by WelcomeStep, theme-aware viauseIsLightTheme).
Props / state
WelcomeStepProps(extend): addoffline: boolean(fromuseOfflineStatus), and — if a language chip is wired —locale?: string+onLocaleChange?: (l: string) => void.OnboardingState(useOnboarding.ts:10-19): optionally addlocale?: string(additive, localStorage-only, no backend). Resume already covered by existingstepfield.
Adapter methods / hooks
- None new required. This screen is pre-network.
useOfflineStatusalready wraps the health probe;adapter.trackTelemetry('onboarding_step', …)already fires on step change (OnboardingWizard.tsx:31-33, :132). No new adapter method.
5. Backend work
This screen needs effectively NO backend. It is the pre-intent splash; every interaction is local UI + localStorage. Cross-referenced against backend-routes inventory and backend-map §03c — nothing on S12 maps to a missing PRD §16 endpoint.
| Capability needed | PRD §16 endpoint | Status | Note / what to EXTEND vs NET-NEW | Substrate / migration |
|---|---|---|---|---|
| Continue / advance step | — (none) | EXISTS (client-only) | Step state is OnboardingState.step in localStorage (useOnboarding.ts). No server call. |
none |
| Offline / local-only state | — (no PRD §16 row) | EXISTS | Reuse GET /api/offline/status (offline.ts) + the health probe already used by useOfflineStatus. No new route. |
none |
| Privacy note / local-first claim | — (none) | EXISTS (static) | Truthful per PRD §6/§18.1; copy-only. No endpoint. | none |
| Language change | — (none) | MISSING (no infra) | No i18n/locale backend anywhere (grep-confirmed). If a real selector is wanted, locale persists client-side in OnboardingState.locale (localStorage) — net-new client field, NOT a server route. Could later piggy-back on PUT /api/profile (profile.ts, EXISTS) or PATCH /api/settings (settings.ts, EXISTS) if locale must sync, but that is out of scope for v1. |
none (no .mind migration) |
| Returning-user / resume detection | — (none) | EXISTS | useOnboarding already calls adapter.getWorkspaces() (GET /api/workspaces, EXISTS) + Tauri first-launch flag to auto-complete returning users. No change. |
none |
No .mind migration. No net-new route. No substrate touch. S12 is the single cleanest screen
in the refactor from a backend standpoint.
6. Shared types needed (PRD §15 vs lib/types.ts)
- None of the PRD §15.2 unions are touched by S12 (no WorkspaceType/Scope/MemoryKind/etc. on a welcome splash).
- The only candidate type change is local: add optional
locale?: stringtoOnboardingState(hooks/useOnboarding.ts:10-19) if the language affordance is wired beyond a static chip. This is a frontend-only interface field, not a PRD §15 shared type, and needs nopackages/sharedchange. WelcomeStepProps(onboarding/types.ts:10-12) gainsoffline(+ optional locale props). Local to the onboarding folder.
7. Dependencies (screens / phases first)
- Phase placement: PRD Sprint 5 / Release Phase 2 ("Onboarding flow: Welcome, Profile, Tool Discovery, Memory Import, Memory Review"). S12 is the entry of that sequence.
- Hard dependency: the wizard shell (
OnboardingWizard.tsx) must remain the host — already exists, so no blocker. S12 can be reworked independently of the later steps. - Sibling screens that share the shell (do these in the same sprint to keep the rework coherent): S13 Who Are You, S14 Tool Discovery, S15 Memory Import, S16 Memory Review, S17 Create Workspace. S12 should land first because it sets the privacy/local-first framing the rest rely on.
- No dependency on Home Cockpit / Workspace Desktop / Command Center backend work — S12 is pre-workspace and pre-network.
- Decision dependency: the language-selector scope question (§9) should be answered before implementation so the footer affordance isn't built twice.
8. Effort
S — Single presentational component rework inside an existing, working shell; reuse
useOfflineStatus + existing motion/UI primitives; zero backend, zero migration, zero shared-type
churn. The only thing that could push it toward M is electing to build a real (even minimal)
language selector + locale plumbing instead of a static English (US) chip.
9. Open questions
- Language selector — real or honest-stub? No i18n exists (grep-confirmed: 0 matches for
i18next/useTranslation/etc.). Options: (a) static disabled
English (US)chip (truthful, S effort, recommended v1); (b) minimal selector that persistsOnboardingState.localebut only English is wired (cosmetic); (c) defer the affordance entirely. PRD §24 lets us treat the mockup as directional, and PRD §4.4 lists native/i18n work as out-of-first-phase scope — so (a) or (c) align with the PRD. Recommend (a). Confirm before building. - Keep the 3 s auto-advance on a privacy screen? Current step-0 auto-advances after 3 s
(
OnboardingWizard.tsx:136-141), which fights the "read the privacy note" intent. Drop it for S12, or keep-but-pause-on-interaction? - Copy alignment: mockup says "Welcome to Waggle" / "Your work. Your memory. Your agents."; current ships "Welcome to the Hive" / "Persistent memory. Workspace-native…". Which brand voice wins? (PRD §24: pixels don't, but the privacy promise must be present either way.)
- "Resumed setup" UX: the step is restored from
localStoragealready — is a distinct "welcome back" treatment on First Launch wanted, or is silent step-restore sufficient? - Privacy note content: inline expandable text vs link to a privacy doc/URL? No privacy-policy route or doc is wired today — needs copy + destination decided.