03 — User Journey (Reports Module)
- J1 — Generate a fee summary (Org Admin / Accountant)
- J2 — Generate an attendance summary for a class (Teacher)
- J3 — Generate a report card (Teacher / Principal)
- J4 — Scheduled report lands in job list (any role with
report.read) - Journey map
- Common failure paths
End-to-end journeys through the async generate → poll → view/download flow. All three journeys share the same server contract:
POST /reports/generate→{jobId, status:'queued'}(reports.service.ts:28-44), then pollGET /reports/:jobId(reports.service.ts:46-50) untilcompleted/failed(report-job.schema.ts:13-18).
J1 — Generate a fee summary (Org Admin / Accountant)
- Entry: Dashboard → "Reports" → "New report".
- Form: select type
fee_summary; no required params (generate-report.dto.ts:6-33— all params optional). - Submit →
POST /reports/generate(reports.controller.ts:14-18).- Success: navigate to Job detail with
jobId, statusqueued. - Error 400/429/5xx: inline error, form preserved.
- Success: navigate to Job detail with
- Poll: client polls
GET /reports/:jobIdevery 2 s (reports.service.ts:46-50). - Completed: result card with
totalInvoices, totalCollected, totalPending, totalOverdue(reports.service.ts:154-158); CTA "Download CSV"(planned). - Failed: status
failedwitherror(report-job.schema.ts:39); CTA "Retry" = re-POST same params (new job) —reports.service.ts:31-41. - Exit: back to job list; job persists for later reads.
Happiness metric: request → visible progress < 1 s; result < 5 s.
J2 — Generate an attendance summary for a class (Teacher)
- Entry: Reports catalog →
attendance_summarytemplate. - Form:
classIdoptional,startDate/endDateoptional (generate-report.dto.ts:17-33); no dates = all records (reports.service.ts:117-123). - Submit/poll as J1.
- Completed: summary of counts per attendance status
(
reports.service.ts:126-129) +total+ period (reports.service.ts:131-136). - View: status-pie (present/late/absent/excused) + totals.
- Edge: empty range →
{total: 0, summary: {}}— render empty state, no error.
J3 — Generate a report card (Teacher / Principal)
- Entry: Student profile → "Report card" → prefill
studentId. - Form:
studentId+examIdrequired by the service, not the DTO — missing → jobfailedwitherror: "studentId and examId required"(reports.service.ts:91). DTO only enforces Mongo-Id format (generate-report.dto.ts:11-13,22-23). Client MUST validate presence before POST (gap flagged in 08). - Submit/poll as J1.
- Completed: card data —
studentName(note: currently the admission number,reports.service.ts:98),subjects[],totalMarksObtained,totalMaximumMarks,percentage,grade(reports.service.ts:96-107). Grade bands A+…D fromresult.service.ts:130-136. - View: subject table + grade badge; "Share as PDF"
(planned)— the blueprint's PDF export does not exist yet. - Student not found →
failedwitherror: "Student not found"(reports.service.ts:94); UI shows retry.
J4 — Scheduled report lands in job list (any role with report.read)
- Entry: scheduler fires daily/weekly attendance report
(
attendance-report.job.ts:13-24) —actorId: 'scheduler'. - Job appears in the shared job list with source badge "Scheduled".
- User polls/opens as J1 — no difference in contract
(
reports.service.ts:52-83). (forward-looking): notification on completion viaReportGeneratedevent (04-Modules/Reports.md:33) — no queue mapping today (event-queue-map.tshas no report route).
Journey map
flowchart LR
A[Catalog] --> B[Generate form]
B -->|POST generate| C[Job detail queued]
C --> D{GET jobId poll 2s}
D -->|processing| D
D -->|completed| E[Result view]
D -->|failed| F[Error + retry]
E --> G[Download (planned)]
F --> B
Common failure paths
| Path | Server behavior | Client UX |
|---|---|---|
Invalid type | 400 (enum validation, generate-report.dto.ts:6-8) | inline field error |
Unknown jobId | 404 Report job not found. (reports.service.ts:48) | "not found" state, back to list |
| Worker crash mid-job | job stays processing (no timeout/requeue in code) | stale spinner; QA item in 14 |
| Duplicate submit | new job per POST (no idempotency key) | disable submit while in flight |