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 (Feature Flags Module)

Module QA specific to the framework + shared 00-shared/10. Every check derives from a specific backend behavior so failure analysis is direct.


1. Functional

  • GET /feature-flags returns all tenant flags sorted by key asc (feature-flags.service.ts:11), plain array, no meta.
  • GET /feature-flags?module=channels returns only matching module (feature-flag.repository.ts:24-26).
  • GET /feature-flags/enabled returns only enabled:true docs (feature-flag.repository.ts:28-30).
  • GET /feature-flags/:key returns the doc; unknown/soft-deleted key → 404 RESOURCE_NOT_FOUND ("Feature flag "" not found." — feature-flags.service.ts:29).
  • PUT /feature-flags with new key creates (upsert:true, feature-flag.repository.ts:38-42); same key updates (merge).
  • Upsert persists exactly enabled + labeldescription/module silently dropped (feature-flag.repository.ts:40): verify the editor warning banner exists and no "saved" claim is made for those fields.
  • Upsert with missing key or non-boolean enabled → 400 VALIDATION_ERROR with details[] (update-feature-flag.dto.ts:5-11).
  • PUT /feature-flags/bulk (array body) applies sequentially (feature-flags.service.ts:40-44); client shows per-row results; a 5xx mid-list leaves earlier items applied (no rollback) → "retry failed" works.
  • Bulk body with one invalid item → whole-body 400 with array-item errors in details[].
  • DELETE /feature-flags/:key soft-deletes (flag disappears from all three list endpoints); second delete of same key → 404 (feature-flags.service.ts:47-52).
  • Delete → re-create same key → expect E11000 → 500 today (OQ-4); QA must verify the current error copy is shown, not a raw crash.
  • Org overlay: PATCH /organizations/:id/feature-flags replaces the whole map (organizations.service.ts:149-151) — QA: PATCH {a:true} then {b:true}a is gone. Merge-first client behavior verified.
  • Flag written via PUT /feature-flags does not appear in org.metadata.featureFlags and vice versa (two disconnected surfaces — OQ-2).
  • Cross-tenant: org A's flag list never contains org B's keys (scoped reads, base.repository.ts:20-30).
  • JWT-only gate: flag endpoints work with a valid JWT of any role (no @Permissions — OQ-5) — QA documents current behavior; UI affordances still follow feature-flags.* (target contract).
  • Rate limit: > 100 req/min on flags → 429 (rate-limit.constants.ts:6).

2. Visual / layout

  • List groups by module; null-module flags land in an "Ungrouped" bucket (schema allows absent module, feature-flag.schema.ts:21-22).
  • Dark/light parity: switches, selected rows, bulk results (no hardcoded colors).
  • Long keys (a.very.long.module.namespace.key) wrap/ellipsize at 200% text scale without clipping.
  • Bulk results row = icon + reason text (never color-only, 09 §9 shared).

3. Accessibility (00-shared/09)

  • TalkBack: browse → toggle → detail → editor save → bulk apply, fully operable without sight.
  • VoiceOver separately.
  • Switch rows announce key + state (Semantics(toggled:)); live region announces "Saving…" and bulk progress/results.
  • Editor: labels linked, first-invalid focus jump, error announced.
  • Gated (hidden) features are removed from semantics — screen readers never read a disabled feature.
  • Keyboard-only desktop: chips → rows → FAB order, visible focus ring.
  • Contrast: body 4.5:1, chrome 3:1; mono keys ≥ 4.5:1 on surfaceVariant.
  • Reduced motion: no stagger/hero/shake.

4. Performance

  • List load (cold) skeleton ≤ 200 ms, content ≤ 2 s (00-shared/10 §1).
  • Toggle round-trip p95 < 1 s (single findOneAndUpdate, feature-flag.repository.ts:38-42).
  • Bulk ≤ 20 flags < 3 s (sequential loop, feature-flags.service.ts:40-44).
  • FeatureFlagsCubit TTL refresh does not rebuild gated screens wholesale (selector-based rebuilds).
  • No duplicate parallel flag requests on screen open + TTL tick.

5. Offline & network (10 §2)

  • Offline → list renders last-good + banner; switches disabled (no silent writes).
  • Gating offline → last-good set; no "disabled" flash from error states.
  • 5xx on toggle → rollback + snackbar with requestId.
  • 429 → countdown, no auto-retry.
  • Reconnect → immediate FeatureFlagsCubit.refresh().

6. Tablet / desktop

  • Master-detail list↔detail at ≥ 840 px.
  • Hover row tint, tooltips (switch disabled reason), right-click menu.
  • Keyboard: Space toggles switch; Ctrl/Cmd+N new; Esc closes sheet/dialog.

7. Localization

  • All strings via i18n keys; module names/labels are tenant data (rendered as-is, not translated).
  • Date/time locale for createdAt/updatedAt.
  • Long localized strings in editor warning banner reflow at 200% scale.

8. Permissions

  • Server: flag endpoints accept any JWT today (OQ-5) — QA confirms and files the gap.
  • Client: routes/affordances hide without feature-flags.read; toggle/edit/bulk/delete without feature-flags.update/.delete (target contract — UI works either way).
  • Org overlay uses organization.update-adjacent gating (org settings context).

9. Dark mode

  • Full visual pass; selected rows, bulk ✓/✕, warning banner (tertiaryContainer) contrast.

10. Animations

  • Tokens only; reduced-motion respected; toggle rollback never animates a false state.

11. Security

  • Keys/values never logged; no tenant data in analytics events (only key names where agreed (proposed)).
  • Flag values not cached in plain-text prefs — in-memory only (13 §5).
  • No tenantId sent in bodies (server derives from JWT; upsert uses requireTenantId(), feature-flag.repository.ts:37).

12. Server-backed edge mirrors

  • 404 detail for deleted flag → "Flag not found — it may have been deleted".
  • E11000 re-create → friendly error (OQ-4).
  • Full-replace org overlay preserved client-side (merge-before-PATCH).
  • isEnabled('anything') with empty catalog → false everywhere (fail-closed, feature-flags.service.ts:24) — gated screens all hidden on fresh tenant.

QA scripts

  • Golden per component: AppFlagRow (on/off/pending/selected/disabled-perm), editor (create/edit/error-banner), bulk sheet (idle/applying/results), light/dark × 3 sizes.
  • E2E (device-cloud P0): login admin → browse flags → toggle → bulk 3 → delete with warning → re-create attempt (expect graceful error today) → verify gated screen hides.
  • Gating journey: teacher logs in on tenant with channels.sms off → SMS entry absent; admin enables → within TTL it appears (or on pull-to-refresh immediately).