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

14 — QA Checklist (Students Module)

Module-specific quality gates on top of 00-shared/10 (baseline applies to every item here). Each checklist row is traceable to a server behaviour cited inline.


1. Data integrity & business rules

#CheckExpectedServer source
1.1Duplicate admission numberCreate → 409 "Admission number "x" already exists."; import row → per-row errorstudent.service.ts:56-62; students-import.adapter.ts:49-54
1.2Duplicate admission via race (two clients)unique index {tenantId, admissionNumber} prevents both; one wins, other 409student.schema.ts:68
1.3Create auto-enrollresponse student + one ACTIVE enrollment with joinedAt ≈ nowstudent.service.ts:71-78
1.4Enroll closes previousold enrollment status:"transferred" + leftAt set; new ACTIVE; history append-onlystudent.service.ts:125-139; COLLECTIONS.md:1674-1677
1.5Transfer guardnon-active status → 409 with exact status in message; no enrollment change happensstudent.service.ts:175-179
1.6Graduate idempotencysecond graduate → 409 "already graduated"; status stays graduatedstudent.service.ts:207-209
1.7Archive/restore idempotencyarchive twice → 409; restore twice → 409 "already active"student.service.ts:228-230
1.8Soft delete isolationafter DELETE, student absent from list/detail/documents/history; isDeleted:truebase.repository.ts:20-30,68-74
1.9No cascade on deletedocuments/links/enrollments remain queryable by idstudent.service.ts:157-168 (no cascade)
1.10Transfer writes profileclassId/academicYearId updated; gradeId/sectionId only when providedstudent.service.ts:185-192

2. Enrollment conflict scenarios

#ScenarioExpected
2.1Enroll same class twice in a rowsecond enroll deactivates first (transferred), creates new ACTIVE — allowed by server; UI warns (no server 409) — flagged OQ-13
2.2Enroll during active transfer UIserver processes sequentially; last write wins (version increments)
2.3Concurrent PATCH + transferfindOneAndUpdate + $inc version — no lost-update corruption (base.repository.ts:57-66); UI refreshes after both

3. Document limits

#CheckExpectedSource
3.1No-file uploadrequest without file → 400 (multer)student.controller.ts:82-90
3.2Oversized fileno server limit today — must be enforced client + proxy (proposed) 10 MBOQ-9; student.service.ts:250-271
3.3Unsupported mimeno server allowlist — client (proposed) allowlist pdf/jpg/png/webpOQ-9
3.4Empty categoryallowed (optional string) — UI shows uncategorized chipupload-student-document.dto.ts:4-9
3.5Uploaded metadata correctnessfileName/mimeType/size match actual file; uploadedBy = actorstudent.service.ts:262-270
3.6List ordernewest first (createdAt desc)student.service.ts:273-279

4. Bulk import — 1000-row file (target scenario per PLAN 15.3)

#CheckExpected
4.1Valid 1000-row CSVreport {totalRows:1000, imported:1000, failed:0, errors:[]}; 1000 students + users created; no timeout → request budget: set client timeout ≥ 120 s for import (00-shared/11 §5)
4.2Header row only (0 data rows)400 "CSV must include a header row and data."
4.3Malformed CSV (unbalanced quotes)400 "Malformed CSV: could not parse file."
4.4Missing required columnper-row error "Missing required column "section"."; row number = index+2
4.5Bad email format"Invalid email format."
4.6Duplicate admission number in file (row 5 duplicates existing)row 5 failed "already exists"; other rows import
4.7Duplicate email in filefirst row creates user; second row fails "already registered" (validate pre-check) — or falls back to existing user inside create if validate missed it (race)
4.8Unknown academic year/grade/sectionper-row "Academic year "x" not found." / "Grade … not found." / "Section … not found."
4.9Grade+section with no class"No class found for grade "g" section "s"."
4.10Grade match by codegrade matched on name or code
4.11Row-level failure isolationone bad row never aborts the batch (try/catch per row)
4.12Import from non-authorized usercurrently allowed (JWT-only) — verify when RBAC lands (OQ-4)

5. Multi-tenancy & security (baseline §10)

#Check
5.1Cross-tenant :id on any endpoint → 404/403, no data leak (base.repository.ts:20-30)
5.2tenantId never in request bodies from client
5.3Duplicate email/user cross-tenant never resolves (users repo is tenant-scoped too)
5.4uploadedBy/createdBy set from JWT, never from body
5.5Soft-deleted students not returned by any scoped query
5.6Parent link of tenant A student with tenant B parent → structurally impossible (both scoped)

6. Performance budgets (baseline §1 applied)

MetricBudget
Roster first frame (cached)< 300 ms
Roster network contentskeleton ≤ 200 ms, content ≤ 2 s (page 1, limit 20)
1000-row importcompletes; client timeout 120 s+; no UI freeze (parse on isolate)
Detail loadprofile immediate; tabs lazy (documents/history only on activation)
Scroll0 dropped frames; ListView.builder + const tiles

7. Offline matrix (baseline §2 applied)

ScenarioExpected
Offline → rostercached rows + AppOfflineBanner; pull-refresh → Retry error state
Offline → create/transfer/upload/import/linkblocked with guidance (no offline queue)
Network loss mid-uploadDocumentUploadTile error + Retry; no silent corruption
Network loss mid-importrequest fails → wizard error; re-import is idempotent per-row (admission/email dedup)

8. A11y spot checks (baseline §9 + 09_Accessibility_Baseline.md)

  • Status badges: icon + text, never color-only (00-shared/09 §9).
  • Search results count in live region; "item X of Y" list position.
  • Wizard: focus first invalid field on Next; step index announced.
  • Import report: live-region summary "997 of 1000 imported".
  • Timeline: readable list semantics; badges announced.
  • Text scale 2×: no clipping in header card, tiles, report cards.
  • Dialogs trap focus; Esc/back closes; focus returns to trigger.

9. Localization & format

  • Dates via Intl (admissionDate, joinedAt/leftAt, createdAt); money none.
  • ADM numbers in mono, not localized.
  • RTL readiness (relationship chips, timelines mirror).

10. Regression pack (server-verified behaviours worth automating)

  1. create → auto-enroll → history shows 1 ACTIVE.
  2. enroll → old enrollment transferred + leftAt.
  3. transfer on archived student → 409.
  4. graduate → archive → restore sequence statuses.
  5. delete → list excludes; detail 404.
  6. import mixed file → report numbers + error strings.
  7. link parent → student missing → 404; parent missing → no error today (OQ-11 — decide and test when resolved).
  8. documents: upload → list order newest-first.
  9. pagination: page 2 offset math (skip = (page-1)*limit, student.service.ts:104).
  10. envelope: every response {success,message,data,meta?,timestamp,requestId}; every error carries code.

11. Analytics events (proposed) to smoke-test

students.list.{view,search,filter,open}, students.create.{start,step,success,failure}, students.transfer.{submit,success,failure}, students.import.{template,upload,report}, students.document.{upload,open}, students.lifecycle.{graduate,archive,restore,delete} — per 00-shared/10 §8.