# Claude Project Context — English Learning App (TOEIC Focus) > File này cung cấp context đầy đủ cho Claude khi làm việc với dự án. > Cập nhật file này mỗi khi có quyết định kiến trúc mới. > **Last updated**: Merged all decisions — Phase 1 scaffold done, Phase 2–4 planned --- ## Tổng quan dự án **Loại sản phẩm**: Web app học tiếng Anh / luyện thi TOEIC & IELTS cho người dùng Việt Nam **Target users**: Sinh viên, người đi làm tại Việt Nam cần TOEIC, IELTS, hoặc học tiếng Anh tổng quát **Focus chính**: TOEIC (mở rộng market), sau đó IELTS **Giai đoạn hiện tại**: Phase 1 — MVP, validate market **Roadmap**: 4 phases — MVP → Auth & Progress → Speaking AI → Full TOEIC --- ## Tech Stack ### Frontend | Layer | Tech | Ghi chú | |---|---|---| | Framework | **React** + **Vite** + **TypeScript** | | | Routing | **TanStack Router** | File-based, type-safe | | Server state | **TanStack Query** | Fetch, cache, sync API data | | Client state | **Zustand** | UI state + localStorage persist | | Styling | **Tailwind CSS** | Desktop-first | | UI Components | **shadcn/ui** | Dùng khi cần, không bắt buộc | ### Design System (từ Stitch export) | Token | Value | |---|---| | Font | Plus Jakarta Sans + Material Symbols Outlined | | Primary | #2563EB | | Success | #16A34A | | Danger | #DC2626 | | Background | #F8FAFC | | Card | #FFFFFF | | Border radius | 12–16px | | Shadow | soft, subtle | ### Responsive Layout | Breakpoint | Layout | |---|---| | Desktop (1280px) | Sidebar trái cố định (240px) + main content — **LAYOUT CHÍNH** | | Tablet (768px) | Sidebar thu gọn icon-only | | Mobile (375px) | Ẩn sidebar, hiện bottom navigation bar | ### Backend | Phase | Tech | Ghi chú | |---|---|---| | Phase 1 | **Supabase** (PostgreSQL + Edge Functions + JS SDK) | Tạm thời, migrate sau | | Phase 2+ | **NestJS** + **PostgreSQL** native | Khi có traction | > ⚠️ Supabase chỉ dùng Phase 1. Schema PostgreSQL thiết kế chuẩn ngay từ đầu để migrate không đau. ### AI | Layer | Tech | Ghi chú | |---|---|---| | Provider | **GLM (Z.ai API)** | Rẻ, OpenAI-compatible format | | Endpoint | `open.bigmodel.cn/api/paas/v4` | | | Model | GLM-4 / GLM-4.7 | | | Fallback | OpenAI / Claude API | Swap dễ vì API compatible | | Gọi từ | Supabase Edge Function (Phase 1) → NestJS service (Phase 2+) | Giấu API key | ### Deploy | Layer | Tech | |---|---| | Frontend | Self-hosted server (có sẵn) | | Backend | Self-hosted server (có sẵn) | | Database | Supabase Cloud (Phase 1) → self-hosted PostgreSQL (Phase 2+) | --- ## Database Schema (PostgreSQL) ```sql -- Câu hỏi TOEIC CREATE TABLE questions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), part INT NOT NULL, -- 1 đến 7 type TEXT, -- photo | q&a | incomplete_sentence | etc. content TEXT NOT NULL, -- nội dung câu hỏi / đoạn văn options JSONB, -- ["A. ...", "B. ...", "C. ...", "D. ..."] answer TEXT NOT NULL, -- "A" explanation TEXT, -- giải thích đáp án bằng tiếng Việt audio_url TEXT, -- Part 1–4 (listening) image_url TEXT, -- Part 1 (photos) created_at TIMESTAMPTZ DEFAULT now() ); -- Từ vựng TOEIC CREATE TABLE vocab ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), word TEXT NOT NULL, phonetic TEXT, -- /wɜːrd/ meaning_vi TEXT NOT NULL, -- nghĩa tiếng Việt topic TEXT NOT NULL, -- business | office | travel | finance | hr | marketing example TEXT, -- câu ví dụ tiếng Anh created_at TIMESTAMPTZ DEFAULT now() ); -- Phase 2+ CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT UNIQUE NOT NULL, name TEXT NOT NULL, password TEXT NOT NULL, -- hashed created_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE user_progress ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id), type TEXT, -- test | vocab | writing reference_id UUID, data JSONB, created_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE writing_submissions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id), content TEXT NOT NULL, feedback JSONB, created_at TIMESTAMPTZ DEFAULT now() ); ``` --- ## TypeScript Interfaces ```typescript interface Question { id: string part: number type: string content: string options: string[] answer: string explanation: string audioUrl?: string imageUrl?: string } interface VocabWord { id: string word: string phonetic: string meaningVi: string topic: 'business' | 'office' | 'travel' | 'finance' | 'hr' | 'marketing' example: string } interface TestResult { testId: string part: number score: number total: number duration: number answers: { questionId: string; selected: string; correct: boolean }[] completedAt: Date } interface WritingFeedback { score: string grammar: string[] vocabulary: string[] structure: string improvedVersion: string summary: string } // Phase 2+ interface User { id: string email: string name: string createdAt: Date } ``` --- ## Cấu trúc thư mục ``` src/ ├── routes/ │ ├── index.tsx ← Trang chủ (/) │ ├── toeic/ │ │ ├── index.tsx ← Chọn Part (/toeic) │ │ ├── part.$partId.tsx ← Config số câu (/toeic/part/$partId) │ │ ├── session.tsx ← Làm bài (/toeic/session) │ │ └── result.tsx ← Kết quả + đáp án (/toeic/result) │ ├── writing.tsx ← AI Writing Checker (/writing) │ ├── vocab.tsx ← Flashcard (/vocab) │ └── auth/ ← Phase 2 │ ├── login.tsx ← Đăng nhập (/auth/login) │ └── register.tsx ← Đăng ký (/auth/register) ├── components/ │ ├── layout/ │ │ ├── Sidebar.tsx ← Desktop sidebar │ │ └── BottomNav.tsx ← Mobile bottom nav │ ├── QuestionCard.tsx │ ├── FlashCard.tsx │ ├── WritingFeedback.tsx │ ├── ProgressRing.tsx │ └── Timer.tsx ├── store/ │ ├── testStore.ts ← Zustand: trạng thái bài thi │ ├── vocabStore.ts ← Zustand: flashcard progress (persist localStorage) │ └── authStore.ts ← Zustand: user session (Phase 2) ├── hooks/ │ ├── useQuestions.ts ← TanStack Query │ ├── useVocab.ts ← TanStack Query │ └── useWritingCheck.ts ← TanStack Mutation → Edge Function ├── lib/ │ └── supabase.ts ← Supabase client init └── utils/ └── rateLimiter.ts ← Rate limit 3 lần/ngày/IP (localStorage) ``` --- ## Supabase Edge Function — AI Writing Checker ```typescript // supabase/functions/writing-check/index.ts import { serve } from "https://deno.land/std/http/server.ts" serve(async (req) => { const { content } = await req.json() const response = await fetch("https://open.bigmodel.cn/api/paas/v4/chat/completions", { method: "POST", headers: { "Authorization": `Bearer ${Deno.env.get("GLM_API_KEY")}`, "Content-Type": "application/json" }, body: JSON.stringify({ model: "glm-4", messages: [ { role: "system", content: `You are an expert English writing evaluator for TOEIC/IELTS. Evaluate the writing and return ONLY valid JSON: { "score": "estimated band score", "grammar": ["error + fix"], "vocabulary": ["suggestion"], "structure": "feedback in Vietnamese", "improved_version": "rewritten version", "summary": "overall feedback in Vietnamese" }` }, { role: "user", content } ] }) }) const data = await response.json() const result = JSON.parse(data.choices[0].message.content) return new Response(JSON.stringify(result), { headers: { "Content-Type": "application/json" } }) }) ``` --- ## Roadmap — 4 Phases --- ### PHASE 1 — MVP (Hiện tại) 🚧 **Mục tiêu**: Ra sản phẩm web dùng thử không cần login, validate market **Stack**: React + Vite + TypeScript + TanStack + Zustand + Tailwind + Supabase + GLM **Tính năng**: - ✅ Luyện đề TOEIC mini test theo từng Part (Part 1–7) - ✅ Chọn số câu: 10 / 20 / full part, có đếm giờ - ✅ Submit → xem điểm + đáp án + giải thích tiếng Việt - ✅ Lịch sử kết quả + thống kê điểm yếu theo Part (localStorage) - ✅ AI Writing Checker (GLM, 3 lần/ngày/IP, không cần login) - ✅ Flashcard từ vựng TOEIC (6 chủ đề, localStorage progress) **Không có**: - ❌ Auth / login - ❌ Progress sync server - ❌ Thanh toán - ❌ Flutter / mobile app - ❌ Full mock test **Timeline**: 5 tuần **Done khi**: - ≥ 50 câu hỏi mỗi Part (Part 1–7) - AI Writing Checker phản hồi < 5 giây - Không lỗi hiển thị trên Chrome mobile - 20+ người dùng thật đã dùng thử - Không critical bug sau 1 tuần beta --- ### PHASE 2 — Auth & Progress **Mục tiêu**: Giữ chân user, sync progress server-side, hiểu behavior trước khi monetize **Trigger**: Phase 1 có traction — 200+ MAU hoặc feedback tích cực **Stack thay đổi**: - Migrate Supabase → **NestJS + PostgreSQL native** - Thêm **Redis** cho cache + session **Guest Access (chưa đăng ký)**: - Xem preview 1 bài test dạng read-only (thấy câu hỏi, không làm được) - Không cho submit đáp án, không xem kết quả - Hiện modal "Đăng ký để luyện thi" khi cố tương tác - Flashcard: xem vài card đầu, bị chặn sau đó - AI Writing: không dùng được, hiện CTA đăng ký **Auth — Đăng ký**: - Form: **Tên + Email + Password** (chỉ 3 field) - Không xác thực email, không OTP, không confirm - Đăng ký xong → **redirect home luôn** **Auth — Đăng nhập**: - Email + Password - Redirect về trang trước hoặc home **Sau khi đăng nhập**: - Làm bài không giới hạn - Progress sync server-side: lịch sử thi, từ vựng, writing submissions - Dashboard cá nhân: streak, biểu đồ điểm, điểm yếu theo Part - AI Writing: 10 lần/ngày **Không có ở Phase 2**: - ❌ Xác thực email - ❌ Quên mật khẩu - ❌ Google / Zalo OAuth - ❌ Flutter / mobile app - ❌ Thanh toán / freemium - ❌ Notification --- ### PHASE 3 — Speaking AI **Mục tiêu**: Tăng differentiation, cover kỹ năng Speaking cho IELTS/TOEIC **Trigger**: Phase 2 ổn định, user quay lại đều đặn **Tính năng**: - AI Speaking Coach: record giọng → AI chấm phát âm + so sánh native speaker - Luyện IELTS Speaking Part 1/2/3 (mock interview với AI) - Shadow reading: nghe → lặp lại → AI so sánh độ chính xác - Pronunciation scoring có điểm số và progress chart **Tech mới**: - Speech-to-text: Whisper API hoặc Google Speech-to-Text - Text-to-speech: native audio - WebRTC / MediaRecorder API (web) --- ### PHASE 4 — Full TOEIC Mock Test **Mục tiêu**: Platform luyện TOEIC toàn diện chuẩn ETS **Trigger**: Phase 3 xong, cần nội dung premium **Tính năng**: - Full TOEIC test chuẩn ETS: 200 câu, 120 phút - Audio Listening chuẩn cho Part 1–4 - Auto-score: tính điểm 10–990 theo bảng quy đổi ETS - Phân tích chi tiết: điểm mạnh/yếu từng Part, so sánh lần trước - Bộ đề theo năm: ETS 2023, 2024, Actual Test... - Đếm ngược đến ngày thi + lịch ôn tập gợi ý --- ## Quyết định kiến trúc quan trọng | Quyết định | Lý do | |---|---| | Không auth Phase 1 | Giảm scope, validate market trước | | Email only Phase 2, không OAuth | Đơn giản nhất để build, OAuth Phase 3+ | | Không xác thực email Phase 2 | MVP — giảm friction đăng ký tối đa | | Chỉ 3 field đăng ký (tên/email/pass) | Friction thấp nhất, đủ để identify user | | Guest chỉ xem preview, không làm được | Buộc đăng ký để dùng, giúp thu thập user data | | Không thanh toán Phase 2 | Hiểu behavior trước khi charge tiền | | Không Flutter Phase 2 | Web đã responsive, mobile app khi có traction rõ ràng | | Supabase tạm Phase 1 | Ra nhanh hơn 2–3 tuần, schema chuẩn để migrate sau | | GLM thay OpenAI/Claude | Rẻ hơn, OpenAI-compatible, swap dễ | | Desktop-first (không mobile-first) | Target TOEIC learner hay dùng máy tính | | TanStack Query + Zustand | Server state tách biệt client state rõ ràng | | localStorage Phase 1 | Đủ cho MVP, không cần backend phức tạp | | NestJS Phase 2 | Supabase đủ để validate, NestJS khi scale | | Speaking AI Phase 3 | Cần infra ổn định trước khi làm realtime audio | | Full mock test Phase 4 | Cần content team + audio, không phải tech problem | --- ## Conventions - **Ngôn ngữ**: Tiếng Việt cho UI người dùng, English cho code/comments/type names - **Giải thích đáp án**: Luôn bằng tiếng Việt - **AI feedback**: Nhận xét tổng thể tiếng Việt, ví dụ sửa tiếng Anh - **Desktop-first**: Design và test trên 1280px trước, mobile sau - **YAGNI / KISS**: Không build thứ chưa cần, từng Phase giải quyết từng vấn đề - **Schema chuẩn ngay từ đầu**: Dù dùng Supabase, PostgreSQL schema phải production-ready --- ## Rủi ro đã nhận diện | Rủi ro | Mức độ | Xử lý | |---|---|---| | Content đề TOEIC chất lượng thấp (crawl) | 🔴 Cao | Crawl ít + clean kỹ, tự soạn dần thay thế | | GLM chấm writing không đủ tin cậy | 🟡 TB | Test prompt kỹ, fallback OpenAI nếu cần | | Latency GLM từ VN cao | 🟡 TB | Benchmark thực tế, cache response nếu cần | | User mất progress (localStorage Phase 1) | 🟡 TB | Chấp nhận Phase 1, auth Phase 2 giải quyết | | Bản quyền đề TOEIC crawl | 🟡 TB | Seed nhanh, thay bằng nội dung tự soạn dần | | Supabase free tier limit | 🟢 Thấp | 500MB đủ Phase 1, migrate trước khi hit limit | | Audio quality Phase 4 | 🟡 TB | Budget cho studio recording hoặc TTS premium |