Trường Số QA/03 Classes and scheduling
Trường Số · QA test suite · Phase 1 · 10/09/2026

03 · Classes and scheduling

Test cases for PRD 03. 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
Cases
55
P0 / P1
17 / 20
Regression pack
19
PRD
03 Classes and scheduling
Phase
P1

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.json and runs/run-1/, and every result field is still not_run.
  • Cases inherit any open question or inconsistency in the PRDs they trace to.

1Summary

P0
17
P1
20
P2
18
P3
0
Typefunctionalui-uxedgenegativeregressionflowa11yperfsecurityi18n
Count33475001131

2Test cases

IDTitleTypePriorityPhasePreconditionsStepsExpected resultPRD traceData neededRun 1
TS-CLS-001Create a course with extension fieldsfunctionalP0P1As U-ACAD-A on /settings/courses.
  1. Click + Thêm khoá học: name "Flyers 1", level Flyers, age 9–11, 48 lessons, duration 90 min, default capacity 12, price 9,600,000, pricing ONE_TIME.
  2. Save.
  3. Open /classes/new and the Khoá học select.
Course saved (PUT/POST to the existing course endpoint with extension fields); appears in the class form; selecting it fills level, duration 90, capacity 12, lessons 48.CLS-01Fixtures belowNot run
TS-CLS-002Course validationnegativeP2P1Course form.
  1. Duration 0; capacity 61; age_from > age_to; currency other than VND.
Each rejected inline; currency locked to VND.CLS-01, 05 §11 currency VNDFixtures belowNot run
TS-CLS-003Class form step 1 fields and auto valuesfunctionalP0P1As U-ACAD-A on /classes/new.
  1. Choose Chi nhánh Quận 1, Khoá học Movers 2.
  2. Observe Tên lớp, Mã lớp.
  3. Pick weekdays T3 and T5 with 18:00.
  4. Pick teacher T2, room P.202, capacity 12, trial seats 2, Khai giảng next Tuesday, Kết thúc theo số buổi (48).
Tên lớp auto-suggests "Movers 2 · T3/T5 18:00"; Mã lớp auto "MOV-<YYMM>-02" editable; per-weekday time-to fills 19:30 from duration 90; holidays list preloaded from tenant holidays.CLS-02, 03 §5 formFixtures belowNot run
TS-CLS-004Class form validationnegativeP1P1Class form.
  1. Leave weekday empty; set from 19:00 to 18:00; capacity 0 and 61; trial seats 6; duplicate name of C1 in branch A; leave room empty.
Errors: "Chọn ít nhất một ngày"; "Giờ kết thúc phải sau giờ bắt đầu"; "1–60"; "Tối đa 5"; "Tên lớp đã tồn tại"; "Chọn phòng" (unless the virtual room is chosen).03 §5 validationFixtures belowNot run
TS-CLS-005Step 2 preview lists generated sessions and conflictsfunctionalP0P1Step 1 completed with 48 sessions.
  1. Click Tiếp.
Preview shows 48 rows with seq, date, time, room, teacher; holidays skipped and the end date extended accordingly; button label exactly "Tạo lớp và 48 buổi"; dry_run=true request seen in the network log.CLS-02, 03 §8 dry_runFixtures belowNot run
TS-CLS-006Create class generates sessions and appears in the listfunctionalP0P1Preview shown.
  1. Click Tạo lớp và 48 buổi.
Redirect to /classes/:id; tab Buổi học has 48 rows numbered 1..48; /classes tab Sắp khai giảng lists it with status Sắp mở; a ClassSchedule is created only when a FLYER program was chosen.CLS-02Fixtures belowNot run
TS-CLS-007Pattern with two sessions on the same weekdayedgeP2P1Class form.
  1. Add T7 08:00–09:30 and T7 14:00–15:30.
Both rows accepted; preview shows two sessions per Saturday.03 §11Fixtures belowNot run
TS-CLS-008Class spanning Tết skips holidays and extends end dateedgeP1P1Tenant holidays include a 7-day Tết block within the class range.
  1. Create a class across that block.
No sessions on holiday dates; end date extends; preview footer shows "Kết thúc dự kiến: <date>".03 §11 TếtFixtures belowNot run
TS-CLS-009Session generation performanceperfP2P1Class with 200 sessions.
  1. Create the class and time the dry_run and commit.
