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

Every form the module exposes, its exact DTO contract, validation rules, error mapping, and submission behavior. All contracts are literal copies of the DTO classes; the client mirrors server rules and adds only what the server cannot express (calendar pickers, confirmations).


1. Request Leave Form

Contract: create-leave-request.dto.ts:4-21; submit POST /leave/requests (leave.controller.ts:32-36).

FieldControlRequiredClient validationServer validation (source)
leaveTypeIddropdown (from GET /leave/types)non-empty@IsMongoId() :6-7; type must exist → 404 leave.service.ts:129
startDatedate picker (no past restriction)non-empty, valid ISO@IsDateString() :9-11
endDatedate pickerstartDate (mirror)@IsDateString() :13-15; endDate < startDate → 400 leave.service.ts:133-134
reasonmultiline (≤ 500 chars client)@IsString() optional :17-20

Server adds (not client-sendable): userId from token (leave.service.ts:138), daysRequested computed (:136), status: pending (:144).

Read-only preview: days count client-side with the same inclusive formula (leave.service.ts:310-312) and label "includes weekends/holidays" when the range contains any.

Error mapping

HTTPSourceUI
400endDate must be on or after startDate. :134inline on endDate
404Leave type not found. :129refetch types + retry
401JWT guard leave.controller.ts:27session refresh
409(no overlap rule exists today — gap)client warning only

Submit: disable while in-flight; success → toast + pop; failure → keep form values.


2. Decision Form (ApprovalActionSheet)

Contract: leave-decision.dto.ts:4-17; submit PATCH /leave/requests/:id/approve (leave.controller.ts:49-53).

FieldControlRequiredNotes
actionsegmented approve | reject@IsEnum(LeaveDecisionAction) :11-12; enum :4-7
notemultiline (≤ 500 client)@IsOptional() @IsString() :14-17; stored as decisionNote leave.service.ts:199

Server rules surfaced in form:

  • request must be pending else 409 (leave.service.ts:175-178) → toast "Already decided" + refetch.
  • cannot decide own request → 409 (:179-180) — client hides own rows.
  • approve with insufficient balance → 409 (:188-189) → block approve, offer reject-with-note.

Confirmation: reject with note → single confirm dialog ("Reject this leave request?"). Approve → immediate (fast path).


3. Create Leave Type Form (org admin)

Contract: create-leave-type.dto.ts:4-28; submit POST /leave/types (leave.controller.ts:61-65).

FieldControlRequiredServer rule
codetext, uppercase transform@IsString() :6-7; unique per tenant leave-type.schema.ts:29
nametext@IsString() :10-11
daysPerYearnumber stepper@IsInt() @Min(1) :14-16
carryForwardswitch@IsBoolean() default false :18-21
maxCarryForwardnumber (visible only when carry on)@IsInt() @Min(0) :23-27

Duplicate code: Mongo E11000 on unique index → client maps to inline "Code already exists" (no server mapper — gap).

Read-only note: isDefault types cannot be duplicated in practice (code uniqueness); defaults appear in list automatically (leave.service.ts:299-306).


4. Assign Substitution Form (org admin)

Contract: assign-substitution.dto.ts:4-37; submit POST /leave/substitutions (leave.controller.ts:73-77).

FieldControlRequiredServer rule
leaveRequestIdhidden (from context)@IsMongoId() :6-7; must exist 404 :225-226; must be approved 409 :227-230
substituteTeacherIdteacher search picker@IsMongoId() :10-11; clash check :241-250
classIdclass picker@IsMongoId() :14-15
subjectIdsubject picker@IsMongoId() :18-19
datedate picker@IsDateString() :22-23; should fall inside approved range (client hint only — gap)
startTimetime picker HH:mm@IsString() :26-27
endTimetime picker HH:mm@IsString() :29-30; start < end (client; implied by timeOverlaps :314-321)
notesmultiline@IsOptional() @IsString() :34-36

Error mapping

HTTPSourceUI
409Leave request must be approved before assigning a substitution. :228-229disable form; back to list
404No teacher record found for the leave requester. :236-237toast, block
409Substitute teacher already assigned in this time slot. :247-248inline under time fields

5. Form system rules (all forms)

  • Validate on submit + on-field-blur; errors in live regions; focus first invalid.
  • Disable submit while loading; never double-submit (idempotency on POSTs is server-side concern — clients retry only on explicit user action).
  • Offline: request/decision forms block (they mutate server state); read-only screens degrade to cache.
  • All text via i18n keys (00-shared/09); dates localized per user locale.