Skip to content

SPA: self-guided product tour / first-run tutorial #596

Description

@mforce

Motivation

New operators — especially non-technical farm workers filling out Daily Entry on a barn phone — currently learn the app with no in-app guidance beyond the static Help page. A self-guided, in-app tour of the core egg loop (Daily Entry → Submit → Egg Lots → Stock → Sales) would shorten that ramp without requiring a human walkthrough.

This is currently a feature idea being scoped, not committed work — filing to track the idea and the design decisions it needs, not to lock in an implementation.

Depends on #595

Don't implement this before the lazy-loading work lands. Reasoning:

Library research (already done)

Measured actual npm package sizes (min+gzip, peer deps excluded) for the common options:

Library Min+gzip Deps Coupling
react-joyride 26.6 KB 10 bundled deps (scroll, scrollparent, @floating-ui/react-dom, …) React-only
shepherd.js 15.3 KB deepmerge-ts, @floating-ui/dom (bundled) Vanilla JS/DOM
react-shepherd 17.2 KB wraps shepherd.js Thin React wrapper
driver.js 7.1 KB (+4.7 KB for the optional hints submodule) zero deps Framework-agnostic vanilla

Recommendation: driver.js, dynamically imported — smallest, no transitive dependency surprises, and being framework-agnostic means it doesn't fight React's render cycle for step positioning. Open to a custom-built alternative if driver.js's DOM-highlighting approach turns out to conflict with the app's inert-based accessibility handling (see below) — the size gap between "smallest library" and "custom" is small enough that this shouldn't be decided on bundle size alone.

Constraints this must satisfy (from repo conventions — not optional)

  • i18n: every tour-step string must route through src/i18n's en/es/tl catalogs — the SPA E2E suite enforces "never hardcode English" via the app's own translation catalogs, and scripts/i18n-scan.mjs should catch a missed key.
  • Accessibility: the app has deliberate inert-based modal/overlay handling (PWA/shell: verify the inert-swallowed announcements with a real screen reader #501, still pending a real screen-reader verification pass). A coachmark/spotlight overlay is exactly the kind of UI that can silently break that — Playwright's ariaSnapshot/getByRole/isVisible do not model inert (per docs/decisions/277-spa-e2e.md), so this needs verification through the CDP-based tools/simulation/ui/src/ax.ts approach, not the usual Playwright accessibility queries.
  • RBAC: Owner/Manager/Worker/Sales see different screens and permissions; a one-size-fits-all tour will reference UI a Worker can't see. Needs at least a decision on whether v1 ships role-agnostic (covering only the universally-visible core loop) or role-scoped from the start.
  • Never trap the user. Skip/dismiss must always be available and the tour must be re-launchable on demand (natural home: the Help page, alongside the planned in-app glossary from F18: In-app help — user guide + glossary in the SPA #71).

Open product questions (deliberately not decided here)

Proposed initial scope (small slice, if greenlit)

  1. driver.js behind a dynamic import(), triggered from a new "Take a tour" entry on the Help page.
  2. One tour: the core egg loop (Daily Entry → Submit → Egg Lots → Stock → Sales) — the app's Phase 1.0 MVP flow, so it's role-agnostic-enough to ship first.
  3. Step copy in en/es/tl.
  4. Vitest coverage for trigger/dismiss/step-advance logic; an ax.ts-based accessibility check that the overlay doesn't break inert handling elsewhere on the page.

Acceptance criteria

  • A user can start, step through, skip, and re-launch the tour without it blocking any other interaction.
  • Tour code is not in the SPA's initial eager payload (network tab / build output shows it as a separate chunk, only fetched on trigger).
  • Tour copy renders in en/es/tl with no missing-key fallback.
  • No regression to the inert/accessibility-tree contract PWA/shell: verify the inert-swallowed announcements with a real screen reader #501 established.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions