-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Refactor the app's navigation from a single general stack into three conditional stacks — Auth, Onboarding, and Main — gated by the Zustand useAuthStore state. This ensures users are always routed to the correct flow based on their authentication and onboarding status.
Motivation
With the current navigation stack, there is no sort of nuance with authentication/onboarding status. By splitting into three declarative stacks that swap based on global state, navigation becomes self-enforcing: the correct screens are simply the only screens that exist in the tree at any given time. This is the standard React Navigation pattern for auth flows and eliminates an entire class of routing bugs.
Requirements
Acceptance Criteria
- Navigation is split into three stack navigators:
AuthStack,OnboardingStack, andMainStack - A root-level navigator conditionally renders the correct stack based on
useAuthStorestate (isAuthenticated,hasCompletedOnboarding) - Unauthenticated users can only access screens in
AuthStack— there is no way to navigate to onboarding or main app screens - Authenticated users who haven't completed onboarding can only access screens in
OnboardingStack - Authenticated users who have completed onboarding land in
MainStack - A splash/loading screen is shown while the Zustand store rehydrates from AsyncStorage — no flash of the wrong stack (This feature may or may not be blocked, will come back)
- Transitions between stacks (e.g., login → onboarding, onboarding → main) are driven by store state changes, not imperative
navigation.navigate()calls - Logging out from any screen in
MainStackreturns the user toAuthStackwith no back gesture available
Out of Scope
- Individual screen UI within any stack (login form, onboarding steps, home screen, etc.)
- Any sort of navigation bar (follow-up ticket)
- The Zustand store itself — that's handled by the auth store ticket; this ticket consumes it
File structure:
src/navigation/
RootNavigator.tsx # Conditional stack switching
stacks/
AuthStack.tsx # Login, Signup, Forgot Password
OnboardingStack.tsx # Onboarding step screens
MainStack.tsx # Home, Tracking, Profile, etc.
Placeholder screens — each stack should have at least one placeholder screen so the navigation is testable end to end before real screen UI is built:
AuthStack: a placeholder login screen with a "Sign In" button that callsuseAuthStore.getState().login()OnboardingStack: a placeholder screen with a "Complete Onboarding" button that callscompleteOnboarding()MainStack: a placeholder home screen with a "Log Out" button that callslogout()
This lets us verify the full routing flow independently of screen UI work.
Affected Areas
src/navigation/RootNavigator.tsx(new or heavily refactored)src/navigation/stacks/AuthStack.tsx(new)src/navigation/stacks/OnboardingStack.tsx(new)src/navigation/stacks/MainStack.tsx(new)- App entry point (
App.tsx) — should renderRootNavigatoras the top-level component - Any existing screen registrations in the current single stack need to be migrated into the appropriate new stack
Dependencies
- Zustand auth store ticket — this ticket directly consumes
useAuthStoreand itsisAuthenticated,hasCompletedOnboarding
Flow diagram:
App Launch
→ Not Authenticated? → AuthStack (Login / Signup)
→ Authenticated + Not Onboarded? → OnboardingStack
→ Authenticated + Onboarded? → MainStack
Testing Notes
- Fresh install — no persisted state → should show Auth stack
- Login flow — calling
login()from Auth stack → should transition to Onboarding stack (if not completed) or Main stack (if completed) - Onboarding completion — calling
completeOnboarding()from Onboarding stack → should transition to Main stack - Logout — calling
logout()from Main stack → should transition to Auth stack with no ability to swipe back - App kill + reopen (authenticated, onboarded) → should show Main stack directly, no flash of Auth
- App kill + reopen (authenticated, not onboarded) → should show Onboarding stack
- Back gesture/button — confirm users cannot navigate backwards across stack boundaries (e.g., pressing back on the first onboarding screen should not return to the login screen)
- Rapid state changes