04 — Information Architecture (Results Module)
- 1. IA map
- 2. Information units (from contracts)
- 3. Navigation rules
- 4. State flags driving IA
- 5. Empty & error placements
IA derives from route structure (
result.controller.ts:9-37,examination.controller.ts:23-56) and the report card contract (result.service.ts:8-26). Navigation labels are client-side; the API shape constrains what each screen can show.
1. IA map
Results (tab / section)
├── Student Results List ← GET /api/v1/results/student/:studentId
│ └── Exam result row (per examination_results row)
│ └── Report Card View ← GET /api/v1/results/report-card/:studentId/:examId
│ ├── Subject rows (marksObtained, maximumMarks, grade, remarks)
│ ├── Totals (totalMarksObtained, totalMaximumMarks)
│ ├── Percentage (2 decimals)
│ └── Overall grade (A+…F)
Examinations (tab / section)
├── Exam List ← GET /api/v1/examinations (paginated)
│ └── Exam Detail ← GET /api/v1/examinations/:id
│ ├── Subject list ← GET /api/v1/examinations/:id/subjects
│ │ └── Exam-Subject Detail
│ │ ├── Results grid ← GET /api/v1/results/exam-subject/:examSubjectId
│ │ └── Marks entry form → POST /api/v1/results/exam-subject/:examSubjectId/marks
│ └── Publish action → POST /api/v1/examinations/:id/publish
│ └── (async) in-app notification → results-published job
2. Information units (from contracts)
| Unit | Fields | Source |
|---|---|---|
| Examination | academicYearId, name, type, startDate, endDate, status (draft/active/completed/published), gradingSchemeId? | examination.schema.ts:8-36 |
| ExaminationSubject | examinationId, subjectId, classId, date, startTime, endTime, maximumMarks, passingMarks | examination-subject.schema.ts:8-31 |
| ExaminationResult | studentId, examinationSubjectId, marksObtained?, grade?, remarks?, publishedAt? + tenantId/timestamps | examination-result.schema.ts:8-25, base.schema.ts |
| ReportCard | studentId, examinationId, subjects[] (subjectId, subjectName*, marksObtained, maximumMarks, grade?, remarks?), totalMarksObtained, totalMaximumMarks, percentage, overallGrade, generatedAt | result.service.ts:8-26 |
| Marks entry input | studentId, marksObtained, grade?, remarks? | examination-subject.dto.ts:47-65 |
* subjectName currently equals the subject ID (result.service.ts:75) — see gaps.
3. Navigation rules
- Marks entry lives under Examinations, not Results: the write endpoint is proxied from
result.controller.ts:26-31into the Exams service, and subjects are exam-owned. Results tab = read-only (student lists + report cards). - Publish is exam-scoped (
examinations/:id/publish), not result-scoped; UI must place it on exam detail, not on a single result row. - Report card requires both
studentIdandexamIdpath params (result.controller.ts:32-37) — navigation must always carry the pair.
4. State flags driving IA
| Flag | Derivation | UI effect |
|---|---|---|
| Exam status | examination.schema.ts:28-33 | published → mark entry read-only*; else editable |
| Result published | publishedAt on row (examination-result.schema.ts:24-25) | badge "Published" on result rows/list items |
| Entry exists | row present for (student, subject) | grid cell shows marks vs. empty |
* Server does not enforce read-only after publish (examination.service.ts:139-195 has no published check) — UI-only for now, flagged (planned).
5. Empty & error placements
- Zero subjects for exam → report card 404 (
result.service.ts:51-52) → screen-level empty state (see06_Screen_Specifications.md). - No results rows for a student →
findByStudentreturns[](repository returns array,examination-result.repository.ts:26-28) → empty state, no error. - Marks > max → 404 at
examination.service.ts:145-146→ inline field error (client normalises code).