IELTS Guru là sản phẩm luyện thi IELTS AI-first của FLYER: mock test theo từng kỹ năng với chế độ thi thật, chấm AI Speaking và Writing với chi phí bằng một phần nhỏ kỳ thi thật, AI Mentor để chat và luyện nói, cùng mô hình kinh doanh kim cương + gói thuê bao. Trang PRD này đặc tả 100% sản phẩm đang chạy: toàn bộ routes, luồng, business rules, data model và các gap đã biết — từ việc quét trực tiếp codebase flyer/webs-ielts cộng số liệu mới từ database production.
Phiên bản
1.0
Ngày
24/08/2026
Owner
Tùng (Product)
Trạng thái
Đang chạy production
📈 Production (24/08/2026)207.767 lượt làm bài all-time28.195 học viên all-time11.612 lượt / 30 ngày661 học viên active / 30 ngàychạy từ 22/10/2024
📚 Nội dung1.789 parts3.550 câu hỏi4 kỹ năngđếm từ read replica production, các bảng ielts_*
IELTS Guru nhắm đến người học cần luyện IELTS sát đề thật không giới hạn và nhận phản hồi chất lượng chuyên gia ngay lập tức, không phải trả tiền thi thật hay thuê gia sư riêng. Câu định vị: "AI Mentor for smart IELTS preparation" — sản phẩm quảng bá chấm AI Speaking/Writing với chi phí bằng 1/50 kỳ thi thật. Phục vụ cùng lúc 3 nhóm: B2C tự học tại Việt Nam, B2C quốc tế (giá USD qua Polar), và B2B trường học qua white-label custom domain (có tenant riêng cho ACCA tại acca.teado.ai).
Thương hiệu & domain: logo và SEO title ghi "IELTS GURU", nhưng codebase vẫn canonical mọi trang về ielts.flyer.us; ieltsguru.ai serve cùng một app (subdomain nằm trong allow-list first-party). SEO title từng trang vẫn mang tên cũ "FLYER IELTS Virtual Testing Platform" — điểm lệch thương hiệu cần xử lý (§13).
Repo:flyer/webs-ielts độc lập trên Gitea (tách từ monorepo flyer/webs, giữ nguyên lịch sử). Nhánh dev → môi trường dev, main → staging, tag v*.*.* → production (hiện ở dòng v1.36.x).
Stack: Next.js 16.3.1 (Pages Router, Turbopack), React 19, TypeScript, Apollo Client (GraphQL v2 là chính), TanStack Query + openapi-fetch (REST v3), Jotai, antd 5 + MUI 5 + Tailwind, next-translate (en/vi), Firebase (Auth, Analytics, Remote Config), Sentry (self-hosted), RecordRTC + wavesurfer/howler cho audio, Rive/Lottie cho animation, toolchain oxlint/oxfmt.
Deploy: Docker (arm64) → ECR → EKS cluster flyer qua Tanka/jsonnet; production HPA 2–5 replicas theo 80% CPU; health check tại /api/ping; CI trên Gitea Actions, báo kết quả về Mattermost.
App đi kèm: app native iOS/Android com.flyer.ielts (App Store id 1671502218) nối qua universal links; phía giáo viên nằm ở teacher.flyer.us (giao bài, chấm tay); thanh toán chạy trên checkout của exam.flyer.us (VN) hoặc Polar (US).
Mục tiêu. (1) Cho người học IELTS luyện sát đề thật không giới hạn theo từng kỹ năng. (2) Thay chấm tay đắt đỏ bằng AI chấm band + phản hồi hành động được. (3) Nuôi hệ sinh thái FLYER: tài khoản dùng chung, bài giao của giáo viên, kỳ thi trường học, gói thuê bao theo band.
2Người dùng & user stories
Vai trò
User story
Ưu tiên
Người tự học
Làm mock test simulation đầy đủ một kỹ năng đúng điều kiện thi thật (đồng hồ, audio phát một lần, chống gian lận) và nhận band score.
P0
Người tự học
Nhận phản hồi AI Writing theo đúng 4 tiêu chí chấm band chính thức, sửa lỗi tới từng câu, kèm bài mẫu.
P0
Người tự học
Nhận phản hồi AI Speaking: transcript, phát âm từng từ (IPA, phoneme) và điểm fluency/grammar/vocab.
P0
Người tự học
Luyện linh hoạt: chọn part, tự đặt giới hạn thời gian, làm lại câu hỏi, dùng từ điển/ghi chú trong lúc luyện.
P0
Học viên
Nói chuyện với AI Mentor — chat tự do hoặc Topic Talk bằng giọng nói có learning outcomes — để luyện tiếng Anh giao tiếp.
P0
Học viên
Theo dõi tiến độ: đường band theo thời gian, radar kỹ năng, độ chính xác, thời gian học, band mục tiêu và số ngày tới kỳ thi.
P1
Học viên
Ôn lại lỗi sai: câu trả lời sai kèm giải thích, từ phát âm sai được thu âm lại và chấm lại, sổ từ vựng.
P1
Học sinh trường
Vào phòng thi nhiều kỹ năng do trường tổ chức có giám sát, vi phạm được báo về giáo viên.
P0 (B2B)
Giáo viên (qua teacher.flyer.us)
Giao đề thành mission có deadline, ẩn đáp án, xem và chấm tay bài của học sinh.
P1
Khách vãng lai
Xem toàn bộ thư viện đề, thậm chí làm bài bằng hồ sơ ẩn danh trước khi được mời đăng ký.
P1 (funnel)
3Kiến trúc thông tin & routes
App một khung sidebar trái (không có footer). Ngôn ngữ: en (mặc định, không prefix) và /vi. Chặn đăng nhập kiểu mềm: không có middleware hay chặn phía server — khách vãng lai nhận toast "mời đăng ký" tắt được ở mọi trang trừ một danh sách loại trừ nhỏ, còn sidebar chặn click vào các mục cần tài khoản để mở modal đăng nhập.
Route
Chức năng
Truy cập
/ → /home
Dashboard: lời chào, ô "Personal AI Teacher" nhập tự do (tạo phiên AI chat), thẻ kỹ năng kèm số mock test/đề, lối vào Speaking Topics, popup kỳ thi trường sắp diễn ra.
Công khai
/libraries
Thư viện học liệu gộp. Hai hàng: Study (đề luyện IELTS do FLYER biên soạn) và Quiz (đề cộng đồng/đối tác). Tab All / FLYER / Community / My school; filter lưu trên URL (tìm kiếm, kỹ năng, band, dạng câu, sắp xếp).
Công khai
/ielts/{skill} ×4
Danh sách mock test theo kỹ năng (listening, reading, writing, speaking) với filter topic/dạng câu/sắp xếp/part và cuộn vô hạn.
Công khai
/ielts/{skill}/[id] ×4
Chi tiết đề + màn làm bài trong cùng một route: preview → chọn chế độ → (kiểm tra loa/mic) → làm bài. SSR cho SEO meta.
Công khai → gate khi bắt đầu
/ielts/{skill}/result/[id] ×4
Màn điểm sau khi nộp; poll 3 giây/lần trong lúc AI đang chấm.
Đăng nhập
/ielts/{skill}/report/[id] ×4
Báo cáo chi tiết: đáp án + giải thích (L/R), phản hồi tiêu chí V2 (W), transcript + phát âm (S). Báo cáo Speaking cố tình để công khai, share được.
Đăng nhập (S: công khai)
/practice/[id] + result/review
Engine quiz: 13 dạng câu hỏi gồm kéo-thả, nối, flashcard, video tương tác, thu âm trả lời, câu mở chấm bằng AI.
Công khai → đăng nhập
/test-results/[id]
Xem lại bài Listening/Reading trong đúng giao diện lúc thi, chỉ đọc.
Chuyển hồ sơ người học (tối đa 20/tài khoản), form hồ sơ, giao diện (8 màu + dark) và ngôn ngữ.
Đăng nhập
/api/*
ping (health), cookies, link-preview, bug-report (→ Google Apps Script), imgproxy, polar-link-payment, student-chat/[id] + student-call/[id] (proxy SSE trên edge), file well-known cho Apple/Android.
—
Sidebar (desktop = drawer mobile): Mock tests → /, Study → /libraries, Missions, Mistakes, Vocabulary book, Learning profile, History; khối dưới: Teacher role (mở teacher.flyer.us), popup Thông báo, số kim cương → /diamonds-preview, popup avatar (Upgrade → /packages, Đổi giao diện, Mã kích hoạt, Đổi hồ sơ, Sửa hồ sơ, Đăng xuất).
4Mô hình nội dung & kho đề
Toàn bộ nội dung nằm trong container CheckPoint dùng chung giữa các sản phẩm FLYER, với các cạnh part riêng cho IELTS theo kỹ năng. Mọi dạng câu hỏi hiển thị (MCQ, T/F/NG, nối, chọn heading, điền form…) đều được ghép từ đúng 3 primitive, điều khiển bằng placeholder <blank id> trong contentHtml:
GAP_FILL — ô nhập tự do, tự lưu khi blur. SELECT — radio, hoặc checkbox nhiều đáp án khi đáp án đúng >1. OPTION — dropdown inline cho dạng nối/heading.
Sub-checkpoint (sectionCheckPoints) cho phép bán/làm riêng từng part Speaking với giá kim cương riêng.
Kho đề & usage production (read replica, 24/08/2026)
Kỹ năng
Parts
Câu hỏi
Lượt làm part
Lượt trả lời câu
Listening
488
857
96.011
165.128
Reading
461
1.258
60.770
150.434
Speaking
342
1.361
37.917
149.311
Writing
498
74
38.585
4.122
Tổng
1.789
3.550
233.283
468.995
Writing ít "câu hỏi" vì phần lớn writing task là đề bài luận cấp part, không chia câu. Ghi chú học viên lưu trong bài: 3.564 dòng (ielts_notes).
5Luồng mock test & practice
Hai chế độ trên mọi đề
Chế độ Practice
Chế độ Simulation (thi thử)
Parts
Học viên chọn tuỳ ý (Speaking: đúng 1 part)
Toàn bộ parts, thứ tự cố định
Đồng hồ
Tự chọn 15/30/45/60 phút
Σ thời gian các part, hết giờ tự nộp
Audio
Tua/dừng/nghe lại tự do
Phát một lần, ẩn nút điều khiển; đề Speaking được nghe lại tối đa 2 lần
Đề bài
Hiện theo cài đặt nội dung
Speaking: ẩn trừ Part 2
Công cụ
Từ điển, dịch, highlight, ghi chú
Tắt từ điển/dịch; chặn copy/paste
Chống gian lận
—
Ép fullscreen; chuyển tab/thoát fullscreen tính là vi phạm, modal cảnh báo, ẩn popup extension; violationCount nộp kèm bài
Luồng từng kỹ năng
Listening / Reading: Preview (thẻ chọn chế độ + giá kim cương + chọn chấm AI hay giáo viên) → kiểm tra loa (chỉ Listening) → màn làm bài với state react-hook-form, đồng hồ đếm từng giây, bảng câu hỏi theo part, trình phát Howler (Listening) hoặc splitter bài đọc/câu hỏi kéo được (Reading) → mỗi câu trả lời tự lưu qua submitPartAttempt → Nộp hoặc hết giờ → endAttempt(violationCount) → trang kết quả.
Writing: Preview với radio chọn cách chấm (Giáo viên — chỉ khi có canRequestTeacher — hoặc FLYER AI) → màn chia đôi: đề + hình bên trái, ô luận bên phải có đếm từ trực tiếp (cảnh báo mềm ở 500 từ, chặn cứng kèm toast) → tự lưu khi blur → nộp → trang kết quả poll trong lúc AI chấm.
Speaking: Preview (practice 1 part hoặc simulation đủ) → kiểm tra loa + mic (thu âm chỉ tại máy) → mỗi part: intro chạy chữ → mỗi câu: audio đề → đếm ngược suy nghĩ (timeToThink) → tự động bắt đầu thu, vòng tròn chạy theo timeToSpeak, tự dừng → upload (RecordRTC mono 16 kHz → /record → recordId) → nộp từng câu (+ ghi chú tuỳ chọn ở simulation) → đồng hồ part có thể ép nộp câu đang dở → kết thúc bài → kết quả.
Kỳ thi trường học (B2B, feature flag student_school_exam): popup chặn liệt kê các phiên thi theo kỹ năng kèm trạng thái; "Enter exam" mở đề với ?examId&sessionId&examMode=1 — ẩn hẳn chế độ Practice, attempt được nối vào phiên thi qua REST (link-attempt), vi phạm còn được báo trực tiếp về POST /v3/learner/exams/cheats.
Tính band. Tính phía server. Bài đủ → band 0–9 hiển thị X.X/9.0 (trang report làm tròn nửa band gần nhất); bài lẻ/practice → hiện số câu đúng/tổng thay vì band; Speaking ưu tiên teacherGrade hơn điểm AI khi có cả hai. Không có bài thi gộp 4 kỹ năng trong app — thi nhiều kỹ năng được tổ chức dưới dạng phiên thi trường học.
6Chấm AI — Writing & Speaking
Writing
Kích hoạt: học viên chọn chấm "FLYER AI" lúc bắt đầu (requestAIReview); trừ kim cương theo giá của đề. Client cố tình không kiểm tra ví trước — backend trả NOT_ENOUGH_DIAMOND (backend còn tính cả quota miễn phí).
Kết quả: trang report poll 3 giây/lần đến khi chấm xong. Hai thế hệ report: bản cũ (4 ô tiêu chí + nhận xét markdown) và V2 khi có detailedFeedback.
Rubric V2 bám đúng band descriptors chính thức — Task Achievement/Response, Coherence & Cohesion, Lexical Resource, Grammatical Range & Accuracy — mỗi tiêu chí chia tiêu chí con (chia đoạn, từ nối, collocation, dấu câu…), mỗi mục là cặp "Feedback + Cách cải thiện" song ngữ kèm machine key gắn badge mức độ.
Sửa tới từng câu:sentenceSuggestion[] gạch chân câu lỗi trong bài của học viên, tô màu theo errorImpact nặng nhất (CRITICAL/SEVERE/MODERATE/MINOR/NONE), popover hiện diff, danh sách gợi ý từ vựng, spotlight cuộn đồng bộ. Bài mẫu hiển thị bên cạnh.
Xuất file: Word (docx), PDF (in), link chia sẻ. Nhánh giáo viên hỗ trợ comment trích dẫn inline, comment giọng nói, bài đã sửa và bảng tiêu chí.
Speaking
Pipeline: thu âm → upload → chấm bất đồng bộ sau khi kết thúc bài (Azure Speech + LLM); trang kết quả poll 3 giây/lần, quá 2 phút thì dừng lịch sự.
Cấp bài: band tổng + 4 thanh điểm (phát âm, trôi chảy, từ vựng, ngữ pháp), mỗi thanh có màu theo mức đúng/cảnh báo/sai.
Từng câu: nghe lại bài nói, transcript, câu trả lời gợi ý (HTML + audio), chip điểm kỹ năng. Phản hồi phát âm tới từng từ: IPA, điểm bản xứ, phân tích từng phoneme, TTS phát âm chuẩn đặt cạnh audio của học viên. Payload Azure còn kèm Cambridge assessment (điểm ngữ pháp/từ vựng, lỗi EN/VI, gợi ý).
Quota: mỗi tuần học viên có lượt chấm AI Speaking miễn phí (aiIeltsSpeakingQuota remaining/total/used) trước khi trừ kim cương. Giá niêm yết: từ 2💎 mỗi AI mini test, 25💎 mỗi AI full test.
Schema DetailedFeedbackSpeaking giàu hơn (phân tích theo band descriptors như Writing V2) đã có phía server nhưng web chưa dùng (§13).
7AI Mentor (Bingo)
Lối vào: ô "Personal AI Teacher" trên Dashboard (tối đa 12.000 ký tự) tạo phiên chat và chuyển tin nhắn đầu tiên sang; hoặc hub /real-time-conversation với 2 thẻ chế độ: Chat và Topic Talk.
Chat (/real-time-conversation/chat/[id]): trả lời markdown stream qua SSE (route API chạy trên edge proxy về backend chat-AI), có rail lịch sử hội thoại, chip gợi ý, cuộn vô hạn, nút chuyển sang gọi.
Topic Talk (/real-time-conversation/topic): chọn chủ đề Bingo (level, topic, số lượt, điểm; sắp xếp được), rồi hội thoại giọng nói: học viên thu âm, audio upload đính vào tin nhắn, phản hồi stream về dạng xen kẽ text + audio MP3 base64 + viseme điều khiển avatar Rive nhép môi, phát theo hàng đợi có thứ tự. Mỗi chủ đề có checklist learningOutcomeSubjects[] tick trực tiếp khi học viên nói trúng ý; phiên kết thúc tường minh.
Giới hạn: quota gọi thoại theo ngày ("You have used up your call limit for today"). Chế độ thứ ba "Free talk / Call Bingo" đã dịch và làm dở nhưng chưa nối vào màn chọn chế độ (§13).
Endpoint AI phụ trợ: gợi ý câu trả lời, TTS (textToSpeak), từ điển (EN-VI/EN-EN/đồng nghĩa, fallback Google Translate + MyMemory), tự chấm câu mở của quiz, chấm lại phát âm từ sai.
8Tiến độ, báo cáo & công cụ học
Công cụ
Hành vi
Màn kết quả
Band hoặc điểm thô kèm pháo hoa; 4 trạng thái: đã có điểm / chờ AI (loader Rive, poll 3s) / chờ giáo viên / không yêu cầu chấm (mời "Làm lại với FLYER AI"). L/R tự mở phần xem đáp án; ẩn toàn bộ khi giáo viên giao bài đặt isHiddenAnswer.
Report chi tiết L/R
Cột điểm: số câu đúng/tổng, thời gian làm, band nửa điểm, lưới đáp án 2 cột (bài làm vs đáp án, nối bằng "or"). Cột chi tiết: audio theo part + tapescript bật/tắt (Listening), câu hỏi hiển thị lại chỉ đọc với ✅/❌, accordion giải thích (EN/VI).
History
Bảng phân trang cursor, tìm kiếm debounce, filter kỹ năng/loại/trạng thái; mỗi dòng mở đúng trang kết quả/report ở tab mới kèm ?url_back. Badge cho mã thách đấu và placement test.
Learning profile
Chọn kỳ (hôm nay → toàn thời gian); 6 thẻ chỉ số (bài hoàn thành, thời gian học, độ chính xác, band mục tiêu, ngày thi, số ngày còn lại); biểu đồ đường band trung bình; radar 4 kỹ năng có nhãn "cần cải thiện"; modal mục tiêu ép bước .0/.5 và điểm vào < mục tiêu.
Luyện từ sai
Từ phát âm sai kèm TTS chuẩn vs bản thu của học viên; thu âm lại và chấm lại (phản hồi IPA từng phoneme) trong hạn mức chấm lại; filter theo CEFR và trạng thái.
Sổ từ vựng
Ghi chú gộp theo đề, sửa được định nghĩa, có TTS, tạo từ tooltip highlight trong bài (Note / Highlight / Dictionary trên đoạn text bôi chọn).
9Tài khoản, đăng nhập & multi-tenant
Cách đăng nhập: số điện thoại-hoặc-username + mật khẩu, và Google qua Firebase. Không có Apple/Facebook; email chỉ là trường hồ sơ, không dùng đăng nhập. Quên mật khẩu qua OTP.
Đăng ký: số điện thoại → OTP → mật khẩu (luồng modal; trang cũ vẫn chạy). Hai kênh OTP: SMS backend cho số VN, Firebase phone OTP + reCAPTCHA ẩn cho quốc tế; thêm Cloudflare Turnstile. ?ref= ghi nhận domain nguồn white-label.
Nhiều hồ sơ: một tài khoản FLYER chứa tối đa 20 hồ sơ người học; đổi tại /profiles; khách vãng lai có hồ sơ ẩn danh theo cookie nên làm bài được trước khi đăng ký. Cookie profile_id trên apex domain đồng bộ các app exam/study/ranking/speaking.
Phiên: Apollo theo cookie với header device: WEB_IELTS; ép một phiên duy nhất — đăng nhập nơi khác đẩy sự kiện qua GraphQL subscription và toast chặn "bạn đã bị đăng xuất từ X".
Cài đặt: tab Hồ sơ (avatar, tên, ngày sinh, giới tính, tỉnh/trường/lớp, email/SĐT chỉ đọc, hạn gói, đổi mật khẩu) và tab Giao diện (sáng/tối + 8 màu nhấn, áp trước khi hydrate; đổi English/Tiếng Việt). Độ tương phản WCAG AA được ép bằng lint gate riêng trên file token.
White-label: mọi subdomain ngoài danh sách first-party là một tenant; route đăng nhập bật về domain chính rồi quay lại; flag theo domain để ẩn kim cương hoặc khoá đổi tên; tenant ACCA có form placement (/join-placementest) và tắt toast mời đăng ký.
Thông báo: chỉ popup trong app (badge, lời mời thách đấu); chưa có trung tâm cài đặt push/email.
10Monetization & các lớp gate
Gói thuê bao (FLYER IELTS PRO)
Gói
Giá VN (VND)
Giá gốc
Giá US
Checkout
3 tháng
790.000
1.000.000
$49
VN → checkout trên exam.flyer.us (VNPay); US → Polar (product ID hardcode); mặc định chọn gói 6 tháng
6 tháng ⭐
1.550.000
2.400.000
$89
12 tháng
2.320.000
3.900.000
$149
Nạp kim cương (tiền tệ chấm AI)
Gói
Kim cương
Giá (VND)
Trial
25
25.000
Basic
50
50.000
Pro Learner ⭐
125
99.000 (gốc 125.000)
Ví = diamond (mua) + freeIeltsDiamond (thưởng), có popover tách hai nguồn. Kênh thứ ba: mã kích hoạt nhập tại /active-account (cộng ngày gói + kim cương, có lịch sử mã đã dùng).
Bốn lớp gate độc lập
Quyền gói — đề khoá (isPremium / viewerCanAccess) chuyển user đã đăng nhập chưa mua sang /packages.
Quyền theo band — gói mang khoảng bandFrom–bandTo; filter band và kho đề nhìn thấy bị giới hạn trong khoảng đó (gói cũ = toàn bộ band 0–10).
Kim cương theo lượt — chấm AI Speaking/Writing trừ giá kim cương của đề; kiểm soát phía server (NOT_ENOUGH_DIAMOND).
Chấm giáo viên — lựa chọn "Request scoring from teacher" chỉ hiện khi hồ sơ có canRequestTeacher.
Attribution: cookie UTM (TTL 24h), referral_code (member-get-member, mới chỉ ghi nhận — chưa có UI giới thiệu), ?ref domain nguồn vào đăng ký. Analytics: GTM + GA4, Firebase Analytics, Meta Pixel; Sentry bắt lỗi. Banner smart-app iOS + universal links về com.flyer.ielts.
11Data, API & hạ tầng
Bề mặt API
GraphQL v2 (chính; ~80 queries, ~62 mutations, 1 subscription; toàn bộ là document codegen inline): danh mục nội dung, vòng đời attempt đối xứng theo kỹ năng startAttempt → submitPartAttempt (từng part/câu) → endAttempt(violationCount), kết quả/report kèm fragment chấm điểm, auth/hồ sơ, thông báo, missions, phiên AI conversation, ghi chú/từ điển/từ sai, thống kê. Subscription duy nhất đẩy sự kiện huỷ phiên đăng nhập.
REST v3 ("Flyer EdTech Platform API", backend Rust; sinh 242 hooks nhưng chỉ dùng 4): feature configs, danh sách kỳ thi, link-attempt (nối attempt ↔ phiên thi trường), báo gian lận. Có sẵn hook thoát hiểm cho 182 path còn lại.
Proxy SSE trên edge cho stream chat/gọi AI; upload audio qua endpoint record REST; speech-to-text qua endpoint REST v2.
Thực thể chính
CheckPoint (container nội dung dùng chung, ~80 trường) → parts theo kỹ năng → câu hỏi → 3 primitive; UserAttempt (~55 trường — một thực thể attempt cho mọi sản phẩm FLYER, gồm part attempts theo kỹ năng, các trường band/điểm, chấm AI + giáo viên, số vi phạm, thưởng gamification); User (ví, gói + quyền band) → tối đa 20 LearnerProfile (band mục tiêu, ngày thi, streak, quota AI speaking, trường/lớp, custom domain). Bảng production: 22 bảng ielts_* trên read replica (parts/câu hỏi/attempts theo kỹ năng + ghi chú).
Hạ tầng
CI Gitea Actions → Docker arm64 → ECR → EKS qua Tanka/jsonnet; dev (nhánh dev), staging (main), production (tag phiên bản). HPA 2–5 replicas theo 80% CPU với ghi chú lý do scaling ngay trong code; probe tại /api/ping.
Pipeline ảnh imgproxy riêng (URL dễ đọc, hỏng thì 307 về Next image); media trên statics.flyer.us.
Sentry self-hosted (init nằm trong module Apollo; sample 10%/1%); GA4 + GTM + Meta Pixel + Firebase Analytics; Remote Config là kênh feature-flag thứ hai bên cạnh /v3/learner/feature-configs.
Quy ước engineering đáng giữ: oxlint/oxfmt, knip, budget "ratchet" cho màu hex hardcode và gate tương phản WCAG AA dưới dạng script lint riêng, file config chú thích rất kỹ ("comment chính là tài liệu").
12Edge cases & xử lý lỗi
Tình huống
Xử lý
Thiếu kim cương lúc bắt đầu
Backend trả NOT_ENOUGH_DIAMOND; modal điều hướng nâng cấp (hiện đang trỏ /packages — xem gap #5).
Lỗi attempt nói chung
Bảng phân loại 16 mã lỗi trên hai kênh, mỗi mã map sang toast-hay-modal, khoá i18n và hành động (login / result / diamond / back / restart / retry); độ chặn tuỳ pha — start chặn hẳn, submit chủ yếu toast, end luôn cho lối ra.
Đồng hồ về 0
Tự nộp; Speaking còn dừng máy thu, ép nộp câu đang dở với lưới an toàn 20 giây.
Thoát fullscreen / chuyển tab trong simulation
Đếm vi phạm + modal cảnh báo + nháy tiêu đề tab; nuốt phím ESC và vào lại fullscreen; số vi phạm gửi kèm end-attempt và (trong kỳ thi trường) báo gian lận trực tiếp.
Đăng nhập nơi khác
Sự kiện subscription trực tiếp → toast chặn "đã bị đăng xuất từ X" kèm đăng nhập lại.
Bỏ dở câu Speaking
Guard theo thế hệ upload loại các audio upload muộn thuộc câu học viên đã rời đi.
AI chấm chậm/lỗi
Poll 3 giây; Speaking dừng lịch sự sau 2 phút; Writing giữ skeleton đến khi có phản hồi.
Giáo viên ẩn đáp án
isHiddenAnswer ẩn toàn bộ phần xem đáp án và đẩy route review về trang chủ.
Khách vãng lai vào trang cần tài khoản
Sidebar chặn bằng modal đăng nhập; gõ thẳng URL thì trang hiện khung rỗng (query bị skip) thay vì redirect.
imgproxy sập
307 fallback về trình tối ưu ảnh của Next, không vỡ ảnh.
13Gaps & nợ kỹ thuật đã biết
Phát hiện trong đợt quét toàn bộ codebase — mỗi mục hoặc là quyết định product cần chốt, hoặc là việc cần xếp lịch sửa.
#
Phát hiện
Loại
1
Chưa có placement test, bộ câu hỏi onboarding hay lộ trình học sinh tự động. "Personalized roadmap" mới chỉ nằm trong mô tả SEO; placementLevel, onboardingInfo và flag STUDENT_ONBOARDING chỉ có ở data model. Band mục tiêu được lưu nhưng chưa dùng để gợi ý nội dung.
Gap product
2
Tiếng Việt bị tắt cứng lúc runtime: cả hai nhánh của check IP đều gọi setLanguage("en"), đè cả lựa chọn tay ở lần tải sau.
Bug
3
Khách quốc tế chưa đăng nhập thấy giá sai: isFlyerUs trả false cho mọi người chưa đăng nhập, nên khách US thấy giá VND và checkout VN.
Bug
4
Chưa có đường Polar cho kim cương — người dùng quốc tế mua được gói nhưng không nạp được kim cương (tiền tệ chấm AI).
Gap product
5
NOT_ENOUGH_DIAMOND điều hướng về /packages (bán gói) thay vì /diamonds-preview (bán kim cương).
UX
6
Chưa có luồng xoá tài khoản (chỉ còn chuỗi lỗi mồ côi) — rủi ro App Store 5.1.1(v) vì app iOS nối thẳng vào đây.
Compliance
7
DetailedFeedbackSpeaking (phản hồi Speaking theo band descriptors kiểu Writing V2) đã có trong schema nhưng web chưa dùng.
Roadmap
8
Chế độ "Free talk / Call Bingo" đã dịch và làm một phần nhưng chưa nối vào màn chọn chế độ; /v3/learner/journey/continue sinh hook nhưng chưa gọi.
Roadmap
9
Thương hiệu/domain chưa nhất quán: canonical, robots.txt, sitemap và success URL của Polar đều trỏ ielts.flyer.us; SEO title từng trang vẫn ghi "FLYER IELTS Virtual Testing Platform". Chuyển hẳn sang ieltsguru.ai động tới ~7 file đã xác định.
Brand
10
Sitemap là 12 URL tĩnh hardcode — không có trang chi tiết đề, không có /packages; phần sinh động đã bị comment.
SEO
11
Secrets commit trong repo: token Polar thật, config Firebase, mật khẩu Redis và nhiều key khác nằm trong các file .env* đã commit — cần xoay vòng và chuyển vào secret store.
Bảo mật
12
Redirect premium chỉ chạy với user đã đăng nhập — paywall gói lách được bằng cách đăng xuất (làm bài ẩn danh vốn là chủ đích).
Cần chốt
13
Route chết còn được tham chiếu (màn thách đấu, /verify-account, /update-profile, /checkout…), ô SĐT disabled gắn console.log, daily reward nối dở, các tab settings (general/notifications/privacy) dịch rồi nhưng chưa build, theme GAMIFICATION đã nghỉ = cây code lớn không chạy tới.
Nợ kỹ thuật
14
Feedback của học viên đổ vào Google Sheet qua Apps Script (widget báo lỗi), không vào database sản phẩm; kênh hỗ trợ là Zalo.
Vận hành
14Acceptance criteria & tương lai
Acceptance criteria (đã kiểm chứng trên production, 24/08/2026)
Cả 4 kỹ năng đều có chế độ Practice và Simulation với các khác biệt ở §5; simulation ép fullscreen chống gian lận và nộp violationCount.
Report AI Writing trả phân tích band 4 tiêu chí với feedback tiêu chí con song ngữ và sửa lỗi tới từng câu; report AI Speaking trả transcript + phát âm từng từ với IPA/phoneme; cả hai poll 3 giây.
Trừ kim cương kiểm soát phía server, tính cả quota miễn phí; ví = kim cương mua + kim cương thưởng.
Gói theo band giới hạn kho đề nhìn thấy qua quyền bandFrom–bandTo.
Phiên thi trường học ẩn chế độ Practice, nối attempt vào phiên thi và báo gian lận trực tiếp.
Khách vãng lai xem và làm bài được trên hồ sơ ẩn danh; một tài khoản tối đa 20 hồ sơ với ép một phiên duy nhất.
Số liệu production trên trang này tái lập được từ read replica (bảng ielts_*; usage = user_attempts.type_attempt='IELTS').
Đề xuất bước tiếp theo (từ danh sách gaps)
Khép vòng cá nhân hoá: placement test + onboarding → dùng ieltsTargetScore/ieltsExamDate để gợi ý nội dung thật (đúng cái "roadmap" marketing đang hứa).
Ship Speaking feedback V2 (schema đã sẵn) và chế độ Free-talk giọng nói.
Sửa doanh thu quốc tế: Polar cho kim cương, giá theo geo đúng cho khách chưa đăng nhập, luồng xoá tài khoản cho chuẩn app store.
Gom thương hiệu về ieltsguru.ai: canonical/sitemap/robots/OG + title từng trang, kèm sitemap động cho trang đề.
Vệ sinh bảo mật: xoay vòng secrets đã commit, chuyển vào secret store của k8s.
← Danh mục PRD · Nguồn: quét trực tiếp flyer/webs-ielts nhánh dev (24/08/2026) + read replica production của FLYER · Nội bộ FLYER.