14 — QA Checklist (Staff Module)
- 1. Uniqueness & duplicates
- 2. Department / designation delete with members
- 3. Deactivate rules
- 4. Status & enum fidelity
- 5. Pagination
- 6. Envelope & errors
- 7. Cross-module joins
- 8. Analytics
(proposed) - 9. Accessibility (shared baseline applied)
- 10. Performance & device matrix (shared budgets)
Module-specific QA items on top of 00-shared/10_QA_Baseline.md. Every item is derived from backend behavior;
(proposed)marks client-side choices.
1. Uniqueness & duplicates
-
Creating two staff with the same
employeeNumberin one tenant → second gets 409DUPLICATE_RESOURCEwith the exact message (staff.service.ts:31-36); inline error shown on the field; first record intact. -
Same
employeeNumberin different tenants succeeds (index is{tenantId, employeeNumber}—staff.schema.ts:57); cross-tenant isolation verified (E2E pattern:p1-school.e2e-spec.ts:445-459uses unique stamps). -
Same
userIdtwice in one tenant → 409 via unique index (staff.schema.ts:58) — a user can have only one staff profile per tenant. -
Duplicate department
name→ 409 (department.service.ts:23-25); duplicate designationname→ 409 (designation.service.ts:25-28). -
Re-using a deleted (soft-deleted)
employeeNumber→ still 409 (index includes soft-deleted rows —base.repository.ts:20-30filters reads, not the unique index) — document in deactivate confirm copy.
2. Department / designation delete with members
-
Deleting a department that has staff referencing it succeeds server-side
(no guard in
department.service.ts:62-65) — members'departmentIdnow dangles. Confirm dialog must warn (OQ-4). -
Same for designations (
designation.service.ts:65-68) and for department→designation links (designation.schema.ts:9-10). -
Detail screens render dangling refs as "—" (resolve via
GET /departments/:id→ 404 →(proposed)null render). -
Deleting a department that is another entity's
headId(staff as head) is not blocked — head ref dangles (department.schema.ts:15-16).
3. Deactivate rules
-
DELETE /staff/:idon an existing record → 200, row gone from list and detail 404 afterwards (base.repository.ts:68-74,staff.service.ts:93-104). -
Second
DELETEon same id → 404 (staff.service.ts:94-95); UI shows "already deactivated" without crash. -
Soft-deleted staff excluded from list and count (
base.repository.ts:20-30,53-55) →meta.totalItemsshrinks. -
Deactivate requires
staff.delete; without it the action is hidden (permissions.constants.ts:22; client gate — server RBAC pending OQ-1). -
No restore endpoint exists — QA must not spec an undo in UI
(
base.repository.ts:68-74; OQ-8).
4. Status & enum fidelity
-
Status badge shows exactly the 4 enum values (
staff.schema.ts:7-12); employment type exactly 4 (staff.schema.ts:14-19). -
Create never sends
status(not increate-staff.dto.ts); server respondsactive(staff.service.ts:39). -
Empty
employmentTypeon create → responsefull_time(staff.service.ts:40-41). -
statusfree-string risk: DTO validates only@IsString(update-staff.dto.ts:35-38) — a bogus status is persisted; client must restrict dropdown to enum values (OQ-9). -
levelnon-integer (e.g."2.5") → 400VALIDATION_ERRORwith details (designation.dto.ts:14-17;http-exception.filter.ts:103-107).
5. Pagination
-
page< 1 → 400;limit> 100 → 400 (pagination-query.dto.ts:6-19). -
Empty
totalItems→meta={page:1, limit:20, totalItems:0, totalPages:1, hasNext:false, hasPrevious:false}(pagination-query.dto.ts:46-54). -
Page controls/infinite scroll respect
meta.hasNext/hasPrevious; no duplicate requests for the same page (perf budget 00-shared/10 §1). -
qandsortsent but ignored — QA labels filters "filtering loaded results" (OQ-2); no crash on anysortvalue. -
Cross-check: staff list query params match
p1-school.e2e-spec.ts:461-470.
6. Envelope & errors
-
Every success payload:
success:true, message:"OK", data, meta?,timestamp,requestId(response-envelope.interceptor.ts:47-60). -
404 on staff/department/designation returns
RESOURCE_NOT_FOUND(http-exception.filter.ts:31), never exposes existence of cross-tenant ids. -
Invalid ObjectId in
:id→ 400 (http-exception.filter.ts:47-48,91-92). -
401 without Bearer token (
jwt-auth.guard.ts:36-38) → client refresh flow.
7. Cross-module joins
- S2 resolves department/designation names; a soft-deleted catalog entry renders "—" (404 on resolve).
-
S3 user picker requires a
userId(create-staff.dto.ts:5-7) — form cannot submit without one. -
Teachers module shares the catalogs (
teacher.schema.ts:22-26) — renaming a department here updates teacher displays on next fetch (no server denormalization).
8. Analytics (proposed)
-
staff.list.view/search/filter,staff.create.submit|success|duplicate,staff.update.submit|success,staff.deactivate.confirm|success,department.create.success|duplicate,designation.create.success|duplicatefire once per action (00-shared/10 §8 naming).
9. Accessibility (shared baseline applied)
- Status never color-only (icon + label) (00-shared/09 §9).
- TalkBack/VoiceOver walkthrough: create → deactivate journey without sight (00-shared/09 §12).
- Keyboard-only: chips, menus, dialogs operable; focus ring visible; ESC closes (00-shared/09 §6).
- Text scale 2×: employee-number rows and form grids reflow, no clipping (00-shared/09 §4).
- Dialog focus trap; focus returns to the deactivate trigger on cancel (00-shared/09 §6).
10. Performance & device matrix (shared budgets)
- Staff list first frame ≤ 300 ms cached / ≤ 2 s network (00-shared/10 §1).
-
0 dropped frames scrolling 500-row roster (profiled);
ListView.builderonly. - Verified on device matrix P0 (00-shared/10 §4): phone/tablet/desktop, light+dark, goldens at 3 sizes.