chore: enforce shared WebUI layouts
Dependency Audit / dependency-audit (push) Successful in 1m36s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 10m29s

This commit is contained in:
2026-08-18 01:03:33 +02:00
parent bec62f38d1
commit b76581a89a
4 changed files with 171 additions and 1 deletions
@@ -51,6 +51,55 @@ rules:
- Preserve a stable way back to the containing object and the broader system.
- Do not let navigation, selection, or a view switch imply consent.
## Shared Component And Layout Architecture
Core owns the reusable WebUI vocabulary; modules own domain composition and
behavior. Centralization follows four layers:
| Layer | Owner | Examples | Rule |
| --- | --- | --- | --- |
| Foundation | Core | theme tokens, spacing, typography, focus and responsive breakpoints | Modules consume the contract and do not redefine it. |
| Primitives | Core | buttons, fields, dialogs, alerts, cards, tables, loading, empty and blocked states | A matching primitive is reused rather than copied locally. |
| Structural layouts | Core | page frame and header, action region, workspace panes, toolbars, grids, form sections and dialog anatomy | Layout owns geometry, scroll, responsive collapse and accessibility, but no domain decisions. |
| Domain compositions | Owning module | a campaign review, mailbox, records explorer or operations dashboard | Modules select shared pieces, bind data and permissions, and retain domain wording and consequences. |
A component belongs in Core when it is used or expected in more than one
module and central ownership materially protects accessibility, responsive
behavior, localization, contextual help, theming, or interaction consistency.
A component stays module-owned when its API would otherwise encode a domain
entity, permission, workflow state, endpoint, or policy decision. Reuse does
not justify moving domain semantics into Core.
`PageLayout` is the standard frame for headed workflow, dashboard,
configuration, monitoring and explanatory pages. It owns the scroll viewport,
content inset, sticky responsive header, title and description geometry,
route-action placement, transient page notices, loading boundary and page help
identity. `PageHeader` is the escape hatch for full-canvas archetypes that need
the same header contract but must own their workspace scroll. Specialized
layouts such as `AdminPageLayout` compose these lower-level Core contracts;
they do not repeat their markup or responsive CSS.
Module CSS may arrange domain content inside a shared layout. It must not
override Core layout internals or copy the outer page, dialog, toolbar, form or
state skeleton under a module-prefixed name. If an archetype cannot be
expressed by the central API, extend the central contract or record a bounded
exception before introducing local structure.
Migration is incremental and enforceable:
1. inventory copied structures and register existing debt;
2. introduce the smallest domain-neutral Core contract with accessibility,
help, localization, theme and narrow-layout tests;
3. migrate representative Core and optional-module consumers;
4. reject new copies while removing registered debt in bounded module batches;
5. promote the next repeated structure only after its variants and extension
points are understood.
The intended next structural contracts are workspace/split-pane layout,
responsive page toolbar, content grid, form-section layout, dialog body/footer
layout and shared empty/error state composition. Their APIs must remain
composable; a central component is not a single oversized page template.
## Surface Archetypes
Choose an archetype from the task, then specialize it for the domain. A route
@@ -101,7 +150,8 @@ one.
creation panel.
- Workflow, configuration, dashboard, and explanatory pages may use a heading.
The heading names the task or scoped object and contains only route-level
actions.
actions. Use the Core `PageLayout` contract for the frame and `PageHeader`
only when a full-canvas archetype owns its own scrolling.
- Put a collection-wide create action in the heading of the collection it
affects. Use a short, specific label such as `Add` when the heading already
names the object. Do not duplicate that action in a permanently visible side