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

Module checklist layered on 00-shared/10 baseline. Severity: P0 ship-blocking.


1. Functional (P0)

  • Provision: POST /organizations with name only → slug auto-derived exactly per slugify (organizations.service.ts:161-169); status = onboarding; 7 default roles seeded (organizations.service.ts:58; role.schema.ts:8-65).
  • Slug conflict → 409 DUPLICATE_RESOURCE inline; domain conflict on update with own-org exemption (organizations.service.ts:115-122).
  • Full-replace semantics: PATCH :id/settings with only {attendance} wipes academic/theme — client must always submit full object; verify no wipe path in UI (S4).
  • Full-replace flags: PATCH :id/feature-flags with {a:true} removes key b — UI must submit merged map; rollback restores prior map exactly.
  • Delete → soft-deleted org absent from GET /organizations + GET /:id (404) (organizations.repository.ts:15-19,60-66).
  • Invalid ObjectId → 400 VALIDATION_ERROR "Invalid resource identifier." (http-exception.filter.ts:47-55,92).
  • Settings collection: PUT /settings upsert idempotent; bulk PUT /settings/bulk; delete 404 path (settings.service.ts:36-41).
  • Flags catalog: upsert persists only enabled+label (feature-flag.repository.ts:32-43); delete soft.
  • Register: duplicate email 409; password <8 → 400; tokens usable immediately (auth.service.ts:54-121).
  • Pagination contract: meta.totalPages/hasNext/hasPrevious exact (pagination-query.dto.ts:41-54); page > totalPages → empty data, hasNext:false.
  • q search case-insensitive on name+slug; sort -createdAt default (organizations.service.ts:78-87).

2. Security & isolation (P0)

  • OQ-4: tenants list + tenant detail reachable by tenant admin today (unguarded controller, unscoped repo) — client MUST gate to isPlatformAdmin; server guard (planned). Test: tenant-admin token → route hidden + 403 screen.
  • Cross-tenant :id access → 404 (never 403-leak-of-existence); verify both self + platform surfaces.
  • JWT tenantId never sent in body (except public register tenantId — by design, register.dto.ts:27-29); all other requests derive from token.
  • Tokens in secure storage; no token in analytics/logs (10_QA_Baseline.md §3).
  • 5xx internals never rendered — generic + requestId only.
  • Typed-confirm delete: destructive button disabled until org name typed exactly.
  • No Idempotency-Key dependency assumed for PATCH/DELETE (retry-safe by nature); register POST is rate-limited, no auto-retry.

3. Visual & design tokens

  • No literal colors/spacing/durations in widget code (D §7); tokens only.
  • Light + dark parity on all 8 screens (surface/cards contrast ≥3:1 chrome, ≥4.5:1 text — 09 §2).
  • Status/plan badges: icon + label, never color-only (A §9); colorblind check (primary/error/success pairs with icons).
  • Slug/domain rendered mono; numerals tabular (02 §2).
  • Golden tests: 8 screens × 3 sizes × light/dark (10 §9).

4. A11y (P0 per changed screen, A §12)

  • TalkBack + VoiceOver full walkthrough: S1 → S4 save flow, S5 toggle, S8 typed-confirm.
  • Keyboard-only desktop: focus order toolbar → search → chips → list; ESC closes everything; N new tenant; typed-confirm traps focus.
  • Text scale 2×: no clipping in cards/forms/badges (S4 chip rows wrap; header wraps).
  • Toggle results announced via live region; errors announced + focus to first invalid field.
  • Color picker hex fallback; contrast warning announced.
  • Focus ring visible primary 2 dp offset 2.

5. Performance (10 §1)

  • Tenants list: skeleton ≤200 ms; content ≤2 s network; 0 dropped frames scrolling 100-row list (ListView.builder).
  • PATCH round-trip feedback ≤100 ms press-state; save spinner consistent.
  • No duplicate parallel requests for same org id (cache + single-flight).
  • Flag map merge on 50+ flags: no rebuild jank (grouped AnimatedSize, list virtualization).
  • Memory: no growth across 20 min of tab-switching (keep-alive disposal policy).

6. Offline matrix (10 §2)

ScenarioExpected
Airplane → S1/S7cached data + AppOfflineBanner + stale badge
Offline → S2/S4 submitblocked with guidance; draft kept in-memory; no silent loss on back (guard)
Offline → S5 toggleswitch disabled + banner (no offline queue)
Offline → onlineauto-refresh on next interaction; no partial writes
3G throttleskeletons, no ANR, retry works
Network loss mid-savepending → error snackbar "Couldn't save — retry"; safe retry (PATCH idempotent)

7. Tablet / desktop / foldable

  • ≥840 dp: S7 master-detail; breadcrumbs at depth ≥2; hover states; scrollbars visible.
  • 600–839 dp: S1 two-column info grid; settings tabs readable.
  • Foldable: cover + unfolded layouts no overlap; 200% text reflow.
  • Landscape tablet: keyboard doesn't cover form fields (scrollable form).

8. Localization

  • All strings via keys (app_en.arb + org-locale); server business messages mapped to keys where available, fallback for 4xx business text (07 §11).
  • Date/number formatting via Intl (academic year, created dates).
  • RTL readiness: no hardcoded alignments (badges/rows use logical direction).
  • Working-day chips localized weekday names (Sunday-first per locale).
  • Smoke strings (fr/hi/es) don't break S4 labels or S1 cards.

9. Animations & motion

  • All transitions use m-* tokens; reduced-motion: fades ≤ m-instant, no stagger/shimmer/hero.
  • No dropped frames during hero S7→S8 (profile 120 fps).
  • Haptics only per 10_Interaction_Specification.md §3; none on desktop.

10. Analytics (proposed contract)

  • Events fire per 05 inventory: organizations.overview.view, organizations.edit.save.success|error, organizations.settings.save.*, organizations.flags.toggle.{key}, organizations.tenants.list.view|search|delete.confirmed.
  • No PII beyond necessity; consent-gated (A4).

11. Regression guardrails (code facts to never break)

  • Settings/flag save always full-object (test asserts sibling keys survive).
  • Slug change flows through confirm dialog; domain conflict check compares existing.id !== id (organizations.service.ts:117).
  • Create never accepts status from client (forced onboarding, :55); update can change status.
  • Register rate limit 5/min — UI countdown, no auto-retry (auth.controller.ts:31).