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

02 — User Personas (Users Module)

Persona base from studylyon-blueprint/01-Product/USER_PERSONAS.md, refined for the Users module. Each persona lists module-specific goals, pains, and the exact capabilities the backend gives them (with file:line).


1. Tenant personas acting on users

P1 — Org Admin (the user manager)

"Manages a single institution (tenant)... Goals: configure branches, invite staff, oversee operations." (USER_PERSONAS.md:22-25)

  • Role in this module: primary operator of every Users screen.
  • Permissions granted by code: user.read/create/update/delete/import + rbac.member.* exist in the permission catalogue (permissions.constants.ts:6-10,15-18); register seeds the org_admin role (auth.service.ts:84-99).
  • Goals
    • Create a user (staff, teacher, parent) in seconds — POST /users (users.controller.ts:36-40).
    • Find anyone: GET /users?q= regex over first/last name, email, displayName, case-insensitive (users.service.ts:92-99).
    • Bulk-import a term-start spreadsheet: POST /users/import (users.controller.ts:104-110) and get a per-row error list.
    • Grant/change roles: POST/PATCH /rbac/members (rbac.controller.ts:63-73).
    • Deactivate or erase (GDPR): DELETE /users/:id, POST /users/:id/erasure.
  • Pains
    • Duplicate emails are hard-rejected (409 — users.service.ts:50-54,120-126); a typo blocks the whole row in import (Row N: email "x" already existsusers.service.ts:260-263).
    • No status/role filter on GET /users (only q, sort, pagination — users.service.ts:90-115) → filters are (planned).
    • Import runs synchronously; a 1,000-row file blocks the request (users.service.ts:233-282) — see 14_QA_Checklist.md scenario C1.
  • Success metric: add a staff member in < 60 s; import 500 rows with all errors locatable to a row number.

P2 — HR / Operations Staff (user manager delegate)

Staff persona: "operations, reception, coordinators... often read-heavy" (USER_PERSONAS.md:34-39).

  • Role: day-to-day user-list operator — new joiner intake, record cleanup, status upkeep. Same screens as P1 but narrower permissions (e.g. user.read + user.create, no user.delete).
  • Goals: search (name/email/displayName), view detail, update contact info (PATCH /users/:id), run the CSV import for new batches.
  • Pains: needs row-level role context on the users list (membership is a separate API — GET /rbac/members, rbac.controller.ts:57-61); without the join the list shows identities only.
  • Constraints enforced by code: soft-delete hides users from every list (base.repository.ts:20-30); if HR "removes" someone, they vanish — the UI must offer erasure vs. status inactive as distinct, labeled choices.

P3 — Teacher / Staff / Parent as managed users

Teacher: "wants minimal clicks; mobile-friendly" (USER_PERSONAS.md:29-32); Parent: "wants proactive, timely communication" (USER_PERSONAS.md:47-50).

  • Role: subject of admin management; consume self-service profile.
  • What they can do today (self-service):
    • Update their own profile data — PATCH /users/:id accepts name/email/ phone/gender/DOB/language/timezone/status/metadata (update-user.dto.ts:5-69). (Note: the controller does not restrict :id to self — client must enforce; server-side self-guard (planned), OQ-3.)
    • Preferences: GET/PATCH /users/:id/preferences (users.controller.ts:78-93) — notification toggles and theme.
    • Avatar: POST /users/:id/avatar (users.controller.ts:95-102).
  • Pains
    • Email change collides if the address is taken — 409 inline (users.service.ts:120-126).
    • Email verification state: auth_accounts.emailVerifiedAt is written by verifyEmail (auth.service.ts:217-223) but the user-level emailVerified flag on the schema (user.schema.ts:74-75) is never updated by that path — UI must not rely on it (OQ-4).

P4 — Self-service user (any role)

  • Same capabilities as P3 minus admin screens; cares about theme (preferences.theme.mode: light|dark|systemupdate-user-preferences.dto.ts:16-20), notification channels (email/push/sms booleans — :8-12), and privacy.
  • Pain: no "account" endpoint that returns own profile — the client resolves self by the JWT sub and calls GET /users/:id (OQ-3).

2. Platform persona

P5 — Super Admin (platform)

"Operates the StudyLyon SaaS itself... needs global visibility without touching tenant data" (USER_PERSONAS.md:10-14).

  • Role in this module: oversight only — user data stays tenant-scoped. Platform admin bypasses tenant scope in repositories (base.repository.ts:21-23) but isPlatformAdmin is a token flag; there is no platform users screen in the module surface (05_Global_IA has no platform section for users). Platform view of users (planned) if ever needed (audit use-case).

3. System personas

P6 — Email Engine (worker)

  • Processes emails queue (queue.constants.ts:2); handles only UserRegistered ("Welcome to StudyLyon" + verify token) and PasswordResetRequested (email.worker.ts:25-42).
  • Consequence: admin-created users get no welcome/invite email today (invite mail (planned)); onboarding UI must say "account created" without promising an e-mail.

P7 — Purge Worker (GDPR)

  • tenant-purge queue (queue.constants.ts:12); erases user doc on gdpr-erasure job (tenant-purge.worker.ts:49-56); purges soft-deleted docs > 30 days (:32-43). Idempotent by design (:26).

P8 — Audit Logger

  • Consumes audit-write for UserUpdated/UserDeleted (event-queue-map.ts:11-12); immutable per PLAN.md 19.3.

P9 — In-app Notifications

  • UserCreatedin-app queue job user-created-notification (event-queue-map.ts:10) — admin gets notified of creations, but not of bulk-import rows (those bypass the event — users.service.ts:264-272).

4. Persona → screen map

PersonaScreens (05_Screen_Inventory.md)Permissions used
P1 Org AdminUsers list, detail, create, edit, bulk import, preferences (as manager)user.*, rbac.member.*
P2 HRUsers list, detail, edit, bulk importuser.read, user.update/create
P3/P4 Teacher/Staff/ParentSelf-profile, preferences, avatarself-scoped GET/PATCH /users/:id (client-enforced)
P5 Super Adminnone today (tenant data)isPlatformAdmin
P6–P9none (background)

Gap note: roles on the users list come from GET /rbac/members (rbac.controller.ts:57-61), which requires org_admin role (rbac.controller.ts:21-22) — a read-only user.read user cannot resolve role chips. Role display for non-admin viewers (planned).