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

08 — Form Specifications (Results Module)

Only one real form exists in the domain: the marks entry form (S1), whose contract is EnterMarksDto (examination-subject.dto.ts:47-65). S5's publish confirmation is a dialog, not a form. Field-by-field below, including the server-side validation each field maps to. (forward-looking) client spec.


F1 — Marks entry (per student, per exam-subject)

Submit: POST /api/v1/results/exam-subject/:examSubjectId/marks (result.controller.ts:26-31) — one submission per student row; idempotent upsert (examination.service.ts:147-175).

F1.1 studentId

Typehidden — from the selected row; never user-editable
Server rule@IsMongoId() required (examination-subject.dto.ts:49-50)
Errors400 VALIDATION_ERROR if malformed
NotesRow identity; unique with examinationSubjectId per DB index (examination-result.schema.ts:31-33)
A11ySemantics(exclude) on the hidden field; row label carries the student name

F1.2 marksObtained

Typenumeric, decimal allowed (backend IsNumber has no integer constraint, :53-55)
KeyboardTextInputType.numberWithOptions(decimal: true); mono + tabularFigures()
Client rule0 ≤ marks ≤ maximumMarks — mirrors server marksObtained > subject.maximumMarks → 404 (examination.service.ts:145-146)
Server rules@IsNumber() @Min(0) required (examination-subject.dto.ts:52-55)
Hint"Max {maximumMarks}" beside field (examination-subject.schema.ts:27-28)
ErrorsClient: over-max inline error before submit (no round trip). Server rejects still possible (stale maximumMarks): 404 RESOURCE_NOT_FOUND → normalise to "marks cannot exceed maximum" (404-vs-422 quirk, 14_QA_Checklist.md §5). 400 if negative or non-numeric.
Focusauto-advance Enter → grade field; commit-on-blur + Enter
A11ylabel "Marks obtained — {student}"; errorText announced via SemanticsService

F1.3 grade (optional)

Typedropdown of A+, A, B+, B, C, D, F + "clear" — but server accepts any string (@IsOptional() @IsString(), examination-subject.dto.ts:57-60), stored verbatim (examination.service.ts:157)
Defaultempty (server derives no per-subject grade; only the overall grade is computed, result.service.ts:130-138)
NoteClient-supplied; do not auto-derive from marks client-side unless the org's scheme is known — flag: server grading (planned) (blueprint Results.md:54-55)
Errors400 if non-string
A11ylabel "Grade — {student}"; selected value announced via R-GradeChip semantics ("grade A plus")

F1.4 remarks (optional)

Typefree text, single-line AppTextField
Server rule@IsOptional() @IsString() (examination-subject.dto.ts:62-65) — no max length in code
Client rulecap 200 chars locally (proposed) — no server contract exists
Errors400 if non-string
A11ylabel "Remarks — {student}"

F1.5 Submission semantics

  • Per-row commit, not a whole-grid POST (no bulk endpoint — (planned) marks-import, IMPLEMENTATION_PLAN.md:219).
  • Re-submitting the same row is an update, never a duplicate (upsert examination.service.ts:147-175).
  • Partial payloads: grade/remarks omitted → cleared on update ($set with undefined fields is not applied — only provided keys are written, :152-161); send all three keys to avoid surprise.
  • Offline: rows queue in the offline draft and replay in row order (15_Flutter §Offline).

F2 — Publish confirmation (dialog, S5)

Trigger"Publish results" → POST /api/v1/examinations/:id/publish (examination.controller.ts:54-56)
Fieldsnone — confirmation copy only: exam name, coverage %, warning "results become visible; cannot be un-published (no endpoint)"
CommitC-AppButton "Publish" (destructive-affirmative), dismissible "Cancel"
Result2xx → banner "Results published"; failure 404 (exam missing) / 429 / 5xx → C-AppErrorState in dialog

F3 — Form validation summary (envelope codes)

ConditionClientServer
marks > maximumMarksinline error, no submit404 RESOURCE_NOT_FOUND (examination.service.ts:145-146)
negative marksMin(0) inline400 VALIDATION_ERROR
malformed id400 VALIDATION_ERROR
wrong tenant / deleted subject404 RESOURCE_NOT_FOUND (examination.service.ts:143-144, scoped repo)
duplicate raceimpossible by design (upsert)unique index backstop (examination-result.schema.ts:31-33) → dup-key 5xx if raced, flagged 14_QA_Checklist.md §6