---
url: https://docs.nemo12.com/architecture/sdd-038/speak-programs.md
description: >-
  Program Speaking, NEMO SPEAK 1 2 3, NEMO WALK, NEMO START, đăng ký thanh toán,
  lịch buổi, link Zoom
---

# SDD-038 · Chương trình Speaking

> Một phần của [SDD-038 Cổng IELTS](index.md). Phần đầu là đặc tả đang áp dụng, mỗi mục giữ số § cũ; diễn biến và lý do các vòng quyết định nằm ở mục **Lịch sử quyết định** cuối trang.

## 136. Program Speaking ở learn.nemo12.com/speaking (SRC-1120, 28.09.2026)

Chủ dự án: một program riêng về speaking ở `/speaking`, nội dung y hệt `/ielts/speaking/pair`; learner vào để
đăng ký học; mỗi learner 3 buổi học thử, đăng ký bất kỳ buổi nào trong tháng 9 hoặc 10/2026; lịch cho public
members luôn là tối thứ Tư 20:00-21:30.

* **Một bộ trang, hai gốc đường dẫn.** `/speaking`, `/speaking/<bài>`, `/speaking/sessions/<mã>` đi vào cùng mạch
  với sân IELTS (`App.tsx` → `ieltsPractice`); `ielts/router.ts` hiểu gốc `/speaking` và `href()` sinh link ở lại
  `/speaking` khi đang đứng trong đó. Thương hiệu trên thanh trên và chân trang là NEMO SPEAKING; chip Target và
  đếm ngày thi (của IELTS) ẩn đi. Bắt đăng nhập như sân IELTS.
* **Luật nằm ở máy chủ.** Mọi lượt gọi lịch từ `/speaking` mang `?program=speaking`. Khi đó API chỉ trả buổi thứ Tư
  trong tháng 9, 10/2026 (`inTrialWindow`), `can_register` tắt khi đã dùng đủ 3 buổi, POST từ chối buổi Chủ nhật,
  buổi ngoài hai tháng và lượt thứ tư. Buổi thử vẫn là một dòng `speak_schedule_signups` (dùng chung danh sách
  người đến, nhắc lịch, link Zoom); bảng `speak_trial_signups` (migration 0310) chỉ đánh dấu lượt nào là buổi thử
  để đếm. Huỷ buổi thì trả lại lượt thử.
* Sân IELTS giữ nguyên luật cũ (thứ Tư và Chủ nhật, không giới hạn buổi).
* **Mở buổi Chủ nhật (SRC-1122, 28.09.2026).** Chủ dự án: "trước mắt" learner đăng ký được cả tối thứ Tư 20:00
  (Speaking Practice) và sáng Chủ nhật 10:00 (Official Speaking Class), giờ Việt Nam. Buổi Chủ nhật đã có sẵn
  trong lịch tính (`schedule.ts`, SRC-1088) nên không cần migration hay seed: `inTrialWindow` bỏ điều kiện
  thứ Tư, chỉ còn hai tháng học thử. Mọi luật khác giữ nguyên và áp chung: 3 buổi thử tính gộp cả hai loại
  buổi, hạn đăng ký 2 giờ (SRC-1124), nhắc lịch, link Zoom dùng chung `SPEAK_ZOOM_URL`. Hai gạch đầu dòng trên nói
  "chỉ buổi thứ Tư" và "POST từ chối buổi Chủ nhật" là luật trước SRC-1122.
* **Lượt thử riêng, tên buổi (SRC-1123, 28.09.2026).** Chủ dự án: "NEMO SPEAK, free 3 lượt riêng... Cần thêm cả
  tên của từng buổi nữa." Nay mỗi loại buổi có 3 lượt thử riêng: 3 buổi thứ Tư (Speaking Practice, luyện kỹ năng
  nền tảng) và 3 buổi Chủ nhật (Official Speaking Class, học theo chương trình chính thức). Máy chủ đếm
  `speak_trial_signups` theo loại buổi (đọc từ giờ trong mã buổi, `weekdayOfId`); `trial` trả `by_session`
  thay cho `used`/`limit`. Mỗi buổi mang `name` và `helper` (`SESSION_NAMES` trong `schedule.ts`), hiện trên lịch
  ở `/speaking` và trong thư nhắc `ielts-speak-reminder`. Chữ lịch ở `/speaking` nói tiếng Việt, tên buổi giữ
  tiếng Anh. Lượt thử Speaking độc lập với kỳ 14 ngày của IELTS và Grammar: thanh trên ở `/speaking` không còn
  đọc gói IELTS (lần đọc đầu tạo kỳ IELTS, tức là chỉ mở trang Speaking cũng đã tiêu nó).
