561 lines
19 KiB
Markdown
561 lines
19 KiB
Markdown
# 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 | 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 — 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 có user đăng ký, 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 ký 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 cá 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 có đủ 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**: 5–6 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, có 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 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) + 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 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 4+ |
|
||
| 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, Flutter Phase 3 khi có 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 2–3 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õ 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, 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
|
||
- **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ử 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 |
|
||
| AdSense bị block (adblocker) | 🟡 TB | Rewarded ads mobile bù 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 | |