Mosaic one model, many lenses

ADR 0045 — Use-case-first web nav (CQRS model demoted to a developer console)

  • Status: accepted
  • Date: 2026-10-05
  • Slice: P45 (builder-roadmap: UI-first — the shell reads as an app, not a model view)

Context

The web shell's default navigation (the branch taken when ui.scenes is empty — i.e. every app that does not hand-author a scene nav) was organized around the CQRS model pages: commands, aggregates, projections, workflows, events, cqrs — all flat and always visible at the top. The use-case list pages (projections with a ui.page hint) were emitted last and sat inside nav groups. Scene groups are already collapsible — collapsed by default in the sidebar/bottom/floating layouts (layout.js applyGroups adds collapsed to every .scene-group-wrap) — so the use-case pages were hidden while the CQRS pages were prominent.

The result: the shell read as a CQRS technical representation, not an app. But CQRS (aggregates / commands / events / projections) is the backend model — how we implement things. The UI/UX should be organized around use cases: list and present things, and trigger/create/update things — without the user needing to know the word "projection" or "command".

Decision

1. Reorder the default nav to be use-case-first

The default (CQRS-derived) nav is now built in use-case-first order:

  1. Primary (always visible / open by default) — dashboard, the declared dashboards (a Dashboards group), the use-case list pages (projections with a ui.page hint — business labels, in their declared groups), and the platform/ops pages (tasks, schedules, flags, notifications).
  2. Developer group (collapsed by default) — the CQRS model pages (commands, aggregates, projections, workflows, events, cqrs) plus the admin: consoles. These are the developer/technical views of the model: still reachable by expanding the group, but no longer the app's front page.
  3. Unconditional entries (knowledge, search, app.ui.nav links) follow.

The app now leads with what the user works on (the use-case pages and their in-page actions — the "trigger/create/update" surface) and treats the CQRS model as a collapsible developer console.

2. Open-by-default groups

A group wrap can be marked open-by-default with a data-group-open="1" attribute. The shell's applyGroups collapses every group by default except those carrying data-group-open. Use-case groups and the Dashboards group are emitted open-by-default (so the app's working pages are visible without a click); the Developer group is not (so it starts collapsed). This reuses the existing collapse mechanism — one attribute plus one hasAttribute check in the shell JS.

3. Example

The full-stack reference app declares business page: hints on the Orders and Tickets projections (RuleSetList already had one), so its primary nav is dashboard / Dashboards / Orders / Tickets / Rule sets, with the CQRS model pages under the collapsed Developer console.

Consequences

  • The shell reads as a use-case app: it leads with business pages (list/present things) and their actions (trigger/create/update), and the CQRS model pages are demoted to a collapsed "Developer" console.
  • The CQRS pages are not removed — they remain reachable by expanding "Developer", preserving the reference app's value for inspecting the model.
  • Reuses the existing group-collapse machinery (one attribute + one JS condition). No new page, route, or backend change; ui.scenes (the explicit scene nav) is untouched — apps that hand-author scenes keep their scene-driven nav.
  • The command palette (P40) shares the nav inventory, so it lists the use-case pages too (a jump-to-any-page tool; it still includes the developer pages).
  • Every app that uses the default nav gets this reframe for free; apps wanting the old layout can still declare ui.scenes.

Verification

  • Goldens (all 5 examples re-pinned): the new nav order + the data-group-open attribute are pinned in each pages.rs; the layout.js applyGroups change is pinned in each shell.
  • Nav order (full-stack): dashboard / Dashboards(ops) / Orders / Tickets / data(rule sets) / tasks / schedules / flags / notifications / Developer(collapsed: commands, aggregates, projections, workflows, events, cqrs) / knowledge / search / docs / github.
  • Real build: full-stack builds (native app + SSR web) and every declared e2e scenario passes — including the command palette (now listing the new use-case pages) and the P39 use-case list views.
  • Gates: 477 workspace tests, clippy -D warnings, cargo fmt --check, conformance re-pinned.