* **Học thử 2 buổi tổng cộng (SRC-1223, 03.10.2026).** Chủ dự án đảo luật "3 lượt riêng" của SRC-1123: mỗi
  learner có 2 buổi học thử TỔNG CỘNG, thứ Tư hay Chủ nhật đều trừ chung một quỹ (`TRIAL_LIMIT = 2` trong
  `schedule.ts`). Máy chủ vẫn đếm `speak_trial_signups` theo loại buổi để hiển thị, nhưng `can_register` và lượt
  POST so TỔNG với giới hạn; buổi thứ ba bị từ chối với câu "Bạn đã dùng hết 2 buổi học thử." bất kể loại buổi.
  `trial` thêm `total: { used, limit }`; `by_session` giữ nguyên hình dạng để client cũ không gãy, `limit` trong đó
  nay là quỹ chung. Trang Sessions ở learn hiện một dòng "Free trial: x of 2 sessions used". Learner đã dùng hơn 2
  buổi theo luật cũ không bị di trú dữ liệu: họ chỉ không đặt thêm được buổi thử. Thành viên IELTS trả phí không
  bị ảnh hưởng. Gạch đầu dòng SRC-1123 ngay trên mô tả luật cũ.
* **Kỳ miễn phí 14 ngày riêng của NEMO GRAMMAR (SRC-1123).** Bảng `learner_grammar_membership` (migration 0311),
  cùng hình dạng `learner_ielts_membership`; `readMembership(..., "grammar")` và route
  `GET /v1/learners/{id}/grammar-membership`. Mở `/grammar` lần đầu tạo kỳ Grammar và không đụng kỳ IELTS, ngược
  lại cũng vậy. Thanh trên `/grammar` hiện chip "Miễn phí: còn N ngày". Như IELTS, kỳ này hiện tại chỉ để hiển
  thị: chưa khoá nội dung nào khi hết hạn (xem SDD-048).

## 140. Gói NEMO SPEAK 1 và khoá NEMO SPEAK 2 (SRC-1129, 29.09.2026)

Chủ dự án: tách 3 bài đầu thành gói NEMO SPEAK 1; khoá NEMO SPEAK 2 gồm 8 bài tiếp theo (4-11 cũ) đánh số lại 1-8,
học phí 1.980.000đ; mỗi gói một trang riêng.

* `SPEAK_COURSES` trong `SpeakPair.tsx` cắt `PAIR_TOPICS` theo `order`; `courseOf(bài)` trả gói và số thứ tự TRONG gói.
  File nội dung giữ nguyên `order` 1-11 và địa chỉ bài (`/speaking/<bài>`) không đổi, để link cũ không gãy.
* Trang riêng: `/speaking/speak-1`, `/speaking/speak-2` (và `/ielts/speaking/pair/speak-1|2`): số bài, số buổi, học phí,
  lưới bài đánh số từ 01. Trang chính thay lưới bài bằng hai thẻ gói. Vệt đường dẫn của trang bài đi qua gói
  ("NEMO SPEAK 2 · Topic 3").
* **Chỉnh cùng ngày (chủ dự án):** NEMO SPEAK 1 là **2 buổi miễn phí**: buổi 1 bài 1 + 2, buổi 2 bài 1 + 3. NEMO SPEAK 2 là
  **5 buổi × 120 phút**, mỗi buổi thực hành 2 bài, học phí vẫn 1.980.000đ. `SPEAK_COURSES[i].plan` giữ kế hoạch từng
  buổi (số bài trong khoá) và `minutes`; trang gói hiện danh sách buổi phía trên lưới bài.

## 141. Đăng ký, thanh toán và mã kích hoạt NEMO SPEAK 2 (SRC-1130, 29.09.2026)

**Đường đi.** Trang `learn.nemo12.com/speaking/speak-2/register` (cũng mở ở
`/ielts/speaking/pair/speak-2/register`; route `speakRegister` khớp TRƯỚC regex tên bài). Ba bước
trên một trang: (1) Register tạo đơn và gửi thư; (2) ô thanh toán: số tiền, nội dung chuyển khoản
\= mã đơn `SPK2-XXXXXX` có nút Copy, thông tin ngân hàng từ `paymentConfig.ts`; (3) nhập mã
kích hoạt `SPEAK2-XXXXXX` → ghi danh → lịch 5 buổi. Đã ghi danh thì hiện lịch ngay. Trang và thẻ
NEMO SPEAK 2 có nút Register và dòng "Starts 01.11.2026 · Sun 10:00-12:00 and Thu 20:00-22:00 ·
5 sessions × 120 min". Admin: tab "Đơn SPEAK 2" ở `admin.nemo12.com`, bấm "Đã nhận tiền".

