Trường Số QA/12 Non-functional requirements
Trường Số · QA test suite · Phase 1 · 10/09/2026
12 · Non-functional requirements
Test cases for PRD 12. Every case names the fixture data it needs (see the dashboard fixtures table), numbered steps, and one observable expected result. Trace points to the user story or rule in the PRD.
Key facts, origin and limits
Drafted by an AI assistant in a single session on 10/09/2026 as part of the Trường Số QA suite, under the request quoted verbatim on the dashboard. A proposal for team review, not a sign-off.
Sources
- The Trường Số PRD set (Draft v1, 10/09/2026): user stories, screen tables, business rules and permission matrices, plus the Cloud theme reference.
Limits
- Phase 1 (authoring) only. Cases are executed in Phase 2 against the local build; results are recorded in
testcases.jsonandruns/run-1/, and every result field is stillnot_run. - Cases inherit any open question or inconsistency in the PRDs they trace to.
1Summary
P0
3
P1
22
P2
9
P3
4
| Type | functional | ui-ux | edge | negative | regression | flow | a11y | perf | security | i18n |
|---|---|---|---|---|---|---|---|---|---|---|
| Count | 8 | 2 | 0 | 0 | 0 | 0 | 5 | 3 | 15 | 5 |
2Test cases
| ID | Title | Type | Priority | Phase | Preconditions | Steps | Expected result | PRD trace | Data needed | Run 1 |
|---|---|---|---|---|---|---|---|---|---|---|
| TS-NFR-001 | List pages time-to-interactive and API p95 | perf | P1 | P1 | Big Center, branch A, 4G throttling in Playwright. |
| TTI ≤ 2.0 s; API p95 ≤ 400 ms per 50-row page. | 12 §2 | Fixtures below | Not run |
| TS-NFR-002 | No client-side filtering of full datasets | perf | P1 | P1 | Network log. |
| Each change issues a server request with q/filters; no request fetches more than limit rows. | 12 §2 design rules | Fixtures below | Not run |
| TS-NFR-003 | Dashboard initial JS bundle ≤ 350 KB gzipped | perf | P2 | P1 | Build output. |
| ≤ 350 KB gzipped; module routes are code-split. | 12 §2 bundle | Fixtures below | Not run |
| TS-NFR-004 | Health endpoint | functional | P1 | P1 | Server running. |
| 200 with checks for database, queue, object storage (stubbed statuses). | 12 §10 | Fixtures below | Not run |
| TS-NFR-005 | Login lockout after 5 failures | security | P1 | P1 | Login page. |
| 6th attempt refused with "Tài khoản tạm khoá 15 phút"; correct password rejected until the lock ends. | 12 §3 rate limits | Fixtures below | Not run |
| TS-NFR-006 | Write rate limit 60/min per user | security | P2 | P1 | API. |
| 61st returns 429 with Retry-After. | 12 §3 | Fixtures below | Not run |
| TS-NFR-007 | Session expiry after 30 days inactivity and password change revokes sessions | security | P2 | P1 | Two sessions for U-ACAD-A. |
| Session 2 rejected (401 → login). | 12 §3 authentication | Fixtures below | Not run |
| TS-NFR-008 | Auth token never reaches third-party origins | security | P1 | P1 | Network log on any page. |
| Auth token header only on same-origin /api/v3 proxy calls; no request to external origins carries it. | 12 §3 | Fixtures below | Not run |
| TS-NFR-009 | Security headers present | security | P1 | P1 | curl. |
| Content-Security-Policy present without unsafe inline third-party scripts; Strict-Transport-Security; cookies SameSite=Lax; X-Content-Type-Options nosniff. | 12 §3 application security | Fixtures below | Not run |
| TS-NFR-010 | Server-side permission checks (UI hiding is not relied on) | security | P0 | P1 | API as U-TEACH. |
| All return 403; nothing changes. | 12 §3 authorisation | Fixtures below | Not run |
| TS-NFR-011 | Upload security: MIME allow-list, size, signed URLs 15 min | security | P1 | P1 | Any upload point. |
| Content-sniffed rejection; size rejection; expired URL 403. | 12 §3 uploads | Fixtures below | Not run |
| TS-NFR-012 | OWASP basics: XSS in names and notes | security | P1 | P1 | Student name "<img src=x onerror=alert(1)>". |
| Rendered as text everywhere; no script executes. | 12 §3 ASVS | Fixtures below | Not run |
| TS-NFR-013 | Dependency scan clean of critical CVEs | security | P2 | P1 | Repo. |
| Zero critical. | 12 §3 | Fixtures below | Not run |
| TS-NFR-014 | Consent captured at every guardian entry point | security | P0 | P1 | Conversion wizard step 2, student form, guardian add, import, portal. |
| A consent row with type, version, granted_at, channel (web/portal/paper or import) and actor exists for each; missing consent means no external channel used. | 12 §4 Art. 11, 12 §11 | Fixtures below | Not run |
| TS-NFR-015 | Consent text is tenant-editable with FLYER default | functional | P2 | P1 | /settings (tenant or notifications). |
| New text and a new version id shown; older consents keep their version. | 12 §4 | Fixtures below | Not run |
| TS-NFR-016 | No direct messaging to students under 16 | security | P1 | P1 | S1 (age 8) with own phone field filled. |
| Recipient is always a guardian; no message row targets the student. | 12 §4 Art. 20 | Fixtures below | Not run |
| TS-NFR-017 | Marketing consent separate from service consent | functional | P1 | P1 | Lead form. |
| marketing_consent_at null then set; bulk ZNS marketing skips the first. | 12 §4 marketing consent | Fixtures below | Not run |
| TS-NFR-018 | Anonymise keeps finance for 10 years | security | P1 | P1 | S5 anonymised with a paid invoice. |
| Rows intact with "Học viên đã xoá"; PDF receipt still retrievable. | 12 §4 deletion | Fixtures below | Not run |
| TS-NFR-019 | Cross-border disclosure in consent text | functional | P3 | P1 | Default consent text. |
| Mentions storage in Singapore (ap-southeast-1). | 12 §4 cross-border | Fixtures below | Not run |
| TS-NFR-020 | Mandatory audited actions all write entries | security | P0 | P1 | Perform each: finance write, attendance edit after day, student status change, guardian contact change, permission change, personal-data export, login from a new device. |
| One entry per action with actor snapshot, action code, entity, before/after, ip, user_agent, request_id; money and status fields always included. | 12 §6, 12 §11 | Fixtures below | Not run |
| TS-NFR-021 | Audit export per tenant as CSV | functional | P2 | P1 | Owner. |
| CSV with all columns; itself logged as an export. | 12 §6 | Fixtures below | Not run |
| TS-NFR-022 | Restore drill report available | functional | P3 | P1 | Release note. |
| Written report for the release week snapshot exists (out of scope for local run; record N/A with reason). | 12 §7, 12 §11 | Fixtures below | Not run |
| TS-NFR-023 | Date and time formats | i18n | P1 | P1 | Any list. |
| dd/MM/yyyy and HH:mm 24-hour in both; timezone Asia/Ho_Chi_Minh; API stores UTC. | 12 §8 | Fixtures below | Not run |
| TS-NFR-024 | Vietnamese collation in sorting | i18n | P1 | P1 | Students "Đặng", "Dương", "Đinh", "Doãn". |
| Order Doãn, Dương, Đặng, Đinh (D before Đ, accents ignored for equal base) per ICU vi. | 12 §8 collation | Fixtures below | Not run |
| TS-NFR-025 | Accent-insensitive search | i18n | P1 | P1 | /students. |
| Finds "Trần Chi". | 12 §8 | Fixtures below | Not run |
| TS-NFR-026 | No raw i18n keys anywhere | i18n | P1 | P1 | Crawl all routes in vi and en. |
| Zero matches. | 12 §8 | Fixtures below | Not run |
| TS-NFR-027 | Hard-coded English removed from settings and form bodies | i18n | P1 | P1 | vi locale. |
| No English UI strings in vi (except brand names and codes). | 00 §6 inconsistency | Fixtures below | Not run |
| TS-NFR-028 | Large font toggle scales the console 110% | a11y | P3 | P1 | Tenant setting "Cỡ chữ lớn". |
| Base font 13.5 → ~14.9 px; layout intact. | 12 §9 | Fixtures below | Not run |
| TS-NFR-029 | axe run with zero serious violations on main screens | a11y | P1 | P1 | Playwright + axe-core. |
| Zero serious or critical violations. | 12 §11 | Fixtures below | Not run |
| TS-NFR-030 | Contrast ≥ 4.5:1 for text | a11y | P1 | P1 | Any page. |
| Ink and muted colours pass 4.5:1 on white and on #fafafa; chip text passes on chip backgrounds. Note: PRD 12 cites #212B36/#637381 while the Cloud reference uses #1b1b1f/#71717a; either passes; record which is used. | 12 §9, Cloud theme §3 | Fixtures below | Not run |
| TS-NFR-031 | Keyboard walkthrough of the daily loop | a11y | P1 | P1 | Keyboard only. |
| Every step completable with keyboard; focus ring always visible; no trap; modals return focus to the trigger on close. | 12 §9, 12 §11 | Fixtures below | Not run |
| TS-NFR-032 | Tables have proper headers and forms have labels | a11y | P1 | P1 | Any table and form. |
| All columns have th; all inputs labelled; error text linked by aria-describedby. | 12 §9 | Fixtures below | Not run |
| TS-NFR-033 | Browser matrix | ui-ux | P2 | P1 | Chrome, Edge, Safari, Firefox latest two. |
| No layout or functional differences. | 12 §9 browsers | Fixtures below | Not run |
| TS-NFR-034 | Feature flag off hides P2 modules cleanly | functional | P1 | P1 | Flags. |
| Nav hides Kho; /inventory shows "Tính năng chưa bật"; no console errors. | 12 §10 feature flags | Fixtures below | Not run |
| TS-NFR-035 | Logs contain no personal data | security | P1 | P1 | Server log stub. |
| No matches (masked). | 12 §10 | Fixtures below | Not run |
| TS-NFR-036 | Error tracking code shown to user | ui-ux | P2 | P1 | Force an API 500. |
| Toast/page with code TS-5xxx and Thử lại; no raw error JSON. | 12 §10 | Fixtures below | Not run |
| TS-NFR-037 | Analytics events exclude student personal data | security | P2 | P1 | Analytics stub. |
| Payloads contain ids and buckets, no names or phones. | 12 §10 | Fixtures below | Not run |
| TS-NFR-038 | Maintenance banner announces windows | functional | P3 | P1 | Set a maintenance window in the stub. |
| In-app banner with the window time appears 48 h ahead. | 12 §2 availability | Fixtures below | Not run |
Trường Số (truongso.net) · FLYER internal