Files
cameleer-server/audit/design-consistency-findings.md
hsiegeln 4ea8bb368a Add UX polish design spec with comprehensive audit findings
Playwright-driven audit of the live UI (build 69dcce2, 60+ screenshots)
covering all pages, CRUD lifecycles, design consistency, and interaction
patterns. Spec defines 8 batches of work: critical bugs, layout
consistency, interaction consistency, contrast/readability, data
formatting, chart fixes, admin polish, and nice-to-have items.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:00:50 +02:00

16 KiB

Design Consistency Audit — Cameleer3 UI

Audited: 2026-04-09 Scope: All pages under ui/src/pages/ Base path: C:/Users/Hendrik/Documents/projects/cameleer3-server/ui/src/

Shared Layout Infrastructure

LayoutShell (components/LayoutShell.tsx)

All pages render inside <main className={css.mainContent}> which applies:

.mainContent {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 0;
}

This is a flex column container with no padding/margin. Each page is responsible for its own content spacing.

Shared CSS Modules (styles/)

Module Class Pattern
section-card.module.css .section Card with padding: 16px 20px, border, shadow, margin-bottom: 16px
table-section.module.css .tableSection Card wrapper for tables, no padding (overflow hidden), with .tableHeader (12px 16px padding)
chart-card.module.css .chartCard Card with padding: 16px
log-panel.module.css .logCard Card for log viewers, max-height 420px
refresh-indicator.module.css .refreshIndicator Auto-refresh dot indicator
rate-colors.module.css .rateGood/.rateWarn/.rateBad Semantic color helpers

Per-Page Findings


1. Exchanges Page (pages/Exchanges/)

Files: ExchangesPage.tsx, ExchangesPage.module.css, ExchangeHeader.tsx, ExchangeHeader.module.css, RouteControlBar.tsx, RouteControlBar.module.css

Container pattern: NO wrapper padding. Uses height: 100% split-view layout that fills the entire mainContent area.

Content wrapper:

.splitView { display: flex; height: 100%; overflow: hidden; }

Table: The exchange list is rendered by Dashboard.tsx (in pages/Dashboard/), which uses:

.content { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; background: var(--bg-body); }
  • Custom .tableHeader with padding: 8px 12px (slightly tighter than shared tableStyles.tableHeader which uses 12px 16px)
  • DataTable rendered with flush and fillHeight props
  • NO card wrapper around the table — it's full-bleed against the background
  • Does NOT import shared table-section.module.css — rolls its own .tableHeader, .tableTitle, .tableRight, .tableMeta

Shared modules used: NONE. All custom.

INCONSISTENCY: Full-bleed table with no card, no container padding. Custom table header styling duplicates shared module patterns with slightly different padding values (8px 12px vs 12px 16px).


2. Dashboard Tab (pages/DashboardTab/)

Files: DashboardPage.tsx, DashboardL1.tsx, DashboardL2.tsx, DashboardL3.tsx, DashboardTab.module.css

Container pattern:

.content { display: flex; flex-direction: column; gap: 20px; flex: 1; min-height: 0; overflow-y: auto; padding-bottom: 20px; }
  • No top/left/right padding — content is full-width inside mainContent
  • Only padding-bottom: 20px and gap: 20px between sections

Tables: Wrapped in shared tableStyles.tableSection (card with border, shadow, border-radius). Imports table-section.module.css.

Charts: Wrapped in design-system <Card> component.

Custom sections: errorsSection and diagramSection duplicate the card pattern:

