09 — User Behaviour (Reports Module)
- 1. Behavioural patterns
- 2. Behavioural anti-patterns to design out
- 3. Behavioural metrics (proposed)
Expected behaviour patterns and the server facts that shape them. Behavior analytics
(proposed)throughout; no analytics SDK in repo (00-shared/10 §8).
1. Behavioural patterns
B1 — Submit-and-watch (dominant)
User submits → lands on S4 → watches status go queued → processing →
completed. Average wait: seconds (attendance/fee) to minutes (term-end card
batches). Server fact: no WebSocket topic, no progress % — polling is the
only mechanism (reports.controller.ts:20-24).
Implications:
- Default poll 2 s (10); show elapsed time so the wait feels productive.
- Do not block navigation — user can leave S4; job continues (server-owned).
B2 — Submit-and-come-back
User submits then leaves; returns later via job list. Server fact: job doc
persists with params + result (report-job.schema.ts:33-36) — result is
re-readable indefinitely (no TTL in schema; blueprint TTL cleanup is for files,
04-Modules/Reports.md:50).
Implication: S4 must render a terminal job from a single GET — no re-poll.
B3 — Re-run with tweaks
Completed fee summary → "New report from these params" (S4 CTA) — users
regenerate monthly with same/edited params. Server: cheap, new job per POST
(reports.service.ts:31-43). Form prefills from params (:33).
B4 — Failure → retry
Job failed → user retries. Server facts: error string stored
(report-job.schema.ts:39, reports.service.ts:79-82); retry = new POST;
known async failures: missing student/exam (:91), student not found (:94),
unknown type (:75).
Implication: surface the exact error; if it says "studentId and examId required", send user to the form, not retry.
B5 — Scheduled report consumption
Daily/weekly attendance jobs (attendance-report.job.ts:13-24) appear in job
list. Today there is no list API (S3 gap) and no completion notification
(ReportGenerated unmapped, event-queue-map.ts) — users discover via history
(forward-looking).
2. Behavioural anti-patterns to design out
| Anti-pattern | Design response |
|---|---|
| Double-submit → duplicate jobs | disable CTA while in flight (B1) |
| Staring at an eternal spinner after network loss | banner + pause polling + manual retry (S4) |
Confusing failed with a server error | distinct failed state + error text + Retry vs form CTA |
| Expecting a PDF that doesn't exist | hide export CTAs until (planned) download endpoint lands |
| Filtering a job list that has no API | local history only; label clearly; no fake "all jobs" count |
3. Behavioural metrics (proposed)
| Metric | Event | Target |
|---|---|---|
| Generate → completed seen | reports.job.status terminal | ≥ 90% of polls reach terminal |
| Time-to-complete (per type) | reports.job.status(completed) + createdAt | fee/attendance < 5 s p95 |
| Retry rate | reports.job.retry | < 5% |
| Repeat generation | "new from params" | ≥ 20% monthly of fee summaries |
| Export adoption | reports.result.download | n/a until (planned) |