MeridiansMeridians

Navigation — pages, deep-links & how you move [Flow]

Source path: knowledge-base/diagrams/flows/navigation.md

# Navigation — pages, deep-links & how you move `[Flow]`

How the app's routes connect, and how a **deep-link intent** travels from the URL to a selected artifact.
The URL `[id]` is the source of truth for the active domain; `src/lib/core/routes.ts` is the **single
source of URL truth** — every path and query deep-link is built there, and consumed through one seam.

```mermaid
flowchart TB
    Home["**/** — Home console<br/>composer: **Note · Ask · Build**<br/>Domains · Extraction · Games · People · Invitations"]
    Onboard["/onboarding — guided setup<br/>6-step stepper"]
    Wizard["CreationWizard<br/>new domain from a premise"]
    Extract["/extraction — Text Extraction"]
    Const["/constellation/[id]<br/>portfolio container — ?tab= surface"]
    Work["/domain/[id] — **THE WORKSPACE**"]
    Extend["/extensions/[id] — add corpus"]
    Play["/scenario/[gameId] — Scenario seat<br/>(guest-pass, one seat)"]
    Exchange["/exchange — the shelf<br/>(shared page, was /library)"]

    Home -->|open a folder| Const
    Home -->|open a domain| Work
    Const -->|open a member domain| Work
    Home -->|new domain| Wizard --> Work
    Home -->|Onboarding| Onboard ==>|"builds a Constellation<br/>+ its Domains"| Const
    Home -->|"Build (paste corpus)"| Extract -->|creates DomainState| Work
    Home -->|GamesLobby → join| Play
    Home -.->|"**Ask** — AI routes to best-fit expert<br/>?ask= seeds + auto-sends the chat"| Work
    Home -.->|"Ask → constellation<br/>?tab=chat&ask="| Const
    Home -.->|"**Note** — routes into an expert's queue<br/>?view=notes&note="| Work
    Work -->|add corpus| Extend -->|APPLY_EXTENSION| Work
    Home --> Exchange
```

## The deep-link lifecycle — one builder, one consumer, one applier

```mermaid
flowchart LR
    Routes["**routes.ts** — the builders<br/>domain(id, opts) · constellation(id, {tab, ask}) ·<br/>stream/merge/tutor/projection/cycle/note ·<br/>artifact(id, NavTarget) · extraction · extensions"]
    Routes -->|"?open=reading:RDG-1 · ?signal=stream:S-1 · ?view= ·<br/>?projection= · ?note= · ?inspect= · ?ask= · ?slides= · ?game="| URL[/"the URL — intents compose;<br/>each param has its own consumer"/]

    URL --> Intent["**useUrlIntent(params, onIntent, {enabled})**<br/>the ONE consumer: latch once ·<br/>strip via takeParams (siblings survive) ·<br/>hold until the surface is ready"]
    Intent --> Nav["**navigateTo(NavTarget)** — the ONE applier<br/>resolveNav (pure) → scene cursor →<br/>stage view → inspector → one-shot navFocus"]
    Nav --> Surface["destination surface consumes navFocus,<br/>selects + descends, then clears it"]

    Hist["**Stage history** — browser-style back/forward<br/>NavPoint = view + focus + inspector + cursors;<br/>stepping back re-dispatches the same plan"]
    Nav <-->|"push / replay"| Hist

    Phone["**phone-route.ts** — pure projection of a<br/>navigation onto the phone pill's leaves<br/>(notes → Outline's Notes lens)"]
    Nav -.->|"on isPhone"| Phone
```

- **Home spine** (in `GatewayShell`, present on every page) carries the role-gated verbs — New domain, People, Usage, Hosting, Environment — plus identity / sign-out.
- **The Home composer routes by intent.** *Note* commits into one domain's Notes queue and lands on `routes.note(...)`; *Ask* routes a message to the best-fit expert (AI-proposed, operator-confirmed) and opens its chat via `?ask=` (a constellation ask implies `?tab=chat`); *Build* stages a corpus and lands on `/extraction?new=1`.
- **`?open=` is the general cross-domain drill.** It carries a whole `NavTarget` (`?open=reading:RDG-1`, `?open=note:entry-1`, `?open=view:runs`), so a PORTFOLIO tap — "Open in workspace" on a constellation Story's attached material — lands inside the owning domain **on that artifact**, not merely at its Stories inbox. One param covers every navigable kind because it encodes the same target an in-workspace drill applies, and `useDomainDeepLinks` consumes it before the narrower `?view=` family so a link naming an artifact is never downgraded to its surface. The narrower params stay for the links that predate it.
- **Intents compose, so consumption is surgical.** `?slides=1&signal=stream:S-1&ask=hi` is one legal link with three consumers on three surfaces. `takeParams` removes only the params a consumer owns; `useUrlIntent` latches (fires once), strips *before* the handler runs, and `enabled` holds the intent until its surface can act (domain live, chat grounded).
- **One applier.** No surface hand-rolls the multi-dispatch: `resolveNav` (pure, tested) maps a `NavTarget` to a plan; `useNavigate` applies it in order (scene cursor before view; one-shot `navFocus` armed last). Stage back/forward replays the same plan shape from a `NavPoint`, so history restores the exact item, not just the tab.
- **Onboarding** is the one path that *creates* a Constellation + its member Domains + their maintenance in one flow ([onboarding](onboarding.md)).
- Providers wrap every route: `ThemeProvider → StoreProvider → WizardProvider → ToastProvider → (ScenarioHost) → AccessProvider → LogsProvider`; the workspace route adds `PropositionClassificationProvider → AudioPlayerProvider`.
- The surfaces themselves: home → [ui/home-console](../ui/home-console.md), workspace → [ui/workspace-shell](../ui/workspace-shell.md), constellation → [ui/constellation](../ui/constellation.md), phone → [ui/mobile](../ui/mobile.md).

**Where it lives:** `src/lib/core/routes.ts` (builders + `takeParams` + `decodeConstellationView`) ·
`src/hooks/useUrlIntent.ts` (the consumer) · `src/hooks/useNavigate.ts` + `src/lib/core/program/stories/nav.ts`
(`resolveNav`, pure) · `src/shell/layout/useDomainDeepLinks.ts` (the workspace's three intents) ·
`src/hooks/useStageHistory.ts` + `src/types/domain/nav.ts` (`NavPoint`) · `src/shell/mobile/phone-route.ts`.
Open on GitHub

Raw Markdown source