.errorsSection {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

This is identical to tableStyles.tableSection but defined separately in DashboardTab.module.css.

Shared modules used: table-section.module.css, refresh-indicator.module.css, rate-colors.module.css

INCONSISTENCY: No container padding means KPI strip and tables sit flush against the sidebar/edge. The .errorsSection duplicates tableStyles.tableSection exactly — should import the shared module instead of copy-pasting.


3. Runtime Tab — Agent Health (pages/AgentHealth/)

Files: AgentHealth.tsx, AgentHealth.module.css

Container pattern:

.content { flex: 1; overflow-y: auto; padding: 20px 24px 40px; min-width: 0; background: var(--bg-body); }
  • Has explicit padding: 20px 24px 40px (top, sides, bottom)

Tables: Uses design-system DataTable inside a DS Card component for agent group cards. The group cards use custom .groupGrid grid layout. No tableStyles.tableSection wrapper.

Cards/sections: Custom card patterns like .configBar, .eventCard:

.configBar {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 12px 16px;
  margin-bottom: 16px;
}

Shared modules used: log-panel.module.css

INCONSISTENCY: Uses padding: 20px 24px 40px — different from DashboardTab (no padding) and Exchanges (no padding). Custom card patterns duplicate the standard card styling. Does not use table-section.module.css or section-card.module.css.


4. Runtime Tab — Agent Instance (pages/AgentInstance/)

Files: AgentInstance.tsx, AgentInstance.module.css

Container pattern:

.content { flex: 1; overflow-y: auto; padding: 20px 24px 40px; min-width: 0; background: var(--bg-body); }
  • Matches AgentHealth padding exactly (consistent within Runtime tab)

Cards/sections: Custom .processCard, .timelineCard duplicate the card pattern. Uses chart-card.module.css for chart wrappers.

Shared modules used: log-panel.module.css, chart-card.module.css

INCONSISTENCY: Consistent with AgentHealth but inconsistent with DashboardTab and Exchanges. Custom card patterns (processCard, timelineCard) duplicate shared module patterns.


5. Apps Tab (pages/AppsTab/)

Files: AppsTab.tsx, AppsTab.module.css

Container pattern:

.container { padding: 16px; overflow-y: auto; flex: 1; }
  • Has padding: 16px all around

Content structure: Three sub-views (AppListView, AppDetailView, CreateAppView) all wrapped in .container.

Tables: App list uses DataTable directly — no tableStyles.tableSection wrapper. Deployment table uses custom .table with manual <table> HTML (not DataTable).

Form controls: Directly on page background with custom grid layout (.configGrid). Uses SectionHeader from design-system for visual grouping, but forms are not in cards/sections — they sit flat against the .container background.

Custom elements:

  • .editBanner / .editBannerActive — custom banner pattern
  • .configGrid — 2-column label/input grid
  • .table — fully custom <table> styling (not DataTable)

Shared modules used: NONE. All custom.

INCONSISTENCY (user-reported): Controls "meshed into background" — correct. Form controls use SectionHeader for labels but no section-card wrapper. The Tabs component provides visual grouping but the content below tabs is flat. Config grids, toggles, and inputs sit directly on var(--bg-body) background via the 16px-padded container. No card/section separation between different config groups. Also uses a manual <table> element instead of DataTable for deployments.


6. Admin — RBAC Page (pages/Admin/RbacPage.tsx, UsersTab.tsx, GroupsTab.tsx, RolesTab.tsx)

Container pattern: AdminLayout provides padding: 20px 24px 40px. RbacPage renders a bare <div> (no extra wrapper class).

Content: Uses StatCard strip, Tabs, then tab content. Detail views use SplitPane (from design-system). User/Group/Role detail sections use SectionHeader without card wrappers.

Stat strip: Custom grid — grid-template-columns: repeat(3, 1fr) with gap: 10px; margin-bottom: 16px

Shared modules used: NONE. Uses UserManagement.module.css (custom).

INCONSISTENCY: Detail sections use SectionHeader labels but content is flat (no section-card wrapper). Similar to AppsTab pattern.


7. Admin — Audit Log (pages/Admin/AuditLogPage.tsx)

Container pattern: Inherits AdminLayout padding (20px 24px 40px). Renders a bare <div>.

Table: Properly uses shared tableStyles.tableSection with .tableHeader, .tableTitle, .tableRight, .tableMeta.

Shared modules used: table-section.module.css

STATUS: CONSISTENT with shared patterns for the table section. Good.


8. Admin — OIDC Config (pages/Admin/OidcConfigPage.tsx)

Container pattern: Inherits AdminLayout padding. Adds .page { max-width: 640px; margin: 0 auto; } — centered narrow layout.

Sections: Uses shared sectionStyles.section from section-card.module.css for every form group. Uses SectionHeader inside each section card.

Shared modules used: section-card.module.css

STATUS: GOOD. This is the correct pattern — form groups wrapped in section cards. Should be the model for other form pages.


9. Admin — Database (pages/Admin/DatabaseAdminPage.tsx)

Container pattern: Inherits AdminLayout padding. Renders bare <div>.

Tables: Uses DataTable directly with NO tableStyles.tableSection wrapper. Tables under custom .section divs with .sectionHeading text labels.

Cards: Uses DS <Card> for connection pool. Stat strip is a flex layout.

Shared modules used: NONE. All custom.

INCONSISTENCY: Tables not wrapped in tableStyles.tableSection. Uses custom section headings instead of SectionHeader. Missing card wrappers around tables. Stat strip uses flex layout while other pages use grid.


10. Admin — ClickHouse (pages/Admin/ClickHouseAdminPage.tsx)

Container pattern: Inherits AdminLayout padding. Renders bare <div>.

Tables: Uses shared tableStyles.tableSection combined with custom .tableSection for margin: className={tableStyles.tableSection} ${styles.tableSection}.

Custom elements: .pipelineCard duplicates card pattern (bg-surface, border, radius, shadow, padding).

Shared modules used: table-section.module.css

PARTIAL: Tables correctly use shared module. Pipeline card duplicates shared card pattern.


11. Admin — Environments (pages/Admin/EnvironmentsPage.tsx)

Container pattern: Inherits AdminLayout padding. Renders via SplitPane (design-system).

Content: Uses SectionHeader, SplitPane, custom meta grids from UserManagement.module.css.

Shared modules used: Uses UserManagement.module.css (shared with RBAC pages)

INCONSISTENCY: Does not use section-card.module.css for form sections. Config sections use SectionHeader without card wrappers. SplitPane provides some structure but detail content is flat.


12. Admin — App Config Detail (pages/Admin/AppConfigDetailPage.tsx)

Container pattern: Adds .page { max-width: 720px; margin: 0 auto; } — centered layout.

Sections: Uses shared sectionStyles.section from section-card.module.css. Uses SectionHeader inside section cards. Custom header card duplicates the card pattern.

Shared modules used: section-card.module.css

STATUS: GOOD. Follows same pattern as OIDC page.


13. Routes pages (pages/Routes/) — NOT ROUTED

These pages (RoutesMetrics.tsx, RouteDetail.tsx) exist but are NOT in router.tsx. They may be deprecated or used as sub-components. RoutesMetrics correctly uses shared tableStyles.tableSection. RouteDetail has many custom card patterns (.headerCard, .diagramPane, .statsPane, .executionsTable, .routeFlowSection) that duplicate the shared card pattern.


Summary: Inconsistency Matrix

Container Padding

Page Padding Pattern
Exchanges NONE (full-bleed) height: 100%, fills container
Dashboard Tab NONE (gap only) gap: 20px, padding-bottom: 20px only
Runtime (AgentHealth) 20px 24px 40px Explicit padding
Runtime (AgentInstance) 20px 24px 40px Explicit padding
Apps Tab 16px Uniform padding
Admin pages 20px 24px 40px Via AdminLayout

Finding: Three different padding strategies. Exchanges and Dashboard have no padding; Runtime and Admin use 20px/24px; Apps uses 16px.

Table Wrapper Pattern

Page Uses tableStyles.tableSection? Card wrapper?
Exchanges (Dashboard.tsx) NO — custom .tableHeader NO — full-bleed
Dashboard L1/L2/L3 YES YES (shared)
Runtime AgentHealth NO YES (via DS Card)
Apps Tab NO NO — bare <table>
Admin — Audit YES YES (shared)
Admin — ClickHouse YES YES (shared)
Admin — Database NO NO

Finding: 4 of 7 table-using pages do NOT use the shared table-section.module.css. The Exchanges page custom header has padding 8px 12px vs shared 12px 16px.

Form/Control Wrapper Pattern

Page Form controls in cards? Uses section-card?
Apps Tab (detail) NO — flat against background NO
Apps Tab (create) NO — flat against background NO
Admin — OIDC YES YES
Admin — App Config YES YES
Admin — RBAC detail NO — flat against background NO
Admin — Environments NO — flat against background NO
Admin — Database PARTIAL (Card for pool) NO
Runtime — AgentHealth YES (custom .configBar) NO (custom)

Finding: Only OIDC and AppConfigDetail use section-card.module.css for form grouping. Most form pages render controls flat against the page background.

Duplicated Card Pattern

The following CSS pattern appears in 8+ custom locations instead of importing section-card.module.css or table-section.module.css:

background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);

