Feature guide

App shell and navigation

The signed-in shell, hash routing, navigation drawers, screen selection, scroll restoration, and route analytics.

← Technical overview

What this domain owns

How a learner moves between product screens. It does not own lesson rules or progress calculations.

Feature flow diagram

Link or browser history
        │ hashchange
        v
app-route.ts ──parse──> AppRoute
        │
        v
app-shell.tsx ──selects──> screen component
        │                         │
        └── navigation / scroll / analytics

This diagram shows the normal direction of control and data. Follow it before changing a boundary or adding a dependency.

Class and relationship diagram

┌───────────────┐     parse(raw)      ┌─────────────────────────┐
│ AppRoute      │◀───────────────────│ RouteParser             │
├───────────────┤                    ├─────────────────────────┤
│ + screen      │                    │ + parseAppRoute()       │
│ + segments    │                    │ + activeNavigation()    │
│ + params      │                    └───────────┬─────────────┘
└───────┬───────┘                                │ selects
        ▼                                        ▼
┌──────────────────────────┐          ┌────────────────────────┐
│ AppShell                 │          │ Screen component       │
├──────────────────────────┤          ├────────────────────────┤
│ + session                │          │ + receives route/state │
│ + learner state          │          │ + renders one screen   │
│ + renderRoute()          │          └────────────────────────┘
└──────────────────────────┘

Boxes show the important data types or services. Their fields and main methods are listed inside; arrows show the primary dependency or data relationship.

Sequence diagram

Learner
Browser
RouteParser
AppShell
Screen
Insights
click link / use Back
hashchange
AppRoute(screen, params)
render selected screen
rendered view
restore scroll position
record route view (if consented)

Read this from top to bottom: each arrow is the next interaction in the normal successful path.

Start here in the code

Choose any filename to open it directly in VS Code.

How it works

  1. A hash changes.
  2. The route parser creates a screen and parameters.
  3. App shell selects one screen component.
  4. Navigation, access checks, analytics, and scroll restoration run around that screen.

Read this code

components/app/app-route.tsOpen in VS Code — Turn a URL hash into a screen request

export function parseAppRoute(raw: string): AppRoute {
  const [path = '', query = ''] = raw.split('?', 2);
  const segments = path.split('/').filter(Boolean);
  const candidate = segments[0] ?? 'today';
  const screen = (knownScreens.has(candidate) ? candidate : 'today') as AppScreen;

  return { screen, params: new URLSearchParams(query), /* … */ };
}

What each part is doing

  1. The browser supplies the part after # as raw.
  2. Unknown screens safely fall back to today instead of rendering an invalid page.
  3. The app shell uses screen to select the page component; add a screen to the allow-list before routing to it.

This is a deliberately short excerpt of the real pattern, with unrelated details omitted. Read the named file for the complete implementation.

Related API and server boundaries

  • Mostly client-side. See /api/auth/session for session refresh and /api/events for route analytics.

Tests to read and run

Implementation notes

This is the home for detailed explanations, decision records, request examples, and diagrams for this feature. Add new feature-specific documentation here instead of expanding the platform overview.