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 (Homework Module)

Every form field-by-field. Validation mirrors class-validator decorators exactly from src/modules/homework/dto/*.ts; messages follow the VALIDATION_ERROR (400) envelope with per-field details (http-exception.filter.ts:27-35,103-108). Client validates inline then submits; server 400 shadows client.


1. Create Homework Form — POST /api/v1/homework (homework.dto.ts:4-33)

#FieldLabelKeyboardValidation (server)Client UX
1classIdClass@IsMongoId() requiredAppDropdown from Academics; required; immutable after create
2subjectIdSubject@IsMongoId() requiredAppDropdown (filtered by class where known); immutable after create
3teacherIdTeacher@IsMongoId() requiredhidden — filled from profile (server trusts body; OQ-9 note in 01)
4titleTitletext@IsString() requiredmaxLength 200 (client), autofocus, TextInputAction.next
5descriptionDescriptionmultiline@IsOptional() @IsString()4–6 line field; "Markdown supported" helper (rendered via AppMarkdownViewer)
6dueDateDue date@IsDateString() requiredAppDatePicker; client min = today; format locale-aware; default time 23:59 local
7attachmentsAttachments@IsOptional() (string[])AppAttachmentUploader (uploads happen before submit; ids sent)

Server 400 mapping: class-validator errors arrive as error: { code: 'VALIDATION_ERROR', details: [{ message }] } — map to fields by trailing field name heuristics where details[].message lacks field ids (http-exception.filter.ts:103-108); always also show the banner message.

Submit: button "Assign homework" → loading → 201 → detail + snackbar. Errors: 5xx → AppErrorState keeping the form; offline → blocked, banner.

2. Edit Homework Form — PATCH /api/v1/homework/:id (homework.dto.ts:35-58)

#FieldRequiredServer validationClient UX
1titleno@IsOptional() @IsString()prefilled; empty string sent → validation ok, doc updated
2descriptionno@IsOptional() @IsString()prefilled
3attachmentsno@IsOptional()list diff; add/remove before PATCH (full replace — server $sets whole array, homework.service.ts:57)
4dueDateno@IsOptional() @IsDateString()date picker; client min = today (moving a due date to the past is possible server-side; flag with helper text)
5statusno@IsOptional() @IsString()AppDropdown active/closed (schema enum homework.schema.ts:33; invalid string → 400 enum cast error → treat as validation)
  • Immutable: classId, subjectId, teacherId are not in the DTO — fields disabled in the edit form with note "Class/subject cannot be changed after assignment".
  • Submit sends only changed fields (changes[] echoed in HomeworkUpdated event payload, homework.service.ts:65); success → detail refresh.
  • 404 → empty state; 400 → field errors.

3. Submission Form — POST /api/v1/homework/:id/submit (submission.dto.ts:4-17)

#FieldLabelKeyboardValidation (server)Client UX
1studentIdStudent@IsMongoId() requiredhidden — from profile; the only identity the server trusts (no JWT-sub binding, OQ-9/01)
2remarksNote to teachermultiline@IsOptional() @IsString()optional; placeholder "Add a note (optional)"; maxLength 2000 (client)
3attachmentsAttachments@IsOptional() (string[])AppAttachmentUploader; at least one of remarks/attachments not required by server — allow empty submission (server accepts; client keeps a confirm)

Flow: submit → button spinner → 201 submission doc → success view → detail. Errors:

  • 409 DUPLICATE_RESOURCE "Already submitted." (homework.service.ts:92) → navigate to detail + AppBanner(info) (not an error state).
  • 404 → homework removed.
  • 400 → field errors; 5xx → keep form.
  • Late due date: inline AppBanner(warning) "The due date has passed" — submission still allowed (server accepts; OQ-1).

4. Grade Form — PATCH /api/v1/homework/:id/submissions/:submissionId/grade (submission.dto.ts:19-26)

#FieldLabelKeyboardValidation (server)Client
1marksMarksnumbernone — no decorator (submission.dto.ts:20-21)required, numeric, 0 ≤ marks ≤ maxMarks (client default 100, org-configurable); hint "Out of {max}"
2remarksFeedbackmultiline@IsOptional() @IsString()optional; maxLength 2000 (client)
  • Server will accept negative/absurd marks (OQ-4) — client is the only guard today; document server-side limit addition as pending.
  • Regrade: if status='graded' already, show existing values + AppBanner(warning) "This overwrites the previous grade" + button "Save new grade" (server overwrites and re-emits HomeworkGraded, homework.service.ts:127-143).
  • Success → snackbar "Grade saved" + row updates from server doc (marks, remarks, status:'graded', gradedAt).
  • Errors: 404 "Submission not found." (homework.service.ts:126) → back+refresh; 400 → field errors; 5xx → keep typed values + retry.

Form-level rules (all)

  • Double-submit: disabled while pending (00-shared/08 §6).
  • Optimistic: no optimistic writes for create/submit/grade — each is server-confirmed; the submission 409 handler is the only "local success" path (00-shared/07 §9).
  • Undo: delete homework → snackbar "Deleted" with no UNDO (soft-delete is irreversible from the client; there is no restore endpoint) — confirm dialog instead (00-shared/05 §5). Attachment removal inside a form = UNDO via snackbar (4 s).
  • Abandonment: create/edit forms preserve drafts locally ((proposed) shared_preferences); back from create → "Discard draft?" dialog.
  • Keyboard: .next sequence, last .done; Ctrl/Cmd+Enter submits on desktop.
  • Error copy: from message of envelope for business 4xx only; codes for the rest (00-shared/07 §11).

Client-side error priority (all forms)

  1. 400 VALIDATION → field.
  2. 404 RESOURCE_NOT_FOUND → empty state / refresh.
  3. 409 DUPLICATE_RESOURCE → info state (submission) / inline (create race).
  4. 429 RATE_LIMITED → countdown (uploads count toward api 100/min tier, 00-shared/07 §4).
  5. 5xx → AppErrorState + requestId.