Files
english/Claude.md
2026-04-12 22:59:46 +07:00

561 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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**: Phase 2 done — thêm Phase 3 Retention & Monetization, đẩy Speaking AI và Full TOEIC sang Phase 4 & 5
---
## 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**: 5 phases — MVP → Auth & Progress → Retention & Monetization → 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 | 1216px |
| 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 14 (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 17)
- ✅ 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 17)
- 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 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 để 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
**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 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 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 — Xu System & Gamification ← Tiếp theo
**Mục tiêu**: Tạo thói quen học hàng ngày, giữ chân user bằng Xu economy + gamification
**Platform**: Web only (không Flutter phase này)
**Trigger**: Phase 2 user đăng , cần convert sang returning users
---
#### Xu Economy — Trung tâm của Phase 3
```
Học hàng ngày / xem ads → kiếm Xu
Xu → dùng tính năng premium
Hết Xu → xem ads thêm
(nạp tiền thật → Phase 4)
```
**Kiếm Xu (miễn phí)**:
| Hành động | Xu nhận |
|---|---|
| Đăng lần đầu (welcome bonus) | 50 Xu |
| Hoàn thành daily goal | 10 Xu |
| Streak milestone (7 / 30 / 100 ngày) | 20 / 50 / 100 Xu |
| Xem rewarded ads trên web | 5 Xu / video (tối đa 5 video/ngày) |
**Dùng Xu**:
| Tính năng | Chi phí |
|---|---|
| Streak freeze (bảo vệ 1 ngày) | 20 Xu |
| Thêm 5 lượt AI Writing (GLM-4.7) | 30 Xu |
| 1 lượt AI Writing cao cấp (GPT-4o) | 15 Xu |
| Mở thêm bài thi khi hết giới hạn free | 10 Xu |
> ⚠️ Chưa có nạp Xu bằng tiền thật ở Phase 3 — chỉ kiếm qua học + ads.
> Nạp tiền thật (VNPay/MoMo) → Phase 4.
---
#### AI Model Tier
| Tier | Model | Free limit | Dùng Xu |
|---|---|---|---|
| Free | GLM-4 base | 3 lần/ngày | |
| Standard | GLM-4.7 | | 30 Xu / 5 lượt |
| Premium | GPT-4o / Claude | | 15 Xu / lượt |
---
#### Gamification
- **Streak hàng ngày**: học ít nhất 1 bài/ngày giữ chuỗi
- **XP points**: mỗi bài thi / flashcard / writing check XP
- **Cấp độ**: Beginner Bronze Silver Gold Master (theo XP tích luỹ)
- **Streak freeze**: dùng Xu bảo vệ streak khi bận hook mạnh nhất
- **Weekly goal**: đặt mục tiêu tuần, hoàn thành badge + thưởng Xu
#### Leaderboard
- Bảng xếp hạng tuần theo XP (reset mỗi tuần, không tích luỹ)
- Hiện top 10 + vị trí của bản thân
- Chia sẻ kết quả lên Facebook/Zalo viral loop tự nhiên
#### Nhắc nhở
- Browser push notification (web, không cần app)
- Giờ nhắc do user tự chọn
- Message nhân hoá: *"Streak 7 ngày của bạn sắp mất!"*
#### Lộ trình AI cá nhân hoá
- Phân tích kết quả thi suggest *"Tuần này tập trung Part 5 và 6"*
- Dashboard: *"Bạn yếu nhất ở Part 5 — luyện ngay"*
- Đặt ngày thi TOEIC đếm ngược + lịch ôn gợi ý
#### Web Ads
- Google AdSense: banner dưới trang + interstitial sau kết quả bài thi
- Rewarded video ads: xem để nhận Xu
- Không ads trong lúc đang làm bài
- User đủ Xu / premium không hiện ads (Phase 4)
---
#### DB Schema bổ sung
```sql
CREATE TABLE user_gamification (
user_id UUID REFERENCES users(id) PRIMARY KEY,
xp INT DEFAULT 0,
level TEXT DEFAULT 'beginner', -- beginner | bronze | silver | gold | master
streak INT DEFAULT 0,
longest_streak INT DEFAULT 0,
last_active DATE,
xu INT DEFAULT 50, -- welcome bonus
freeze_count INT DEFAULT 0
);
CREATE TABLE xu_transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
type TEXT, -- earn_welcome | earn_daily | earn_streak | earn_ads | spend_freeze | spend_writing | spend_test
amount INT, -- dương = nhận, âm = tiêu
balance INT, -- số Xu sau giao dịch (để audit)
description TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE weekly_leaderboard (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
week_start DATE,
xp_earned INT DEFAULT 0,
rank INT
);
```
**Tech mới**:
- Google AdSense (banner + rewarded video)
- Browser Push Notification API
- Cron job: reset leaderboard mỗi tuần, check streak hàng ngày
**Không có ở Phase 3**:
- Nạp tiền thật (VNPay / MoMo) Phase 4
- Flutter / mobile app Phase 4
- Subscription / Premium plan Phase 4
**Timeline**: 56 tuần
---
### PHASE 4 — Speaking AI
**Mục tiêu**: Tăng differentiation, cover kỹ năng Speaking cho IELTS/TOEIC
**Trigger**: Phase 3 ổn định, doanh thu đều
**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 điểm số 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) + Flutter audio recording
---
### PHASE 5 — Full TOEIC Mock Test
**Mục tiêu**: Platform luyện TOEIC toàn diện chuẩn ETS
**Trigger**: Phase 4 xong, cần nội dung premium cao cấp hơn
**Tính năng**:
- Full TOEIC test chuẩn ETS: 200 câu, 120 phút
- Audio Listening chuẩn cho Part 14
- Auto-score: tính điểm 10990 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 | 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 4+ |
| Không xác thực email Phase 2 | MVP giảm friction đăng tối đa |
| Chỉ 3 field đăng (tên/email/pass) | Friction thấp nhất, đủ để identify user |
| Guest chỉ xem preview, không làm được | Buộc đăng để 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, Flutter Phase 3 khi traction |
| Coins tên "Xu" | Gần gũi user VN hơn "Credits" hay "Points" |
| Pay-as-you-go thay subscription | User VN ít cam kết dài hạn, mua theo nhu cầu dễ convert hơn |
| AI model tier theo Xu | Tạo upsell tự nhiên user thấy feedback tốt hơn khi dùng model cao hơn |
| Rewarded ads mobile, banner ads web | Phù hợp từng platform mobile chịu video, web chịu banner |
| Supabase tạm Phase 1 | Ra nhanh hơn 23 tuần, schema chuẩn để migrate sau |
| GLM thay OpenAI/Claude | Rẻ hơn, OpenAI-compatible, swap dễ |
| Desktop-first | Target TOEIC learner hay dùng máy tính |
| TanStack Query + Zustand | Server state tách biệt client state ràng |
| NestJS Phase 2 | Supabase đủ để validate, NestJS khi scale |
| Speaking AI Phase 4 | Cần infra + monetization ổn định trước khi làm realtime audio |
| Full mock test Phase 5 | 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, dụ sửa tiếng Anh
- **Desktop-first**: Design 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ùng Supabase, PostgreSQL schema phải production-ready
- **Coins = "Xu"**: Dùng nhất quán trong code lẫn UI
---
## Rủi ro đã nhận diện
| Rủi ro | Mức độ | Xử |
|---|---|---|
| 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 |
| AdSense bị block (adblocker) | 🟡 TB | Rewarded ads mobile lại, không phụ thuộc 1 nguồn |
| VNPay/MoMo integration phức tạp | 🟡 TB | Dùng payment gateway trung gian (Stripe VN, PayOS) |
| Audio quality Phase 5 | 🟡 TB | Budget cho studio recording hoặc TTS premium |