Preview and creation each complete in ≤ 2 s.12 §2 timetable generationFixtures belowNot run
TS-CLS-010Room conflict shown inline with override for permitted rolesfunctionalP0P1C1 uses P.201 T3/T5 18:00–19:30.
  1. As U-ACAD-A create a class in P.201 on T3 18:30–20:00.
  2. Observe preview.
  3. Repeat as U-BM-A.
Preview rows carry a red chip "Trùng phòng: Movers 2A 18:00–19:30"; U-ACAD-A has no "Vẫn lưu" (no classes.override_conflict) and cannot submit; U-BM-A sees "Vẫn lưu" and can create; API returns 409 CONFLICT with conflicts[] until override_conflict=true.CLS-03Fixtures belowNot run
TS-CLS-011Teacher conflict is checked across branchesfunctionalP0P1T1 teaches C3 at branch B T2/T4 17:00–18:30.
  1. Create a class at branch A with teacher T1 on T2 17:30–19:00 in P.202.
Conflict chip "Trùng giáo viên: Movers 1C (Thủ Đức)"; 409 CONFLICT.CLS-03, 03 §6 teacher conflict any branchFixtures belowNot run
TS-CLS-012Buffer between sessions tenant settingfunctionalP2P1Set buffer 15 min in settings.
  1. Create sessions in P.201 ending 19:30 and starting 19:40.
Conflict reported; with buffer 0 no conflict.03 §6 bufferFixtures belowNot run
TS-CLS-013Cancelled sessions do not conflictedgeP2P1A cancelled C1 session on date D.
  1. Create a one-off session in P.201 at the same time on D.
No conflict.03 §6 both not cancelledFixtures belowNot run
TS-CLS-014Edit one session marks it adjustedfunctionalP0P1C1 planned session next week.
  1. Open tab Buổi học, edit the session: move to next Wednesday 18:00, room P.202.
  2. Save.
Only that row changes; chip "Đã điều chỉnh"; other sessions untouched; guardians of enrolled students receive a schedule_change message if the notification policy is enabled (status Chờ duyệt template → fallback push/email).CLS-04Fixtures belowNot run
TS-CLS-015Apply to following regenerates future planned sessions onlyfunctionalP0P1C1 with 20 held sessions.
  1. Edit a future session, change time to 18:30–20:00 with "Áp dụng cho các buổi sau".
All future planned sessions move to 18:30; the 20 held sessions unchanged; numbering preserved by date order; audit entry.CLS-04, 03 §6 regenerationFixtures belowNot run
TS-CLS-016Session edit conflict on savenegativeP1P1Another class occupies P.202 at the target time.
  1. Move a C1 session into that slot.
409 CONFLICT inline list; Vẫn lưu only for override roles.CLS-03Fixtures belowNot run
TS-CLS-017Concurrent session edit returns STALEedgeP1P1Two admins open the same session drawer.
  1. Admin 1 saves a room change.
  2. Admin 2 saves a time change with the old updated_at.
Admin 2 receives 409 STALE and a toast "Buổi học đã được thay đổi, tải lại"; no silent overwrite.03 §11 optimistic concurrencyFixtures belowNot run
TS-CLS-018Cancel a session with make-up appendedfunctionalP0P1C1 planned session 3 days ahead.
  1. Cancel with reason "GV ốm", choose "Thêm buổi bù cuối khoá", notify on.
Status Đã huỷ; a new session appended after the last one with chip Học bù (is_makeup) at the same weekday/time; no package sessions consumed; guardians receive session_cancelled; total non-cancelled count stays 48.CLS-05Fixtures belowNot run
TS-CLS-019Late cancellation within 24 h marks cancelled_latefunctionalP1P1Session starting in 10 hours.
  1. Cancel it, "Không bù".
Status cancelled_late (chip "Huỷ muộn"); visible for PRD 06 pay rules; no make-up added.CLS-05, 03 §6 thresholdFixtures belowNot run
TS-CLS-020Cancelling a session with a saved sheet is blockednegativeP1P1SES-PAST (sheet saved).
  1. Try to cancel it.
Blocked with "Xoá phiếu điểm danh trước" (admin) and the delete action requires attendance.delete_sheet.04 §5 rule 8Fixtures belowNot run
TS-CLS-021Assign a substitutefunctionalP0P1SES-TODAY.
  1. Edit the session, set Dạy thay = T2. Save.
  2. As U-TEACH2 open /teach/today.
