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

Verification baseline for dashboard screens. Builds on 00-shared/10 (QA baseline) and 00-shared/09 (a11y). Items cite the source they guard.


1. Data correctness (what the numbers mean)

  • Students card shows active-only count (status:'active'dashboard.service.ts:31), not all students.
  • Attendance is today-only ({$gte: startOfDay, $lt: tomorrow}:34); rate = server-rounded present/total×100, 0 when no records (:57-64).
  • Finance card counts only issued|partial|overdue invoices (:36-37) and sums totalAmount − paidAmount (:45-48); currency formatted INR.
  • Client never recalculates; it formats only (09_User_Behaviour.md B9) — assert in widget tests that the raw payload values are displayed verbatim.
  • Zero states are real zeros, not errors (:31-33,:64).

2. Role gating & permission behaviour

  • With org_admin (all perms — role.schema.ts:23): full overview renders.
  • Roles without dashboard.read (teacher :31, staff :39, accountant :47, parent :55, student :63): dashboard route hidden, no 403 dead-end (00-shared/06 §5).
  • Finance widgets must be role-restricted when server-side widget filtering ships (planned) (Dashboard.md:52); accountant finance-only layout (planned).
  • Customize entry visible only with dashboard.widget.manage (permissions.constants.ts:38); absent permission → entry not rendered.
  • Open question: RBAC guard is not yet enforced on GET /dashboard/overview (dashboard.controller.ts:8 — JwtAuthGuard only) — track enforcement (planned) (permissions audit, IMPLEMENTATION_PLAN.md Phase 5).

3. Caching staleness (critical)

  • Server TTL 60 s (Dashboard.md:41) — verify the overview key sl:{tenantId}:dashboard:overview expires on time (planned); today the service live-scans (dashboard.service.ts:24-38) — regression guard: if/when caching lands, assert no live scan on warm cache.
  • Event invalidation: after AttendanceMarked / PaymentRecorded / InvoiceGenerated / ResultPublished (Dashboard.md:34) the next fetch returns fresh data (planned).
  • Client: stale data past 60 s shows StaleBanner with correct age; ≥10 min → offline treatment (06_Screen_Specifications.md §1.3).
  • Client cache never written on error; last-good survives refresh failure.
  • WS-triggered refetch is debounced (2 s) — bulk attendance marking (many events per second) coalesces to ≤ a few requests (10_Interaction_Specification.md §4).
  • Poll budget: 60 s poll + pull + WS ≤ api tier 100/min (12_API_Mapping.md rate limits).

4. Interaction states

  • First load: skeletons only, no partial numbers; failure → AppErrorState + retry.
  • Pull-to-refresh: no skeleton flash; success silent, failure keeps numbers + snackbar ≥ 4 s.
  • Single-flight: double pull/in-flight triggers coalesce, no duplicate requests.
  • KPI tap drills to owning module with matching filters (issued/partial/overdue:36-37).
  • Back from drill: dashboard refreshes by staleness check, scroll preserved.
  • Customize (planned): optimistic toggle rollback on failure; conflict (409) reload; per-widget saving indicator.

5. Accessibility (per 00-shared/09)

  • Chart summaries: every ChartCard has a text caption + semanticsLabel ("Attendance 93% today, 812 of 874 present") — screen readers never hit a silent chart (06_Screen_Specifications.md §1.5).
  • KPI card semantics: value-first single node ("93 percent, Attendance"), button when tappable.
  • Live region announces KPI deltas ≥ 1% after WS/poll updates; silent below.
  • Trend colour never sole signal: ▲/▼ glyphs + hidden text (07_Component_Library.md §2).
  • Touch targets ≥ 48 dp; Tab order cards → charts → AppBar actions.
  • Dynamic type 200%: KPI row reflows vertical, no overflow; charts keep aspect, caption reflows.
  • Dark/light AA contrast for all tokens incl. chart series (11_Design_System_Mapping.md §8).

6. Performance

  • Dashboard paints KPI values before charts (values-first, 09_User_Behaviour.md B1); charts below fold load non-blocking.
  • No jank on WS value swap: AnimatedSwitcher 200 ms only; no full-list rebuild — cards keyed by widget id.
  • Skeleton shimmer disabled on reduceMotion (00-shared/02 §6).
  • Poll timer paused when backgrounded / route not active.
  • One in-flight request at a time (single-flight) — no request storms.
  • Rebuilds: KpiRow children const-eligible where possible; Overview compares via == to skip rebuilds.

7. Offline & degraded

  • Offline: last-good payload + AppOfflineBanner; retry works after reconnect.
  • No offline writes (module is read-only today; customize (planned) disabled offline).
  • WS reconnect handled by socket layer; poll covers gaps; no duplicate refresh on reconnect + timer overlap (coalesce).

8. Blueprint-conformance regressions to track

  • "KPIs served from Redis, never live-scanned on request" (Dashboard.md:49) — currently violated by the service; track until the caching layer lands (01_Product_Overview.md §3 gap).
  • "Cache rebuilt by scheduled worker + on relevant events" (Dashboard.md:50) — no worker exists (planned).
  • "Role determines which KPIs are visible" (Dashboard.md:52) — enforcement (planned).