Skip to content

Onboarding — feature status

Status: WelcomeStory shippable (pending iOS-PWA sign-off); setup wizard built against a stubbed service, not yet backend-wired, nothing committed. The merchant first-run experience is the second real mobile feature (after the WelcomeStory intro) and sets the precedent for form primitives, a typed data-service seam, multi-step wizard state, and form i18n that Profile, Settings, and the web app inherit. Verified against the codebase 2026-07-23.

What it delivers

The merchant first-run flow, end to end:

  • BrandSplash — held branded intro after the native OS splash (seamless mark hand-off → wordmark + By / Digious Platforms Pvt. Ltd. attribution), ~1.9s (0.9s reduced-motion).
  • WelcomeStory — 6-scene, auto-advancing, tri-lingual (en/mr/hi), fully animated story ending in a business-vs-individual fork. Headline words emphasised with the QR-monogram brand gradient (see Brand & Typography).
  • OnboardingSetup — the lean post-fork setup wizard (below).

The lean flow (a deliberate cut)

Lengthy onboarding frustrates users, so first-run is cut to the minimum path to a live, personalized card; everything else moves to progressive profile-completion on the dashboard.

PathSteps
Businessauth → name + mobile → brand → industry → slug → celebrate
Individualauth → name → slug → celebrate (brand + industry omitted, not greyed)

Deferred to progressive profile-completion (not built here; the wizard store + service already model the full field set so they slot in without rework): location (country/state/city/pin), the notifications-permission ask (surfaced contextually on the first enquiry/booking — never a blocking step), and the feature-highlights screen (becomes the dashboard "get-started" cards).

In-flow language picker

A LanguageSelect control (en / मराठी / हिंदी) lives in the wizard header from AuthStep on, bound to the global localeStore. The device seeds the locale; the user is never forced to it. The same control becomes the Settings › General field when that screen is built. Emits onboarding_language_selected.

Architecture — presentation over a typed service seam

Data logic is written once; only UI is written twice (ADR-0011/0012). Onboarding establishes the pattern:

  • packages/schemasprofileSetupSchema + per-step slices, using the exact public.profiles column names (full_name, mobile_number, brand_name, business_domain_id, country/state/city/pin_code, slug) — no invented fields, so the stub swaps for real persistence with no shape drift. brand_name IS the business name.
  • packages/data — the typed OnboardingService interface (sendEmailOtp, verifyOtp, checkSlug, saveProfileStep, completeOnboarding) + an in-memory stub (fake OTP 428193, reserved/taken slug sets, mock timers, a deterministic failure hook so the error path is exercised). The real Supabase/EF impl (email-OTP via ADR-0008/ZeptoMail, a slug-uniqueness EF, manage-profile write) replaces the stub behind the same interface.
  • Wizard state — feature-local Zustand store useOnboardingFlow (account type, per-type step order, current index, accumulated draft), seeded from ?type=business|individual&ref=.
  • UI — shared @/ui form primitives (Button, TextField, OtpInput, ChoiceGrid, StepProgress, Chip, LanguageSelect) + feature-local SetuCardPreview (the live "aha" card) and StepShell.

Tests

Exhaustive, co-located, using the real component (never the component-under-test or its icons mocked — the "RiEdit3Line lesson"); @testing-library/react-native + jest-expo, with the stub service injected and edge/advanced paths covered, not just the happy path:

  • Primitives — every state/branch of each @/ui primitive.
  • Steps — validation gating (name<2, mobile≠10 digits, brand<2), OTP wrong-code/resend/Google-stub, slug empty/short/reserved/taken/available + slugify, single-select industry, celebrate hand-off.
  • Controller — business vs individual step order, referral chip, mid-flow language switch re-renders copy, dashboard hand-off routes to /dashboard.
  • Schema + service stub — boundary rejections and OTP/slug/save behaviour incl. the simulated failure.

Cross-platform parity status

WelcomeStory + BrandSplash: Android native ✅ on device; Web PWA ⏳ headless-validated, on-device/browser walk pending; iOS native ⏳ pending.

OnboardingSetup wizard: Web PWA ⏳ builds/serves via expo export -p web (route /onboarding/setup), full manual walk pending sign-off; Android ⏳ pending on-device walk (APK on request only); iOS native ⏳ pending. Divergence seams: none while stubbed (pure presentation + in-memory service) — they appear only when the real auth/push wiring lands, and each gets a working impl or approved fallback per surface in that follow-on PR. See ADR-0011 (surface-matched frontend) and ADR-0008 (email-OTP).

Deferred / sequenced follow-ons

Real backend wiring (Supabase email-OTP + session, business_domains table + seed, slug-uniqueness EF, the manage-profile allow-list fix so slug/onboarding_completed persist, promotion to both projects); progressive profile-completion on the dashboard; the first-run dashboard + mobile console; responsive desktop onboarding; iOS-PWA verification. Tracked in the dev-tracker.