Files
cameleer-server/docs/superpowers/specs/2026-04-06-role-based-ui-access-design.md
hsiegeln e54f308607
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m5s
CI / docker (push) Successful in 10s
CI / deploy (push) Successful in 39s
CI / deploy-feature (push) Has been skipped
docs: add role-based UI access control design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:35:59 +02:00

4.4 KiB

Role-Based UI Access Control

Date: 2026-04-06 Status: Approved

Problem

The UI shows all features to all authenticated users regardless of role. VIEWER users see the Admin sidebar section, can navigate to admin pages, and encounter 403 errors from the backend. App Config is under the Admin section despite being accessible to VIEWER/OPERATOR.

Design

Role-Permission Matrix

Feature VIEWER OPERATOR ADMIN
Main tabs
Exchanges (view) Yes Yes Yes
Dashboard Yes Yes Yes
Runtime Yes Yes Yes
Logs Yes Yes Yes
Config (new tab, per-app) Read-only Read + Edit Read + Edit
Operator actions
Route control (start/stop/suspend/resume) Hidden Yes Yes
Replay exchange Hidden Yes Yes
Diagram context menu Hidden Yes Yes
Admin section (hidden entirely from non-admin)
Users & Roles Hidden Hidden Full CRUD
Audit Log Hidden Hidden Read-only
OIDC Config Hidden Hidden Full CRUD
Database Admin Hidden Hidden Read + Kill query
ClickHouse Admin Hidden Hidden Read-only
Sidebar
Applications section Yes Yes Yes
Starred section Yes Yes Yes
Admin section Hidden Hidden Yes
API Docs link Yes Yes Yes

Changes

1. Sidebar — hide Admin section for non-ADMIN

In LayoutShell.tsx, read roles from useAuthStore and conditionally render the Admin sidebar section only when the user has the ADMIN role.

2. Router — add role guard for /admin/*

In router.tsx, wrap admin routes with a RequireRole guard component that checks for ADMIN role and redirects to / if not authorized. Reuse the existing useAuthStore roles.

3. Move App Config to main application tabs

  • Remove App Config from the Admin sidebar items
  • Add a "Config" tab alongside Exchanges/Dashboard/Runtime/Logs in the main tab bar
  • Route: /config/:appId (scoped per-app, like other tabs)
  • The config page already exists (AppConfigPage.tsx, AppConfigDetailPage.tsx) — reuse it
  • Hide edit/save controls for VIEWER (check roles for OPERATOR+)
  • Backend ACL already correct: GET /api/v1/config/* is VIEWER+, PUT /api/v1/config/* is OPERATOR+

4. Role helper

Add a small utility (e.g., hasRole(role) or useHasRole(role)) to reduce boilerplate. The existing pattern roles.some(r => r === 'OPERATOR' || r === 'ADMIN') is repeated — centralize it.

Files to modify

File Change
ui/src/auth/auth-store.ts Add hasRole(role) / isAdmin / isOperator helpers
ui/src/components/LayoutShell.tsx Hide Admin sidebar for non-ADMIN; remove App Config from admin items
ui/src/router.tsx Add RequireRole guard on admin routes; add /config/:appId route
ui/src/components/sidebar-utils.ts Remove App Config from buildAdminTreeNodes()
ui/src/pages/Admin/AppConfigPage.tsx Adapt for per-app context (read appId from route params)
ui/src/pages/Admin/AppConfigDetailPage.tsx Hide edit controls for VIEWER
ui/src/pages/Exchanges/ExchangesPage.tsx Conditionally pass onNodeAction to diagram based on role

5. Diagram node toolbar — hide for VIEWER

The process diagram's NodeToolbar (hover actions: inspect, toggle-trace, configure-tap, copy-id) exposes operator-level actions. Hide it for VIEWER users by not passing the onNodeAction prop to ProcessDiagram / ExecutionDiagram. When onNodeAction is undefined, the toolbar is not rendered (already handled in ProcessDiagram.tsx line 394: toolbar.hoveredNodeId && onNodeAction && ...). The inspect action (node selection) still works via onNodeSelect which is separate.

What stays the same

  • Backend ACLs — already correct, no changes needed
  • Route control bar — already gated on OPERATOR+ in ExchangeHeader.tsx and ExchangesPage.tsx
  • All admin pages — no individual page changes needed (router guard handles access)

Verification

  • Log in as VIEWER: sidebar has no Admin section, /admin/* routes redirect to /, Config tab is read-only, diagram node toolbar hidden, route control bar hidden
  • Log in as OPERATOR: same as VIEWER + route control buttons visible + Config tab is editable + diagram node toolbar visible
  • Log in as ADMIN: full Admin sidebar visible, all admin pages accessible, all features enabled