14 — QA Checklist (Biometric Module)
- 1. Functional — ingest pipeline (REAL today)
- 2. Functional — device sync (
(planned); queue stub today) - 3. Functional — device CRUD
(planned) - 4. Functional — verify check-in
(planned) - 5. Template enrollment & storage
(planned — OQ-3) - 6. False-match / verification quality
(planned) - 7. Device sync failures & health
- 8. Visual / layout
- 9. Accessibility (00-shared/09)
- 10. Performance
- 11. Offline & network (10 §2)
- 12. Permissions & security
- 13. Localization
- QA scripts
Module QA specific to framework + shared 00-shared/10. Every check derives from a specific backend behavior or blueprint rule so failure analysis is direct. The first block is testable today; the rest activates as planned endpoints land.
1. Functional — ingest pipeline (REAL today)
-
POST /api/v1/biometric/ingestwith valid body → 201, returned doc hasstudentId/deviceId/timestamp/mode+tenantIdfrom JWT (biometric.controller.ts:14-18,biometric.service.ts:14-16). -
400 on bad
studentId(non-MongoId) / missingdeviceId/ non-ISOtimestamp(create-biometric-log.dto.ts:4-20). -
modeoptional; omitted OK; extra body fieldrawDatarejected silently or dropped — verify which (schema has it, DTO doesn't — OQ-2). - Duplicate ingest (same body twice) → two log rows (logs immutable; dedupe is derivation's job — confirm this is intended, OQ-6).
-
Tenant isolation: tenant A's log never visible via tenant B repo queries
(
BaseRepositoryscoping). -
Unauthenticated request → 401 (global
JwtAuthGuard,app.module.ts:130). -
No permission check — any authenticated user can ingest (no
@Permissions; confirm product intent, OQ-5).
2. Functional — device sync ((planned); queue stub today)
-
biometric-syncrepeatable job registered*/15 * * * *(scheduler.service.ts:70-76). - Known gap: no worker — jobs enqueue and stall. QA script: observe queue depth growth; expect 0 processed (OQ-4).
-
When worker lands: retries = 4, exponential 2000 ms (blueprint
RETRIES.md:38); exhausted jobs reach DLQ (blueprintBiometric.md:58). -
POST /biometric/devices/:id/synctriggers immediate run(planned).
3. Functional — device CRUD (planned)
-
Create: unique
(tenantId, deviceId)enforced (biometric-device.schema.ts:36); duplicate → 409. -
statusrestricted toactive|inactive|offline(:7-11); defaultactive(:24-25). -
PATCH partial update;
configobject round-trips.
4. Functional — verify check-in (planned)
-
Punch timeline matches
biometric_logsindex order(tenantId, studentId, timestamp -1)(biometric-log.schema.ts:26). -
AttendanceSource.BIOMETRICrows render "source: biometric" (attendance.schema.ts:18). -
Mismatch verdict appears when punch exists but no derived attendance (derivation
gap — currently guaranteed, since derivation is
(planned)). - No-punch day → clear evidence-absent state (never "absent" verdict without proof).
5. Template enrollment & storage (planned — OQ-3)
- Storage format decision recorded (hash / encrypted blob / vendor raw) before UI build — nothing stored today; verify no template bytes in any response.
- Template size bound defined (e.g., ≤ N KB per template) and enforced server-side.
-
"Maps to a verified student record" acceptance (
ACCEPTANCE_CRITERIA.md:39). - Enrollment overwrite requires confirm; duplicate warning surfaced.
-
Privacy/security: templates never in logs, analytics, or screenshots; encrypted
at rest; device config credentials live in
integrations, encrypted (blueprintBiometric.md:59).
6. False-match / verification quality (planned)
- Vendor SDK acceptance threshold documented; FAR/FRR targets defined before pilot.
- Dry-hand / misread failure path reaches UI (capture-fail, retry) — no silent drop.
- Mismatch between punch and attendance flagged, never auto-corrected.
7. Device sync failures & health
-
Offline device detection — nothing sets
OFFLINEtoday (blueprint health-checkBiometric.md:19unbuilt): verify who flips status once implemented. - Sync failure banner copy matches retry policy (4× exp → DLQ).
-
Catch-up punches preserve original
timestamp(blueprintCOLLECTIONS.md:1883). -
Retention:
biometric_logs> 1 year TTL+archive (blueprintDATA_RETENTION.md:25); dispute UI explains vanished records.
8. Visual / layout
- Hub reads at a glance (3-device summary ≤ 2 s); offline is banner-grade, not badge-grade.
- Device/punch rows stable width (badge 72 dp fixed) — no jitter on refresh.
- Dark-light parity on all state colors (11 §5).
9. Accessibility (00-shared/09)
- TalkBack/VoiceOver: hub summary + sync results + verdicts announced (live regions).
- Keyboard-only desktop: register form TAB order; menus operable.
- Timeline nodes individually focusable; raw payload reader labeled read-only.
- Contrast: state chips 3:1, body 4.5:1; reduced-motion → fades only.
10. Performance
-
Ingest p95 < 1 s (PRD
PRODUCT_REQUIREMENTS_DOCUMENT.md:136). -
Log list paginated (high-volume insert-only collection, blueprint
INDEXING.md:68); no full-scan client fetches. - Memory stable over long log scrolling.
11. Offline & network (10 §2)
- All writes blocked offline (banner + disabled CTA); reads cached last-good.
- Verify verdicts never cached — offline = blocked, not stale.
- Sync retry no-op if already running (single-flight).
12. Permissions & security
-
Route guards: Devices subtree needs
biometric.device.manage; Logs subtree needsbiometric.log.read(permissions.constants.ts:41-43). -
biometric.syncpermission missing from constants (blueprintBiometric.md:67) — decide name before sync UI ships. - Tokens never logged; ingest bodies never in analytics.
- No template/biometric data on student-parent surfaces (privacy posture).
- Machine ingest path uses dedicated token, not user rate tiers (OQ-5).
13. Localization
- All strings i18n; status words (Active/Inactive/Offline) translatable, not hardcoded.
- Timestamps locale-aware (relative + absolute).
QA scripts
- Golden per component (light/dark × phone/tablet/desktop × key states).
- E2E (when endpoints land): register device → sync → ingest → verify check-in → dispute → attendance hop.
- Security smoke: cross-tenant ingest attempt (expected: tenant-scoped rejection); unauthenticated ingest (401); template response leak check.
- Pipeline drill: kill device mid-sync → expect 4 retries → DLQ → replay.