12 KiB
RBAC Management UI — Design Specification
Overview
This document describes the Monitor RBAC management interface: its layout, navigation, entity model, visual conventions, badge/chip meanings, and inheritance behaviour. It is intended as a handoff reference for developers implementing the production version.
Application layout
The app is a two-column shell with a fixed top bar.
┌─────────────────────────────────────────────────┐
│ Top bar (brand + environment badge + avatar) │
├──────────────┬──────────────────────────────────┤
│ │ │
│ Sidebar │ Main panel │
│ (200px) │ (fills remaining width) │
│ │ │
└──────────────┴──────────────────────────────────┘
Top bar
| Element | Purpose |
|---|---|
| Brand dot (green) | Indicates a live/healthy connection to the monitoring backend |
Monitor RBAC wordmark |
App name |
Environment badge (production, staging, etc.) |
Reminds operators which environment they are modifying — destructive changes in production are intentional |
| User avatar circle | Current operator identity; initials derived from name |
Sidebar
Three navigation sections:
- Overview —
Dashboard(system summary + inheritance model diagram) - Identity —
Users,Groups,Roles(the three core entity types) - Audit —
Audit log(change history, out of scope for this spec)
Each identity nav item shows a count badge (e.g. 8, 5, 6) reflecting the total number of entities of that type. The active item is indicated by a green left border accent and bold label.
Panels
Dashboard (Overview)
Displays three stat cards at the top:
| Card | Content |
|---|---|
| Users | Total user count + active sub-count |
| Groups | Total group count + max nesting depth |
| Roles | Total role count + note about direct vs inherited |
Below the stat cards is an inheritance model diagram — a three-column schematic showing how Groups → Roles on groups → Users form the inheritance chain. This is a read-only orientation aid, not interactive.
A note block (green left border) explains the inheritance rule in plain language.
Users panel
Split into a list pane (left, ~52% width) and a detail pane (right).
List pane
Each row is a user card containing:
| Element | Description |
|---|---|
| Avatar circle | Two-letter initials; background colour varies by user for visual distinction |
| Name | Full display name |
| Meta line | Email address · primary group path (e.g. Engineering → Backend) |
| Tag row | Compact role and group badges (see Badge reference below) |
| Status dot | Green = active, grey = inactive/suspended |
A search input at the top filters rows by any visible text (name, email, group, role).
Clicking a row selects it (blue tint) and loads the detail pane.
Detail pane — user
Shows full user information organised into sections:
| Section | Contents |
|---|---|
| Header | Avatar, full name, email address |
| Fields | Status, internal ID (truncated), created date |
| Group membership | Chips for every group the user directly belongs to. Sub-groups are also shown if membership was inherited via a parent group, with a small via GroupName annotation. |
| Effective roles | All roles the user holds — both direct assignments and roles inherited through group membership (see Role chips below) |
| Group tree | A visual indented tree showing the ancestry path of the user's groups |
Groups panel
Same split layout as Users.
List pane — group cards
| Element | Description |
|---|---|
| Avatar square (rounded) | Two-letter abbreviation; colour indicates domain (green = engineering, amber = ops, red = admin) |
| Name | Group display name |
| Meta line | Parent group (if nested) · member count |
| Tag row | Roles assigned directly to this group; inherited roles shown with italic/faded styling |
Detail pane — group
| Section | Contents |
|---|---|
| Header | Avatar, group name, hierarchy level label |
| Fields | Internal ID |
| Members (direct) | Name chips for users who are direct members of this group |
| Child groups | Chips for any groups nested inside this one |
| Assigned roles | Roles directly assigned to this group — what all members will inherit |
| Inheritance note | Plain-language explanation of how roles propagate to children |
| Group hierarchy | Indented tree showing parent → this group → children |
Roles panel
Same split layout.
List pane — role cards
| Element | Description |
|---|---|
| Avatar square | Two-letter abbreviation of the role name |
| Name | Role identifier (lowercase slug) |
| Meta line | Short description of access level · assignment count |
| Tag row | Groups and/or users the role is directly assigned to |
Detail pane — role
| Section | Contents |
|---|---|
| Header | Avatar, role name, description |
| Fields | Internal ID, scope |
| Assigned to groups | Group chips where this role is directly configured |
| Assigned to users (direct) | User chips that hold this role outside of any group |
| Effective principals | All principals (users) who effectively have this role, whether directly or via group inheritance |
| Inheritance note | Explains direct vs inherited assignments |
Badge and chip reference
Role tags (amber / orange)
Appear on user and group list rows to show which roles apply.
| Style | Meaning |
|---|---|
| Solid amber background, normal text | Direct assignment — the role is explicitly assigned to this entity |
| Faded / italic text, dashed border | Inherited role — the role flows from a parent group, not assigned directly |
In the detail pane, inherited role chips include a small ↑ GroupName annotation identifying the source group.
Group tags (green)
Appear on user list rows and role detail panes.
| Style | Meaning |
|---|---|
| Solid green background | The entity belongs to or is assigned to this group directly |
Status dot
| Colour | Meaning |
|---|---|
| Green (filled) | User account is active |
| Grey (filled) | User account is inactive or suspended |
Environment badge (top bar)
| Value | Meaning |
|---|---|
production |
Live system — changes are immediate and real |
staging |
Pre-production — safe for testing |
Count badge (sidebar nav)
Small pill next to each nav label showing the total number of entities of that type. Updates to reflect search/filter state when implemented.
Inheritance model
The RBAC system implements two inheritance axes:
1. Group → child group
Groups can be nested to any depth. A child group inherits all roles assigned to its parent group. This is transitive — a role on Engineering propagates to Backend and Frontend, and would continue to any groups nested inside those.
Engineering (role: viewer)
├── Backend (role: editor, inherits: viewer)
└── Frontend (role: editor, inherits: viewer)
2. Group → member users
All roles effective on a group (direct + inherited from parent groups) are inherited by every user who is a member of that group.
User: Alice
Direct member of: Engineering, Backend
Effective roles:
- admin (direct on Alice)
- viewer (inherited via Engineering)
- editor (inherited via Backend)
Role resolution
When checking if a user has a given role, the system should:
- Check direct role assignments on the user.
- For each group the user belongs to (directly or transitively), check all roles on that group.
- Union the full set — no role negation in the base model (roles only grant, never deny).
This makes effective role computation a union of all reachable role sets across the user's group membership graph.
Visual conventions
| Convention | Meaning |
|---|---|
| Dashed chip border | Inherited / transitive — not directly configured here |
↑ GroupName annotation |
Points to the source of an inherited permission |
| Green left border on nav item | Currently active section |
| Indented tree with corner connector | Shows parent–child group hierarchy |
| Green note block (left border) | Contextual explanation of inheritance behaviour — appears wherever inherited permissions could be confusing |
| Blue tint on selected list row | Currently selected entity; detail pane reflects this entity |
Entity data model (for implementation reference)
User
interface User {
id: string; // e.g. "usr_01HX…4AF"
name: string;
email: string;
status: "active" | "inactive";
createdAt: string; // ISO date
directGroups: string[]; // group IDs — direct membership only
directRoles: string[]; // role IDs — assigned directly to this user
// Computed at read time:
effectiveGroups: string[]; // all groups including transitive
effectiveRoles: string[]; // all roles including inherited
}
Group
interface Group {
id: string; // e.g. "grp_02KX…9BC"
name: string;
parentGroupId?: string; // null for top-level groups
directRoles: string[]; // role IDs assigned to this group
// Computed at read time:
effectiveRoles: string[]; // direct + inherited from parent chain
memberUserIds: string[]; // direct members only
childGroupIds: string[]; // direct children only
}
Role
interface Role {
id: string; // e.g. "rol_00AA…1F2"
name: string; // slug, e.g. "admin", "viewer"
description: string;
scope: string; // e.g. "system-wide", "monitoring:read"
// Computed at read time:
directGroupIds: string[]; // groups this role is assigned to
directUserIds: string[]; // users this role is assigned to directly
effectivePrincipalIds: string[]; // all users who hold this role
}
Recommended API surface
| Method | Path | Description |
|---|---|---|
GET |
/users |
List all users with effectiveRoles and effectiveGroups |
GET |
/users/:id |
Single user detail |
POST |
/users/:id/roles |
Assign a role directly to a user |
DELETE |
/users/:id/roles/:roleId |
Remove a direct role from a user |
POST |
/users/:id/groups |
Add user to a group |
DELETE |
/users/:id/groups/:groupId |
Remove user from a group |
GET |
/groups |
List all groups with hierarchy |
GET |
/groups/:id |
Single group detail |
POST |
/groups/:id/roles |
Assign a role to a group |
POST |
/groups/:id/children |
Nest a child group |
GET |
/roles |
List all roles with effective principals |
GET |
/roles/:id |
Single role detail |
Handoff notes for Claude Code
When implementing this in a production stack:
- State management — effective roles and groups should be computed server-side and returned in API responses. Do not compute inheritance chains in the frontend.
- Component split —
EntityListPane,UserDetail,GroupDetail,RoleDetail,InheritanceChip,GroupTreeare the natural component boundaries. - CSS tokens — all colours use CSS variables (
--color-background-primary,--color-border-tertiary, etc.) that map to the design system. Replace with your own token layer (Tailwind, CSS Modules, etc.). - Search — currently client-side string matching. For large deployments, wire to a server-side search endpoint.
- Inheritance note blocks — always render these wherever inherited permissions are displayed. They prevent operator confusion when a user has a role they didn't expect.