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

All create/update/assign forms. Validation mirrors DTOs exactly (create-vehicle.dto.ts, create-driver.dto.ts, create-route.dto.ts, assign-route.dto.ts; updates are PartialTypes of the creates - update-*.dto.ts). Server is the source of truth; client validates for latency, server for correctness.

Legend: * required. All forms: keyboard-avoidance, autofill where noted, submit button disabled until valid, loading state on submit.


1. Vehicle Create Form (create-vehicle.dto.ts:5-42)

FieldTypeRequiredValidation (DTO)Notes
plateNumbertext*IsString (:7-8)trim; unique/tenant (vehicle.schema.ts:50); 409 inline (transport.service.ts:38-45)
modeltext*IsString (:11-12)
capacitynumber*IsNumber @Min(1) (:15-17)step 1; warn if > 80 (client heuristic)
typesegmented*IsEnum(VehicleType) (:19-21)bus / van / car (vehicle.schema.ts:7-11)
yearnumber-IsNumber @IsOptional (:24-26)
colortext-IsString @IsOptional (:28-31)
insuranceExpirydate-string @IsOptional (:33-36)note: schema prop declared String, typed Date (vehicle.schema.ts:42-43) - send ISO string
notesmultiline-IsString @IsOptional (:38-41)

Submit: POST /transport/vehicles (transport.controller.ts:30-34). Update: same fields all optional (update-vehicle.dto.ts:4), PATCH /transport/vehicles/:id (transport.controller.ts:48-52).

2. Driver Create Form (create-driver.dto.ts:4-50)

FieldTypeRequiredValidation (DTO)Notes
firstNametext*IsString (:6-8)autofill given-name
lastNametext*IsString (:10-12)autofill family-name
licenseNumbertext*IsString (:14-16)unique/tenant (driver.schema.ts:50); 409 inline (transport.service.ts:177-184)
phonetel*IsString (:18-20)unique/tenant (driver.schema.ts:51); 409 inline (:185-190)
emailemail-IsEmail @IsOptional (:22-24)autofill email
licenseExpirydate-IsDateString @IsOptional (:27-29)parsed to Date server-side (transport.service.ts:193-196)
addresstext-IsString @IsOptional (:31-34)autofill street-address
emergencyContacttext-IsString @IsOptional (:36-39)tel keyboard
joinedAtdate-IsDateString @IsOptional (:41-44)parsed to Date (transport.service.ts:192-193)
notesmultiline-IsString @IsOptional (:46-49)

Submit: POST /transport/drivers (transport.controller.ts:90-94). Update: PATCH /transport/drivers/:id (transport.controller.ts:108-112), update-driver.dto.ts:4.

3. Route Create Form (create-route.dto.ts:21-60)

FieldTypeRequiredValidation (DTO)Notes
nametext*IsString (:23-25)unique/tenant (route.schema.ts:44); 409 inline (transport.service.ts:113-116)
startPointtext*IsString (:27-29)
endPointtext*IsString (:31-33)
stopsRouteStopEditor-IsArray @ValidateNested({each}) @Type(RouteStopDto) (:34-39)items {name: IsString, order: IsNumber} (:11-19)
vehicleIdResourcePicker-IsString @IsOptional (:41-44)converted to ObjectId (transport.service.ts:117-119)
driverIdResourcePicker-IsString @IsOptional (:46-49)converted to ObjectId (transport.service.ts:119)
estimatedDurationnumber-IsNumber @IsOptional (:51-54)minutes
notesmultiline-IsString @IsOptional (:56-59)

Submit: POST /transport/routes (transport.controller.ts:60-64). Update: PATCH /transport/routes/:id (transport.controller.ts:78-82), update-route.dto.ts:4; ObjectId conversion also on update (transport.service.ts:159-161).

4. Assign Student to Route (assign-route.dto.ts:4-26)

FieldTypeRequiredValidation (DTO)Notes
routeIdResourcePicker*IsString (:6-8)
studentIdStudentPicker*IsString (:10-12)from students module; filter transportRequired toggle (student.schema.ts:53-54)
shiftShiftPicker*IsEnum(['morning','evening','both'] as const) (:13-15)
stopNametext-IsString @IsOptional (:17-20)suggest from route stops
notesmultiline-IsString @IsOptional (:22-25)

Submit: POST /transport/assign (transport.controller.ts:120-124). Server sets assignedAt = now, status default active (transport.service.ts:259-266, route-assignment.schema.ts:23-28). 409 duplicate (route, student) inline (transport.service.ts:252-258).

5. Form behaviour (shared)

  • 409 conflict handling: ConflictFieldError under the offending field with server message verbatim (07 §8); never silently retry.
  • Debounce: search-as-you-type fields (student picker) 300 ms; single-flight requests (00-shared/11).
  • Dirty tracking: updates send only touched fields (PartialType semantics, update-*.dto.ts); unchanged optional dates re-sent as-is to avoid accidental clearing (transport.service.ts:159-161, 228-234 re-parse only when present).
  • Offline: submit blocked with AppOfflineBanner; no queue (no offline mutation contract).
  • Success: navigate to detail + snackbar; events VehicleCreated, RouteCreated fire server-side (transport.service.ts:47-57, 121-128).