# Tasks: enterprise-browser-react-tour **Change ID**: enterprise-browser-react-tour **Package**: `@suaveplan/react-tour` **Target path**: `browser/react/react-tour` **Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/events`, `@suaveplan/logger`, `@suaveplan/schema-registry` --- ## 0. Pre-flight (non-negotiable) - [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each) - [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest. ## 1. Scaffold - [ ] Create directory tree per `proposal.md`. - [ ] `package.json` v0.0.0, `"sideEffects": false`. - `dependencies`: `@suaveplan/error workspace:^`, `@suaveplan/events workspace:^`, `@suaveplan/logger workspace:^`, `@suaveplan/schema-registry workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build`, `react catalog:react` - `peerDependencies`: `react` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `happy-dom catalog:testing`, `@testing-library/react catalog:testing`, `@suaveplan/testing workspace:^`, `@suaveplan/testing-dom workspace:^` - Subpath exports: `"."`, `"./core/tour/tour"`, `"./utils/positioning"`, `"./persistence"` - [ ] `tsconfig.json`, `vitest.config.ts` (pool: forks, happy-dom environment). --- ## 2. Error codes - [ ] `TOUR_CONFIG_INVALID`, `TOUR_STEP_NOT_FOUND`. - [ ] `registerTourErrorCodes()` — call eagerly. --- ## 3. Types (`src/types/common.ts`) - [ ] `TourConfig`, `TourStep`, `TourState`, `TourActions`, `TooltipPlacement`, `TooltipPosition`, `SpotlightInset`. - [ ] Write `common.md`. --- ## 4. `TourSchema` (`src/schema/tour-schema/`) - [ ] `tour-schema.ts` — `TourConfigSchema`, `TourStepSchema` (Zod); `registerTourSchemas()`. - [ ] Write `tour-schema.md`. --- ## 5. Positioning utilities (`src/utils/positioning/`) - [ ] `positioning.ts` — `calculateSpotlightInset`, `calculateTooltipPosition`, `getTargetRect`, `scrollTargetIntoView`. - [ ] All functions SSR-safe (`typeof document` guard). - [ ] Write `positioning.test.ts` (happy-dom geometry, SSR import smoke test). Write `positioning.md`. --- ## 6. Observer utility (`src/utils/observe-target/`) - [ ] `observe-target.ts` — composite `observeTarget(selector, callback)` using `ResizeObserver` + `IntersectionObserver` + scroll listener; returns cleanup. - [ ] Write `observe-target.test.ts` (observer fires on resize, fires on scroll). Write `observe-target.md`. --- ## 7. Persistence adapters (`src/persistence/persistence/`) - [ ] `persistence.ts` — `PersistenceAdapter` interface; `LocalStoragePersistence` (SSR-safe), `SessionStoragePersistence`, `MemoryPersistence`. - [ ] Write `persistence.test.ts` (each adapter: isCompleted, markCompleted, clear, SSR no-throw). Write `persistence.md`. --- ## 8. Tour state helpers (`src/core/tour/tour-state.ts`) - [ ] `computeProgress(step, total): number`, boundary guards, `shouldSkip` evaluation. --- ## 9. Tour effects (`src/core/tour/tour-effects.ts`) - [ ] Observer wiring: call `observeTarget` on step change, update `targetRect` on callback. - [ ] Emit `@suaveplan/events` lifecycle events (`tour:start`, `tour:step-change`, `tour:complete`, `tour:skip`, `tour:error`). - [ ] Wire OTel metrics. --- ## 10. Tour actions (`src/core/tour/tour-actions.ts`) - [ ] `next()`, `prev()`, `goTo(n)`, `skip()`, `reset()` — with boundary checks and `shouldSkip` evaluation. --- ## 11. `useTour` hook (`src/core/tour/tour.ts`) - [ ] Compose state + effects + actions. - [ ] Validate `TourConfig` via `TourConfigSchema` on entry; throw `TOUR_CONFIG_INVALID`. - [ ] Log storage errors via `@suaveplan/logger` instead of swallowing. - [ ] Write `tour.test.ts` (config validation, next/prev/goTo/skip, persistence, SSR no-throw). Write `tour.md`. --- ## 12. Storybook stories (`src/stories/use-tour.stories.tsx`) - [ ] Default story: basic 3-step tour. - [ ] Spotlight overlay: CSS spotlight with `calculateSpotlightInset`. - [ ] Scroll-into-view: target below the fold. - [ ] Completion persistence: reload and confirm tour does not restart. - [ ] Accessibility-compliant tooltip: `role="dialog"`, focus trap, `aria-live`. --- ## 13. Integration test (`tests/integration.test.ts`) - [ ] Full tour flow: start, navigate, complete, verify persistence adapter called. - [ ] `MemoryPersistence` swap: no `localStorage` touched. - [ ] `shouldSkip` step evaluated; step skipped automatically. --- ## 14. Playwright E2E (`e2e/react-tour.spec.ts`) - [ ] `targetRect` stays aligned after element resizes (Playwright + Chromium). - [ ] Completion persists across reload (Playwright localStorage). - [ ] SSR smoke: import from Node without throwing. --- ## 15. Docs + verify - [ ] Write `.md` per module (≥200 words, API reference, examples). - [ ] Write `README.md` with subpath table, persistence-adapter guide, SSR guide, a11y notes. - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/react-tour` — green. - [ ] `bunx turbo test:coverage` — 100%. - [ ] No `@ts-expect-error` in `src/` or tests. No `vi.stubGlobal`. - [ ] Storybook stories render and pass axe-core. - [ ] Playwright E2E green on Chromium. - [ ] `bun scripts/publish.ts --package @suaveplan/react-tour`. - [ ] Archive to `openspec/archive/2026-04-24-enterprise-browser-react-tour/`.