Files
cameleer-server/UI-CONSISTENCY-AUDIT.md
hsiegeln f24a5e5ff0
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m20s
CI / docker (push) Successful in 27s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 40s
docs: update CLAUDE.md, audit, and spec for today's changes
- CLAUDE.md: security (last-admin guard, password policy, brute-force,
  token revocation), environment filtering (queries + commands), Docker
  reconciliation, UI shared patterns, V8/V9 migrations
- UI-CONSISTENCY-AUDIT.md: marked RESOLVED
- UI consistency design spec: marked COMPLETED

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

12 KiB

Status: RESOLVED — All phases (1-5) executed on 2026-04-09. Remaining: responsive design (separate initiative).

UI Consistency Audit — cameleer3-server

Date: 2026-04-09 Scope: All files under ui/src/ (26 CSS modules, ~45 TSX components, ~15 pages) Verdict: ~55% design system adoption for interactive UI. Significant duplication and inline style debt.


Executive Summary

Dimension Score Key Issue
Design system component adoption 55% 32 raw <button>, 12 raw <select>, 8 raw <input> should use DS
Color consistency Poor ~140 violations: 45 hardcoded hex in TSX, 13 naked hex in CSS, ~55 fallback hex in var()
Inline styles Poor 55 RED (static inline styles), 8 YELLOW, 14 GREEN (justified)
Layout consistency Mixed 3 different page padding values, mixed gap/margin approaches
CSS module duplication 22% ~135 of 618 classes are copy-pasted across files
Responsive design None Zero @media queries in entire UI

1. Critical: Hardcoded Colors (CLAUDE.md violation)

The project rule states: "Always use @cameleer/design-system CSS variables for colors — never hardcode hex values."

Worst offenders

