Six personas derived from the roles and permissions available in
src/modules/rbac/ and the flows the exams API supports (examination.controller.ts,
result.controller.ts). Permissions quoted are the available ones in
permissions.constants.ts:1-97 — note no exam.* permission exists yet (OQ-4,
see 01_Product_Overview.md §10); the RBAC column below is the target contract from
studylyon-blueprint/04-Modules/Exams.md:64-72 and is (planned) until seeded.
Senior academic admin (principal, vice-principal, academic coordinator) at the tenant org
Roles / permissions
Admin role (all permissions, role.schema.ts:23); target: exam.create, exam.update, exam.delete, exam.publish(planned)
Frequency
Weekly during planning season; daily during results week
Device
Tablet + desktop web; office Wi-Fi
Goals
Create the term's exam calendar (name, type midterm/final/unit_test/quarterly/other — examination.schema.ts:15-20); attach subject slots per class (date + 09:00-style time window + maximumMarks/passingMarks); keep statuses honest (draft → active → completed → published); publish results only when every subject is marked
Pain points
No server-side conflict detection for subject dates (OQ-2) — they must eyeball overlaps; publish is irreversible in UI terms (examination.service.ts:203-220 sets status published); no bulk tools — each subject slot is one POST (examination.controller.ts:45-50)
Behaviors
Reviews the exam list (GET /examinations, paginated) by status; drills into a detail (GET /examinations/:id + GET /examinations/:id/subjects) to check marks coverage (GET /results/exam-subject/:id); uses the publish dialog as a final checklist
Exit criteria
Exam visible with correct slots; all marks entered; publish succeeded → snackbar + list shows published badge
Class teacher / subject teacher marking a class's answer sheets
Roles / permissions
Teacher role (role.schema.ts:31); target: exam.mark(planned)
Frequency
Daily during exam week; per subject-slot
Device
Phone + tablet; classroom Wi-Fi may be flaky
Goals
Open the slot for my class+subject, enter marksObtained per student fast (numeric keyboard, row-swipe cadence), fix typos in place, finish and verify coverage
Pain points
Marks above the slot maximum are rejected by the server with a 404NotFoundException('Marks cannot exceed maximum.') (examination.service.ts:145-146) — confusing if not pre-validated; per-subject grade is free text (examination-subject.dto.ts:57-60) so they must type it or leave blank; no bulk marks endpoint today (/marks-import is (planned), IMPLEMENTATION_PLAN.md:219)
Behaviors
Enters marks row by row; re-taps a cell to correct (upsert updates in place — examination.service.ts:147-175); checks the coverage summary bar (marked / total students) before leaving
Exit criteria
Every roster student has a mark ≤ maximumMarks; coverage 100%
Verify marks coverage across subjects, approve publish; afterwards, confirm students/parents can see results (publishedAt stamped on every result — examination-result.repository.ts:42-51)
Pain points
Publish has no guard against re-publish or post-publish edits (OQ-5) — trust in the UI's "published = locked" treatment; no server-side check that all marks are entered before publish (it publishes whatever exists — examination.service.ts:203-220)
Behaviors
Opens exam detail, glances at per-subject coverage, taps Publish, confirms in the dialog, watches for the published status flip
Student role (role.schema.ts:63); reads via result.read(planned)/student.read today
Frequency
After each exam's publish; before each exam to see schedule
Device
Phone; shared data plan
Goals
See the exam schedule and their marks per subject (GET /results/student/:studentId), open the report card (percentage + overallGrade A+…F — result.service.ts:130-138), see grade/remarks per subject
Pain points
Results before publish are invisible server-side only if they never appear; a subject with no mark renders as 0 marks on the report card (result.service.ts:70) — must be explained in UI; marks are visible regardless of publish state through the student-results route (no visibility filter — result.repository.ts:26-28)
Behaviors
Checks the results tab after "results published" notification (in-app/results-published job — event-queue-map.ts:27(planned)); screenshots the report card
Parent role (role.schema.ts:55); reads via result.read(planned) / student.read today
Frequency
After each published exam
Device
Phone; home Wi-Fi
Goals
Verify the child's report card; compare marksObtained vs maximumMarks per subject; check remarks from teachers
Pain points
Same as student: unpublished results reachable via the route; subject-name resolution is raw subjectId in the report card payload (result.service.ts:75 — OQ-9) — client must resolve names locally
Behaviors
Passive reader; shares the card with family
Exit criteria
Full subject table + totals rendered from GET /results/report-card/:studentId/:examId
Trace a "wrong marks" complaint: check exam status, slot max marks, the student's result doc, and the version counter (base.schema.ts:30-31) to confirm how many edits happened; verify publish timestamps (publishedAt)
Pain points
Events like MarksEntered are emitted but not persisted to an audit queue (no queue route in event-queue-map.ts — OQ-8); soft-deleted exams are invisible after DELETE (base.repository.ts:68-74)
Behaviors
Replays the flow read-only; compares server state against the client's optimistic UI claims
* exam.* / result.* permissions are not yet in permissions.constants.ts:1-97
(see 01_Product_Overview.md §10 OQ-4); the matrix is the design target, not the
current server contract.