Skip to content

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

Một phần của SDD-038 Cổng IELTS. 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 0Hai buổi mỗi tuần (giờ Việt Nam)Plan (số bài trong khoá)
NEMO SPEAK 2CN 01.11.2026CN 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 3T3 01.12.2026T3 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.

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ổiNgày (giờ Việt Nam)Bài trong khoá
1CN 01.11.2026 10:00-12:001 + 2
2T5 05.11.2026 20:00-22:003 + 4
3CN 08.11.2026 10:00-12:005 + 6
4T5 12.11.2026 20:00-22:007 + 8
5CN 15.11.2026 10:00-12:00ôn bài 1 và bài 8