Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

09 — User Behaviour (RBAC Module)

Behavioural rules for the RBAC surface: state machines, refresh, caching, offline, destructive paths, and the permission-change propagation story. Server rules quoted from rbac.service.ts / rbac.guard.ts; client conventions from 00-shared/06.


1. Core state machine (all lists)

Initial → Loading → Success(Empty) ─┐
            │                       ├→ Content
            └→ Error(ApiException) ←┘
  Error → Retry → Loading
  Success → PullToRefresh → Loading(background, keep content)

Per 00-shared/06 §3.1; screens never render blank.

2. Data freshness rules

ListServer cacheClient cache (proposed, 00-shared/06 §3.3)Refresh triggers
Roles (GET /rbac/roles)none (rbac.service.ts:75-77 raw)5 min, stale-while-revalidatepull-to-refresh; return from editor; after delete
Permissions (GET /rbac/permissions)none (static constant)24 h — catalog only changes with deploys (permissions.constants.ts:1-97)app foreground if > 24 h
Members (GET /rbac/members)none5 minpull-to-refresh; after add/edit/remove
Users (profile merge)none24 h reference cache (00-shared/06 §3.3)
Audit (GET /audit-logs)none (paginated)none beyond current pageinfinite scroll; pull-to-refresh

3. Permission propagation (the critical behaviour)

Derived from source — three different latencies:

ChangeTakes effectSource
Role permission edit≤ 300 s (Redis cache TTL sl:{tenantId}:perm:{userId} EX 300)rbac.service.ts:48,68
Member roles changenext login (JWT roles claim minted at login, auth.service.ts:145-154; refresh reuses old claim auth.service.ts:192-196)OQ-R4
Member removedimmediate for new requests IF the permission check runs (guard resolves via member doc, rbac.service.ts:56-65); JWT roles claim still valid until re-login — role-checked endpoints (@Roles, e.g. rbac.controller.ts:21) stay open until token expiryrbac.guard.ts:39-41

UI behaviour:

  • After saving a role's permissions, the editor shows: "Permissions apply to holders within 5 minutes; role claims refresh at next login." (info banner).
  • Route-tree rebuild (05 §9) happens on login/permission refresh — not on RBAC writes by a different admin (no server push event exists; OQ-R9).
  • Removing/deleting while own token holds the affected role → post-save hint + offer "Refresh session" (re-login) — else the UI may show screens the server now denies.

4. Destructive actions

ActionConfirmServer behaviour (source)
Delete roleAppDialog — lists holder count (proposed); copy: "N member(s) hold this role. They lose its permissions."soft delete (rbac.service.ts:106); system → 400 (blocked in UI)
Remove memberAppDialog destructivesoft delete, silent 200 even if absent (rbac.service.ts:138-140)
Remove own org_admintyped confirm (type org_admin slug, 05 §5) + "You will lose access" warningsame as above; JWT keeps access until expiry (see §3)

No optimistic deletes with undo: deletes are irreversible-enough (soft-delete but no restore endpoint — rbac.service.ts:106,139) → server-confirm then remove row (00-shared/03 F rule: irreversible ops are never optimistic).

5. Offline behaviour

  • Reads: last-good cache renders + AppOfflineBanner; all write CTAs disabled with tooltip "Connect to retry" (no offline write queues for RBAC — 00-shared/12 C3).
  • Stale matrix: if editor opened offline, matrix renders from 24 h permission cache and 5 min role cache; Save blocked; on reconnect → refetch + compare (banner "Permission catalog updated" if diff).

6. Concurrency / multi-admin

  • Two admins editing the same role: last-writer-wins ($set whole doc, rbac.service.ts:96; version field exists in base.schema.ts:30-31 but no optimistic lock is enforced on role update — OQ-R10). Mitigation: client shows "edited elsewhere" on conflict only if the fetched doc differs at save time — refresh detail before save when the screen has been backgrounded > 5 min.
  • Duplicate member add across two admins: server 500 (E11000, OQ-R5) — client shows conflict copy + refreshes list.

7. Empty / zero states

  • Roles: system section always renders (7 seeded roles, role.schema.ts:8-65); custom section empty-state.
  • Members: "No members yet — add your first member." (org_admin always exists in practice — created at registration auth.service.ts:88-91).
  • Matrix search: "No permissions match 'xyz'".
  • Audit: "No activity recorded" (empty meta.totalItems === 0).

8. Rate limiting

  • /rbac/* uses the default api tier, 100/min (rate-limit.guard.ts:36-37); audit default too. Enforcement only in production (rate-limit.guard.ts:30).
  • 429 → AppBanner countdown + backoff, no auto-retry (00-shared/06 §5).

9. Session expiry mid-edit

  • 401 during Save → silent refresh → retry once → failure: preserve form state in memory, route to login with "re-login to continue" snackbar; matrix selections survive re-login (state held by cubit, 13 §2).

10. Behaviour by persona (summary)

PersonaWhat they seeWhat they can do
org_adminfulleverything
role manager (planned)roles/members/auditper OQ-R1 grants; edit matrix
member viewermembers list read-onlysearch, view
platform_admintenant picker shell (planned)cross-tenant reads via repo bypass (base.repository.ts:21) — never inside tenant RBAC UI without org_admin token
teacher etc.nothing403 screen if route reached