**API** (migration 0312: `speak_course_orders`, `speak_course_enrollments`):
`GET/POST /v1/learners/{id}/speak-orders`, `POST /v1/learners/{id}/speak-enroll`,
`GET /v1/admin/speak-orders?status=pending`, `POST /v1/admin/speak-orders/{id}/paid`.

**Quyết định (tự chốt theo chỉ đạo, ghi sổ):**

1. Đơn thuộc learner đặt, ghi danh thuộc learner NHẬP MÃ: mọi learner đã đăng nhập nhập được mã
   của một đơn đã trả, để bố mẹ mua cho con. Mã dùng một lần (`UNIQUE(activation_code)` trong
   bảng ghi danh); nhập lại chính mã của mình không lỗi; mỗi learner ghi danh một lần.
2. Bấm Register lần nữa trả về đơn đang chờ hoặc đã trả, không tạo đơn thứ hai, không gửi thư thứ hai.
3. "Đã nhận tiền" idempotent: gọi lại trả đúng mã cũ; thư mã kích hoạt khoá chống trùng theo đơn.
4. Mã dùng bảng chữ không nhầm lẫn `23456789ABCDEFGHJKMNPQRSTUVWXYZ` (như mã trường SRC-1110).
5. Hai thư `ielts-speak-order`, `ielts-speak-activation` là thư GIAO DỊCH (trả lời hành động vừa
   bấm) nên miễn trần ngày. Người nhận: email của learner, không có thì bố mẹ.
6. Thư KHÔNG in số tài khoản: số tài khoản có một chỗ (`paymentConfig.ts`) và đang là số tạm; thư
   đưa số tiền + nội dung chuyển khoản + link trang đăng ký, và nói rõ trang còn báo chưa sẵn sàng
   thì chưa chuyển khoản.
7. Ô thanh toán dùng lại đúng `PayCard` của Membership (tách ra `apps/learn/src/ielts/PayCard.tsx`),
   kể cả cảnh báo và khung QR chờ khi `PAYMENT.active` còn false. Chủ dự án 29.09.2026: không cần
   tích hợp cổng thanh toán, số tài khoản thật gửi sau.
8. (Đã thay bởi §142.) Lịch khoá là hàm thuần `cohortSessions()` (`workers/api/src/modules/speakCourses/cohort.ts`),
   không lưu D1. Learn đọc bài từng buổi và độ dài buổi từ `SPEAK_COURSES[i].plan` / `minutes`;
   worker giữ bản sao `SPEAK2_PLAN`, test `apps/learn/src/ielts/cohortAgrees.test.ts` giữ hai bản
   khớp. Link Zoom (`SPEAK_ZOOM_URL`) chỉ trả cho người đã ghi danh.
9. Ngôn ngữ: tên trang, nhãn, bước tiếng Anh đơn giản như phần còn lại của Speak together; câu
   hướng dẫn TIỀN tiếng Việt, cùng lý lẽ SRC-953: một lời dặn về tiền hiểu sai thì thà đừng dặn.
10. Rate limit: tạo đơn 10 lần/giờ, nhập mã 20 lần/10 phút.

**Chưa có:**

* Đối soát ngân hàng tự động: admin đọc sao kê và bấm xác nhận bằng tay.
* Số tài khoản và mã QR thật: chờ chủ dự án gửi (`PAYMENT.active` vẫn false).
* Huỷ đơn / hoàn tiền: trạng thái `cancelled` có trong schema nhưng chưa có nút.
* Nối ghi danh vào lịch Speak together hằng tuần (thư nhắc trước buổi, danh sách người tham gia
  từng buổi của khoá): lịch khoá hiện chỉ hiển thị, chưa có thư nhắc riêng.
* Khoá 2 trở đi: ngày khai giảng đang cố định trong `SPEAK2_DAYS`.

## 142. Lịch cuốn chiếu NEMO SPEAK 2 và khoá NEMO SPEAK 3 (SRC-1131, 29.09.2026)

Chủ dự án 29.09.2026 (qua điều phối viên): NEMO SPEAK 2 chạy liên tục, không bao giờ dừng, và
thêm khoá nâng cao NEMO SPEAK 3.

**Lịch cuốn chiếu.** Mỗi khoá có một dòng buổi liên tục, hai buổi mỗi tuần; buổi k (k = 0, 1, 2 ...)
học vị trí plan `k mod 5`. Learner kích hoạt lúc nào cũng được và học **5 buổi kế tiếp có giờ bắt
đầu cách lúc kích hoạt ít nhất 2 giờ**; năm buổi liên tiếp luôn phủ đủ 5 vị trí plan, chỉ khác thứ
tự. Học xong 5 buổi thì thôi. Chỉ số buổi đầu lưu ở `speak_course_enrollments.first_session_index`
(migration 0312, sửa trước khi gộp), nên 5 ngày của mỗi người cố định dù dòng buổi chạy tiếp.

