Stage 1 PR 7 (ADR 0063). A module becomes a first-class part of the Dashboard.
- Manifest v9 = v8 plus optional `navigation`: a Lucide icon from the curated
MODULE_NAVIGATION_ICONS set, and up to 12 primary pages (stable id, safe
label, kebab-case path relative to the module root; no traversal, schemes,
queries, duplicates, or nesting). Validated before activation.
- Version 8 stays accepted beside version 9, each read strictly as itself
(discriminated union); no released manifest is rewritten. The template
moves to v9; the released Signage 0.1.5 manifest is a test fixture.
- Real module routes: /<id> is the landing view, /<id>/<page> a declared
page, anything beneath a page a module-owned detail route; anything else
is not-found and mounts nothing. api/assets/display are never pages.
- Sidebar: declared icons, pages nested under an open module, one
aria-current, collapsed and drawer behaviour; v8 modules unchanged.
- module-ui-sdk: ModuleUiHostContext.navigation (location, subscribe,
navigate, link, settings), refusing anything outside the module's routes;
undefined on the display host. Mount ABI unchanged.
- Return-to-origin: one `?return=` carrier on Settings URLs, validated by
parseReturnTarget and against running modules' declared routes; Settings
Back returns to exactly the originating module page, across refreshes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>