# Journey: Onboarding wizard, ten steps

The authenticated onboarding wizard ships ten ordered steps, browser-persisted
draft/resume, required-field gates, a local preference projection, and a best-
effort BFF preference sync. The current controls are narrower than the original
journey described: guide style is one persona-family choice, notification
settings do not include SMS or a quiet-hours window, accessibility has four
toggles, and memory offers three modes plus five categories. The wizard does not
currently emit its declared onboarding analytics events.

## Personas

- **New member** — completes required goals, domains, and routine choices.
- **Privacy-conscious member** — chooses memory mode, categories, and consent.
- **Accessibility user** — selects reduced motion, high contrast, larger text,
  or haptics.
- **Returning member** — resumes a locally saved draft after leaving the flow.

## Pre-conditions

- Sign in before visiting `/onboarding`; the route is protected and an anonymous
  request redirects through authentication.
- Start with a supported browser storage context. Draft state is stored under
  `oshun.onboarding`.
- The canonical step order in `ONBOARDING_STEPS` is `welcome`, `goals`,
  `domains`, `interests`, `routine`, `guide`, `notifications`, `accessibility`,
  `memory`, `complete`.
- Keep browser completion separate from server synchronization. A completed
  local wizard can exist even when the preference API is unavailable or not
  configured.

## Steps

### 1. Welcome and resume

The welcome step introduces the flow. `OnboardingResumeBanner` appears only when
a draft exists; it is not a universal onboarding banner. Continuing uses the
stored current step and selected values.

### 2. Choose required goals and domains

Goals and domains are required before advancing. The wizard validates these
steps locally and keeps the draft current after each change. A missing required
selection prevents forward navigation without inventing a server validation
request.

### 3. Choose optional interests and a routine

Interests expose eight broad topics. The sensitive-context controls are two
separate toggles—wellbeing signals and sensitive traits—not eight per-interest
consent switches. Routine is required and captures the supported cadence/time
choice in the onboarding draft.

### 4. Choose one guide family

The guide step selects one persona family. Teacher style and content tone are
derived through `resolveAssistantPreferenceDefaults`; they are not independent
controls on this screen. This choice updates the local preference projection
when the wizard completes.

### 5. Configure notifications

The current step offers four topics—daily, events, research, and achievements—
plus push, email digest, and quiet-hours toggles. It does not offer in-app/SMS
delivery, sample-content previews, or a quiet-hours time range. The quiet-hours
toggle is therefore a preference flag, not a complete scheduling policy.

### 6. Configure accessibility

Choose among reduced motion, high contrast, larger text, and haptics. The wizard
does not currently expose screen-reader or caption controls. Verify those four
fields in the resulting local preference state rather than mapping them to
unrendered options.

### 7. Configure memory and consent

Choose `off`, `session`, or `profile`, decide whether to grant consent, and
select from the five displayed memory categories. The screen does not promise
30- or 90-day retention. Its normal UI keeps sensitive traits off during
onboarding; automation can still exercise explicit sensitive-category payloads
at the underlying contract boundary.

### 8. Complete and inspect synchronization

`completeWizard` marks the browser wizard complete, patches the local preference
store, and then attempts profile-preference synchronization. If the browser is
already offline and a service-worker controller/token are present, it queues
`PATCH /v1/preferences`. An online transport/5xx failure displays an error after
local completion, but that failed online request is not automatically placed
into the queue. A 4xx `not-configured` result is treated as non-blocking and the
member proceeds.

No display-name field exists on the ready step. The declared
`onboarding_step_completed` and `onboarding_completed` names exist elsewhere,
but the audited wizard does not call an analytics emitter.

## Post-conditions

- The local wizard records completion and its selected preference projection.
- Required goals, domains, and routine fields passed local validation.
- Offline completion is queued only when the explicit controller/token/offline
  conditions are met.
- Server read-back is claimed only after a successful preference request or
  replay; local completion alone is not treated as that proof.
- No onboarding telemetry, display-name capture, SMS delivery, or retention
  duration is claimed.

## Failure modes

- **Anonymous route access** — the member is redirected instead of receiving a
  resumable wizard.
- **Storage unavailable** — draft/resume cannot be guaranteed; the active UI may
  still work for the current page lifetime.
- **Required choice missing** — goals, domains, or routine blocks progress.
- **Offline queue prerequisites missing** — no service-worker controller or
  token means the preference patch cannot be queued.
- **Online sync fails after local completion** — an error is shown, but the
  request is not automatically scheduled for replay.
- **Not-configured API** — expected 4xx handling permits local completion; do
  not report a server profile write.
- **Analytics overclaim** — declared event names are mistaken for emissions from
  this component.

## E2E coverage

- [`apps/oshun/web/e2e/onboarding-lifecycle.spec.ts`](../../apps/oshun/web/e2e/onboarding-lifecycle.spec.ts)
  covers step progression, draft/resume, completion, and synchronization states.
- [`apps/oshun/web/e2e/onboarding-deepening.spec.ts`](../../apps/oshun/web/e2e/onboarding-deepening.spec.ts)
  exercises preference details and failure branches.
- [`apps/oshun/web/e2e/onboarding-depth-introduction.spec.ts`](../../apps/oshun/web/e2e/onboarding-depth-introduction.spec.ts)
  covers introductory anatomy and access behavior.
- Coverage is **deep for the rendered wizard**. It intentionally does not count
  absent telemetry, SMS, retention, or an online-failure replay as covered.

## Per-view files touched

- [`customer/01-onboarding/onboarding.md`](../customer/01-onboarding/onboarding.md)
  — ten-step wizard shell.
- [`shell/04-auth-session.md`](../shell/04-auth-session.md) — protected-route
  boundary.
- [`customer/09-account/profile.md`](../customer/09-account/profile.md) —
  downstream preference read-back.
- [`shell/03-pwa-behavior.md`](../shell/03-pwa-behavior.md) — offline queue
  prerequisite.

## Cross-references

- [`first-time-anonymous-visitor.md`](./first-time-anonymous-visitor.md) —
  anonymous-to-authenticated funnel.
- [`offline-first-time-use.md`](./offline-first-time-use.md) — explicit queue
  semantics.
- [`memory-edit-pause-forget.md`](./memory-edit-pause-forget.md) — later memory
  controls and data-rights boundaries.
- Code: `apps/oshun/web/src/lib/hooks/use-onboarding.ts`,
  `apps/oshun/web/src/components/onboarding/OnboardingWizard.tsx`, and
  `apps/oshun/web/src/lib/assistant-preferences.ts`.

## Open questions

- Should an online preference-sync failure be queued automatically, or should
  local completion remain visibly pending?
- Which notification service will turn the quiet-hours flag into a time-zone-
  aware schedule?
- Should guide style and content tone become independent, explainable controls?
- Where should retention duration and sensitive-memory policy be explained?
- Should the wizard emit the existing onboarding event vocabulary, with consent
  and retry semantics defined?