Session row shows T1 (main) and T2 (dạy thay); T2 sees the session in /teach/today and can open the sheet; T1 still sees it with a substitute marker.CLS-06Fixtures belowNot run
TS-CLS-022Teacher can only request a substitutesecurityP1P1As U-TEACH on SES-TODAY.
  1. Open the session; look for substitute assignment.
  2. Call PATCH /sessions/{id} substitute_staff_id.
UI offers "Yêu cầu dạy thay" (creates a request/notification) but no direct assignment; PATCH returns 403.03 §9 sessions.manage teacher request onlyFixtures belowNot run
TS-CLS-023Add student to class up to capacity then waiting listfunctionalP0P1C1 11/12; S3 Waiting; another Waiting student S10.
  1. Tab Học viên → + Thêm học viên → S3, start date today.
  2. Repeat with S10.
After S3: 12/12, class chip Đầy, list tab Đầy includes C1. S10: dialog 409 CLASS_FULL offers waiting list; S10 appears in the Danh sách chờ section with position 1.CLS-07Fixtures belowNot run
TS-CLS-024Roster table columns and level-match hintfunctionalP1P1C1 tab Học viên.
  1. Read the roster and open the add dialog.
Columns: name, guardian phone, start date, status, sessions attended/total, balance, flags (Cần lưu ý); actions Chuyển lớp, Kết thúc, Gửi tin; the add dialog searches branch students and shows a level match chip (Movers → "Phù hợp").03 §5 Học viên tabFixtures belowNot run
TS-CLS-025Transfer class ends and starts on the same dayfunctionalP0P1S1 in C1; C4 has seats.
  1. Chuyển lớp S1 → C4 effective today.
C1 enrollment ends today; C4 enrollment starts today; S1 on today's C1 roster (end ≥ date) and on C4 rosters from today; Lớp & lịch sử shows both rows.CLS-07 transfer, 04 §10 transferred out on the dateFixtures belowNot run
TS-CLS-026Ending an enrollment early asks for reasonfunctionalP1P1S6 in C1.
  1. Click Kết thúc on S6 with end date today.
Reason dialog required; S6 with no other enrollment becomes Đã nghỉ per lifecycle; enrollment status ended with end_reason.CLS-07, 02 §3Fixtures belowNot run
TS-CLS-027Capacity counts trials and make-ups per sessionedgeP1P1C1 12/12 with a make-up booking on session X.
  1. Open session X roster.
Roster shows 12 enrolled + 1 Học bù; trial seats counted separately ("Học thử 1/2"); attendance sheet lists all 13.03 §6 capacityFixtures belowNot run
TS-CLS-028Waiting list promotion when a seat freesfunctionalP2P1C1 full with S10 waiting.
  1. End S6's enrollment.
Admin gets a prompt/notification "Có chỗ trống: Movers 2A · Danh sách chờ: Trần S10"; S10 is not auto-enrolled.03 §5 waiting list sectionFixtures belowNot run
TS-CLS-029Book a make-up into another class of the same levelfunctionalP0P1S1 has an excused absence on SES-PAST; tenant allow make-up; class C2 same level with a free seat next week.
  1. On S1 attendance tab click Học bù on the absence; pick C2 session; consumes_package per policy.
makeup_booking created; C2 session roster shows S1 with chip Học bù; attending does not consume a package session when policy says so; S1 absences table shows "Đã đặt học bù".CLS-08Fixtures belowNot run
TS-CLS-030Make-up as a one-off sessionfunctionalP1P1Same as above.
  1. Choose "Tạo buổi bù riêng": date, time, room, teacher.
A one-off session (is_makeup) is created with conflict check; booking created.CLS-08, 03 §8 POST sessions one-offFixtures belowNot run
TS-CLS-031Make-up blocked when policy disallowsnegativeP2P1Tenant allow_makeup false or class allow_makeup false.
  1. Try to book.
Button hidden; API 409 or 403 with message.CLS-08 Given policyFixtures belowNot run
TS-CLS-032Timetable week grid by roomfunctionalP0P1As U-ACAD-A, /timetable?view=room&week=<this week>.
  1. Open the page.