File Violations Severity
ProcessDiagram/DiagramNode.tsx ~20 hex values in SVG fill/stroke Critical
ExecutionDiagram/ExecutionDiagram.module.css 17 naked hex + ~40 hex fallbacks in var() Critical
ProcessDiagram/CompoundNode.tsx 8 hex values Critical
ProcessDiagram/DiagramEdge.tsx 3 hex values High
ProcessDiagram/ConfigBadge.tsx 3 hex values High
ProcessDiagram/ErrorSection.tsx 2 hex values High
ProcessDiagram/NodeToolbar.tsx 2 hex values High
ProcessDiagram/Minimap.tsx 3 hex values High
Dashboard/Dashboard.module.css #5db866 (not even a DS color) High
AppsTab/AppsTab.module.css var(--accent, #6c7aff) (undefined DS variable) Medium

Undefined CSS variables (not in design system)

Variable Files Should be
--accent EnvironmentSelector, AppsTab --amber (or define in DS)
--bg-base LoginPage --bg-body
--surface ContentTabs, ExchangeHeader --bg-surface
--bg-surface-raised AgentHealth --bg-raised

Missing DS tokens needed

Several tint/background colors are used repeatedly but have no DS variable:

  • --error-bg (used as #FDF2F0, #F9E0DC)
  • --success-bg (used as #F0F9F1)
  • --amber-bg / --warning-bg (used as #FFF8F0)
  • --bg-inverse / --text-inverse (used as #1A1612 / #E4DFD8)

2. Critical: CSS Module Duplication (~22%)

~135 of 618 class definitions are copy-pasted across files.

Table section pattern — 5 files, ~35 duplicate classes

.tableSection, .tableHeader, .tableTitle, .tableMeta, .tableRight are identical in:

  • DashboardTab.module.css
  • AuditLogPage.module.css
  • ClickHouseAdminPage.module.css
  • RoutesMetrics.module.css
  • RouteDetail.module.css

Log viewer panel — 2 files, ~50 lines identical

.logCard, .logHeader, .logToolbar, .logSearchWrap, .logSearchInput, .logSearchClear, .logClearFilters, .logEmpty, .sortBtn, .refreshBtn, .headerActions — byte-for-byte identical in AgentHealth.module.css and AgentInstance.module.css.

Tap modal form — 2 files, ~40 lines identical

.typeSelector, .typeOption, .typeOptionActive, .testSection, .testTabs, .testTabBtn, .testTabBtnActive, .testBody, .testResult, .testSuccess, .testError — identical in TapConfigModal.module.css and RouteDetail.module.css.

Other duplicates

Pattern Files Lines
Rate color classes (.rateGood/.rateWarn/.rateBad/.rateNeutral) DashboardTab, RouteDetail, RoutesMetrics ~12 each
Refresh indicator + @keyframes pulse DashboardTab, RoutesMetrics ~15 each
Chart card (.chartCard) AgentInstance, RouteDetail ~6 each
Section card (.section) AppConfigDetailPage, OidcConfigPage ~7 each
Meta grid (.metaGrid/.metaLabel/.metaValue) AboutMeDialog, UserManagement ~9 each

3. High: Inline Styles (55 RED violations)

Files with zero CSS modules (all inline)

File Issue
pages/Admin/AdminLayout.tsx Entire layout wrapper is inline styled
pages/Admin/DatabaseAdminPage.tsx All layout, typography, spacing inline — no CSS module
auth/OidcCallback.tsx Full-page layout inline — no CSS module

Most inline violations

File RED count Primary patterns
pages/AppsTab/AppsTab.tsx ~25 Fixed-width inputs (width: 50-90px x18), visually-hidden pattern x2, table cell layouts
components/LayoutShell.tsx 6 StarredList sub-component, sidebar layout
pages/Admin/EnvironmentsPage.tsx 8 Raw <select> fully styled inline, save/cancel button rows
pages/Routes/RouteDetail.tsx 5 Heading styles, tab panel margins

Repeated inline patterns that need extraction

Pattern Occurrences Fix
style={{ display: 'flex', justifyContent: 'center', padding: '4rem' }} (loading fallback) 3 files Create shared <PageLoader>
style={{ position: 'absolute', width: 1, height: 1, clip: 'rect(0,0,0,0)' }} (visually hidden) 2 in AppsTab Create .visuallyHidden utility class
style={{ width: N }} on <Input>/<Select> (fixed widths) 18+ in AppsTab Size classes or CSS module rules
style={{ marginTop: 8, display: 'flex', gap: 8, justifyContent: 'flex-end' }} (action row) 3+ in EnvironmentsPage Shared .editActions class

4. High: Design System Component Adoption Gaps

Native HTML that should use DS components

Element Instances Files DS Replacement
<button> 32 8 files Button, SegmentedTabs
<select> 12 4 files Select
<input> 8 4 files Input, Toggle, Checkbox
<label> 9 2 files FormField, Label
<table> (data) 2 2 files DataTable, LogViewer

Highest-priority replacements

  1. EnvironmentSelector.tsx — zero DS imports, entire component is a bare <select>. Used globally in sidebar.
  2. ExecutionDiagram/tabs/LogTab.tsx — reimplements LogViewer from scratch (raw table + input + button). AgentInstance and AgentHealth already use DS LogViewer correctly.
  3. AppsTab.tsx sub-tabs — 3 instances of homegrown <button> tab bars. DS provides SegmentedTabs and Tabs.
  4. AppConfigDetailPage.tsx — 4x <select>, 4x <label>, 2x <input type="checkbox">, 4x <button> — all have DS equivalents already used elsewhere.
  5. AgentHealth.tsx — config bar uses Toggle (correct) alongside raw <select> and <button> (incorrect).

Cross-page inconsistencies

Pattern Correct usage Incorrect usage
Log viewer AgentInstance, AgentHealth use DS LogViewer LogTab rebuilds from scratch
Config edit form Both pages render same 4 fields AgentHealth uses Toggle, AppConfigDetail uses <input type="checkbox">
Sub-tabs RbacPage uses DS Tabs AppsTab uses homegrown <button> tabs with non-DS --accent color
Select dropdowns AppsTab uses DS Select for some fields Same file uses raw <select> for other fields

5. Medium: Layout Inconsistencies

Page padding (3 different values)

Pages Padding
AgentHealth, AgentInstance, AdminLayout 20px 24px 40px
AppsTab 16px (all sides)
DashboardTab, Dashboard No padding (full-bleed)

Section gap spacing (mixed approaches)

Approach Pages
CSS gap: 20px on flex container DashboardTab, RoutesMetrics
margin-bottom: 20px AgentInstance
Mixed margin-bottom: 16px and 20px on same page AgentHealth, ClickHouseAdminPage

Typography inconsistencies

Issue Details
Card title weight Most use font-weight: 600, RouteDetail .paneTitle uses 700
Chart title style RouteDetail: 12px/700/uppercase, AgentHealth: 12px/600/uppercase
Font units ExchangeHeader + TabKpis use rem, everything else uses px
Raw headings DatabaseAdminPage uses <h2>/<h3> with inline styles; all others use DS SectionHeader or CSS classes
Table header padding Most: 12px 16px, Dashboard: 8px 12px, AgentHealth eventCard: 10px 16px

Stat strip layouts

Page Layout Gap
AgentHealth, AgentInstance, RbacPage CSS grid repeat(N, 1fr) 10px
ClickHouseAdminPage Flexbox (unequal widths) 10px
DatabaseAdminPage Inline flex 1rem (16px)

Empty state patterns (4 different approaches)

  1. DS <EmptyState> component (AgentInstance — correct)
  2. EntityList emptyMessage prop (EnvironmentsPage, RbacPage)
  3. .logEmpty CSS class, 12px, var(--text-faint) (AgentHealth, AgentInstance)
  4. .emptyNote CSS class, 12px, italic (AppsTab)
  5. Inline 0.875rem, var(--text-muted) (ExchangesPage)

Loading state patterns (3 different approaches)

  1. <Spinner size="lg"> in flex div with inline padding: 4rem — copy-pasted 3 times
  2. <Spinner size="md"> returned directly, no centering (EnvironmentsPage)
  3. No loading UI, data simply absent (DashboardL1/L2/L3)

6. Low: Other Findings

  • !important: 1 use in RouteControlBar.module.css — works around specificity conflict
  • Zero responsive design: no @media queries anywhere
  • Z-index: only 4 uses, all in diagram components (5 and 10), consistent
  • Naming convention: all camelCase — consistent, no issues
  • Unused CSS classes: ~11 likely unused in AppsTab (old create-modal classes) and TapConfigModal

Phase 1: Design system tokens (unblocks everything else)

  1. Add missing DS variables: --error-bg, --success-bg, --amber-bg, --bg-inverse, --text-inverse
  2. Fix undefined variables: --accent -> --amber, --bg-base -> --bg-body, --surface -> --bg-surface

Phase 2: Eliminate CSS duplication (~22% of all classes)

  1. Extract shared tableSection pattern to shared CSS module (saves ~140 duplicate lines across 5 files)
  2. Extract shared log viewer CSS to shared module (saves ~50 lines across 2 files)
  3. Remove duplicate tap modal CSS from RouteDetail (saves ~40 lines)
  4. Extract shared rate/refresh/chart patterns

Phase 3: Fix hardcoded colors

  1. Replace all hex in ProcessDiagram/*.tsx SVG components (~45 values)
  2. Replace all hex in ExecutionDiagram.module.css (~17 naked + strip ~40 fallbacks)
  3. Fix remaining CSS hex violations (Dashboard, AppsTab, AgentHealth)

Phase 4: Replace native HTML with DS components

  1. EnvironmentSelector -> DS Select
  2. LogTab -> DS LogViewer
  3. AppsTab sub-tabs -> DS SegmentedTabs
  4. AppConfigDetailPage form elements -> DS Select/Toggle/FormField/Button
  5. Remaining <button> -> DS Button

Phase 5: Eliminate inline styles

  1. Create CSS modules for AdminLayout, DatabaseAdminPage, OidcCallback
  2. Extract shared <PageLoader> component
  3. Move AppsTab fixed-width inputs to CSS module size classes
  4. Move remaining inline margins/flex patterns to CSS classes

Phase 6: Standardize layout patterns

  1. Unify page padding to 20px 24px 40px
  2. Standardize section gaps to gap: 20px on flex containers
  3. Normalize font units to px throughout
  4. Standardize empty state to DS <EmptyState>
  5. Standardize loading state to shared <PageLoader>