Pulse/docs/release-control/v6/internal/subsystems/frontend-primitives.md
2026-03-19 17:57:07 +00:00

14 KiB

Frontend Primitives Contract

Contract Metadata

{
  "subsystem_id": "frontend-primitives",
  "lane": "L8",
  "contract_file": "docs/release-control/v6/internal/subsystems/frontend-primitives.md",
  "status_file": "docs/release-control/v6/internal/status.json",
  "registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
  "dependency_subsystem_ids": []
}

Purpose

Own reusable frontend primitives and canonical page-shell patterns so feature work extends shared components instead of creating new local variants.

Canonical Files

  1. frontend-modern/src/components/shared/
  2. frontend-modern/src/components/Settings/Settings.tsx
  3. frontend-modern/src/components/Settings/SettingsPageShell.tsx
  4. frontend-modern/src/components/Settings/settingsPanelRegistry.ts
  5. frontend-modern/src/components/Settings/APIAccessPanel.tsx
  6. frontend-modern/src/components/Settings/AISettings.tsx
  7. frontend-modern/src/components/Settings/AuditLogPanel.tsx
  8. frontend-modern/src/components/Settings/AuditWebhookPanel.tsx
  9. frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx
  10. frontend-modern/src/components/Settings/NetworkSettingsPanel.tsx
  11. frontend-modern/src/components/Settings/RecoverySettingsPanel.tsx
  12. frontend-modern/src/components/Settings/SecurityAuthPanel.tsx
  13. frontend-modern/src/components/Settings/SecurityOverviewPanel.tsx
  14. frontend-modern/src/components/Settings/settingsHeaderMeta.ts
  15. frontend-modern/src/components/Settings/SettingsPageShell.tsx
  16. frontend-modern/src/components/Settings/settingsPanelRegistry.ts
  17. frontend-modern/src/components/Settings/SSOProvidersPanel.tsx
  18. frontend-modern/src/components/Settings/UpdatesSettingsPanel.tsx
  19. frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts
  20. tests/integration/tests/15-settings-shell-consistency.spec.ts
  21. frontend-modern/src/components/shared/PageControls.guardrails.test.ts
  22. frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts
  23. frontend-modern/src/features/
  24. frontend-modern/src/components/SetupWizard/SetupWizard.tsx
  25. frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx
  26. frontend-modern/src/components/SetupWizard/__tests__/SetupWizard.test.tsx
  27. frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPreview.test.tsx
  28. frontend-modern/src/components/shared/MonitoredSystemLimitWarningBanner.tsx

Shared Boundaries

  1. frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx shared with security-privacy: the general settings privacy panel is both a security/privacy control surface and a canonical settings-shell presentation boundary.
  2. frontend-modern/src/components/Settings/SecurityAuthPanel.tsx shared with security-privacy: the authentication settings surface is both a security/privacy control surface and a canonical settings-shell presentation boundary.
  3. frontend-modern/src/components/Settings/SecurityOverviewPanel.tsx shared with security-privacy: the security overview settings surface is both a security/privacy control surface and a canonical settings-shell presentation boundary.

Extension Points

  1. Add shared primitives in frontend-modern/src/components/shared/
  2. Route new top-level settings surfaces through the canonical settings shell instead of introducing page-local framing
  3. Add feature-specific presentation only when no shared primitive should own it
  4. Add guardrail tests when a new shared pattern is introduced

Forbidden Paths

  1. Reinventing table/filter/toggle primitives when a shared version exists
  2. Feature-local styling forks of canonical shared components without explicit justification
  3. Direct imports that bypass shared presentation helpers where guardrails exist
  4. Top-level settings panels introducing bespoke page-level headers or outer framing instead of the canonical settings shell and SettingsPanel contract

Completion Obligations

  1. Update guardrail tests when new shared primitives are added
  2. Keep top-level settings surfaces routed through the canonical settings shell and maintain both frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts plus tests/integration/tests/15-settings-shell-consistency.spec.ts
  3. Update this contract when a new canonical UI pattern is adopted
  4. Remove local forks after the shared primitive is introduced

Current State

