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

12 — API Mapping (Results Module)

Exact endpoints per screen. Wire contract per 00-shared/07_API_Conventions.md: base /api/v1, Bearer JWT, success {success:true, message:"OK", data, meta?, timestamp, requestId}, error {success:false, message, error:{code, details?}, timestamp, requestId}; codes VALIDATION_ERROR(400), UNAUTHENTICATED(401), PERMISSION_DENIED(403), RESOURCE_NOT_FOUND(404), DUPLICATE_RESOURCE(409), BUSINESS_RULE_VIOLATION(422), RATE_LIMITED(429), INTERNAL_SERVER_ERROR(5xx). Pagination page/limit(1-100, default 20)/sort(-desc)/q. Sources: result.controller.ts, examination.controller.ts, examination.service.ts, result.service.ts. Note: no endpoint is paginated in this module — all results routes return bare arrays; pagination exists only on the exams list.

E1 — List results for a student (S3)

EndpointGET /api/v1/results/student/:studentId (result.controller.ts:16-20)
GuardJwtAuthGuard only (:10) — no ownership/visibility check; RBAC (planned)
Response200 envelope, data = flat ExaminationResult[] (examination-result.repository.ts:26-28) — no meta
Errors400 (malformed id); 429 RATE_LIMITED; 5xx; cross-tenant/deleted → [] (scoped repo, not 404)
ClientS3 rows; group by examinationSubjectId → E5

E2 — List results for an exam-subject (S1, S5)

EndpointGET /api/v1/results/exam-subject/:examSubjectId (result.controller.ts:21-25)
Response200 envelope, data = ExaminationResult[] (examination-result.repository.ts:20-24)
Errors400; 404 via repo scoping (subject not in tenant → []); 429; 5xx
ClientS1 table rows; S5 per-subject aggregation
NotesIncludes rows with publishedAt — no filter param exists ((planned))

E3 — Enter / update marks (S1)

EndpointPOST /api/v1/results/exam-subject/:examSubjectId/marks (result.controller.ts:26-31)
GuardJwtAuthGuard; intended result.compute (planned)
BodyEnterMarksDto (examination-subject.dto.ts:47-65): studentId (MongoId, req), marksObtained (Number, Min 0, req), grade? (String), remarks? (String)
Behaviouridempotent upsert on (studentId, examSubjectId) (examination.service.ts:147-175); unknown subject → 404 (:143-144); marksObtained > maximumMarks404 RESOURCE_NOT_FOUND (:145-146, quirk — see 14_QA_Checklist.md §5)
Response2xx envelope, data = saved ExaminationResult
Errors400 VALIDATION_ERROR (bad id, negative marks); 404 (subject missing / over-max); 429; 5xx (incl. dup-key race → 500, examination-result.schema.ts:31-33)
Side effectsMarksEntered event → no queue route in event-queue-map.ts (audit only, examination.service.ts:163-173)
ClientS1 per-row save; replay-safe offline (idempotent)

E4 — Report card (S4)

EndpointGET /api/v1/results/report-card/:studentId/:examId (result.controller.ts:32-37)
Response200 envelope, data = ReportCard (result.service.ts:8-26): studentId, examinationId, subjects[] (subjectId, subjectName=subject ID string :75, marksObtained 0-filled :70, maximumMarks, grade?, remarks?), totalMarksObtained, totalMaximumMarks, percentage (2 dp :83-86), overallGrade (computeGrade bands :130-138), generatedAt
Errors404 No subjects found for this examination. (:51-52); 400 malformed ids; 429; 5xx
ClientS4; cache key (studentId, examId); subjectName → local display-name map
NotespublishedAt not checked — report card works pre-publish ((planned) visibility)

E5 — Get examination (S3 grouping, S5 header)

EndpointGET /api/v1/examinations/:id (examination.controller.ts:33-35)
Response200 envelope, data = Examination (examination.schema.ts:8-36): academicYearId, name, type (`midterm
Errors404 Examination not found. (examination.service.ts:63); 429; 5xx
ClientS3 group headers (name + status chip); orphan-group drop when 404

E6 — List subjects of an exam (S1 header, S2, S5)

EndpointGET /api/v1/examinations/:id/subjects (examination.controller.ts:51-53)
Response200 envelope, data = ExaminationSubject[] (examination-subject.schema.ts:8-31): examinationId, subjectId, classId, date, startTime, endTime, maximumMarks, passingMarks
Errors400; 429; 5xx (no subject → [])
ClientS1 header context; S2 single-row pick; S5 aggregation input

E7 — Publish exam results (S5)

EndpointPOST /api/v1/examinations/:id/publish (examination.controller.ts:54-56)
Behaviourstamps publishedAt on all results of all subjects (examination.service.ts:203-207, examination-result.repository.ts:42-51), sets exam status: 'published' (:209-211), emits ExamResultsPublished (:212-219) → in-app queue / results-published job (event-queue-map.ts:27)
Response2xx envelope, data null; exam with zero subjects → still publishes (subjectIds.length guard, :206)
Errors404 (exam missing via subjectRepo/examRepo); 429; 5xx
NotesNo unpublish endpoint; repeat publish is idempotent (re-stamps publishedAt)
BlueprintResults.md:37 names event ResultPublishedcode emits ExamResultsPublished (naming mismatch, flag for backend alignment)

E8 — List examinations (S1/S5 entry navigation) — paginated

EndpointGET /api/v1/examinations?page&limit&sort&q (examination.controller.ts:30-32)
Paramspage ≥1 default 1; limit 1–100 default 20; sort (-field desc); q (pagination-query.dto.ts:5-30)
Response200 envelope, data + meta {page,limit,totalItems,totalPages,hasNext,hasPrevious} (pagination-query.dto.ts:32-39)
Clientexam picker for S1/S5; infinite scroll while hasNext

E9 — (planned) bulk marks import

EndpointPOST /api/v1/examinations/:id/marks-import — spreadsheet import, validation + rollback (IMPLEMENTATION_PLAN.md:219) (planned)
ClientS1 "Import" action; async job progress (planned)

E10 — (proposed) analytics

EndpointGET /api/v1/results/analytics (blueprint Results.md:28) — not implemented (proposed)
ClientS5 today = client-side aggregation of E2 + E6

E11 — (planned) rank

FactBlueprint Results.md:54 "Rank computed per class per exam"; no code exists (planned)
ClientS4 rank slot reserved; hidden until shipped

Event side-effect map

EventQueue / jobSource
MarksEnterednone routed (audit-write (planned))examination.service.ts:163-173
ExaminationResultCreatednone routed (emitted by ResultService.create, result.service.ts:114-126 — path unused by controller)result.service.ts:114-126
ExamResultsPublishedin-app / results-publishedevent-queue-map.ts:27