Duplicated in:

  • DashboardTab.module.css.errorsSection, .diagramSection
  • AgentHealth.module.css.configBar, .eventCard
  • AgentInstance.module.css.processCard, .timelineCard
  • ClickHouseAdminPage.module.css.pipelineCard
  • AppConfigDetailPage.module.css.header
  • RouteDetail.module.css.headerCard, .diagramPane, .statsPane, .executionsTable, .routeFlowSection

Prioritized Fixes

P0 — User-reported issues

  1. Exchanges table full-bleed: Dashboard.tsx should wrap its table in tableStyles.tableSection and use the shared table header classes instead of custom ones. Custom .tableHeader padding (8px 12px) should match shared (12px 16px).
  2. Apps detail flat controls: AppsTab.tsx config sections should wrap form groups in sectionStyles.section (from section-card.module.css), matching the OIDC page pattern.
  3. Apps deployment table: Replace manual <table> with DataTable inside tableStyles.tableSection.

P1 — Padding normalization

  1. Standardize container padding: Choose ONE pattern for scrollable content areas. Recommended: padding: 20px 24px 40px (currently used by Runtime + Admin). Apply to DashboardTab's .content. Exchanges is an exception due to its split-view height-filling layout.
  2. DashboardTab.module.css: Add side padding to .content.

P2 — Shared module adoption

  1. Replace duplicated card patterns: Import section-card.module.css or table-section.module.css instead of duplicating the card CSS in:
    • DashboardTab.module.css (.errorsSection -> use tableStyles.tableSection)
    • AgentHealth.module.css (.configBar, .eventCard)
    • AgentInstance.module.css (.processCard, .timelineCard)
    • ClickHouseAdminPage.module.css (.pipelineCard)
  2. Database admin: Wrap tables in tableStyles.tableSection.
  3. Admin detail pages (RBAC, Environments): Wrap form sections in sectionStyles.section.