Skip to content

Make auth root navigation single-owned without initial=false or synthetic Back history #162

Description

@artiphishle

Problem

After #159, opening the Nutrition Scanner app through the Studio dashboard at / resolves to /products, but the Products screen still displays a Back button. The navigation also carries an initial=false parameter.

This is not the desired behavior:

  • / should resolve to the authenticated post-sign-in route /products
  • /products must be the effective root entry and must not show a Back button
  • no initial=false workaround or navigation parameter should be required
  • deeper routes should retain normal Back navigation to /products

Root cause

Generated auth apps currently have two owners for the root transition:

  1. src/app/index.tsx is generated with a redirect to the non-root post-sign-in route.
  2. The generated root layout also performs the authenticated / → post-sign-in transition with router.replace(...) after auth bootstrap.

The redirect introduced by #159 uses withAnchor. Expo Router anchoring and initialRouteName are intended to reconstruct navigator history for deep links. In this flow that can create synthetic previous navigation state and expose a Back button, rather than making /products the true root entry.

Using initial=false only suppresses part of that behavior at the navigation call site and leaves the competing ownership unresolved.

Proposed solution

Make the generated root layout the sole owner of auth bootstrap and root canonicalization.

Generator

For apps with global auth enabled:

  • do not generate src/app/index.tsx solely to redirect to postSignInRoute
  • remove the generated Redirect / withAnchor path for this case
  • keep the existing auth-ready boundary in the root layout
  • after auth is ready, use router.replace(AUTH_POST_SIGN_IN_ROUTE_TARGET) when an authenticated user enters /

Navigator structure

Keep natural navigator initial routes:

  • root Stack initial route: (app)
  • authenticated app Stack initial route: (tabs)
  • tabs initial route: products

Do not pass or generate initial=false as a workaround.

Expected behavior

Enter through Studio dashboard

Dashboard opens /
  → root layout bootstraps auth
  → authenticated root canonicalization replaces / with /products
  → Products is the effective root screen
  → no Back button

Direct route

/products
  → Products is the initial screen
  → no Back button

Nested route

/products/:id
  → normal navigation history back to /products
  → Back button is shown

Acceptance criteria

  • Auth-enabled apps with a non-root postSignInRoute do not generate a synthetic root redirect screen.
  • Opening / while authenticated ends at /products with no Back button.
  • Opening /products directly has the same navigation state and no Back button.
  • The URL and router params do not contain initial=false or another navigation-history workaround.
  • Opening a nested Product route retains a functional Back button to /products.
  • Unauthenticated root entry still resolves to the configured sign-in route after auth bootstrap.
  • Studio admin routes remain excluded from auth canonicalization.

Regression coverage

Add generator assertions that:

  • no src/app/index.tsx redirect is generated for an auth app whose post-sign-in route is products
  • the root layout owns the authenticated / replacement
  • the root, app, and tabs initialRouteName chain remains correct

Add a web integration/E2E test that:

  1. prepares an authenticated session
  2. opens /
  3. waits for /products
  4. verifies no Back button and no initial parameter
  5. opens a nested Product route
  6. verifies Back returns to /products

Context

Follow-up to #158 and #159. The goal is navigator-owned history with a single root-navigation owner, not header hiding or an initial=false hack.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions