08 — Form Specifications (Reports Module)
- 1. Generate report — field table
- 2. Conditional visibility
- 3. Client-side validation rules
- 4. Submit payloads (examples)
- 5. Server-side error mapping
- 6. Accessibility / behavior
The single form: Generate Report (S2). Fields mirror
GenerateReportDto(generate-report.dto.ts:5-34). Field-level contract, validation, and conditional visibility per report type.
1. Generate report — field table
Server DTO: generate-report.dto.ts:5-34. All params @IsOptional; only
type is required and enum-validated (:6-8).
| Field | Control | Type | Required (DTO) | Required (service) | Notes |
|---|---|---|---|---|---|
type | fixed selector (from catalog) | enum | ✅ | — | 3 values (report-job.schema.ts:7-11) |
studentId | student picker | MongoId | ❌ | ✅ for report_card | reports.service.ts:91 — client must require |
classId | class picker | MongoId | ❌ | ❌ | attendance filter reports.service.ts:118 |
examId | exam picker | MongoId | ❌ | ✅ for report_card | reports.service.ts:91 |
startDate | date picker | string | ❌ | ❌ | $gte filter reports.service.ts:120-121 |
endDate | date picker | string | ❌ | ❌ | $lte filter reports.service.ts:122 |
DTO format checks: @IsMongoId on id fields (:11-13,17-19,22-23),
@IsString on dates (:27-33) — no ISO/date-format validation server-side.
2. Conditional visibility
| Type | Visible fields | Hidden |
|---|---|---|
report_card | studentId, examId | classId, dates |
attendance_summary | classId (optional), startDate, endDate (optional) | studentId, examId |
fee_summary | none — info card | all |
Hidden fields must NOT be sent (server echoes params blindly:
reports.service.ts:31-33; sending junk pollutes the job doc).
3. Client-side validation rules
report_card:studentId+examIdrequired before submit — the service fails the job asynchronously otherwise:"studentId and examId required"(reports.service.ts:91). This is the only real required rule.startDate ≤ endDate(client check; server does no comparison —reports.service.ts:119-123builds a range regardless).- Dates serialized ISO
YYYY-MM-DD(server treats as strings,reports.service.ts:120-122). - No duplicate submit while in flight (server has no idempotency key —
each POST = new job,
reports.service.ts:31-43).
4. Submit payloads (examples)
{ "type": "report_card", "studentId": "64f…", "examId": "65a…" }
{ "type": "attendance_summary", "classId": "64e…", "startDate": "2026-08-01" }
{ "type": "fee_summary" }
5. Server-side error mapping
| Failure | Source | Client handling |
|---|---|---|
400 invalid type | DTO @IsEnum (:6-8) | inline, catalog shouldn't produce it |
| 400 malformed id | @IsMongoId (:11-13) | inline field error |
| 429 rate limit | global (00-shared/07) | countdown, no auto-retry |
| 401 expired token | JWT guard (reports.controller.ts:9) | silent refresh → resubmit |
| 5xx | filter (http-exception.filter.ts) | snackbar + form kept (re-POST safe) |
job failed (async) | reports.service.ts:79-82 | surfaced on S4, NOT the form |
6. Accessibility / behavior
- Picker fields: searchable dropdowns; semantics "select
- Dates via
AppDatePicker(00-shared/03), range constraint (2). - Keyboard:
TextInputAction.nextchain; submit on last fielddone(mobile). - Errors: inline + live-region announcement, focus first invalid field.