The frontend already has several guardrail tests. The next step is to keep turning repeated local patterns into explicit shared primitives with hard usage bounds.

The subsystem registry now also requires explicit proof-policy coverage for all shared runtime files, and shared-component guardrails fail if raw table composition is reintroduced in new shared components outside the canonical allowlist. Infrastructure summary and detail surfaces now also use the shared normalized identity lookup helper from frontend-modern/src/utils/resourceIdentity.ts so dotted hostnames and alias variants stay consistent between the shared table, drawer, and detail views instead of each component carrying its own identifier-variant logic. Those same surfaces also share the trimmed-string helper from frontend-modern/src/utils/stringUtils.ts so shared components do not keep their own copy of the same whitespace-trimming identity logic.

General settings segmented selectors for theme preference and temperature unit must now also route through the shared FilterButtonGroup primitive instead of maintaining local button-group styling forks inside frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx.

Reporting time-range/export selectors and General settings Proxmox VE polling presets must now also route through the shared FilterButtonGroup prominent variant instead of maintaining local blue segmented-control styling forks in feature components. That same shared FilterButtonGroup primitive must stay CSP-safe: touch-scroll overflow behavior must come from canonical CSS classes rather than inline style attributes so settings and reporting selectors do not reintroduce browser console CSP violations under the release build policy.

Selectable settings cards for compact provider pickers and detail choice panels must now route through the shared SelectionCardGroup primitive instead of duplicating border-2 active-card styling in feature components.

Settings informational callouts with icon-plus-copy layouts must now route through the shared CalloutCard primitive instead of maintaining feature-local blue bordered wrappers.

Alert incident-event filter containers, labels, and chips must now route through the shared presentation helpers in frontend-modern/src/utils/alertIncidentPresentation.ts instead of allowing frontend-modern/src/pages/Alerts.tsx and frontend-modern/src/features/alerts/OverviewTab.tsx to fork their own filter button styling.

Alert incident acknowledged badges, event cards, and note-editor controls must also route through frontend-modern/src/utils/alertIncidentPresentation.ts instead of letting the alerts page and overview timeline maintain duplicate inline incident-detail styling.

Alert incident meta-row and detail-text presentation must also route through frontend-modern/src/utils/alertIncidentPresentation.ts instead of letting the alerts page and overview timeline maintain duplicated inline incident typography rules.

Alert incident timeline event card structure must also route through frontend-modern/src/components/Alerts/IncidentTimelineEventCard.tsx so the alerts page and overview timeline share one canonical event-card renderer instead of reimplementing the same summary/detail/output block twice.

Resource incident panel card and summary-row presentation must also route through frontend-modern/src/utils/alertIncidentPresentation.ts instead of maintaining page-local incident panel styling inside frontend-modern/src/pages/Alerts.tsx.

Shared primitive consumers that split status-dot tone and status-text tone must now keep both values routed through the same exported presentation helper. Feature cards such as RAID status may not call shadow local aliases that drift from the canonical shared class/variant helpers.

Active alert card state and action-button presentation must also route through frontend-modern/src/utils/alertOverviewPresentation.ts instead of leaving feature-local alert card styling inside frontend-modern/src/features/alerts/OverviewTab.tsx.

Alert resource display labels used by the thresholds editor and alerts page must now route through the shared helper in frontend-modern/src/features/alerts/helpers.ts instead of rebuilding resource display-name fallback chains inline. Governed resources must preserve their canonical policy-aware label across grouped node headers, docker host grouping, and saved override rows rather than collapsing back to raw names or friendly-name truncation.

Shared search inputs must now keep their forwarded keyboard, blur, and clear handlers as explicit callable functions instead of relying on loose Solid event-handler unions. Shared search primitives still need to accept the real input/button event targets, but direct invocation inside the primitive must stay type-safe so consumers do not reintroduce union-call regressions while adding history, shortcut, or trailing-control behavior.

Shared shared-shell primitives that expose semantic title or value-level onChange props must now explicitly omit the conflicting DOM attribute names from their inherited HTML props. CalloutCard, FilterSegmentedControl, and Subtabs may still forward ordinary div attributes, but their canonical API must preserve JSX element titles and value-callback handlers instead of widening back to raw DOM attribute unions.

