# Shell: Routing and layouts

Source: `apps/oshun/web/src/app/`, `apps/oshun/web/src/proxy.ts` (Next 16 —
exports `proxy` + a `config` matcher; there is no `middleware.ts`)

How Next.js route groups, segment layouts, error boundaries, and loading states
compose under the root layout. Walk this when you suspect a bug is in the layout
stack, not the leaf page.

## Route groups in `app/`

- `(workspace)/` — workspace surface; catch-all at `/workspace/[[...path]]`
- All other top-level segments are addressable routes.

## Catch-all routes

- [ ] `/app/[surface]/[[...path]]` — generic surface proxy; honors
      `?surface=pwa` query for installed-PWA cold-start
- [ ] `/(workspace)/workspace/[[...path]]` — workspace shell proxy
- [ ] `/d/[domain]/[[...path]]` — short-link entry; redirects to canonical
      domain route
- [ ] `/domains/[domainId]` — legacy domain landing; redirect or render?

## Layout files

Walk the layout file (if any) for each top-level segment. Each segment that has
a `layout.tsx` defines header/nav state for everything beneath.

- [ ] **Root** — `apps/oshun/web/src/app/layout.tsx` (shell composition; see
      01-app-shell.md)
- [ ] **`/(workspace)/`** — workspace shell layout
- [ ] **`/studio/`** — studio-specific layout (if present)
- [ ] **`/operator/`** — operator-specific layout (if present)
- [ ] **Domain layouts** — `/tara/layout.tsx`, `/arete/layout.tsx`, etc., where
      present, set domain chrome

For each layout, verify:

- [ ] **`children` always renders** — no conditional return that drops the slot
- [ ] **`generateMetadata`** (if used) returns valid metadata
- [ ] **Suspense boundary** at expected depth — loading.tsx triggers, not a
      blank screen
- [ ] **Error boundary** at expected depth — error.tsx catches, not the root
      global-error

## Special files

- [ ] `app/error.tsx` — segment-level error boundary; shows recoverable error UI
      with `reset()` button
- [ ] `app/global-error.tsx` — catastrophic error UI (replaces `<html>`); logs
      to telemetry; offers reload
- [ ] `app/not-found.tsx` — 404 UI; preserves shell chrome where possible;
      includes search affordance
- [ ] `app/loading.tsx` (if present) — skeleton matches final layout

## Proxy (`proxy.ts`)

Authentication and entitlement gates run at the edge before page rendering.
(Next 16 renamed `middleware` → `proxy`; the file exports `proxy` and a `config`
matcher. There is no `middleware.ts`.)

- [ ] **Public path allowlist** — `/welcome`, `/landing`, `/legal/*`, `/lilith`,
      `/system`, `/status`, `/v2`, `/v3/landing`, opengraph/twitter images
- [ ] **Public prefix allowlist** — `/_next`, `/api`, `/icons`, `/images`,
      `/fonts`, `/screenshots`, `/scene`, `/studio/compose`
- [ ] **AAA-only studio routes** — `AAA_ONLY_STUDIO_ROUTES`; non-AAA users get
      gated UI
- [ ] **`OSHUN_PWA_RELAUNCH_TARGET_COOKIE`** — preserved across SSR redirects
- [ ] **Auth bounce** — sessionless user on a gated route → redirect to
      `/welcome` with `?redirect=` preserving the deep link

## Route prefetching

- [ ] **Shell route links** prefetch on hover/focus (Next.js default)
- [ ] **Domain switcher** prefetches the destination domain layout
- [ ] **`<MobileBottomNav>`** does not aggressively prefetch (battery cost on
      cellular)

## E2E coverage

- Backed by
  [`apps/oshun/web/e2e/shell-route-signoff.spec.ts`](../../apps/oshun/web/e2e/shell-route-signoff.spec.ts)
  — authenticated shell route signoff for Home, Explore, Library, Activity,
  Search, Profile, profile notifications, the shell notifications drawer,
  contextual assistant dock, and shell loading/empty/offline/error previews. The
  2026-06-25 update removed the legacy Nisaba workspace fixture from this
  signoff path: the Nisaba compare and passage evidence now uses a real
  per-session notebook seed/readback through `/v1/nisaba/notebooks`, clears
  stale offline Nisaba snapshots, and waits for live `/v1/nisaba/passages/daily`
  or `/v1/nisaba/passages/:id` hydration before asserting route posture and
  screenshots.

## Cross-references

- [01-app-shell.md](./01-app-shell.md)
- [03-pwa-behavior.md](./03-pwa-behavior.md) — service worker intercepts
  navigation
- [04-auth-session.md](./04-auth-session.md) — what the proxy checks against

## Open questions / known gaps

- [ ] Document every per-segment `layout.tsx` that exists today
      (`apps/oshun/web/src/app/**/layout.tsx`) — first sweep should produce that
      inventory
