Appearance
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.
| Path | Steps |
|---|---|
| Business | auth → name + mobile → brand → industry → slug → celebrate |
| Individual | auth → 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/schemas—profileSetupSchema+ per-step slices, using the exactpublic.profilescolumn 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_nameIS the business name.packages/data— the typedOnboardingServiceinterface (sendEmailOtp,verifyOtp,checkSlug,saveProfileStep,completeOnboarding) + an in-memory stub (fake OTP428193, 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-profilewrite) 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
@/uiform primitives (Button,TextField,OtpInput,ChoiceGrid,StepProgress,Chip,LanguageSelect) + feature-localSetuCardPreview(the live "aha" card) andStepShell.
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
@/uiprimitive. - 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.