SDD-038 · NEMO WALK
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.
146. NEMO WALK và đổi tên ba khoá Speaking (SRC-1136, 29.09.2026)
Chủ dự án 29.09.2026: thêm chuỗi hoạt động NEMO WALK bên cạnh các khoá, và đổi tên NEMO SPEAK 1 → NEMO START, NEMO SPEAK 2 → NEMO SPEAK 1, NEMO SPEAK 3 → NEMO SPEAK 2.
Đổi tên: tên và URL đổi, id nội bộ giữ. course_id trong D1 (speak-2, speak-3, migration 0312 đã áp), đơn và mã kích hoạt đã phát đều giữ nguyên. Bảng nối duy nhất slug ↔ id ↔ tên: apps/learn/src/ielts/speakSlugs.ts (SpeakPair.tsx re-export). Bảng không nằm thẳng trong SpeakPair.tsx vì router.ts cần nó, còn SpeakPair.tsx import Shell, Shell import router: đặt ở đó là vòng import. Phía worker, COURSES[id].slug trong speakCourses/cohort.ts là bản sao; test cohortAgrees.test.ts giữ tên và slug hai bên khớp.
| Tên mới | Id nội bộ | /speaking/... | /ielts/speaking/pair/... |
|---|---|---|---|
| NEMO START | speak-1 | start | start |
| NEMO SPEAK 1 | speak-2 | speak-1, speak-1/register | như cột trái |
| NEMO SPEAK 2 | speak-3 | speak-2, speak-2/register | như cột trái |
| NEMO WALK | (không có) | walk | walk |
- URL cũ mới sống một ngày:
/speak-3và/speak-3/registerchuyển sang/speak-2...bằngreplaceState(không thêm mục lịch sử)./speak-1,/speak-2cũ nay mang nghĩa MỚI: chủ dự án chấp nhận. - Thư đơn và thư mã kích hoạt trỏ link theo slug mới (
courseSlug), không theo id nội bộ. - Tiền tố nội dung chuyển khoản và mã (
SPK2-,SPK3-,SPEAK2-,SPEAK3-) không đổi cho đơn mới: chúng là chuỗi mờ, đổi thì phải đổi cả phép kiểm mã và hai kiểu mã cùng sống song song. Hệ quả là một đơn NEMO SPEAK 1 mang mãSPK2-...: chấp nhận được, ghi ra đây để không ai "sửa cho khớp". - Admin (tab Đơn SPEAK) hiện tên mới theo id.
NEMO WALK. Hoạt động luyện Speaking miễn phí, Chủ nhật hằng tuần 15:00-16:30 giờ Việt Nam (90 phút), ở khu Phố Cổ Hà Nội. Lịch qua ba lượt chỉ đạo cùng ngày 29.09.2026: 09:00 thứ Bảy 60 phút → 15:00-16:30 thứ Bảy → 15:00-16:30 Chủ nhật (bản hiện hành). Không trùng lớp nào: NEMO SPEAK 1 (id speak-2) học Chủ nhật 10:00-12:00, xong trước ba tiếng.
- Trang
/speaking/walk(và/ielts/speaking/pair/walk): chữ giới thiệu nguyên văn của chủ dự án (em dash đổi thành dấu hai chấm), dòng "Every Sunday 15:00 · Hanoi Old Quarter · Free", danh sách "What you will do", thẻ "Next walk", rồi lịch các tuần sau. Mỗi tuần: tên khu, ngày giờ, điểm hẹn, chủ đề, Speaking Mission, "n going" và một trong Join / Cancel / You are in / Closed. - Thẻ thứ tư ở
/speakingvẫn chỉ xem, không nút: ảnh (cảnhwalktrong PairScene: hồ, cầu đỏ, cây), tên, "Every Sunday 15:00 · For SPEAK 1 and SPEAK 2 learners". - Bốn khu luân phiên theo tuần: Hoan Kiem Lake, Old Quarter (Phố Cổ), Food Tour (ăn vặt Phố Cổ), Hanoi Cathedral (Nhà Thờ Lớn). Tám tuần đầu là 8 Chủ nhật 04.10 đến 22.11.2026, mỗi tuần một điểm hẹn cụ thể, một chủ đề hợp khu, một nhiệm vụ tiếng Anh đơn giản. Điểm hẹn, chủ đề, nhiệm vụ và dòng "Hanoi Old Quarter": chủ dự án giao điều phối viên quyết, 29.09.2026. Câu giới thiệu của chủ dự án vẫn nói "đi bộ quanh Hồ Hoàn Kiếm" dù ba trong bốn khu không phải hồ; giữ nguyên văn theo cùng lượt giao.
- Dữ liệu:
apps/learn/src/ielts/walk/weeks.json, mỗi dòng{date, area, place, topic, mission}; worker giữ bản sao ởworkers/api/src/modules/walks/weeks.ts(chặn ngày lạ, viết thư).walkWeeks.test.tsgiữ hai bản khớp từng chữ; thêm tuần thì thêm ở cả hai. Tuần tự ẩn khi buổi KẾT THÚC (16:30 giờ Việt Nam).
Đăng ký WALK (migration 0314, walks/routes.ts). Miễn phí, cần đăng nhập, mỗi learner một lượt mỗi tuần (khoá chính walk_date, learner_id của bảng walk_registrations).
GET /v1/learners/{id}/walks: các tuần chưa kết thúc vớisignups,registered,can_register, cùngeligiblevàslots: {total, used, left, by_course: [{course_id, name, total, used}]}.POST /v1/learners/{id}/walks/{date}đăng ký, gọi lại vẫn 200 và không lấy suất thứ hai;DELETEhuỷ. Cả hai đóng 2 giờ trước 15:00 (409closed); ngày không có buổi là 404.- Suất: chủ dự án viết "NEMO TALK 1/2", điều phối viên đọc là NEMO SPEAK 1 (
speak-2) và NEMO SPEAK 2 (speak-3). Chỉ learner có dòng trongspeak_course_enrollmentscủa hai khoá ấy mới đăng ký được (không có thì 403not_enrolled, câu "NEMO WALK is for NEMO SPEAK 1 and NEMO SPEAK 2 learners."). Mỗi lượt ghi danh cho 2 suất (khoá = 4 buổi online + 2 buổi WALK, xem dưới); học cả hai khoá là 4, 2 của mỗi khoá. Cộtcourse_idghi suất của khoá nào: đăng ký lấy khoá ghi danh SỚM NHẤT còn suất. Hết suất là 409no_slots. Huỷ trước giờ đóng trả suất (xoá dòng); buổi đã qua thì dòng còn đó, tức là suất đã dùng. - Trang WALK: chưa ghi danh thì hiện "NEMO WALK is for NEMO SPEAK 1 and NEMO SPEAK 2 learners" kèm link hai trang khoá, không nút Join; đã ghi danh thì hiện "Walk slots: n of 2 left" cho từng khoá, hết suất thì Join bị khoá.
- Thư xác nhận
walk-registered: ngày, giờ, khu, điểm hẹn, chủ đề, nhiệm vụ. Thư giao dịch, miễn trần; khoá chống trùng theo tuần + người + email, nên huỷ rồi đăng ký lại không gửi lần hai. Không mang nhận diện NEMO IELTS. - Admin: tab "NEMO WALK" liệt kê người đăng ký theo từng tuần (tên, email, khoá dùng suất).
Cấu trúc khoá mới (chủ dự án 29.09.2026, cùng SRC): NEMO SPEAK 1 (speak-2) và NEMO SPEAK 2 (speak-3) mỗi khoá = 4 buổi online + 2 buổi NEMO WALK, học phí giữ 1.980.000đ.
- Plan (learn
SPEAK_COURSESvà bản sao workercohort.ts, testcohortAgreesgiữ khớp): SPEAK 1: 8 bài, [1,2] [3,4] [5,6] [7,8]. Buổi 5 cũ (tổng kết, demo trước lớp, SRC-1133) bỏ; phần demo và chia sẻ chuyển sang các buổi WALK (điều phối viên quyết). SPEAK 2: 10 bài trong 4 buổi, [1,2,3] [4,5,6] [7,8] [9,10] (✍️ điều phối viên quyết: hai buổi đầu 3 bài, chờ chủ dự án nếu muốn chia khác). - Lịch cuốn chiếu nay xoay 4 vị trí plan (chỉ số buổi mod 4); kích hoạt xong học 4 buổi online kế tiếp, vẫn cắt 2 giờ (
SESSIONS_PER_ENROLLMENT = 4ở cả hai phía).first_session_indexđã lưu vẫn đúng vì nó là chỉ số trong dòng buổi liên tục, không phụ thuộc số vị trí plan. - Chữ: dòng lịch "... · join any time · 4 online sessions × 120 min + 2 NEMO WALK"; nhãn "4 online sessions", "2 walks"; thẻ học phí "4 online sessions × 120 min + 2 NEMO WALK sessions"; thẻ ở
/speaking"x topics · 4 sessions + 2 walks"; trang đăng ký và thư "4 buổi".SHOWCASE_LABEL(buổi không bài) giữ làm nhánh an toàn, hiện không plan nào dùng.
Trang bài Speak together chỉ xem (chủ dự án 29.09.2026, cùng SRC). SpeakPairTopicPage (vd /speaking/family) bỏ nút Start a room, ô nhập mã, nút Join và cả luồng phòng cặp trên giao diện; ai mở cũng đọc được bối cảnh, vai, mọi lượt hỏi (3 cách hỏi a_variants) và đáp ("Answer 1/2/3" từ b_variants, không có thì lấy b, nên gộp trước hay sau nhánh thêm b_variants đều được), gợi ý, cụm từ. Client speakPairApi và các component phòng đã xoá; API speak-pairs ở worker giữ nguyên, không ai gọi. Câu giới thiệu ở /speaking và ở thẻ Speak together của trang Nói: "Pick a topic. Read the questions and answers. Practise them with a partner in class." Trang hướng dẫn một buổi nói về breakout room của lớp, không nói về phòng mã, nên giữ nguyên.
Còn để ngỏ: thư nhắc trước buổi, giới hạn số người mỗi buổi, số liên lạc tại điểm hẹn.
Kiểm chứng: e2e/speakWalk.spec.ts (đồng hồ ghim; bốn khu; Join/Cancel/You are in/Closed; chưa ghi danh thì không Join; hết suất thì Join khoá; thẻ học phí), e2e/speakRegister.spec.ts (bốn thẻ, tên mới, chuyển hướng /speak-3), mobileAudit.spec.ts thêm start và walk, walkWeeks.test.ts (Chủ nhật, bốn khu luân phiên, hai bản lịch khớp), walks/routes.test.ts (đăng ký, gọi lại, huỷ, đóng sau giờ, quyền, 403 chưa ghi danh, 2 suất, 4 suất khi học cả hai khoá, trả suất, lượt thứ ba 409, buổi đã qua vẫn tính), cohortAgrees.test.ts, và test worker kiểm link trong thư NEMO SPEAK.
150. Trang NEMO WALK tối giản, mặc định giấu gần hết (SRC-1148, 30.09.2026)
Chủ dự án yêu cầu trang /speaking/walk (và bí danh /ielts/speaking/pair/walk) cực kỳ tối giản, gọn và dễ hiểu: mặc định giấu gần hết, learner bấm vào chỗ nào cần thì mới mở. Đây là luật tối giản SRC-048 áp lên §146. Chỉ đổi cách trình bày; API, Join, Cancel, suất và thông báo 403/409 giữ nguyên.
Mặc định chỉ còn:
- Tiêu đề
NEMO WALK, câuWalk. Talk. Speak English.và một dòng mờEvery Sunday 15:00 · Free. Hình lớn đổi thành một hình nhỏ đứng cạnh tiêu đề. - Một thẻ
Next walk: ngày giờ, khu và MỘT nút. Đủ điều kiện:Join, hoặcYou are in+Cancel, hoặcClosed. Không ghi danh NEMO SPEAK 1/2: một link nhỏFor NEMO SPEAK 1 and 2 learners(tới trang NEMO SPEAK 1); thẻ "Who can join" riêng đã gỡ. Bấm thân thẻ mở chi tiết: điểm hẹn, chủ đề, Speaking Mission, số người đi, thời lượng và giờ đóng đăng ký. - Bốn hàng đóng sẵn, mỗi hàng một nút có
aria-expanded+aria-controls, mở bằng preset MotionReveal:Upcoming walks(các tuần sau, mỗi tuần lại mở được để xem chi tiết và nút),Your walk slots(chỉ khi đủ điều kiện, ghi "n of m left" ngay trên hàng),What you will do(5 gạch đầu dòng của chủ dự án) vàAbout NEMO WALK(chữ giới thiệu nguyên văn của chủ dự án, kể cả câu kết).
Hàng bấm cao tối thiểu 44px, nút hành động 40px; ở 375px không cuộn ngang.
Kiểm chứng: apps/learn/e2e/speakWalk.spec.ts (mặc định chỉ có tiêu đề, thẻ Next walk và bốn hàng đóng; mở thẻ và từng hàng; Join/Cancel gọi đúng API; không đủ điều kiện chỉ có link nhỏ; hết suất thì Join bị khoá; tuần đã qua tự ẩn; 375px không cuộn ngang, hàng bấm >= 40px; ảnh chụp mặc định và mở ra ở desktop và 375px). mobileAudit.spec.ts đã phủ /speaking/walk.
161. NEMO WALK: hồ sơ một-câu-một-màn và quiz luật 10/10 trước buổi đầu (SRC-1193, 03.10.2026)
Chủ dự án 03.10.2026: trang learn.nemo12.com/walk dẫn tới một quiz 10 câu kiểm learner hiểu luật chung của NEMO WALK; phải đúng 10/10 mới qua, qua thì sang trang chúc mừng và server GHI LẠI là người này đã qua bài kiểm tra để bắt đầu tham gia. Trước quiz là một hồ sơ cá nhân hỏi từng câu một. Toàn bộ chữ là tiếng Anh rất đơn giản như trang Walk.
- Đường đi:
/walk(thẻ "Before your first walk") → đăng nhập Google nếu chưa →/walk/join(stepper) →/walk/quiz→/walk/passed. Mỗi bước lưu server ngay, mở lại thì về bước còn thiếu đầu tiên. Đã qua thì/walkhiện "You passed the NEMO WALK test" + link/speak/walk; vào/walk/quizbị đưa sang/walk/passed; vào quiz khi hồ sơ chưa xong bị đưa về/walk/join. - Stepper (9 câu, chi nhánh "Something else" còn 8): số điện thoại (di động VN, lưu E.164) · họ tên · ngày sinh (ba ô số, hiện DD.MM.YYYY, 8 đến 100 tuổi) · can-do Speaking A1..C1 kèm tình huống (chọn nhiều) · nói liền được bao lâu về gia đình · gặp du khách hỏi đường thấy thế nào · điểm thi 2 năm gần đây (IELTS Speaking / thi khác / chưa) · học sinh hay đi làm · trường + lớp hoặc nơi làm + nghề. Màn cuối xem lại, có nút Change.
- Ước lượng Speaking (
packages/walk/profile.ts): can-do chỉ đếm chuỗi liên tục từ A1; tự đánh giá = 0,6 can-do + 0,2 thời lượng + 0,2 độ thoải mái, không vượt quá chuỗi can-do một bậc; có IELTS Speaking thì 0,6 band (bảng IELTS-CEFR) + 0,4 tự đánh giá, độ tin "medium", không có thì "low". Thi khác chỉ lưu cho staff đọc. - Quiz (
packages/walk/quiz.ts, phiên bảnwalk-rules-v1): điểm hẹn cổng Nhà Thờ Lớn, check-in, ghép cặp bởi app/host, vai guide/tourist, vòng 2 đổi vai đổi chỗ, điện thoại chỉ xem nhanh, ghi chú sau mỗi vòng, chỉ tiếng Anh trong vòng, ở cạnh bạn cặp và tử tế, kết thúc bánh rán Lý Quốc Sư rồi trà chanh. Sai thì hiện câu nào sai kèm luật cần đọc lại (không đánh dấu đáp án), "Try again" chỉ hỏi lại các câu sai. - Trang Walk thành 5 thẻ gập (chủ dự án 03.10.2026, 5 thẻ là được): What you will do · The rules (luật điện thoại + 5 luật quiz hỏi, link "Know the rules? Take the quiz") · How it works (6 bước) · After the walk (bánh rán + trà chanh) · 5 places to visit. Mọi đáp án quiz đều đọc được trên trang.
- Server (
workers/api/src/modules/walks/entry.ts, migration 0325):GET /v1/learners/{id}/walk-entry,PUT .../walk-entry/profile(từng phần, gộp),POST .../walk-entry/quiz(chấm bằng cùng mã với UI; lưu mọi lượt với điểm, câu trả lời, phiên bản; lượt qua duy nhất mỗi phiên bản nhờ index UNIQUE có điều kiện; đề đổi phiên bản thì 409quiz_changed; hồ sơ chưa xong thì 409profile_incomplete),GET /v1/admin/walk-entriescho staff/admin. Riêng tư: chỉ chính learner ghi; đọc là learner, staff, admin; phụ huynh và mentor bị chặn dùcanAccessLearnerthường cho qua. Không PII trong URL, log hay localStorage. - Một nguồn: quiz, luật trường và ước lượng nằm ở gói
packages/walk(@nemo12/walk), learn và api cùng import;.github/app-paths.jsonkhaiwalklà nguồn chung để đổi gói thì deploy lại cả hai.
Kiểm: workers/api/src/modules/walks/entry.test.ts (quyền, từng nhánh hỏng, luật 10/10), apps/learn/src/walk/walkEntry.test.ts (chấm quiz, số điện thoại, ngày sinh, ước lượng Speaking), apps/learn/e2e/walkEntry.spec.ts (cả mạch ở 375px).