04 — Information Architecture (RBAC Module)
- 1. Placement in the app shell
- 2. Information hierarchy
- 3. Screen-to-route table
- 4. Navigation rules
- 5. Content model (what each screen shows)
- 6. Related modules (cross-references)
Where RBAC lives in the app shell (00-shared/05). RBAC is an admin-governance surface: it sits under the Settings umbrella, gated by the
rbac.*permission family, and is invisible to non-admin personas.
1. Placement in the app shell
AppShell (role-aware, 05_Global_Information_Architecture.md §1)
└─ NavigationDrawer / Rail
├─ Home, Students, Attendance, Academics, Fees, … (module destinations)
└─ Settings (roles: admin — 05 §2 "Settings | /settings | admin")
├─ Organization profile
├─ Roles & Permissions ← RBAC package entry
│ ├─ Roles (list)
│ ├─ Create role
│ ├─ Role detail
│ └─ Role editor (permission matrix)
├─ Members (organization people + roles)
│ ├─ Add member
└─ Access audit (permission audit view; audit.read)
- Entry point: Settings → "Roles & Permissions" (routes
/settings/roles,/settings/members,/settings/access-audit). - Why Settings, not a top-level tab: the global nav (05 §2) reserves top-level
destinations for daily-use modules; RBAC is occasional governance. Matches
05 §2"Users & Roles |/users,/roles| admin".
2. Information hierarchy
Roles & Permissions
├─ Roles (the "what can be done" catalog) [GET /rbac/roles, GET /rbac/permissions]
│ ├─ System roles (7, locked badges)
│ └─ Custom roles (tenant)
│ └─ Role detail: identity + priority + permission summary
│ └─ Editor: full permission matrix (hero)
└─ Members (the "who has which roles") [GET /rbac/members]
├─ Member tile: user identity (merged via user.read, OQ-R7) + role chips
└─ Add member: user picker + role picker [POST /rbac/members]
└─ Access audit (the "who did what") [GET /audit-logs, audit.controller.ts:17]
└─ Filter: action / entityType / actorId
Parent-child rule: Role detail is reachable from Roles list only; member rows link
forward to nothing (no per-member detail screen — the API exposes none; PATCH /rbac/ members/:id is the only member write, rbac.controller.ts:69-73).
3. Screen-to-route table
| Route | Screen | Guard (client) | Server gate |
|---|---|---|---|
/settings/roles | Roles list | rbac.role.read | @Roles('org_admin') (rbac.controller.ts:21) |
/settings/roles/new | Role editor (create) | rbac.role.create | same |
/settings/roles/:id | Role detail | rbac.role.read | same |
/settings/roles/:id/edit | Role editor (edit) | rbac.role.update | same |
/settings/members | Members list | rbac.member.read | same |
/settings/members/add | Add member (sheet) | rbac.member.create | same |
/settings/access-audit | Permission audit | audit.read | @UseGuards(JwtAuthGuard) only (audit.controller.ts:9; perm gate (planned)) |
Client guard vs server gate mismatch (flagged): the client gates on
rbac.*permissions, the server on theorg_adminrole (OQ-R1). Until OQ-R1 lands, client routes must additionally require theorg_adminrole claim, else users withrbac.*perms would see screens that 403. Implemented asroleOrPermissionGuard(['org_admin'], ['rbac.role.read'])(see 13 §4, 15 §5).
4. Navigation rules
- Destinations hidden for anyone without the gate (05 §3 "Unauthorized destinations are hidden and unroutable").
RolesandMembersare sibling tabs under one "Access" section header;Access auditis a third tab (not nested deeper).- Breadcrumb (desktop ≥ 2 levels):
Settings / Roles / {role name}. - Keyboard:
Ctrl+Kglobal search may surface roles/members by name;Non Roles and Members lists starts the create flow (desktop).
5. Content model (what each screen shows)
| Screen | Primary entities | Secondary | Empty state |
|---|---|---|---|
| Roles list | Role (name, slug, description, isSystem, priority, permissions[] — role.schema.ts:69-85) | perm count badge, member count (proposed) | "No custom roles yet" |
| Role detail | Role identity + full perm set | member holders (proposed) | — |
| Role editor | 95-perm matrix | search, group select-all, count | — |
| Members list | Member (userId, roles[], status, joinedAt — organization-member.schema.ts:15-31) + merged user profile | role chips, status badge | "No members yet" |
| Add member | User picker + role picker | — | — |
| Access audit | AuditLog rows (action, entityType, actorId, ts) | filters | "No activity recorded" |
6. Related modules (cross-references)
- Users — identity for member tiles;
user.read…user.import(studylyon-blueprint/04-Modules/Users.md:71-79). - Auth — JWT carries
rolesclaim (jwt-payload.interface.ts:3); re-login required for claim refresh. - Organizations — tenant context;
seedDefaults(org.slug)quirk (organizations.service.ts:58). - Audit —
GET /audit-logsbacks the permission audit view (audit.controller.ts:17-34). - 05 Shared GIA §9 — client mirrors
permissions.constants.ts; route rebuild on role change.