Shared entitlement/migration warning banners that live under frontend-modern/src/components/shared/ must also keep their counted fleet surface on the Pulse Unified Agent term. Shared primitive copy may describe legacy/API-connected resources separately, but it may not regress the primary banner label or CTA text back to host-agent product language. The self-hosted commercial paywall copy on those shared warning surfaces is now also explicitly locked to monitored systems rather than agents. When a shared banner or shared settings shell is explaining self-hosted plan caps, the operator-facing commercial term must follow the monitored-system model even if explicit legacy-v5 compatibility helpers still decode older alias fields at import boundaries. That banner boundary now also owns the canonical monitored-system naming surface directly: the shared warning component path and exported symbol are MonitoredSystemLimitWarningBanner, and future work may not reintroduce an agent-era banner filename or component name as the primary primitive. First-session educational surfaces must also stay brief, flat, and model-led. When Pulse needs to teach a user how a flow works, the primary on-screen guidance should collapse to a few short descriptions of the real product mental model instead of a logo wall, feature brochure, or verbose internal mechanics dump. The runtime wizard itself now stays on the two-step Welcome -> Security path, while the separate setup-completion preview owns the brief three-step explanation: install the Unified Agent, get the first Pulse resource, then layer on additional context.

The settings shell is now also a governed frontend primitive boundary. Top-level settings surfaces must route through Settings.tsx, SettingsPageShell.tsx, and frontend-modern/src/components/shared/SettingsPanel.tsx instead of reintroducing bespoke outer page headers or one-off top-level panel framing. The shell metadata driving those surfaces is part of the same boundary as well: frontend-modern/src/components/Settings/settingsHeaderMeta.ts and representative top-level panels such as frontend-modern/src/components/Settings/APIAccessPanel.tsx, frontend-modern/src/components/Settings/AISettings.tsx, frontend-modern/src/components/Settings/AuditLogPanel.tsx, frontend-modern/src/components/Settings/AuditWebhookPanel.tsx, frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx, frontend-modern/src/components/Settings/NetworkSettingsPanel.tsx must keep frontend-modern/src/components/Settings/SecurityAuthPanel.tsx must keep frontend-modern/src/components/Settings/SecurityOverviewPanel.tsx, frontend-modern/src/components/Settings/RecoverySettingsPanel.tsx, frontend-modern/src/components/Settings/SSOProvidersPanel.tsx, and frontend-modern/src/components/Settings/UpdatesSettingsPanel.tsx must keep page-shell titles, descriptions, and lead panel framing aligned instead of letting navigation/header labels drift away from the actual settings surface. First-session runtime framing is now part of that same owned primitive story. frontend-modern/src/components/SetupWizard/SetupWizard.tsx must stay on the real two-step runtime shape (Welcome, then Security) and hand successful setup directly into the canonical Infrastructure Operations install route instead of regrowing a second setup-only completion step. The standalone preview surface in frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx may still exist for guarded preview coverage, but it must remain explicitly separate from the runtime wizard so first-session UX does not split into two competing product flows again. The release-ready shell proof now also includes a representative desktop Playwright rehearsal in tests/integration/tests/15-settings-shell-consistency.spec.ts so general, organization, billing, relay, security, AI, updates, and recovery panels are all exercised through the built app shell under a seeded multi-tenant runtime. The security-facing settings panels within that shell now also follow an explicit shared boundary with security-privacy so shell framing stays here while auth posture, token controls, and privacy semantics remain governed as a trust surface instead of generic UX copy.

Single-surface settings pages that only render one canonical SettingsPanel must stay rooted directly at that panel instead of wrapping it in an extra page-level space-y-* container. frontend-modern/src/components/Settings/UpdatesSettingsPanel.tsx frontend-modern/src/components/Settings/RecoverySettingsPanel.tsx, and frontend-modern/src/components/Settings/AuditLogPanel.tsx are the current reference cases, and frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts locks that direct-root contract so single-surface pages do not quietly regain redundant outer spacing chrome.