| Khoá | Buổi 0 | Hai buổi mỗi tuần (giờ Việt Nam) | Plan (số bài trong khoá) |
| --- | --- | --- | --- |
| NEMO SPEAK 2 | CN 01.11.2026 | CN 10:00-12:00, T5 20:00-22:00 | \[1,2] \[3,4] \[5,6] \[7,8] \[1,8] (buổi 5 ôn) |
| NEMO SPEAK 3 | T3 01.12.2026 | T3 20:00-22:00, T7 10:00-12:00 | \[1,2] \[3,4] \[5,6] \[7,8] \[9,10] |

Ví dụ: kích hoạt SPEAK 2 lúc 18:01 thứ Năm 12.11.2026 thì buổi 20:00 hôm ấy đã quá hạn 2 giờ, nên
5 buổi là 15.11, 19.11, 22.11, 26.11, 29.11.2026.

**NEMO SPEAK 3.** 10 bài mới (order 12-21 trong `apps/learn/src/ielts/speakPair/content/`), sâu hơn
SPEAK 2: nêu ý kiến, lý do, so sánh, vấn đề và giải pháp, câu hỏi nối kiểu IELTS Part 3. Bài:
Technology and Young People, City Life and Countryside Life, Protecting the Environment, Online
Learning and Classroom Learning, Jobs of the Future, Social Media, A Healthy Lifestyle, Tourism,
Teamwork and Leadership, Reading Habits. Mỗi bài 5 lượt, 3 cách hỏi, gợi ý hai thứ tiếng, ít nhất
3 cụm từ; `audit-content` phần speak vẫn 100. Mỗi bài một cảnh `PairScene`. 5 buổi x 120 phút,
1.980.000đ. Trang `/speaking/speak-3` và `/speaking/speak-3/register` (cũng ở
`/ielts/speaking/pair/...`); thẻ thứ ba ở trang chủ Speak together.

**Quyết định:**

1. **Lịch SPEAK 3 (T3 20:00 + T7 10:00 từ 01.12.2026) do điều phối viên chọn để không trùng giờ
   SPEAK 2 - CHỜ CHỦ DỰ ÁN XÁC NHẬN.** Đổi thì sửa `COURSES["speak-3"]` ở worker và `rolling` ở
   `SPEAK_COURSES`; test giữ hai bản khớp sẽ đỏ nếu chỉ sửa một bên.
2. Đăng ký, thanh toán, mã kích hoạt dùng chung một luồng tham số theo khoá: nội dung chuyển khoản
   `SPK2-`/`SPK3-XXXXXX`, mã `SPEAK2-`/`SPEAK3-XXXXXX`; mỗi learner một đơn đang mở và một ghi danh
   mỗi khoá; trang admin "Đơn SPEAK" có cột khoá.
3. Lịch tính ở hai nơi: worker (`speakCourses/cohort.ts`, chốt 5 buổi thật khi nhập mã, kèm Zoom)
   và learn (`speakRolling.ts` + `SPEAK_COURSES[i].plan/minutes/rolling`, vẽ buổi sắp tới và bản
   xem trước). `apps/learn/src/ielts/cohortAgrees.test.ts` so plan, học phí, thứ tự bài, 30 buổi đầu
   và buổi đầu cho nhiều thời điểm.
4. Thêm bài không đổi vòng học thử hằng tuần: `TOPICS` ở `speakPair/schedule.ts` giữ 11 bài gốc;
   `FREE_ROTATION_TOPICS` ở learn là 11 bài đầu; test ở worker và learn khoá điều này.
5. API `GET /v1/learners/{id}/speak-orders` trả `orders`, `enrollments` (mỗi khoá đã ghi danh kèm 5
   buổi riêng) và `preview` (5 buổi nếu kích hoạt ngay); `POST .../speak-orders` nhận
   `course: "speak-2" | "speak-3"`.
6. Trang khoá hiện "Runs every week · ... · join any time · 5 sessions × 120 min" và buổi sắp tới
   gần nhất; trang đăng ký hiện "If you join now, your 5 sessions" trước khi kích hoạt, và 5 buổi
   riêng sau khi kích hoạt.

**Chưa có:** thư nhắc trước từng buổi của khoá có phí; giới hạn sĩ số một buổi; nghỉ lễ (dòng buổi
chạy cả ngày lễ, Tết); đổi buổi cho learner lỡ một buổi.

