270 lines
17 KiB
Markdown
270 lines
17 KiB
Markdown
|
|
# Cameleer SaaS Platform UI Audit Findings
|
||
|
|
|
||
|
|
**Date:** 2026-04-09
|
||
|
|
**Auditor:** Claude Opus 4.6
|
||
|
|
**URL:** https://desktop-fb5vgj9.siegeln.internal/
|
||
|
|
**Credentials:** admin/admin
|
||
|
|
**Browser:** Playwright (Chromium)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Login Page (`/sign-in`)
|
||
|
|
|
||
|
|
**Screenshot:** `03-login-page.png`, `04-login-error.png`
|
||
|
|
|
||
|
|
### What works well
|
||
|
|
- Clean, centered card layout with consistent design system components
|
||
|
|
- Fun rotating subtitle taglines (e.g., "No ticket, no caravan") add personality
|
||
|
|
- Cameleer logo is displayed correctly
|
||
|
|
- Error handling works -- "Invalid username or password" alert appears on bad credentials (red alert banner)
|
||
|
|
- Sign in button is correctly disabled until both fields are populated
|
||
|
|
- Loading state on button during authentication
|
||
|
|
- Uses proper `autoComplete` attributes (`username`, `current-password`)
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| Important | **No password visibility toggle** -- the Password input uses `type="password"` with no eye icon to reveal. Most modern login forms offer this. | Password field |
|
||
|
|
| Important | **Branding says "cameleer3"** not "Cameleer" or "Cameleer SaaS" -- the product name on the login page is the internal repo name, not the user-facing brand | `.logo` text content |
|
||
|
|
| Nice-to-have | **No "Forgot password" link** -- even if it goes to a "contact admin" page, users expect this | Below password field |
|
||
|
|
| Nice-to-have | **No Enter-key submit hint** -- though Enter does work via form submit, there's no visual affordance | Form area |
|
||
|
|
| Nice-to-have | **Page title is "Sign in -- cameleer3"** -- should match product branding ("Cameleer SaaS") | `<title>` tag |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Platform Dashboard (`/platform/`)
|
||
|
|
|
||
|
|
**Screenshots:** `05-platform-dashboard-loggedin.png`, `15-dashboard-desktop-1280.png`, `19-tenant-info-detail.png`, `20-kpi-strip-detail.png`
|
||
|
|
|
||
|
|
### What works well
|
||
|
|
- Clear tenant name as page heading ("Example Tenant")
|
||
|
|
- Tier badge next to tenant name provides immediate context
|
||
|
|
- KPI strip with Tier, Status, License cards is visually clean and well-structured
|
||
|
|
- License KPI card shows expiry date in green "expires 8.4.2027" trend indicator
|
||
|
|
- "Server Management" card provides clear description of what the server dashboard does
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| **Critical** | **Label/value collision in Tenant Information card** -- "Slugdefault", "Created8.4.2026" have no visual separation between label and value. The source uses `flex justify-between` but the deployed Card component doesn't give the inner `div` full width, so items stack/collapse. | Tenant Information card |
|
||
|
|
| **Critical** | **"Open Server Dashboard" appears 3 times** on one page: (1) primary button in header area below tenant name, (2) "Server Management" card with secondary button, (3) sidebar footer link. This is redundant and clutters the page. Reduce to 1-2 locations max. | Header area, Server Management card, sidebar footer |
|
||
|
|
| Important | **Breadcrumb is always empty** -- the `breadcrumb` prop is passed as `[]`. Platform pages should have breadcrumbs like "Platform > Dashboard" or "Platform > License". | TopBar breadcrumb nav |
|
||
|
|
| Important | **Massive empty space below content** -- the dashboard only has ~4 cards but the page extends far below with blank white/cream space. The page feels sparse and "stub-like." | Below Server Management card |
|
||
|
|
| Important | **Tier badge color is misleading** -- "LOW" tier uses `primary` (orange) color, which doesn't convey it's the lowest/cheapest tier. The `tierColor()` function in DashboardPage maps to enterprise=success, pro=primary, starter=warning, but the actual data uses LOW/MID/HIGH/BUSINESS tiers (defined in LicensePage). Dashboard and License pages have different tier color mappings. | Tier badge |
|
||
|
|
| Important | **Status is shown redundantly** -- "ACTIVE" appears in (1) KPI strip Status card, (2) Tenant Information card with badge, and (3) header area badge. This is excessive for a single piece of information. | Multiple locations |
|
||
|
|
| Nice-to-have | **No tenant ID/slug in breadcrumb or subtitle** -- the slug "default" only appears buried in the Tenant Information card | Page header area |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. License Page (`/platform/license`)
|
||
|
|
|
||
|
|
**Screenshots:** `06-license-page.png`, `07-license-token-revealed.png`, `16-license-features-detail.png`, `17-license-limits-detail.png`, `18-license-validity-detail.png`
|
||
|
|
|
||
|
|
### What works well
|
||
|
|
- Well-structured layout with logical sections (Validity, Features, Limits, License Token)
|
||
|
|
- Tier badge in header provides context
|
||
|
|
- Feature matrix clearly shows enabled vs disabled features
|
||
|
|
- "Days remaining" with color-coded badge (green for healthy, warning for <30 days, red for expired)
|
||
|
|
- Token show/hide toggle works correctly
|
||
|
|
- Token revealed in monospace code block with appropriate styling
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| **Critical** | **Label/value collision in Validity section** -- "Issued8. April 2026" and "Expires8. April 2027" have no separation. Source code uses `flex items-center justify-between` but the flex container seems to not be stretching to full width. | Validity card rows |
|
||
|
|
| **Critical** | **Label/value collision in Limits section** -- "Max Agents3", "Retention Days7", "Max Environments1" have labels and values mashed together. Source uses `flex items-center justify-between` layout but the same rendering bug prevents proper spacing. | Limits card rows |
|
||
|
|
| Important | **No "Copy to clipboard" button** for the license token -- users need to manually select and copy. A copy button with confirmation toast is standard UX for tokens/secrets. | License Token section |
|
||
|
|
| Important | **Feature badge text mismatch** -- Source code says `'Not included'` for disabled features, but deployed version shows "DISABLED". This suggests the deployed build is out of sync with the source. | Features card badges |
|
||
|
|
| Important | **"Disabled" badge color** -- disabled features use `color='auto'` (which renders as a neutral/red-ish badge), while "Enabled" uses green. Consider using a muted gray for "Not included" to make it feel less like an error state. Red implies something is wrong, but a feature simply not being in the plan is not an error. | Features card disabled badges |
|
||
|
|
| Nice-to-have | **Limits values are not right-aligned** -- due to the label/value collision, the numeric values don't align in a column, making comparison harder | Limits card |
|
||
|
|
| Nice-to-have | **No units on limits** -- "Retention Days7" should be "7 days", "Max Agents3" should be "3 agents" or just "3" with clear formatting | Limits card values |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Admin Pages (`/platform/admin/tenants`)
|
||
|
|
|
||
|
|
**No screenshot available -- page returns HTTP error**
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| **Critical** | **Admin page returns HTTP error (net::ERR_HTTP_RESPONSE_CODE_FAILURE)** -- navigating to `/platform/admin/tenants` fails with an HTTP error. The route exists in the router (`AdminTenantsPage`), but the admin section is not visible in the sidebar (no "Platform" item shown). | Admin route |
|
||
|
|
| Important | **Admin section not visible in sidebar** -- the `platform:admin` scope check in Layout.tsx hides the "Platform" sidebar item. Even though the user is "admin", they apparently don't have the `platform:admin` scope in their JWT. This may be intentional (scope not assigned) or a bug. | Sidebar Platform section |
|
||
|
|
| Important | **No graceful fallback for unauthorized admin access** -- if a user manually navigates to `/admin/tenants` without the scope, the page should show a "Not authorized" message rather than an HTTP error. | Admin route error handling |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Navigation
|
||
|
|
|
||
|
|
**Screenshots:** `21-sidebar-detail.png`, `12-sidebar-collapsed.png`
|
||
|
|
|
||
|
|
### What works well
|
||
|
|
- Clean sidebar with Cameleer SaaS branding and logo
|
||
|
|
- "Open Server Dashboard" in sidebar footer is a good location
|
||
|
|
- Sidebar has only 2 navigation items (Dashboard, License) which keeps it simple
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| **Critical** | **No active state on sidebar navigation items** -- when on the Dashboard page, neither Dashboard nor License is highlighted/active. The sidebar uses `Sidebar.Section` components with `open={false}` as navigation links via `onToggle`, but `Section` is designed for expandable/collapsible groups, not navigation links. There is no visual indicator of the current page. | Sidebar items |
|
||
|
|
| Important | **Sidebar collapse doesn't work visually** -- clicking "Collapse sidebar" toggles the `active` state on the button but the sidebar doesn't visually collapse. The Layout component passes `collapsed={false}` as a hardcoded prop and `onCollapseToggle={() => {}}` as a no-op. | Sidebar collapse button |
|
||
|
|
| Important | **No clear distinction between "platform" and "server" levels** -- there's nothing in the sidebar header that says "Platform" vs "Server". The sidebar says "Cameleer SaaS" but when you switch to the server dashboard, it becomes a completely different app. A user might not understand the relationship. | Sidebar header |
|
||
|
|
| Nice-to-have | **"Open Server Dashboard" opens in new tab** -- `window.open('/server/', '_blank', 'noopener')` is used. While reasonable, there's no visual indicator (external link icon) that it will open a new tab. | Sidebar footer link, dashboard buttons |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Header Bar (TopBar)
|
||
|
|
|
||
|
|
**Screenshot:** `22-header-bar-detail.png`
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| **Critical** | **Server-specific controls shown on platform pages** -- the TopBar always renders: (1) Search (Ctrl+K), (2) Status filters (OK/Warn/Error/Running), (3) Time range pills (1h/3h/6h/Today/24h/7d), (4) Auto-refresh toggle (MANUAL/AUTO). None of these are relevant to the platform dashboard or license page. They are observability controls designed for the server's exchange/route monitoring. | Entire TopBar filter area |
|
||
|
|
| Important | **Search button does nothing** -- clicking "Search..." on the platform does not open a search modal. The CommandPaletteProvider is likely not configured for the platform context. | Search button |
|
||
|
|
| Important | **Status filter buttons are interactive but meaningless** -- clicking OK/Warn/Error/Running on platform pages toggles state (global filter provider) but has no effect on the displayed content. | Status filter buttons |
|
||
|
|
| Important | **Time range selector is interactive but meaningless** -- similarly, changing the time range from 1h to 7d has no effect on platform pages. | Time range pills |
|
||
|
|
| Important | **Auto-refresh toggle is misleading** -- shows "MANUAL" toggle on platform pages where there's nothing to auto-refresh. | Auto-refresh button |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. User Menu
|
||
|
|
|
||
|
|
**Screenshot:** `02-user-menu-dropdown.png`
|
||
|
|
|
||
|
|
### What works well
|
||
|
|
- User name "admin" and avatar initials "AD" displayed correctly
|
||
|
|
- Dropdown appears on click with Logout option
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| Important | **User menu only has "Logout"** -- there's no "Profile", "Settings", "About", or "Switch Tenant" option. For a SaaS platform, users should at minimum see their role and tenant context. | User dropdown menu |
|
||
|
|
| Nice-to-have | **Avatar shows "AD" for "admin"** -- the Avatar component appears to use first 2 characters of the name. For "admin" this produces "AD" which looks like initials for a different name. | Avatar component |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. Dark Mode
|
||
|
|
|
||
|
|
**Screenshots:** `08-dashboard-dark-mode.png`, `09-license-dark-mode.png`
|
||
|
|
|
||
|
|
### What works well
|
||
|
|
- Dark mode toggle works and applies globally
|
||
|
|
- Background transitions to dark brown/charcoal
|
||
|
|
- Text colors adapt appropriately
|
||
|
|
- Cards maintain visual distinction from background
|
||
|
|
- Design system tokens handle the switch smoothly
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| Nice-to-have | **Dark mode is warm-toned (brown)** rather than the more common cool dark gray/charcoal. This is consistent with the design system's cameleer branding but may feel unusual to users accustomed to dark mode in other apps. | Global dark theme |
|
||
|
|
| Nice-to-have | **The same label/value collision issues appear in dark mode** -- these are layout bugs, not color bugs, so dark mode doesn't help or hurt. | Card content |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. Responsiveness
|
||
|
|
|
||
|
|
**Screenshots:** `13-responsive-tablet.png`, `14-responsive-mobile.png`
|
||
|
|
|
||
|
|
### Issues found
|
||
|
|
|
||
|
|
| Severity | Issue | Element |
|
||
|
|
|----------|-------|---------|
|
||
|
|
| **Critical** | **Mobile layout is broken** -- at 375px width, the sidebar overlaps the main content. The KPI strip cards are truncated ("LO...", "AC..."). The header bar overflows. Content is unreadable. | Full page at mobile widths |
|
||
|
|
| Important | **Tablet layout (768px) is functional but crowded** -- sidebar takes significant width, header bar items are compressed ("Se..." for Search), but content is readable. KPI strip wraps correctly. | Full page at tablet widths |
|
||
|
|
| Important | **Sidebar doesn't collapse on mobile** -- there's no hamburger menu or responsive sidebar behavior. The sidebar is always visible, eating screen space on narrow viewports. | Sidebar |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 10. Cross-cutting Concerns
|
||
|
|
|
||
|
|
### Loading States
|
||
|
|
- Dashboard and License pages both show a centered `Spinner` during loading -- this works well.
|
||
|
|
- `EmptyState` component used for "No tenant associated" and "License unavailable" -- good error handling in components.
|
||
|
|
|
||
|
|
### Error States
|
||
|
|
- Login page error handling is good (alert banner)
|
||
|
|
- No visible error boundary for unexpected errors on platform pages
|
||
|
|
- Admin route fails silently with HTTP error -- no user-facing error message
|
||
|
|
|
||
|
|
### Toast Notifications
|
||
|
|
- No toast notifications observed during the audit
|
||
|
|
- License token copy should trigger a toast confirmation (if a copy button existed)
|
||
|
|
|
||
|
|
### Confirmation Dialogs
|
||
|
|
- No destructive actions available on the platform (no delete/deactivate buttons) so no confirmation dialogs needed currently
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Summary of Issues by Severity
|
||
|
|
|
||
|
|
### Critical (5)
|
||
|
|
1. **Label/value collision** throughout Tenant Information card, License Validity, and License Limits sections -- labels and values run together without spacing
|
||
|
|
2. **"Open Server Dashboard" appears 3 times** on the dashboard page -- excessive redundancy
|
||
|
|
3. **No active state on sidebar navigation items** -- users can't tell which page they're on
|
||
|
|
4. **Server-specific header controls shown on platform pages** -- search, status filters, time range, auto-refresh are all meaningless on platform pages
|
||
|
|
5. **Mobile layout completely broken** -- sidebar overlaps content, content truncated
|
||
|
|
|
||
|
|
### Important (17)
|
||
|
|
1. No password visibility toggle on login
|
||
|
|
2. Branding says "cameleer3" instead of product name on login
|
||
|
|
3. Breadcrumbs always empty on platform pages
|
||
|
|
4. Massive empty space below dashboard content
|
||
|
|
5. Tier badge color mapping inconsistent between Dashboard and License pages
|
||
|
|
6. Status shown redundantly in 3 places on dashboard
|
||
|
|
7. No clipboard copy button for license token
|
||
|
|
8. Feature badge text mismatch between source and deployed build
|
||
|
|
9. "Disabled" badge uses red-ish color (implies error, not "not in plan")
|
||
|
|
10. Admin page returns HTTP error with no graceful fallback
|
||
|
|
11. Admin section invisible in sidebar despite being admin user
|
||
|
|
12. Sidebar collapse button doesn't work (no-op handler)
|
||
|
|
13. No clear platform vs server level distinction
|
||
|
|
14. Search button does nothing on platform
|
||
|
|
15. Status filters and time range interactive but meaningless on platform
|
||
|
|
16. User menu only has Logout (no profile/settings)
|
||
|
|
17. Sidebar doesn't collapse/hide on mobile
|
||
|
|
|
||
|
|
### Nice-to-have (8)
|
||
|
|
1. No "Forgot password" link on login
|
||
|
|
2. Login page title uses "cameleer3" branding
|
||
|
|
3. No external link icon on "Open Server Dashboard"
|
||
|
|
4. Avatar shows "AD" for "admin"
|
||
|
|
5. No units on limit values
|
||
|
|
6. Dark mode warm-toned (not standard cool dark)
|
||
|
|
7. No Enter-key submit hint
|
||
|
|
8. No tenant ID in breadcrumb/subtitle
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Overarching Assessment
|
||
|
|
|
||
|
|
The platform UI currently feels like a **thin shell** around the server dashboard. It has only 2 functioning pages (Dashboard and License), and both suffer from the same fundamental layout bug (label/value collision in Card components). The header bar is entirely borrowed from the server observability UI without any platform-specific adaptation, making 70% of the header controls irrelevant.
|
||
|
|
|
||
|
|
**Key architectural concerns:**
|
||
|
|
1. The TopBar component from the design system is monolithic -- it always renders server-specific controls (status filters, time range, search). The platform needs either a simplified TopBar variant or the ability to hide these sections.
|
||
|
|
2. The sidebar uses `Sidebar.Section` (expandable groups) as navigation links, which prevents active-state highlighting. It should use `Sidebar.Link` or a similar component.
|
||
|
|
3. The platform provides very little actionable functionality -- a user can view their tenant info and license, but can't manage anything. The "Server Management" card is just a link to another app.
|
||
|
|
|
||
|
|
**What works well overall:**
|
||
|
|
- Design system integration is solid (same look and feel as server)
|
||
|
|
- Dark mode works correctly
|
||
|
|
- Loading and error states are handled
|
||
|
|
- Login page is clean and functional
|
||
|
|
- KPI strip component is effective at summarizing key info
|
||
|
|
|
||
|
|
**Recommended priorities:**
|
||
|
|
1. Fix the label/value collision bug (affects 3 cards across 2 pages)
|
||
|
|
2. Hide or replace server-specific header controls on platform pages
|
||
|
|
3. Add sidebar active state and fix the collapse behavior
|
||
|
|
4. Add clipboard copy for license token
|
||
|
|
5. Fix mobile responsiveness
|