Navigation state
Navigation state
Application navigation state is the shared record-detail navigation platform inside @norbital-ai/pod. The runtime bootstraps PageSurfaceState (an internal
class name, not a tenant-authored layout component) and persists record navigation in the URL.
What people see
The Pod shell renders a sidebar and a main app surface. Platform and Applications are uppercase muted section labels in the sidebar — host plugins and tenant apps remain visually distinct. They are not navigation items themselves.
Opening a record does not navigate to a new document route. The app stays on /app/{appName}; the selected record stack lives in ?stack= and the
shell renders a detail sheet when viewMode === 'sidesheet'.
┌─ TenantWorkspaceShell ─────────────────────────────────────┐
│ [Sidebar] │ Main app surface │
│ PLATFORM — host plugins │ CollectionTable / … │
│ APPLICATIONS — tenant apps │ │ click row │
│ │ ▼ │
│ │ pushes ?stack= in URL │
└─────────────────────────────────┴─────────────────────────┘
│
viewMode=sidesheet ▼
┌──────────────────────────────────────┐
│ Right sheet (DetailSurfaceStack) │
│ Record detail snippet + breadcrumbs │
└──────────────────────────────────────┘ Stack contract
Navigation state is a single selected record stack serialized in ?stack=:
type NavState = {
stack: NavStackItem[];
};
type NavStackItem = {
collection_name: string;
record_id: string;
node_id: string; // which registered detail snippet to render
viewMode: 'page' | 'sidesheet';
expand?: string[];
}; Tenant apps register their own routeKey values through DetailSurfaceService. CollectionTable and CollectionKanban register detail snippets and open records via the surface navigation
API — they build a nav target, merge it into the current URL stack, and the shell renders the
registered snippet.
Route context
Lightweight route context only identifies where the URL belongs: organization, optional appName, and optional workspace-manifest mode. It does not decide rendering behavior.
When switching apps or clearing selection, the shell uses that context to preserve or reset ?stack= while staying on the current app URL.
Forms in detail surfaces
Create, display, and edit in table, kanban, and detail views share one compiler-owned collection
role: +representation.svelte. Collection surfaces resolve it from the generated static
map and pass record={null} for create or the existing row for display/edit — call
sites do not register or override record components. See Form system.
Related guides
- Apps — tenant application entry components the shell loads
- Collections — models that table and kanban surfaces navigate into
- Form system — inline forms in table, kanban, and detail