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]>
The Dashboard's shell now follows DESIGN.md §4 (ADR 0058):
- A collapsible left sidebar replaces the header-and-column layout. It
is icons and labels when expanded and icons only when collapsed; each
collapsed item keeps its name, visually hidden, and shows a tooltip
on hover and on keyboard focus (WCAG 2.2 §1.4.13). The Overview comes
first, then the server's groups and modules. There is no top bar.
- The expanded/collapsed choice is remembered in this browser's
localStorage, behind a SidebarPreference interface that a synced
store can replace later.
- An account menu at the bottom of the sidebar follows the WAI-ARIA menu
button pattern and offers only Sign out, which now lives there rather
than in the header.
- On phones (below 48em) the same navigation opens in a modal drawer:
the page behind it is inert and focus is trapped inside it. Escape,
its close button, and the backdrop close it and return focus to the
menu button. Choosing a page closes it and focuses the page. Changing
layout keeps the route, the desktop mode, and the mounted module.
- Lucide (lucide-react 1.48.0, shell only) is Ekklesia's icon
vocabulary. Every module shows one generic icon until manifest v9
lets modules declare their own; there is no per-module icon map.
- The identity slot is a neutral placeholder with no inputs, waiting
for branding (#101).
The tooltip, menu, and drawer stay shell-local until a second consumer
needs them (ADR 0039). The deploy smoke now signs out through the
account menu, and drives the drawer at phone size in a real browser.
Co-Authored-By: Claude Opus 5.5 <[email protected]>