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

Exact field-by-field form contracts. Validation mirrors server DTOs (class-validator); field sources are cited. Shared form UX: labels linked, per-field errors under fields (00-shared/06 §5), double-submit guard (00-shared/08 §6), keyboard types per field.


1. Form rules (all forms)

  • Required = server-required (server is authoritative; client pre-validates).
  • MongoId fields render as dropdowns/pickers fed by the owning module (academics grade/section/academicYear/class; staff for assignment/panel) — cross-module reads (planned) where endpoints are missing; fallback: raw-id field hidden in "Advanced".
  • 400 VALIDATION_ERROR details map field → message under the matching field.
  • Optimistic updates: never for create/submit; only for safe toggles (00-shared/06 §3.5).

2. Lead Form (S3) — create POST /crm/leads / edit PATCH /crm/leads/:id

FieldReqControlValidation (server)DefaultSource
firstName✅text@IsString—create-lead.dto.ts:12-14
middleName—textoptional string—create-lead.dto.ts:16-19
lastName✅text@IsString—create-lead.dto.ts:21-23
email✅text (.emailAddress, autofill email)@IsEmail; stored lowercase (lead.schema.ts:52-53)—create-lead.dto.ts:25-27
phone—text (.phone, autofill tel)optional string—create-lead.dto.ts:29-32
source—dropdownenum 6 valueswebsite (lead.schema.ts:58)create-lead.dto.ts:34-37
status—dropdown (Advanced)enum 5 valuesnew (lead.schema.ts:61)create-lead.dto.ts:39-42
gradeId—dropdown@IsMongoId—create-lead.dto.ts:44-47
sectionId—dropdown@IsMongoId—create-lead.dto.ts:49-52
academicYearId—dropdown@IsMongoId—create-lead.dto.ts:54-57
classId—dropdown@IsMongoId—create-lead.dto.ts:59-62
notes—multilineoptional string—create-lead.dto.ts:64-67
assignedTo—staff dropdown@IsMongoId—create-lead.dto.ts:69-72

Edit-only fields: closedReason (string, update-lead.dto.ts:77-80).

Conditional logic

  • status = closed → reveal closedReason (client); server auto-stamps closedAt when reason absent (crm.service.ts:94-96).
  • status = converted → blocked in form; Convert flow only (S4).
  • Placement warning when editing without grade/year/class: "Set all three to enable conversion" (rule at crm.service.ts:145-149).
  • Submit → 409 duplicate email banner (crm.service.ts:42-47): "A lead with this email already exists" + "Edit details" / "Go back".

3. Admission Form (S7) — create POST /crm/admissions

FieldReqControlValidation (server)Source
firstName✅text@IsStringcreate-admission.dto.ts:6-8
middleName—textoptionalcreate-admission.dto.ts:10-12
lastName✅text@IsStringcreate-admission.dto.ts:14-16
email✅text .emailAddress@IsEmail; stored lowercase (admission.schema.ts:102-103)create-admission.dto.ts:18-20
phone—text .phoneoptional stringcreate-admission.dto.ts:22-25
gradeId—dropdown@IsMongoIdcreate-admission.dto.ts:27-30
academicYearId—dropdown@IsMongoIdcreate-admission.dto.ts:32-35
classId—dropdown@IsMongoIdcreate-admission.dto.ts:37-40
notes—multilineoptional stringcreate-admission.dto.ts:42-45
  • Update form (PATCH /crm/admissions/:id, update-admission.dto.ts = PartialType) reuses this table; submit blocked client-side when status closed (server 400: admission.service.ts:257-269).
  • Note: no admission status field — server always creates submitted (admission.service.ts:43).

4. Follow-Up Form (S2 sheet) — POST /crm/leads/:id/follow-ups

FieldReqControlValidationSource
note✅multiline@IsStringcreate-follow-up.dto.ts:5-7
scheduledAt✅datetime picker@IsDateString (ISO)create-follow-up.dto.ts:9-11
completedAt—toggle + datetime@IsDateString optionalcreate-follow-up.dto.ts:13-16
  • Display uses followUps[] (lead.schema.ts:24-39); createdBy set server-side from token (crm.service.ts:111).

5. Campaign Form (S11) — POST /crm/campaigns

FieldReqControlValidationDefaultSource
name✅text@IsString—create-campaign.dto.ts:5-8
description—multilineoptional—create-campaign.dto.ts:10-13
type—dropdownenum 5email (campaign.schema.ts:30)create-campaign.dto.ts:15-18
status—dropdownenum 4draft (campaign.schema.ts:33)create-campaign.dto.ts:20-23
startDate—date picker@IsDateString—create-campaign.dto.ts:25-28
endDate—date picker@IsDateString—create-campaign.dto.ts:30-33
  • Client: endDate ≥ startDate (no server check today — flagged).
  • No edit form (no PATCH endpoint) — (planned).

6. Document Upload Form (S6 sheet) — POST /crm/admissions/:id/documents

FieldReqControlValidationSource
type✅dropdownenum tc/marksheet/certificate/photo/othercreate-admission-document.dto.ts:5-8; admission.schema.ts:27-33
fileId✅file pick → storage upload (storage provider; upload endpoint (planned))@IsStringcreate-admission-document.dto.ts:10-12
filename—auto from fileoptional string, defaults to fileId server-side (admission.service.ts:107)create-admission-document.dto.ts:14-17
  • Server appends doc + auto-transitions submitted → documents_pending (admission.service.ts:112-114).

7. Interview Form (S8 sheet) — POST /crm/admissions/:id/schedule-interview

FieldReqControlValidationDefaultSource
scheduledAt✅datetime picker@IsDateString—schedule-interview.dto.ts:11-14
panel—staff multi-pick chipsarray of @IsMongoId—schedule-interview.dto.ts:16-20
mode—segmented online/offlineenumoffline (admission.schema.ts:76-78)schedule-interview.dto.ts:22-25
feedback—multilineoptional string—schedule-interview.dto.ts:27-30

8. Decision Form (S9 dialog) — POST /crm/admissions/:id/decision

FieldReqControlValidationSource
decision✅radio/segmentedenum approve/reject/waitlistadmission-decision.dto.ts:4-8,10-13
comment—multilineoptional stringadmission-decision.dto.ts:15-18
  • Offered only from decidable statuses (admission.schema.ts:20-25); server 400 otherwise (admission.service.ts:141-145).
  • Reject/waitlist warnings per 06 §S9.

9. Autofill & accessibility

  • Lead/admission identity fields: given-name, family-name, email, tel autofill hints; labels linked; group headers (Applicant / Contact / Placement / Assignment); first-invalid focus; 409 banner in live region.