Comprehensive Playwright-driven audit of the live Cameleer UI (build 69dcce2, 60+ screenshots) combined with the existing UI_FINDINGS.md visual audit (2026-03-25) and 16 open Gitea issues. Three code-level audits performed: layout consistency (CSS modules), interaction patterns (dialogs, buttons, toasts), and design system adoption.
8 theme-based batches, ordered by impact. Each batch groups related fixes that share code paths.
---
## Batch 1: Critical Bug Fixes
**Effort:** 1 day
### 1.1 SSE Navigation Bug
**Problem:** Admin pages sporadically redirect to `/server/exchanges` during form editing. The SSE exchange data stream triggers React state updates that cause route changes, losing unsaved work.
**Fix:** Guard SSE-driven state updates so they never trigger navigation when the current route is outside the exchanges scope. The exchange list polling/SSE should update data stores without pushing route state. Likely in `LayoutShell.tsx` or the SSE connection manager — the exchange data subscription must be decoupled from route navigation.
### 1.2 User Creation in OIDC Mode
**Problem:** `UserAdminController.createUser()` returns `ResponseEntity.badRequest().build()` (empty body) when OIDC is enabled. The UI still shows "+ Add user" and the full creation form. Toast says "Failed to create user" with no explanation.
**Fix (backend):** Return `{ "error": "Local user creation is disabled when OIDC is enabled" }` as the response body.
**Fix (frontend):** When OIDC is enabled, show an inline banner replacing the create form: "Local user creation is disabled when OIDC is active. Users are provisioned automatically via SSO." Hide or disable the "+ Add user" button.
**Files:** `UserAdminController.java:92-93`, `UsersTab.tsx` (create form section)
### 1.3 `/server/deployments` 404
**Problem:** Direct URL shows unhandled React Router dev error. The Deployments tab lives at `/server/apps`.
**Problem:** Renders ~60 full ISO-8601 timestamps overlapping into an unreadable block. All other agent charts (CPU, Memory, Throughput, Error Rate, Thread Count) use concise time labels.
**Fix:** Use the same X-axis time formatter as the other 5 agent charts. The GC Pauses chart likely passes raw ISO strings to the chart library instead of using the shared time axis configuration.
**Files:** `AgentInstance.tsx` or `AgentInstance.module.css` (GC Pauses chart config)
---
## Batch 2a: Design/Layout Consistency
**Effort:** 2 days
Reference: `audit/design-consistency-findings.md`
### 2a.1 Exchanges Table Containment
**Problem:** Only full-bleed table in the app. `Dashboard.tsx` rolls its own `.tableHeader` with `padding: 8px 12px` instead of using `table-section.module.css` (shared: `12px 16px`). No card wrapper.
**Fix:** Import and use `tableStyles.tableSection` wrapper. Replace custom `.tableHeader`, `.tableTitle`, `.tableRight`, `.tableMeta` with the shared module classes. The exchange table should look like every other table (Audit Log, ClickHouse, Dashboard L2/L3).
**Problem:** `AppsTab.tsx` renders all form controls flat against the background. Config tabs (Monitoring, Resources, Variables, Traces & Taps, Route Recording) have labels and controls but no card wrappers. Controls "mesh into background."
**Fix:** Wrap each configuration group in `sectionStyles.section` from `section-card.module.css`, matching the OIDC page pattern (`OidcConfigPage.tsx`) and AppConfigDetail pattern (`AppConfigDetailPage.tsx`). Each sub-tab's content gets a section card.
**Problem:** RBAC detail (Users/Groups) and Environments detail render form controls without section cards.
**Fix:** Wrap detail sections in `sectionStyles.section`. For master-detail pages, the detail panel should use section cards to group related fields (Identity, Roles, Group Membership, etc.).
**Problem:** Only admin form without Edit mode toggle or Cancel button. No way to discard changes.
**Fix:** Add explicit Edit mode with Cancel/Save, matching Environment resource editing and AppConfigDetail patterns. Show read-only view by default, Edit button to enter edit mode.
**Problem:** Mix of `Spinner size="md"`, `Spinner size="lg"`, `PageLoader`, and `null`.
**Fix:** Use `PageLoader` for all full-page loading states. Replace bare `<Spinner size="md" />` returns in UsersTab, GroupsTab, RolesTab, EnvironmentsPage, AppListView, AppDetailView with `<PageLoader />`. Fix OidcConfigPage returning `null`.
**Files:** All admin page files, `pages/Admin/OidcConfigPage.tsx`
### 2b.10 Error Toast Title Format (MEDIUM)
**Problem:** RBAC: "Failed to create user" / AppsTab: "Save failed" — two patterns.
**Fix:** Standardize on "Failed to [verb] [noun]" (more descriptive). Update AppsTab and AppConfigDetailPage error toasts.
**Problem:** 5 different approaches. DS `EmptyState` component only used in AgentInstance.
**Fix:** Replace all `<p className={emptyNote}>`, `<span className={inheritedNote}>`, `<div className={emptyText}>`, and plain text empty states with DS `EmptyState` component or a consistent shared `emptyNote` class with centered, muted styling.
**Problem:** Shows both toast AND inline Alert on error. No other page does this.
**Fix:** Remove the inline Alert. Use toast only, matching all other pages. Or remove the toast and keep only the inline Alert (useful for form context). Pick one — don't show both.
- Dark mode: `--text-muted: #9A9088` (achieves 4.5:1)
Single highest-impact fix — affects every page.
**Files:** Design system CSS variables (light and dark theme definitions)
### 3.2 WCAG AA Fix for `--text-faint`
**Problem:** Dark mode #4A4238 on #242019 = 1.4:1 — essentially invisible.
**Fix:** Restrict `--text-faint` to decorative use only (borders, dividers), or change dark mode value to `#6A6058` (achieves 3:1 minimum). Audit all usages and replace any `--text-faint` on readable text with `--text-muted`.
**Files:** Design system CSS variables, all files using `--text-faint`
### 3.3 Font Size Floor
**Problem:** 10px text used for StatCard labels, overview labels, chain labels, section meta, sidebar tree labels. 11px for table meta, error messages, pagination, toggle buttons, chart titles.
**Fix:** Establish `--font-size-min: 12px`. Update all 10px and 11px instances to 12px minimum. Grep for `font-size: 10px` and `font-size: 11px` across all CSS modules.
**Files:** All CSS modules containing sub-12px font sizes
---
## Batch 4: Data Formatting & Terminology
**Effort:** 2 days
### 4.1 Exchange ID Truncation
**Problem:** 33-char hex dominates the table (e.g., `96E395B0088AA6D-000000000001E75C`).
**Fix:**
- Show last 8 chars with ellipsis: `...0001E75C`
- Full ID on hover tooltip
- Copy-to-clipboard on click (show brief "Copied" indicator)
- Apply to: exchange table, detail breadcrumb, command palette results
### 4.2 Attributes Column
**Problem:** Always shows "---" for every row.
**Fix:** Hide the column when all rows in the current result set have no attributes. Show as colored badges when populated (infrastructure exists in `attribute-color.ts`).
### 4.3 Status Terminology
**Problem:** "OK/ERR" in exchange table vs "COMPLETED/FAILED" in detail panel.
**Fix:** Standardize on the table convention (OK/WARN/ERR) everywhere. Update the detail panel's status display.
**Problem:** Locale-specific decimals ("1.050" ambiguous), inconsistent unit spacing.
**Fix:** Use `Intl.NumberFormat` with explicit locale handling. Always put space before unit: "6.7 s", "1.9 %", "7.1 msg/s". Use K/M suffixes consistently for large numbers.
---
## Batch 5: Chart & Visualization Fixes
**Effort:** 1 day
### 5.1 Agent Throughput Y-axis
**Problem:** 2 msg/s data on 1.2k scale — flat line.
**Fix:** Auto-scale Y-axis to data range with ~20% headroom. Apply to all 6 agent charts.
**Problem:** All API error handlers show generic "Failed to X" without the response body message.
**Fix:** Extract response body message in all API error handlers and include in toast description. Fallback to generic only when body is empty.
### 6.2 Unicode Escape in Roles
**Problem:** Role descriptions show `\u00b7` literally.
**Fix:** Decode unicode escapes in the role description strings. Either fix at the backend (return actual character) or frontend (decode before render).