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

04 — Information Architecture (Users Module)

Module IA within the global shell (00-shared/05). The module owns the Users & Roles surface (/users, 05_Global_Information_Architecture.md:47) for admin/HR, plus the account/profile self-service surface (05_Global_IA §8: avatar menu → profile, password, 2FA, devices, preferences). Routes are (planned) — no client repo exists; they follow go_router conventions (00-shared/11 §6).


1. Navigation placement

SurfaceDestinationShell slotVisible to
Users management/usersSettings group: "Users & Roles" (00-shared/05 §2)Org Admin + HR/custom roles with user.read; full management needs user.create/update/delete/import
Roles & memberships/rolessame grouporg_admin (RBAC controller is org_admin-gated — rbac.controller.ts:21-22)
Self profileavatar menu → /settings/profilecross-cutting account surface (00-shared/05 §8)all authenticated users
  • Role-gating note: GET /rbac/members requires org_admin (rbac.controller.ts:21-22); if the Users list must show role chips to non-org_admin viewers, that data source is unavailable — role chips degrade to "—" for those viewers (planned) server-side join.

2. Screen hierarchy (admin surface)

/users ──────────────────────────── Users list (master)
 ├── /users/new ─────────────────── Create user (full-screen wizard-lite form)
 ├── /users/import ──────────────── Bulk import wizard (3 steps: upload → preview → result)
 ├── /users/:id ─────────────────── User detail (tabs: Profile | Membership | Preferences | Audit)
 │    ├── /users/:id/edit ───────── Edit user (reuses create form w/ UpdateUserDto)
 │    ├── /users/:id/preferences ── Preferences (manager view)
 │    └── delete / erase ────────── (dialogs, not routes)
 /roles ─────────────────────────── Roles & members list (RBAC module surface, referenced)
  • Master-detail on tablet/desktop (≥ 840 dp, 00-shared/05 §3); push-on-top on phone; breadcrumbs on desktop at depth ≥ 2.

3. Screen hierarchy (self-service surface)

/settings/profile ──────────────── Self profile (read own GET /users/:id)
 ├── edit (inline page form)
 ├── preferences (notification toggles, theme mode)
 └── avatar (upload dialog)
  • Identity self-:id resolution: JWT sub claim (auth.service.ts:461); server-side self-guard (planned) (OQ-3).

4. Modal hierarchy (per 00-shared/05 §5)

LevelUsed forWidget
Snackbarcreate/update success, import summary, avatar saved, undo-less soft notesAppSnackbar
Bottom sheetrole picker (from GET /rbac/roles), status picker, language/timezone pickers, row actionsAppBottomSheet
Dialogdeactivate confirm (consequence copy), delete confirm (typed), GDPR erasure confirm (typed, "ERASE"), avatar replace/removeAppDialog
Full-screenCreate user, Edit user, Import wizard, Preferences, User detailPage routes
Loaderonly submit waits; screens prefer skeletonsAppProgress

Destructive rules (00-shared/05 §5): delete needs typed confirm ("delete") — irreversible after 30-day purge; GDPR erasure needs typed confirm ("ERASE") — irreversible immediately (anonymized + purge job, users.service.ts:186-209, tenant-purge.worker.ts:49-56).

5. Screen relationships

  • List → Detail → Edit → back to Detail (refresh). List → Create → back to List (refresh). List → Import → Result → back to List (refresh).
  • Detail tabs fetch from three sources: GET /users/:id (profile), GET /rbac/members (membership — join by userId), GET /users/:id/preferences (preferences).
  • Preferences manager view and self-profile preferences share the same screen component (PATCH target differs only by :id).
  • Status change happens from Detail (top-bar action) and from list row context menu.
RouteScreenGuard
/usersUsers listauthed + user.read
/users/newCreate useruser.create
/users/importImport wizarduser.import
/users/:idUser detailuser.read
/users/:id/editEdit useruser.update
/users/:id/preferencesPreferencesuser.read + user.update
/settings/profile (+ /preferences, avatar)Self profileauthed (self :id)

Deep links:

  • studylyon://users/:id — notification "user-created" → detail (UserCreated → in-app job user-created-notification, event-queue-map.ts:10).
  • studylyon://settings/profile — own profile ((forward-looking) push).

7. Nested nav & state survival

  • Detail tabs use TabBarView keep-alive (00-shared/03 AppTabs); switching bottom-nav destinations preserves tab state (00-shared/05 §3).
  • Import wizard state (file, preview, errors) survives screen navigation via the BulkImportCubit (13_State_Management.md §6) — never re-parse a file the user already validated unless they pick a new one.

8. Quick actions, FABs, context menus

ScreenFABQuick actionContext menu (rows)
Users list"Add user" (extended)Ctrl+K search global; N new (desktop); "Import CSV" toolbar actionView · Edit · Deactivate/Activate · Delete · GDPR erase
User detailEdit (top bar), status menu, erase (top-bar overflow)
Import wizardprimary CTA per step (Upload → Review → Start import)
Self profileavatar camera, edit actions
  • FAB hidden while scrolling down / shown on scroll-up (00-shared/03 AppFAB); unique heroTag per screen.
  • Import entry point is deliberately a toolbar/empty-state action, not a second FAB (one FAB rule, 00-shared/03 §D).

9. Global search integration

  • Users list: q → regex on firstName/lastName/email/displayName, case-insensitive (users.service.ts:92-99), debounced 300 ms (AppSearchBar).
  • Global search backend indexing users (planned) (search module exists as permission search, permissions.constants.ts:93).

10. Filters & sorting (list semantics)

  • Server-supported today: pagination page/limit(1-100,20)/sort(±field)/q (pagination-query.dto.ts:5-30); default sort -createdAt (users.service.ts:103).
  • Status filter and role filter are (planned) — no query params exist in users.service.ts:90-115. Until then the client filter bar filters the loaded pages client-side (explicitly labeled, and honest about the limitation) or defers until server support lands.