This commit is contained in:
187
docs/ONBOARDING-DAY-2-BACKLOG-2026-04-30.md
Normal file
187
docs/ONBOARDING-DAY-2-BACKLOG-2026-04-30.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# Onboarding — Day-2 Backlog
|
||||
|
||||
**Authored:** 2026-04-30 (post-investigation `b34897c` + Option A2 implementation)
|
||||
**Owner:** Engineering + Product
|
||||
**Priority:** Day-2 (post-launch). Day-0 unblock = `?forceWizard=true` URL param shipped.
|
||||
|
||||
---
|
||||
|
||||
## Why this exists
|
||||
|
||||
The onboarding investigation (`docs/ONBOARDING-INVESTIGATION-2026-04-30.md`) surfaced three distinct issues that are best handled separately from the immediate launch:
|
||||
|
||||
1. **The auto-complete heuristic is too coarse.** `useOnboarding.ts:91-120` flips the wizard to "completed" whenever `/api/workspaces.length > 0`. But the backend ALWAYS creates `default-workspace` at boot via `wsManager.ensureDefault()`, so the heuristic fires even for genuinely-fresh installs.
|
||||
|
||||
2. **Production users have no "redo onboarding" affordance.** Once the wizard is completed (or auto-completed), there is no in-product way to re-trigger it short of editing `~/.waggle/` on disk — friction for support, demos, persona-evaluation marathons, and product education.
|
||||
|
||||
3. **The wizard's actual production behavior is undocumented.** Support team / new hires / partners need to know: "the wizard appears at most once per machine, even after browser cache clear, even after Tauri webview reset". That assumption isn't written down anywhere user-facing.
|
||||
|
||||
---
|
||||
|
||||
## A3 — Smarter auto-complete heuristic
|
||||
|
||||
**Current code (`apps/web/src/hooks/useOnboarding.ts:91-120`):**
|
||||
|
||||
```ts
|
||||
const workspaces = await adapter.getWorkspaces();
|
||||
if (Array.isArray(workspaces) && workspaces.length > 0) {
|
||||
// auto-complete the wizard
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:** `workspaces.length > 0` is true even when the only workspace is the boot-time stub from `wsManager.ensureDefault()`. So:
|
||||
- Genuine first-launch → wizard would render… but `ensureDefault()` runs BEFORE the hook's first render, so wizard is auto-completed before the user ever sees it.
|
||||
- Tauri webview switch on real user → correct (workspaces exist with content).
|
||||
- localStorage clear on real user → correct (workspaces exist with content).
|
||||
- localStorage clear after manual workspace deletion → wizard auto-completes again because `ensureDefault()` recreates the stub.
|
||||
|
||||
**Net effect:** the wizard only shows up if `~/.waggle/` doesn't exist at all when the backend boots. After that, it's invisible until a developer manually deletes the `default-workspace` directory (and even then, see Option A2 — backend recreates it). For 99%+ of installs, the wizard fires exactly **once** in the user's lifetime.
|
||||
|
||||
That might be desirable. But if not, the heuristic should be **content-aware**:
|
||||
|
||||
**Proposed:**
|
||||
|
||||
```ts
|
||||
const [workspaces, health] = await Promise.all([
|
||||
adapter.getWorkspaces(),
|
||||
adapter.getSystemHealth().catch(() => null),
|
||||
]);
|
||||
if (cancelled) return;
|
||||
|
||||
// Treat "zero memory across all workspaces" as fresh-state regardless of stubs.
|
||||
// The default-workspace shell from wsManager.ensureDefault has frameCount=0
|
||||
// until the user actually does something. Distinguish that from a real
|
||||
// returning user who has built up memory.
|
||||
const frameCount = health?.memoryStats?.frameCount ?? 0;
|
||||
const isReturningUser = Array.isArray(workspaces)
|
||||
&& workspaces.length > 0
|
||||
&& frameCount > 0;
|
||||
|
||||
if (isReturningUser) {
|
||||
// auto-complete (existing logic)
|
||||
}
|
||||
```
|
||||
|
||||
**Side effects:**
|
||||
- Genuine first-launch → wizard renders (frameCount=0).
|
||||
- Tauri webview switch on real user → still auto-completes (frames > 0).
|
||||
- localStorage clear on real user → still auto-completes (frames > 0).
|
||||
- After "reset onboarding" (proposed below) clears memory → wizard renders again.
|
||||
|
||||
**Cost:** ~10 LOC, single file. One extra `/health` call per hook mount (cheap, idempotent).
|
||||
|
||||
**Risk:** if a returning user has somehow lost all memory (recovery-from-corruption, mind file deleted manually), they'd see the wizard again — but that's actually the right UX in that scenario.
|
||||
|
||||
**Test plan:**
|
||||
- Add `apps/web/src/hooks/useOnboarding.test.ts` with mocked adapter:
|
||||
- workspaces=[], frames=0 → wizard renders
|
||||
- workspaces=[{id:'default-workspace'}], frames=0 → wizard renders (the new behavior)
|
||||
- workspaces=[{id:'default-workspace'}], frames=5 → auto-completes
|
||||
- workspaces=[], frames=0, sidecar throws → wizard renders (unchanged fallback)
|
||||
|
||||
**Status:** **deferred to Day-2.** The Option A2 URL bypass is sufficient for PM walkthrough. Production behavior with the current heuristic is "wizard fires once per fresh install" which is *plausibly* the right default. Worth a product call before changing.
|
||||
|
||||
---
|
||||
|
||||
## Reset Onboarding affordance
|
||||
|
||||
**Where it lives:** Settings → Advanced → "Reset onboarding wizard" (button).
|
||||
|
||||
**What it does:**
|
||||
|
||||
```ts
|
||||
async function resetOnboarding() {
|
||||
// 1. Confirm via dialog (destructive action — clears workspace + memory).
|
||||
if (!await confirmDestructive('Reset onboarding will clear all workspaces and memory. Continue?')) return;
|
||||
|
||||
// 2. Backend: drop default-workspace + clear personal mind.
|
||||
// New endpoint POST /api/admin/reset-onboarding does the disk wipe
|
||||
// server-side (rm -rf workspaces/default-workspace, drop personal.mind,
|
||||
// drop sessions/*, drop awareness/preferences). Atomic. Logs to audit.
|
||||
await adapter.resetOnboarding();
|
||||
|
||||
// 3. Clear localStorage onboarding state.
|
||||
localStorage.removeItem('waggle:onboarding');
|
||||
localStorage.removeItem('waggle:tooltips_done');
|
||||
|
||||
// 4. Reload to ?forceWizard=true so the wizard renders even before the
|
||||
// backend has a chance to re-ensureDefault.
|
||||
window.location.assign(window.location.pathname + '?forceWizard=true');
|
||||
}
|
||||
```
|
||||
|
||||
**Use cases:**
|
||||
- Demo prep: reset to clean state before showing the product.
|
||||
- Support escalation: "let's start over" when the user's workspace is in a weird state.
|
||||
- Persona-evaluation marathon: between persona swaps, reset to baseline.
|
||||
- New-hire training: walk through the wizard as designed.
|
||||
|
||||
**Threat model:** destructive button. Must be:
|
||||
- Behind Settings → Advanced (not surfaced casually).
|
||||
- Confirmation dialog with strong copy ("This will erase your memory. Continue?").
|
||||
- Requires the user to type "RESET" or click two distinct buttons (defense against fat-finger).
|
||||
- Audit-logged via `auditStore` so it's traceable.
|
||||
|
||||
**Cost:** ~80 LOC across:
|
||||
- `apps/web/src/components/os/apps/SettingsApp.tsx` — Advanced tab + button + dialog
|
||||
- `apps/web/src/lib/adapter.ts` — `resetOnboarding()` method
|
||||
- `packages/server/src/local/routes/admin.ts` — new `POST /api/admin/reset-onboarding` endpoint (or existing admin route)
|
||||
- One vitest spec exercising the disk-side wipe
|
||||
|
||||
**Status:** **Day-2.** Not needed for launch. PM can use the URL bypass for walkthrough.
|
||||
|
||||
---
|
||||
|
||||
## Document the production behavior
|
||||
|
||||
**Audience:** Support team, customer success, product education content authors.
|
||||
|
||||
**Content (rough draft):**
|
||||
|
||||
> ### Onboarding wizard frequency
|
||||
>
|
||||
> The Waggle OS onboarding wizard appears **at most once per install**. After
|
||||
> the user dismisses it (either via "Let's go!" on the Ready step or via
|
||||
> the Skip option), the wizard does not re-trigger automatically.
|
||||
>
|
||||
> The wizard does NOT re-appear on:
|
||||
> - Browser cache / localStorage clear (the backend has workspace data).
|
||||
> - Tauri webview profile reset (same — the backend has workspace data).
|
||||
> - Computer reboot (data persists in `~/.waggle/`).
|
||||
> - App upgrade (data persists across versions).
|
||||
>
|
||||
> The wizard DOES re-appear on:
|
||||
> - Fresh install on a new machine (no `~/.waggle/` directory exists).
|
||||
> - User explicit "Reset onboarding" via Settings → Advanced (Day-2 feature, see backlog).
|
||||
> - Developer URL bypass `?forceWizard=true` (DEV mode only).
|
||||
>
|
||||
> ### Why
|
||||
>
|
||||
> A returning user who clears their browser cookies or switches Tauri
|
||||
> profiles still has all their memory and workspaces on the sidecar
|
||||
> (`~/.waggle/`). Forcing them through the wizard again would be jarring
|
||||
> ("why does Waggle want me to re-pick a template I already have?").
|
||||
> The wizard's job is to teach + configure on the very first encounter;
|
||||
> after that, the same surfaces are reachable through the normal UI
|
||||
> (Settings, dock, persona switcher, harvest tab, etc.).
|
||||
|
||||
**Where it goes:**
|
||||
- `docs/user-guide/onboarding.md` (or whatever the user-facing docs entry point is)
|
||||
- Internal Notion page for support team
|
||||
|
||||
**Cost:** ~30 min of writing.
|
||||
|
||||
**Status:** **Day-2.** Not blocking launch. Should land before any large support cohort hits production (week 2-3 post-launch).
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Item | Cost | Day-X | Notes |
|
||||
|---|---|---|---|
|
||||
| **A2 URL bypass** (this commit) | ~12 LOC + tests | Day-0 ✅ | Shipped. PM uses `?forceWizard=true` for walkthrough. |
|
||||
| **A3 smarter heuristic** | ~10 LOC + 4 tests | Day-2 | Awaiting product decision: keep "once per machine" or move to "once until memory exists". |
|
||||
| **Reset Onboarding button** | ~80 LOC + admin route + 1 test | Day-2 | Demo / support / training affordance. |
|
||||
| **Document production behavior** | ~30 min writing | Day-2 | User-facing docs + support runbook. |
|
||||
|
||||
**No work scheduled today** beyond the A2 ship + this backlog doc. Marko reviews Day-2 ordering when launch dust settles.
|
||||
Reference in New Issue
Block a user