## 143. Chủ dự án duyệt lịch SPEAK 3; buổi 5 SPEAK 2 là buổi tổng kết (SRC-1133, 29.09.2026)

* **Lịch SPEAK 3 đã duyệt:** tối thứ Ba 20:00-22:00 và sáng thứ Bảy 10:00-12:00, bắt đầu 01.12.2026, cuốn chiếu như
  SPEAK 2 (SRC-1131 trước đó ghi là tự chọn, chờ duyệt).
* **Buổi 5 của SPEAK 2 là buổi tổng kết**: demo, cùng nhau chia sẻ public trong lớp; không học bài mới, thay cho
  "ôn bài 1 + bài 8" đã tự chốt ở SRC-1129. Trong dữ liệu: `plan` vị trí 5 có `topics: []` (cả bản learn lẫn bản
  worker `speakCourses/cohort.ts`, test `cohortAgrees` giữ hai bản khớp); giao diện hiện `SHOWCASE_LABEL`
  "Wrap-up and demo: share what you learned in front of the class" thay cho tên bài.

## 144. Học phí ra thẻ riêng; trang Speak together chỉ xem (SRC-1134, 29.09.2026)

Chủ dự án: học phí đưa riêng ra một card; ở trang ngoài đừng hiện ngay học phí; learner vào xem khoá rồi mới đăng ký
trong trang chi tiết; trang ngoài chỉ xem, không có nút nào ghi vào database.

* Trang `/speaking`: thẻ khoá chỉ còn ảnh, tên, số bài, số buổi; cả thẻ là một link vào trang khoá. Không giá, không nút.
* Trang khoá: bỏ viên giá cạnh "8 topics · 5 sessions" và nút Register cạnh dòng lịch; thêm thẻ **Fee** (giá, số buổi ×
  số phút, nút Register cho khoá có lịch cuốn chiếu) nằm sau danh sách buổi, trước lưới bài.

## 153. Speaking Mentors cuối trang /speaking (SRC-1156, 30.09.2026)

Chủ dự án 30.09.2026: cuối `SpeakPairHome` (phục vụ cả `/speaking` lẫn `/ielts/speaking/pair`) có khối
"Speaking Mentors" gồm hai người: Hồng Hà và Đặng Tuyết Hồng. Component `apps/learn/src/ielts/SpeakMentors.tsx`.

* **Nguồn dữ liệu:** cùng endpoint công khai nemo12.com dùng, `GET /v1/public/mentors?audience=public`
  (bảng `mentor_profiles`, chỉ hồ sơ published), lọc theo slug cố định `hong-ha`, `dang-tuyet-hong`
  (migration 0071). Không chép tên, vai hay tag vào mã; API không đổi.
* **Thẻ bày:** ảnh (`photo_media_id`) hoặc cá heo SRC-576 khi chưa có ảnh; `full_name`; `headline` làm
  nhãn vai; tối đa hai dòng sự kiện: `card_tag` và `alumni.track` + `alumni.grad_year`. Cả thẻ là link
  tới trang hồ sơ `https://nemo12.com/mentors/{slug}`. Chỉ xem.
* **Ngôn ngữ:** khu /speaking nói tiếng Anh (SRC-1155), còn `card_tag` và `track` lưu tiếng Việt. Một bảng
  cụm từ nhỏ dịch đúng các cụm đang có (Kiểm soát chất lượng, ex-Chuyên Ngữ, Chuyên Pháp, Chuyên Hàn);
  dòng nào dịch xong vẫn còn chữ có dấu thì bỏ, không bày nửa Việt nửa Anh. Tên riêng giữ nguyên dấu.
* **Bố cục:** trong cột giữa `max-w-5xl`, hai cột từ `md`, xếp chồng trên mobile. API lỗi hoặc thiếu
  người thì khối tự ẩn.

Kiểm chứng: `apps/learn/e2e/speakPages.spec.ts` ca "Speaking Mentors, two cards" (desktop và 375px,
mock có người thứ ba để gác phép lọc, không còn chữ "Chuyên", ảnh chụp); mock `/v1/public/mentors` trong
`e2e/fixtures.ts` nên `mobileAudit` của `/speaking` và `/ielts/speaking/pair` cũng phủ khối này.

## 155. NEMO SPEAK ở learn.nemo12.com/speak, và năm chỉnh sửa trang bài (SRC-1158, 30.09.2026)

**Đổi tên.** Chủ dự án 30.09.2026: logo NEMO SPEAKING thành NEMO SPEAK, gốc `learn.nemo12.com/speaking`
thành `learn.nemo12.com/speak`, link cũ tự chuyển. Mọi điều ở §136 về program Speaking vẫn đúng, chỉ đổi gốc.

* `SPEAKING_BASE = "/speak"` trong `apps/learn/src/ielts/router.ts`. So khớp theo ĐOẠN đường dẫn
  (`=== "/speak"` hoặc `startsWith("/speak/")`), nên `/speaking` không bị đọc thành `/speak` + `ing`.
  `/ielts/speaking/pair/**` giữ nguyên.
* **301 phía máy chủ:** `apps/learn/public/_redirects` (Cloudflare Workers static assets đọc file này
  trong `dist/`): `/speaking` → `/speak` và `/speaking/*` → `/speak/:splat`. Cloudflare giữ query,
  trình duyệt giữ hash. Test: `apps/learn/src/ielts/redirects.test.ts` đọc chính file ấy.
* **Lưới phía trình duyệt:** `redirectLegacySpeaking()` (`history.replaceState`) chạy trong `main.tsx`
  trước khi render và trong hai trình nghe `popstate`, cho khung SPA đã nằm trong cache và mục lịch sử
  cũ. `vite preview` không đọc `_redirects`, nên e2e đo đúng lớp này.
* Khoá kỹ thuật giữ nguyên: `?program=speaking`, cột `program` của migration 0310, nhóm Zalo
  `speaking`, thư mục bài viết `articles/speaking`. Trang công khai `nemo12.com/students/speaking` giữ
  URL, chỉ đổi link trỏ vào learn. Không có mục `speaking` nào trong bảng `PROGRAMS` của thư
  (`workers/api/src/modules/email/program.ts`), nên tên người gửi không có gì để đổi.
* Nội dung D1 còn link cũ: `scripts/seed-speak-url-rename.sql` (idempotent, chưa chạy) và
  `scripts/seed-articles-speaking.sql` sinh lại.
* Video đã render (tools/videos) không render lại.

**Trang bài.**

1. **Công tắc Band đọc được.** Nấc đang chọn trước đây `bg-ocean-900 text-white`; trên nền biển sâu
   `ocean-900` đảo thành gần trắng nên chữ trắng trên nền trắng. Nay nấc đang chọn `bg-accent-deep
   text-white`, nấc kia trong suốt `text-muted-foreground`. E2e đo tương phản nấc đang chọn ≥ 4,5:1.
2. **Chế độ xem "1 answer | 3 answers"** (radiogroup `aria-label="View"`), đặt cạnh công tắc Band.
   Mặc định "1 answer": mỗi cụm chỉ cách hỏi và câu trả lời đầu tiên (biến thể \[0], của `band6` khi
   đang Band 6.0). Chữ do điều phối viên chọn (chủ dự án giao): đếm số câu trả lời thay vì "Compact /
   Expand", vì learner hiểu ngay mình sẽ thấy gì; mặc định một câu theo luật tối giản. Nhớ trong
   localStorage (`nemo12.speakView`), `?view=all` trên URL thắng.
3. **Số 1-5** ở đầu header mỗi thẻ cụm, vòng tròn `accent-deep` chữ trắng, số `tabular-nums`, hiện cả
   khi thẻ gập.
4. **Practice steps (4 rounds)**, thẻ gập ngay trên 5 thẻ cụm: bốn vòng đổi vai (hai vòng theo mẫu, hai
   vòng không nhìn mẫu), ô chọn lưu theo bài (`nemo12.speakRounds.<topic>`), dòng "N of 4 done", nút
   Reset. Khi đã chọn vòng 3 hoặc 4 thì có nút "Hide model": làm mờ chữ câu trả lời mẫu (và ẩn khỏi
   trình đọc màn hình), bấm lại để hiện.
5. **Ảnh banner.** `PairScene banner`: cảnh gốc đứng giữa, trời và sàn kéo sang hai bên, khung ~4,6:1,
   cao 150px trên máy tính và 110px trên điện thoại. Trang khoá và trang buổi giữ cỡ cũ.

**Trang chủ /speak chỉ còn bốn khoá** (chủ dự án 30.09.2026, đảo lại phần "buổi tối thứ Tư gần nhất
trong thẻ NEMO START" của §152): NEMO START, NEMO SPEAK 1, NEMO SPEAK 2, NEMO WALK là bốn thẻ ngang nhau
(ảnh, tên, một dòng tóm tắt), lưới 2x2 trong cột giữa. Trang chủ không còn buổi sắp tới, nút "View
session" hay số người đi. Lịch nằm trong trang từng khoá, mục "Calendar": START lấy các tối thứ Tư sắp tới
từ API lịch (hàng gọn như trang Sessions, mỗi hàng dẫn tới trang buổi); SPEAK 1 và SPEAK 2 hiện bốn buổi
kế tiếp của lịch cuốn chiếu (tính sẵn ở speakRolling.ts) cạnh thẻ Fee; WALK giữ trang lịch riêng. Link How
a session works, video và Speaking Mentors vẫn ở trang chủ. `useNextWedSession` gỡ vì không còn ai gọi.

**Speaking Mentors** (thay §153): bốn người theo thứ tự hong-ha, dang-tuyet-hong, tu-minh,
nguyen-tat-dac; chỉ chữ, không ảnh và không avatar cá heo. Mỗi thẻ gập sẵn (tên, vai, một dữ kiện từ
`card_tag`), bấm mở ngay trên trang (FoldCard, Motion) để xem About (từ `expertise_bio` +
`personal_bio`), School, Now at, Teaches, Website và link "Full profile on nemo12.com". Dịch bằng bảng
cụm (`EN`) và bảng nguyên câu (`SENTENCES`); câu chưa có bản dịch thì bỏ. Unit test chạy trên bản chụp
bốn hồ sơ thật và đòi không câu nào rơi mất.

**Trang một buổi.** Thẻ Zoom (link, hoặc câu "The Zoom link will be here before the session" và dòng
email) sang cột phải, dưới thẻ giờ và trên "Who is coming"; link "How a session works" dưới "Who is
coming". Cột trái: tên, ảnh, bối cảnh, khối hành động, "See the lesson". Mobile: thẻ giờ, tên, ảnh, bối
cảnh, hành động, Zoom, See the lesson, Who is coming, How a session works.

**Audio đọc nhanh, nhất là câu đầu.** `speak-audio` nay ở khoá `speak-audio/v2/...`: mọi câu (b5, b6, mọi
bài) sinh lại dần khi có người bấm, file v1 bỏ yên. Mỗi file có 250 ms lặng ở đầu (trình duyệt hay nuốt
vài chục mili-giây đầu khi vừa mở luồng) và 150 ms ở cuối. `normalizePcm` (dictation/tts.ts): nếu model
trả kèm header RIFF thì đọc tần số thật, bóc khối `data` và đưa về 16 kHz, thay vì đọc header thành
tiếng và dán nhãn sai tần số. Phía trình duyệt ghim `playbackRate = 1` và `preload = "auto"`. Aura-2 trên
Workers AI không công bố tham số tốc độ đọc (schema chỉ có text, speaker, encoding, container,
sample_rate, bit_rate), nên chưa làm chậm giọng; đo thời lượng trên binding thật còn chờ.

## 156. NEMO START bỏ thẻ Sessions, đổi chủ đề hai buổi thứ Tư, nhãn thẻ bài hai dòng (SRC-1160, 30.09.2026)

Chủ dự án 30.09.2026, ba việc ở learn.nemo12.com/speak:

1. **Trang NEMO START (`/speak/start`) bỏ thẻ gập "Sessions (2)".** Giữ thẻ Fee, danh sách Calendar và lưới
   bài. SPEAK 1 và SPEAK 2 GIỮ thẻ này: Calendar của hai khoá cuốn chiếu chỉ hiện bốn buổi kế tiếp, còn thẻ
   Sessions là cả kế hoạch khoá (mọi buổi, câu lịch cuốn chiếu, buổi kế tiếp), nên bỏ đi là mất thông tin.
2. **Đổi chủ đề cho hai buổi thứ Tư cụ thể**, qua bảng `TOPIC_OVERRIDES` trong
   `workers/api/src/modules/speakPair/schedule.ts`, khoá bằng mã buổi: `2026-10-07-2000` thành Favourite
   Food (vòng là Your Weekend), `2026-10-14-2000` thành Your Weekend (vòng là Asking the Way). Vòng `TOPICS`
   không đổi. Bảng được áp trong `slotAt`, chỗ DUY NHẤT tính chủ đề của một buổi, nên danh sách lịch, trang
   buổi, thư nhắc (`reminders.ts`) và giao diện learn (đọc `topic` từ API) cùng nhận. Mã buổi giữ nguyên nên
   đăng ký cũ vẫn đúng buổi. Dữ liệu lưu không phải sửa: `speak_schedule_signups` và `speak_trial_signups`
   chỉ lưu `session_id`, thư nhắc tính chủ đề lúc gửi. Test: `schedule.test.ts`.
3. **Thẻ trong lưới bài của mọi trang khoá hiện nhãn hai dòng**: dòng 1 là thẻ nhỏ `Topic N`
   (`data-part=topic-tag`), dòng 2 là tên bài (`data-part=topic-title`). Giữ `data-part=topic-grid`.

e2e: `speakAboutMe.spec.ts` (nhãn hai dòng, START không còn thẻ Sessions, Calendar 07.10 Favourite Food và
14.10 Your Weekend với lịch giả), `speakPages.spec.ts`.

## 158. Link Zoom riêng cho từng buổi (SRC-1165, 30.09.2026)

Chủ dự án gửi link Zoom của buổi tối 30.09.2026. `ZOOM_OVERRIDES` trong `speakPair/schedule.ts` giữ link theo mã buổi; `zoomFor` dùng link ấy trước, không có thì rơi về `SPEAK_ZOOM_URL`. Áp cho API chi tiết/danh sách buổi (chỉ người đã đăng ký thấy) và thư nhắc 1-2 giờ trước buổi.

## 158. Trang /speak: thứ tự thẻ và câu điểm thú vị; trang NEMO START có cột phải (SRC-1164, 30.09.2026)

* Trang `/speak`: dòng trên NEMO START + NEMO WALK, dòng dưới NEMO SPEAK 1 + NEMO SPEAK 2. Dưới tên khoá không ghi số bài,
  số buổi mà ghi điểm thú vị nhất, tiếng Anh đủ dễ cho học sinh 10 tuổi (chủ dự án duyệt ý, điều phối viên viết chữ):
  START "Your first time speaking English freely, with no pressure."; WALK "Be a tour guide for the first time and show
  Hanoi to new friends."; SPEAK 1 "Your first real, step-by-step course. A strong start for what comes next.";
  SPEAK 2 "Go deeper, build it strong and speak at a higher level."
* Trang khoá: hai cột (`max-w-5xl`), cột phải có thẻ Fee và Calendar; riêng NEMO START thêm nút to "Go to the next session"
  (`NextWedButton`) vào thẳng buổi tối thứ Tư gần nhất. Trên điện thoại cột phải lên trước.

## 162. Trang /speak bớt một nửa element; thanh trên không lặp tên chương trình (SRC-1200, 03.10.2026)

Chủ dự án: "Nhiều text quá, cần giảm 50% elements trên trang này."

* Trên mọi trang chương trình của learn, nút tên chương trình của ProgramMenu là gốc duy nhất: `NavBar` bỏ ô `left` (logo + tên) khi đứng trong một chương trình; vệt đường dẫn của `ielts/Shell` bỏ nhánh gốc NEMO IELTS / NEMO SPEAK và giữ các nhánh còn lại (`keepLeftInProgram`).
* /speak bỏ câu dẫn, link "How a session works" và video một phút; video chuyển sang trang How a session works (đích của tab Cách học). Tiêu đề "Speak together" chỉ còn cho trình đọc màn hình.
* Thẻ khoá chỉ còn ảnh + tên; câu điểm thú vị (SRC-1164) chuyển vào trang của từng khoá, ngay dưới tên khoá.
* Speaking Mentors gập sau một dòng "Speaking Mentors (n)", bấm mới mở bốn thẻ.

## Lịch sử quyết định

### Từ mục 140. Gói NEMO SPEAK 1 và khoá NEMO SPEAK 2 (SRC-1129, 29.09.2026)

* **Tự chốt, chờ chủ dự án duyệt:** buổi 5 của SPEAK 2 ôn bài 1 và bài 8 (8 bài cho 5 buổi × 2 bài thì dư một buổi).
* **Chưa có:** đường thanh toán cho NEMO SPEAK 2 (trang mới chỉ ghi học phí); lịch buổi vẫn xoay vòng 11 bài chung.

### Từ mục 141. Đăng ký, thanh toán và mã kích hoạt NEMO SPEAK 2 (SRC-1130, 29.09.2026)

Chủ dự án 29.09.2026: cần trang riêng để đăng ký và thanh toán; đăng ký xong hệ thống gửi mã để
kích hoạt khoá (vào lớp). Khoá 1 mở đầu tháng 11.2026. Bản sửa trong ngày: **5 buổi, mỗi buổi
120 phút, mỗi buổi luyện 2 bài**, học phí vẫn 1.980.000đ cho cả 5 buổi (thay "8 buổi" của §140).
Bảng lịch cố định dưới đây đã được thay bằng lịch CUỐN CHIẾU ở §142 (SRC-1131); giữ lại để thấy
vòng đầu tiên trông thế nào.

| Buổi | Ngày (giờ Việt Nam) | Bài trong khoá |
| --- | --- | --- |
| 1 | CN 01.11.2026 10:00-12:00 | 1 + 2 |
| 2 | T5 05.11.2026 20:00-22:00 | 3 + 4 |
| 3 | CN 08.11.2026 10:00-12:00 | 5 + 6 |
| 4 | T5 12.11.2026 20:00-22:00 | 7 + 8 |
| 5 | CN 15.11.2026 10:00-12:00 | ôn bài 1 và bài 8 |