Columns P.201, P.202, Trực tuyến; rows 07:00–22:00 in 30-min steps; C1 block on Tue/Thu 18:00–19:30 with class name, T1, "11/12"; block colour by level; clicking opens the session drawer.CLS-09Fixtures belowNot run
TS-CLS-033Timetable views by teacher and by class, date navigationfunctionalP1P1Timetable.
  1. Switch to By teacher, then By class; move to next week and back.
Columns change to teachers (T1, T2...) then classes; URL week param updates (2026-W38 etc.); filters branch and level apply.CLS-09Fixtures belowNot run
TS-CLS-034Drag a block to move with conflict check on dropfunctionalP1P1Desktop timetable.
  1. Drag the C1 Tuesday block to Wednesday 18:00 in P.202.
  2. Drag another block onto an occupied slot.
First drop asks for confirmation and updates the session (marked adjusted); second drop shows the conflict and reverts unless overridden.03 §5 timetable dragFixtures belowNot run
TS-CLS-035Print produces A4 landscape per roomui-uxP2P1Timetable by room.
  1. Click In and inspect the print preview.
One A4 landscape page per room with header (branch, week), grid legible; no sidebar or top bar printed.CLS-09 printFixtures belowNot run
TS-CLS-036iCal export for teacher view is a signed linksecurityP2P1Timetable by teacher.
  1. Click Xuất iCal for T1; open the URL; modify one character of the signature.
Valid URL returns text/calendar with the sessions; tampered URL returns 401/403; the link can be revoked from the staff profile.03 §8 timetable.ics signed, test seed 03Fixtures belowNot run
TS-CLS-037Timetable day view on mobileui-uxP2P1390 px.
  1. Open /timetable.
A day view (not the week grid) with a date stepper; blocks tappable; no horizontal scroll.03 §5 day view mobileFixtures belowNot run
TS-CLS-038Teacher timetable scopesecurityP1P1As U-TEACH.
  1. Open /timetable.
Only T1's sessions (C1 and C3) appear; view switcher limited to own view; other teachers not listed.03 §9 timetable.view ownFixtures belowNot run
TS-CLS-039Close a classfunctionalP0P1C1 as U-ACAD-A; S1 has only the C1 enrollment.
  1. Kebab → Kết thúc lớp; confirm.
Class status Đã kết thúc; enrollments ended; S1 status Hoàn thành; /classes tab Đã kết thúc lists C1; planned future sessions cancelled or removed; no attendance sheets deleted.CLS-10Fixtures belowNot run
TS-CLS-040Class auto-completes after the last session is heldfunctionalP2P1A class whose last session is marked today.
  1. Save attendance on the last session.
Class status becomes completed automatically (or on the nightly job); students with no other enrollment become Hoàn thành.CLS-10 Given last session heldFixtures belowNot run
TS-CLS-041Class list tabs, columns and status chipsfunctionalP0P1As U-OWNER, branch A.
  1. Open /classes; read tabs and rows for C1, C2, C4, C5.
Tabs Đang học · Sắp khai giảng · Đầy · Đã kết thúc · Tất cả; columns Mã lớp, Tên lớp (link + level chip), Lịch ("T3, T5 · 18:00–19:30"), Phòng, Giáo viên (avatar + name), Sĩ số ("11/12" with bar; C2 "12/12" red with "Chờ: 1"), Tiến độ ("20/48"), Khai giảng · Kết thúc, Trạng thái chips Sắp mở (blue) / Đang học (green) / Đầy (yellow) / Đã kết thúc (grey), Thao tác Xem lịch · Thêm học viên · Điểm danh hôm nay.03 §5 class listFixtures belowNot run
TS-CLS-042Class list filtersfunctionalP1P1/classes.
  1. Filter teacher T1; weekday T3; time band tối; has seats.
Only C1 remains (C2 has no seats); clearing restores.03 §5 filtersFixtures belowNot run
TS-CLS-043Class list empty stateui-uxP1P1Tenant EMPTY.
  1. Open /classes.
Exactly "Chưa có lớp. Tạo khoá học trước, rồi mở lớp từ khoá học." with buttons + Tạo lớp and a link to courses.03 §5 emptyFixtures belowNot run
TS-CLS-044Class detail header and right rail per Cloud lop-hoc frameui-uxP1P1C1.
  1. Open /classes/<C1 id>.
Breadcrumb; name; subtitle "T3 & T5, 18:00 · 11 học viên · Movers"; buttons Sửa · Giao bài · kebab (Nhân bản lớp, Kết thúc lớp); tabs Tổng quan · Học viên · Buổi học · Điểm danh · Bài tập · Học phí · Cài đặt; right rail Thông tin lớp with code + copy icon, teacher, room, capacity, course, program, fill rate bar, next session.03 §5 class detailFixtures belowNot run
TS-CLS-045Buổi học tab toolbar and per-row actionsfunctionalP1P1C1.
  1. Open tab Buổi học.
Toolbar Tạo buổi, Tạo lại lịch, Nghỉ lễ; columns No., date, time, room, teacher, substitute, status, attendance marked, note; row actions edit, cancel, substitute; held rows are not editable for date/time.03 §5 Buổi họcFixtures belowNot run
TS-CLS-046Regenerate never touches held or cancelled sessionsfunctionalP0P1C1 with 20 held, 1 cancelled.
  1. Tạo lại lịch with a new pattern from today.
Held and cancelled rows identical before/after (ids and timestamps); planned rows regenerated; numbering recalculated among non-cancelled by date.03 §6 rules 1–2Fixtures belowNot run
TS-CLS-047Nhân bản lớp clones settings without studentsfunctionalP2P1C1.
  1. Kebab → Nhân bản lớp.
Class form opens prefilled with course, pattern, room, teacher, capacity; name suffix changed; no enrollments copied.03 §5 kebabFixtures belowNot run
TS-CLS-048Rooms settings: unique per branch, deactivate blocked with future sessionsfunctionalP1P1As U-ACAD-A on /settings/rooms.
  1. Add room "P.201" in Quận 1 (duplicate).
  2. Deactivate P.201 (has future sessions).
  3. Add "P.203" cap 10 and deactivate it.
Duplicate rejected "Tên phòng đã tồn tại"; deactivating P.201 blocked with "Còn N buổi học sắp tới, chuyển phòng trước"; P.203 created then deactivated successfully.03 §5 rooms, 03 §11 room deactivatedFixtures belowNot run
TS-CLS-049Virtual room "Trực tuyến" allowed for online classesfunctionalP2P1Class form.
  1. Choose room Trực tuyến.
Class saves; no room conflicts computed for the virtual room (or conflicts only for teacher).03 §12 open question proposedFixtures belowNot run
TS-CLS-050Levels catalog with score bands drives placement suggestionfunctionalP1P1As U-OWNER /settings/levels.
  1. Read the seeded list.
  2. Change Movers band to 60–79.
Seeded: Pre-A1, A1, A2, B1, B2, C1 and Starters, Movers, Flyers, KET, PET with bands; after edit, a placement result of 72 suggests Movers.03 §6 level mappingFixtures belowNot run
TS-CLS-051Teacher removed from branch with future sessionsedgeP2P1T2 assigned to future sessions; remove T2 from branch A.
  1. Perform the removal in staff settings.
A list of affected sessions is shown for reassignment; sessions keep T2 until changed.03 §11Fixtures belowNot run
TS-CLS-052Holiday list managementfunctionalP2P1/settings/tenant holidays.
  1. Add a holiday next month; open the class form.
Holiday preloaded in Ngày nghỉ; new classes skip it; existing planned sessions are not auto-moved (admin uses Nghỉ lễ tool).03 §8 holidaysFixtures belowNot run
TS-CLS-053Timezone at month boundaryedgeP2P1Session on the 30th at 23:00 local.
  1. Create it and view in timetable and API.
Displayed on the 30th; API returns timestamptz with +07:00; not shifted to the next day.03 §11 time zone, 06 §11 month boundaryFixtures belowNot run
TS-CLS-054Class pages in en localei18nP2P1en locale.
  1. Open /classes and /classes/<C1>.
Tabs and chips translated (Open, Full, Ended, Upcoming); schedule text "Tue, Thu · 18:00–19:30".12 §8Fixtures belowNot run
TS-CLS-055Class form keyboard navigation and focusa11yP2P1Class form.
  1. Tab through weekday chips and time fields; use arrow keys in the room select.
Chips toggle with Space; all fields reachable; error text linked via aria-describedby.12 §9Fixtures belowNot run

Trường Số (truongso.net) · FLYER internal