Skip to content

[$500] Centralize navigation redirects with guard system #79974

@mountiny

Description

@mountiny

Coming from this proposal

Background

When users sign up for Expensify or migrate from OldDot to NewDot, they go through an onboarding flow that consists of several screens (personal details, purpose selection, company size, etc.). The app needs to ensure users complete onboarding before accessing the main application. Currently, this redirect logic exists in multiple places across the codebase: useOnboardingFlow hook (with ~20 dependencies in its useEffect), openReportFromDeepLink action (triggered from Expensify.tsx with minimal dependencies), and various other places that check onboarding status.
Each location independently determines whether to redirect to onboarding and when to do so. The redirect from openReportFromDeepLink typically happens early since it only depends on session data being loaded, while the redirect from useOnboardingFlow happens later due to its many dependencies. Additionally, certain paths like onboarding/migrated-user-welcome are excluded from being saved as the last visited onboarding path, meaning users can be redirected back to different onboarding paths when they reopen the app.

Problem

When navigation redirects are scattered across multiple locations with different dependency arrays, if different redirect logic executes at different times, then users experience race conditions that cause onboarding loops and incorrect navigation states.

Solution

Implement a navigation guard system that centralizes all redirect logic at the router level, eliminating race conditions by evaluating navigation synchronously before any state changes occur.

The guard system eliminates race conditions by moving all redirect decisions to a single evaluation point at the router level. A guard infrastructure with a registry evaluates guards in explicit order, integrated directly into RootStackRouter.getStateForAction() before any routing logic runs. When any navigation action occurs, guards evaluate synchronously with complete, up-to-date Onyx data and can return ALLOW, BLOCK, or REDIRECT results. The OnboardingGuard subscribes to relevant Onyx keys and implements logic to redirect users to onboarding screens when needed, or block navigation away from incomplete onboarding. The scattered redirect logic is removed from useOnboardingFlow, openReportFromDeepLink, and Expensify.tsx, replaced with simple navigation calls that trigger guard evaluation.

Issue OwnerCurrent Issue Owner: @CortneyOfstad

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions