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 (Results Module)

Behavioural requirements derived from server semantics. Each behaviour cites the code fact that justifies it. Reference 00-shared/08_Interaction_&_Motion.md for motion defaults and 00-shared/09_Accessibility_Baseline.md for a11y obligations.


B1 — Marks entry is incremental and re-entrant

  • Teachers type marks row-by-row; each committed row is an independent upsert (examination.service.ts:147-175). The UI must not block other rows on one failing save (per-row saving state, S1 §3).
  • Re-entry must be frictionless: the same row can be re-submitted any number of times (update path :152-161). No "already entered" blocking.

B2 — Client-side guardrails beat server round trips

  • Over-max and negative values are caught client-side (08_Form_Specifications.md F1.2) because the server's rejection (404, examination.service.ts:145-146) is semantically wrong for the user. Users expect "try again", not "not found".

B3 — Missing marks read as zero on the report card

  • result.service.ts:70 fills marksObtained: 0 and totals still include the subject maximum (:72). Behaviour rule: never silently show a plausible zero — S4 marks the "not entered" row (hint chip) and S1 shows empty rows, so users can tell "0 scored" (has a row) from "not graded" (no row). Server cannot distinguish.

B4 — Publish is a point of no return

  • publishResults (examination.service.ts:203-220) is the only visibility switch; no unpublish endpoint exists. The confirm dialog must state this. After publish, S5 disables the action; S1 rows show locked-but-editable state (server still accepts writes — (planned) lock).

B5 — Publication informs, asynchronously

  • The visible effect of publish is the ExamResultsPublished event → in-app queue → results-published job (event-queue-map.ts:27). Users should be told "notification queued", not "notification sent" — delivery is async.

B6 — The results list is a flat feed

  • GET /api/v1/results/student/:studentId returns flat examination_results rows (examination-result.repository.ts:26-28). Users expect exam-grouped results; the client groups (S3) and must tolerate rows whose exam lookup 404s (exam soft-deleted — examination.repository.ts scoped soft-delete) by dropping the orphan group silently.

B7 — Filters are local until the server supports them

  • Filter chips on S3/S5 (published-only, grade, class) are client-side. A user filtering "published only" must not assume server-side security — publishedAt is never filtered on read paths (examination-result.repository.ts:20-40, (planned)).

B8 — Error recovery is code-driven, not message-driven

  • Envelope codes (07_API_Conventions.md §3) drive copy: VALIDATION_ERROR → inline field errors; RESOURCE_NOT_FOUND → keep input + explain (404 quirk §B2); RATE_LIMITED → backoff + retry after window; 5xx → generic + requestId.
  • Marks save failures never discard the row edit — dirty state persists (S1 §3).

B9 — Offline-first grading

  • Mobile context: teachers grade in classrooms with flaky connectivity. Edits must survive into an offline draft and replay in order when connectivity returns (15_Flutter §Offline). Idempotent upsert makes replay safe.

B10 — Behavioural metrics (client instrumentation (proposed))

  • Save attempts per row (convergence ≤ 2, per 01_Product_Overview.md §5), rejection rate (404 quirk encounters), publish-to-view latency, offline-draft replay failures.