Thiết Kế Bài Test Chẩn Đoán 4 Loại Bệnh Tiếng Anh

Date: 2026-01-09 Status: Design Complete - Ready for Implementation Duration: 5-10 phút (adaptive based on performance) Philosophy: "Proving they haven't been taught correctly" NOT "proving they're bad"

Constants Reference: Xem definitions.md cho tất cả constants và enums.


Tổng Quan

Bài test chẩn đoán 4 loại "bệnh" tiếng Anh (Mù/Điếc/Câm/Yếu phản xạ) để cá nhân hóa lộ trình học 120 ngày. Test sử dụng adaptive logic với progressive gate để tối ưu thời gian và tâm lý người học.

Triết Lý Thiết Kế

Core Principles:

  1. Không ai bị "loại" - chỉ có "được hỏi ít hơn"
  2. Micro-step difficulty increase - tăng độ khó rất chậm
  3. Foundation-first strictness - Mù/Điếc khắt khe, Câm/Phản xạ nhân văn
  4. Empathy in UI - không hiển thị % điểm, không dùng từ "skip" hay "fail"

I. Cấu Trúc Test - Progressive Gate Logic

Gate Flow Architecture

START
  ↓
┌─────────────────────────────────┐
│  GATE 1: MÙ (Vocabulary)       │
│  Duration: 2-3 phút             │
│  Questions: 8-12 câu (adaptive) │
└──────────┬──────────────────────┘
           ↓
    ┌──────┴──────┐
    │  Evaluate   │
    │  Score      │
    └──────┬──────┘
           ↓
    ≥60%  │  40-59%  │  <40%
    ────┬─┴─┬────────┴────
        ↓   ↓             ↓
      Full  Reduced    Flag: Mù Nặng
      Next  Difficulty  Shorten Rest
           ↓
┌─────────────────────────────────┐
│  GATE 2: ĐIẾC (Listening)      │
│  Duration: 2-3 phút             │
│  Questions: 8-10 câu (adaptive) │
└──────────┬──────────────────────┘
           ↓
    ≥55%  │  35-54%  │  <35%
    ────┬─┴─┬────────┴────
      Normal  Fewer Qs  Flag: Điếc Nền
              Slower
           ↓
┌─────────────────────────────────┐
│  GATE 3: CÂM (Speaking)        │
│  Duration: 1-3 phút             │
│  Questions: Adaptive 1-4 câu    │
│                                  │
│  • Mù+Điếc OK → 3-4 câu         │
│  • 1 yếu → 1-2 câu              │
│  • Cả 2 yếu → 1 câu có hint     │
└──────────┬──────────────────────┘
           ↓
┌─────────────────────────────────┐
│  GATE 4: PHẢN XẠ (Speed)       │
│  Duration: 1-2 phút             │
│  Questions: 3-5 câu (adaptive)  │
│                                  │
│  • Nếu nền yếu: không countdown │
│  • Luôn có ít nhất 1 câu        │
└──────────┬──────────────────────┘
           ↓
      ┌────────┐
      │ RESULT │
      └────────┘

Thời Gian Tổng (Trong Khung 5-10 Phút)

User Profile Tổng Thời Gian Lý Do
Mù nặng (<40%) 4-5 phút Rút gọn Câm/Phản xạ
Mù+Điếc yếu 6-7 phút Test đủ 4 phần, giảm số câu
Qua nền (≥60%) 8-10 phút Full test tất cả phần

Key Insight: Không ai cảm thấy bị "tra khảo" - thời gian tự điều chỉnh tự nhiên.


II. Chi Tiết Từng Phần Test

A. GATE 1 - MÙ (Vocabulary / Reading Comprehension)

Mục tiêu: Đánh giá vốn từ vựng và khả năng đọc hiểu cơ bản

Số Lượng Câu Hỏi

  • Baseline: 10 câu
  • Adaptive: 8-12 câu tùy performance
    • Đúng 2-3 câu liên tiếp → tăng độ khó
    • Sai 2-3 câu liên tiếp → giữ nguyên/giảm nhẹ

Loại Câu Hỏi (2 Types)

Type 1: Word Recognition (Image + 4 Words) - 60% câu

[Hiển thị hình ảnh quả táo]

Question: What is this?
A) apple ✓
B) orange
C) banana
D) grape

Difficulty levels:
- Pre-A1: apple/cat/dog
- Pre-A1+: table/chair/door
- A1-: beautiful/difficult/important
- A1: approach/consider/develop
- A1+: circumstance/acknowledge/efficient

Type 2: Word Definition Matching - 40% câu

Question: Match the word "teacher" with its meaning

A) A person who teaches ✓
B) A large building
C) An animal that flies
D) A type of food

Difficulty levels:
- Pre-A1: Simple nouns (teacher/student/doctor)
- A1-: Action verbs (run/jump/swim)
- A1: Abstract concepts (happiness/freedom/truth)
- A1+: Complex meanings (analyze/interpret/establish)

Adaptive Logic (Micro-Steps)

# Pseudocode
current_level = "A1-"  # Start at medium
consecutive_correct = 0
consecutive_wrong = 0

for question in questions:
    if answer_correct:
        consecutive_correct += 1
        consecutive_wrong = 0

        if consecutive_correct >= 3:
            current_level = increase_level_by_one_step(current_level)
            # Pre-A1 → Pre-A1+ → A1- → A1 → A1+
            consecutive_correct = 0
    else:
        consecutive_wrong += 1
        consecutive_correct = 0

        if consecutive_wrong >= 3:
            current_level = decrease_level_by_one_step(current_level)
            consecutive_wrong = 0

Gate Thresholds

≥ 60% correct → Full test tiếp theo
40-59% correct → Test tiếp, giảm độ khó
< 40% correct → Flag: Mù nặng, rút gọn Câm/Phản xạ

Question Bank Requirements

  • Pre-A1: 30 câu (15 image + 15 definition)
  • Pre-A1+: 20 câu (12 image + 8 definition)
  • A1-: 20 câu (10 image + 10 definition)
  • A1: 15 câu (7 image + 8 definition)
  • A1+: 15 câu (6 image + 9 definition)
  • Total: 100 câu

B. GATE 2 - ĐIẾC (Listening Comprehension)

Mục tiêu: Đánh giá khả năng nghe hiểu và phân biệt âm thanh

Số Lượng Câu Hỏi

  • Baseline: 9 câu
  • Adaptive: 8-10 câu
    • Nếu Mù ≥ 60%: 10 câu full
    • Nếu Mù 40-59%: 9 câu
    • Nếu Mù < 40%: 8 câu, tốc độ chậm hơn

Loại Câu Hỏi (2 Types)

Type 1: Word Recognition (Audio → Choose Image) - 70% câu

[Play audio: "apple"]
[Show 4 images: apple, orange, banana, grape]

User clicks correct image

Audio settings:
- Pre-A1: Slow speed (0.75x), clear pronunciation
- A1-: Normal speed (1x)
- A1+: Natural speed with slight accent variation

Type 2: Sound Discrimination (Same/Different) - 30% câu

[Play audio 1: "ship"]
[Play audio 2: "sheep"]

Question: Are these words the same or different?
A) Same
B) Different ✓

Common pairs for Vietnamese:
- ship/sheep (khó nhất cho người Việt)
- bad/bed
- cat/cut
- lock/rock
- very/berry

Adaptive Logic

# Similar to Mù, but with audio speed adjustment
if score < 50%:
    audio_speed = 0.8  # Slower
    add_visual_transcript = True  # Show text for last 2 questions
else:
    audio_speed = 1.0  # Normal

Gate Thresholds

≥ 55% correct → Bình thường
35-54% correct → Giảm câu + tăng nghe chậm
< 35% correct → Flag: Điếc nền

Question Bank Requirements

  • Pre-A1: 25 câu (18 audio→image + 7 discrimination)
  • A1-: 20 câu (14 audio→image + 6 discrimination)
  • A1+: 15 câu (10 audio→image + 5 discrimination)
  • Total: 60 câu

C. GATE 3 - CÂM (Speaking / Pronunciation)

Mục tiêu: Xác nhận xu hướng, KHÔNG đánh giá năng lực nói đầy đủ

⚠️ Important: Phần này adaptive dựa trên kết quả Mù + Điếc

Số Lượng Câu Hỏi (Highly Adaptive)

Trạng thái Mù + Điếc Số câu Câm
Cả 2 ≥ 55% (OK) 3-4 câu
1 trong 2 yếu 1-2 câu
Cả 2 < 40% (yếu) 1 câu demo có hint

Loại Câu Hỏi (2 Types)

Type 1: Word Pronunciation (Single Word) - 60% câu

[Show image: apple]
[Show text: "apple"]
[Play sample audio]
[Mic button: "Tap to speak"]

User speaks: "apple"
Azure Speech API scores: 0-100

Scoring:
- 80-100: Excellent
- 60-79: Good
- 40-59: Fair (needs work)
- 0-39: Needs improvement

Type 2: Sentence Reading - 40% câu

[Show text: "I like coffee."]
[Play sample audio - optional]
[Mic button: "Tap to read this sentence"]

User reads sentence
AI scores: pronunciation + intonation

Focus areas for Vietnamese:
- /th/ sound (think, that)
- Final consonants (cat, dog, book)
- Word linking (an apple → "anapple")

Mic Permission & Fallback

If mic permission denied:
  → Skip Câm section entirely
  → Show message: "Không thể test phát âm. Kết quả dựa trên các phần khác."
  → Câm score = "Not tested"

Question Bank Requirements

  • Pre-A1: 15 words + 5 sentences
  • A1: 10 words + 5 sentences
  • A1+: 5 words + 5 sentences
  • Total: 45 items

D. GATE 4 - PHẢN XẠ (Response Speed)

Mục tiêu: Kiểm tra tốc độ nhận diện và phản ứng (foundation skill check)

⚠️ Key Rule: Luôn có ít nhất 1 câu, nhưng nếu nền yếu thì không đo tốc độ

Số Lượng Câu Hỏi

Trạng thái nền Số câu Có countdown?
Mù+Điếc ≥ 55% 5 câu Yes (3s/câu)
1 yếu 3 câu No countdown
Cả 2 < 40% 1 câu No countdown, có hint

Loại Câu Hỏi (2 Types)

Type 1: Flash Card (Image → Choose Word Fast) - 60% câu

[Show image: apple for 2 seconds]
[Fade image to 20% opacity]
[Show 4 options]

Countdown: 3 seconds (nếu nền tốt)

A) apple ✓
B) orange
C) banana
D) grape

Score calculation:
- Correct + < 2s = 100%
- Correct + 2-3s = 80%
- Correct + > 3s = 60%
- Wrong = 0%

Type 2: Audio Response (Hear → Choose Fast) - 40% câu

[Play audio: "apple"]
[Show 4 images immediately]

User clicks image quickly

Countdown: 3 seconds (nếu nền tốt)

Similar scoring as Type 1

Adaptive Behavior

if foundation_weak:  # Mù hoặc Điếc < 40%
    show_countdown = False
    questions = 1  # Demo only
    show_hint = True  # Highlight correct answer area
    message = "Phản xạ chưa hình thành - điều này bình thường!"
else:
    show_countdown = True
    questions = 3-5
    show_hint = False

Question Bank Requirements

  • Pre-A1: 15 flashcards + 10 audio
  • A1: 10 flashcards + 10 audio
  • Total: 45 items

III. Thuật Toán Tính Điểm & Phân Loại

A. Scoring System (Backend - Internal)

Formula: severity_score = 100 - correct_percentage

def calculate_severity_score(correct_count, total_questions):
    """
    Returns internal severity score (0-100)
    Higher score = more severe disease
    """
    correct_percentage = (correct_count / total_questions) * 100
    severity_score = 100 - correct_percentage
    return severity_score

# Example:
# User gets 7/10 correct on Mù
# correct_percentage = 70%
# severity_score = 100 - 70 = 30
# → Mù severity: 30/100 (Nhẹ)

B. Threshold Mapping (UI - User-Facing)

Philosophy: Foundation skills (Mù/Điếc) strict, Output skills (Câm/Phản xạ) humane

Disease Nặng (Severe) Trung Bình (Moderate) Nhẹ (Mild)
< 50% correct 50-70% correct > 70% correct
ĐIẾC < 45% correct 45-65% correct > 65% correct
CÂM < 30% correct 30-55% correct > 55% correct
PHẢN XẠ < 30% correct 30-60% correct > 60% correct

Rationale:

  • (strictest): No vocabulary = everything else is useless
  • Điếc (slightly easier): Listening is harder than reading
  • Câm (forgiving): People understand but can't speak - common pattern
  • Phản xạ (most forgiving): Develops last, needs time
def map_to_severity_category(disease_name, correct_percentage):
    """
    Maps correct percentage to user-facing category
    """
    thresholds = {
        "Mù": {"Nặng": 50, "Trung bình": 70},
        "Điếc": {"Nặng": 45, "Trung bình": 65},
        "Câm": {"Nặng": 30, "Trung bình": 55},
        "Phản xạ": {"Nặng": 30, "Trung bình": 60},
    }

    t = thresholds[disease_name]

    if correct_percentage < t["Nặng"]:
        return "Nặng"
    elif correct_percentage < t["Trung bình"]:
        return "Trung bình"
    else:
        return "Nhẹ"

IV. Kê Đơn Thuốc (Prescription Logic)

A. Prescription Types (5 Types Total)

Prescription ID Tên Đơn Khi Nào Kê Thời Lượng
RX_MU Đơn Mù - Học Từ Vựng Mù nặng nhất 120 ngày (ưu tiên từ vựng 70%)
RX_DIEC Đơn Điếc - Luyện Nghe Điếc nặng nhất 120 ngày (ưu tiên nghe 50%)
RX_CAM Đơn Câm - Luyện Phát Âm Câm nặng nhất 120 ngày (ưu tiên phát âm 60%)
RX_PHAN_XA Đơn Phản Xạ Phản xạ nặng nhất 120 ngày (ưu tiên phản xạ 60%)
RX_FOUNDATION Đơn Nền Tảng Mù + Điếc cùng nặng 120 ngày (cân bằng)

Lưu ý quan trọng: Tất cả đơn thuốc đều kéo dài 120 ngày. Sự khác biệt nằm ở tỷ trọng thời gian dành cho mỗi kỹ năng, không phải tổng thời lượng. Xem Section C để biết chi tiết về tỷ trọng daily content.

B. Prescription Algorithm

def determine_prescription(test_results):
    """
    Determines which prescription to give based on test results

    Args:
        test_results = {
            "Mù": {"correct_pct": 35, "severity": "Nặng", "score": 65},
            "Điếc": {"correct_pct": 40, "severity": "Nặng", "score": 60},
            "Câm": {"correct_pct": 50, "severity": "Trung bình", "score": 50},
            "Phản xạ": {"correct_pct": 45, "severity": "Trung bình", "score": 55}
        }

    Returns:
        prescription_id, focus_areas, duration_days
    """

    # Step 1: Check if all skills are good (> 70%)
    if all(r["severity"] == "Nhẹ" for r in test_results.values()):
        return "NOT_SUITABLE", "User already has foundation", 0

    # Step 2: Count severe diseases
    severe_diseases = [
        name for name, result in test_results.items()
        if result["severity"] == "Nặng"
    ]

    # Step 3: Decision logic
    if len(severe_diseases) == 0:
        # No severe, pick highest moderate
        highest = max(test_results.items(), key=lambda x: x[1]["score"])
        return f"RX_{map_disease_to_id(highest[0])}", [highest[0]], 60

    elif len(severe_diseases) == 1:
        # One severe disease
        disease = severe_diseases[0]
        return f"RX_{map_disease_to_id(disease)}", [disease], 90

    elif len(severe_diseases) >= 2:
        # Multiple severe - check if Mù + Điếc combo
        if "Mù" in severe_diseases and "Điếc" in severe_diseases:
            return "RX_FOUNDATION", ["Mù", "Điếc"], 120
        else:
            # Use priority hierarchy internally
            priority = ["Mù", "Điếc", "Câm", "Phản xạ"]
            for disease in priority:
                if disease in severe_diseases:
                    return f"RX_{map_disease_to_id(disease)}", [disease], 90

def map_disease_to_id(disease_name):
    mapping = {
        "Mù": "MU",
        "Điếc": "DIEC",
        "Câm": "CAM",
        "Phản xạ": "PHAN_XA"
    }
    return mapping[disease_name]

C. Prescription Affects Daily Content

Mỗi đơn thuốc ảnh hưởng đến nội dung học hàng ngày như sau:

Đơn Thuốc Từ Vựng Nghe Phát Âm Phản Xạ Daily New Words
RX_MU 70% 10% 10% 10% 25
RX_DIEC 20% 50% 20% 10% 10
RX_CAM 20% 10% 60% 10% 10
RX_PHAN_XA 20% 10% 10% 60% 10
RX_FOUNDATION 35% 35% 15% 15% 15

Ví dụ cụ thể:

User nhận RX_MU sẽ có bài học hàng ngày:

  • 25 từ vựng mới (như mô tả trong don-mu-vocabulary.md)
  • 2-3 bài nghe ngắn (10%)
  • 2-3 từ luyện phát âm (10%)
  • 1-2 bài phản xạ nhanh (10%)

User nhận RX_DIEC sẽ có bài học hàng ngày:

  • 10 từ vựng mới (20%)
  • 10-15 bài nghe đa dạng (50%)
  • 5 từ luyện phát âm (20%)
  • 2-3 bài phản xạ (10%)

User nhận RX_CAM sẽ có bài học hàng ngày:

  • 10 từ vựng mới (20%)
  • 2-3 bài nghe (10%)
  • 15-20 từ luyện phát âm với feedback chi tiết (60%)
  • 2-3 bài phản xạ (10%)

User nhận RX_PHAN_XA sẽ có bài học hàng ngày:

  • 10 từ vựng mới (20%)
  • 2-3 bài nghe (10%)
  • 2-3 từ luyện phát âm (10%)
  • 15-20 bài luyện phản xạ với tốc độ tăng dần (60%)

User nhận RX_FOUNDATION sẽ có bài học hàng ngày cân bằng:

  • 15 từ vựng mới (35%)
  • 8-10 bài nghe (35%)
  • 5 từ luyện phát âm (15%)
  • 3-5 bài phản xạ (15%)

D. Prescription ID Mapping

Code Reference Database Value Display Name (VI) Display Name (EN)
RX_MU don_mu Đơn Mù - Học Từ Vựng Vocabulary Prescription
RX_DIEC don_diec Đơn Điếc - Luyện Nghe Listening Prescription
RX_CAM don_cam Đơn Câm - Luyện Phát Âm Speaking Prescription
RX_PHAN_XA don_yeu_phan_xa Đơn Phản Xạ Reflex Prescription
RX_FOUNDATION don_foundation Đơn Nền Tảng Foundation Prescription

Naming Convention:

  • Disease name: "Yếu phản xạ" (full name - tên bệnh)
  • Prescription name: "Đơn Phản Xạ" (short name - tên đơn thuốc)
  • Database value: don_yeu_phan_xa (matches disease for consistency)

E. Tie-Breaking Rules

User-Facing: KHÔNG bắt user chọn. Hệ thống quyết định một cách nhân văn.

Internal Priority Hierarchy (only for system logic):

Mù > Điếc > Câm > Phản xạ

Used for:

  • Lesson ordering (Mù lessons first)
  • Time weighting (Mù gets 40% of study time)
  • Progress tracking priority

NOT used for: UI display or user messaging


V. Results Display (UI/UX Design)

A. Medical Report Style

Layout Structure:

┌─────────────────────────────────────────────────┐
│  Kết Quả Chẩn Đoán Của Bạn                     │
├─────────────────────────────────────────────────┤
│                                                  │
│  [Empathy message]                              │
│  "Chúng tôi hiểu bạn đã cố gắng nhiều lần.     │
│   Đây là kết quả chẩn đoán để giúp bạn bắt     │
│   đầu đúng cách lần này."                       │
│                                                  │
├─────────────────────────────────────────────────┤
│                                                  │
│  📚 TỪ VỰNG (Mù)                    [Nặng]     │
│  Bạn đang thiếu từ vựng nền tảng               │
│  → Chúng tôi sẽ giúp bạn học 1,500-3,000 từ   │
│                                                  │
│  👂 NGHE HIỂU (Điếc)          [Trung bình]     │
│  Bạn nghe được một số từ đơn giản              │
│  → Chúng tôi sẽ cải thiện khả năng nghe        │
│                                                  │
│  🗣️ PHÁT ÂM (Câm)                   [Nhẹ]      │
│  Bạn có thể phát âm khá tốt!                   │
│  → Chúng tôi sẽ giúp bạn hoàn thiện            │
│                                                  │
│  ⚡ PHẢN XẠ                    [Trung bình]     │
│  Phản xạ của bạn đang hình thành               │
│  → Chúng tôi sẽ luyện tốc độ phản ứng          │
│                                                  │
├─────────────────────────────────────────────────┤
│                                                  │
│  💊 ĐƠN THUỐC CHO BẠN                          │
│                                                  │
│  [Icon Đơn Mù]                                 │
│  "Đơn Từ Vựng Nền Tảng"                        │
│  60-90 ngày | 1,500-3,000 từ Oxford           │
│                                                  │
│  [Button: Bắt Đầu Ngay]                        │
│                                                  │
└─────────────────────────────────────────────────┘

B. Visual Design Specifications

Color Coding (Severity Levels):

.severity-nang {
  background: #FEE2E2; /* Red-50 */
  border-left: 4px solid #DC2626; /* Red-600 */
  color: #991B1B; /* Red-800 */
}

.severity-trung-binh {
  background: #FEF3C7; /* Yellow-50 */
  border-left: 4px solid #F59E0B; /* Amber-500 */
  color: #92400E; /* Amber-900 */
}

.severity-nhe {
  background: #D1FAE5; /* Green-50 */
  border-left: 4px solid #10B981; /* Green-500 */
  color: #065F46; /* Green-900 */
}

Icons (Disease Types):

📚 Mù (Vocabulary) - Book icon
👂 Điếc (Listening) - Ear icon
🗣️ Câm (Speaking) - Speaking head icon
⚡ Phản xạ (Reflex) - Lightning bolt icon

C. Copy Guidelines

✅ DO USE:

  • "Chúng tôi đã có đủ thông tin để hiểu cách bạn học tốt nhất"
  • "Bạn đang gặp khó khăn với..." (not "bạn yếu/kém")
  • "Chúng tôi sẽ giúp bạn khắc phục trong X ngày"
  • "Phản xạ chưa hình thành - điều này bình thường!"

❌ DON'T USE:

  • "Bạn không đủ điều kiện làm tiếp"
  • "Skipped due to low score"
  • "Điểm của bạn: 25%"
  • "Bạn thất bại ở phần..."
  • Any form of shame or judgment

D. Edge Case: User Too Good (All > 70%)

┌─────────────────────────────────────────────────┐
│  Kết Quả Của Bạn                                │
├─────────────────────────────────────────────────┤
│                                                  │
│  🎉 Chúc mừng!                                  │
│                                                  │
│  Bạn đã có nền tảng tiếng Anh khá tốt         │
│  (A2-B1 level). Chương trình Learn English     │
│  Zero được thiết kế cho người mất gốc hoàn     │
│  toàn.                                          │
│                                                  │
│  Chúng tôi gợi ý bạn:                          │
│                                                  │
│  • Học IELTS/TOEIC để có chứng chỉ            │
│  • Thử các khóa B2+ trên Coursera              │
│  • Xem kênh YouTube: [list channels]           │
│                                                  │
│  [Button: Tìm Hiểu Thêm]                       │
│                                                  │
└─────────────────────────────────────────────────┘

VI. Edge Cases & Error Handling

A. Technical Issues

Issue Handling User Message
Mic permission denied Skip Câm section "Không thể test phát âm. Kết quả dựa trên các phần khác."
Audio playback fails Retry 3 times, then skip question "Đang tải lại audio..."
Internet disconnect Save progress, resume on reconnect "Mất kết nối. Đang lưu tiến trình..."
API timeout (Azure) Use fallback scoring Silent fallback, no user message

B. User Behavior Edge Cases

Scenario Detection Handling
Random clicking < 1s per answer, all wrong Flag test as invalid, ask to retake
Tab switching Blur event > 30s Pause timer, show warning
Mic test fail Silent audio input Show mic setup guide
Leaves mid-test Save progress Resume from last gate on return

C. Retesting Policy

Rule: Initial diagnostic test is locked after completion

┌─────────────────────────────────────────────────┐
│  ⚠️ Test Đã Hoàn Thành                         │
├─────────────────────────────────────────────────┤
│                                                  │
│  Bạn đã hoàn thành test chẩn đoán.            │
│                                                  │
│  Test này chỉ làm 1 lần để đảm bảo kết quả    │
│  chính xác và "đơn thuốc" phù hợp nhất.       │
│                                                  │
│  • Bạn sẽ có "mini-check" mỗi 30 ngày          │
│    để theo dõi tiến bộ                          │
│                                                  │
│  • Kết quả sẽ được cập nhật tự động            │
│                                                  │
│  [Button: Xem Kết Quả Hiện Tại]                │
│                                                  │
└─────────────────────────────────────────────────┘

Monthly Mini-Checks (separate feature):

  • Same format but shorter (3-4 phút)
  • 5 questions per disease type
  • Tracks progress over time
  • Does NOT change prescription

VII. Data Model & Storage

A. Database Schema

# diagnosis_test table
class DiagnosisTest(Base):
    __tablename__ = "diagnosis_tests"

    id = Column(UUID, primary_key=True)
    user_id = Column(UUID, ForeignKey("users.id"))
    test_type = Column(String)  # "initial" | "monthly_check"

    # Test metadata
    started_at = Column(DateTime)
    completed_at = Column(DateTime)
    duration_seconds = Column(Integer)

    # Raw scores (internal)
    mu_correct = Column(Integer)
    mu_total = Column(Integer)
    mu_score = Column(Float)  # Severity score (0-100)

    diec_correct = Column(Integer)
    diec_total = Column(Integer)
    diec_score = Column(Float)

    cam_correct = Column(Integer)
    cam_total = Column(Integer)
    cam_score = Column(Float)

    phan_xa_correct = Column(Integer)
    phan_xa_total = Column(Integer)
    phan_xa_score = Column(Float)

    # Categorized results (user-facing)
    mu_severity = Column(String)  # "Nặng" | "Trung bình" | "Nhẹ"
    diec_severity = Column(String)
    cam_severity = Column(String)
    phan_xa_severity = Column(String)

    # Prescription
    prescription_id = Column(String)  # RX_MU, RX_FOUNDATION, etc.
    prescription_focus = Column(JSON)  # ["Mù", "Điếc"]
    prescription_duration_days = Column(Integer)

    # Adaptive test metadata
    questions_asked = Column(JSON)  # Array of question IDs
    gate_adjustments = Column(JSON)  # Track difficulty changes

    # Flags
    is_valid = Column(Boolean)  # False if cheating detected
    invalid_reason = Column(String)


# test_question_responses table
class TestQuestionResponse(Base):
    __tablename__ = "test_question_responses"

    id = Column(UUID, primary_key=True)
    test_id = Column(UUID, ForeignKey("diagnosis_tests.id"))
    question_id = Column(UUID)

    # Question details
    disease_type = Column(String)  # "Mù" | "Điếc" | "Câm" | "Phản xạ"
    question_type = Column(String)  # "word_recognition", "sound_discrimination", etc.
    difficulty_level = Column(String)  # "Pre-A1", "A1-", etc.

    # Response
    user_answer = Column(JSON)
    correct_answer = Column(JSON)
    is_correct = Column(Boolean)
    response_time_ms = Column(Integer)

    # Audio/pronunciation specific
    audio_url = Column(String)  # For Điếc/Câm
    pronunciation_score = Column(Float)  # For Câm (0-100 from Azure)

    created_at = Column(DateTime)


# question_bank table
class QuestionBankItem(Base):
    __tablename__ = "question_bank"

    id = Column(UUID, primary_key=True)
    disease_type = Column(String)
    question_type = Column(String)
    difficulty_level = Column(String)

    # Question content
    question_data = Column(JSON)
    # Example for Mù word_recognition:
    # {
    #   "image_url": "/assets/images/apple.jpg",
    #   "correct_answer": "apple",
    #   "options": ["apple", "orange", "banana", "grape"]
    # }

    correct_answer = Column(JSON)

    # Audio for Điếc/Câm
    audio_url = Column(String)
    audio_speed = Column(Float)  # 0.75, 1.0, etc.

    # Metadata
    usage_count = Column(Integer)
    avg_correct_rate = Column(Float)

    is_active = Column(Boolean)
    created_at = Column(DateTime)

B. Question Bank Statistics (Target)

Disease Difficulty Count Ratio
Pre-A1 30 30%
Pre-A1+ 20 20%
A1- 20 20%
A1 15 15%
A1+ 15 15%
Total 100
Điếc Pre-A1 25 42%
A1- 20 33%
A1+ 15 25%
Total 60
Câm Pre-A1 20 44%
A1 15 33%
A1+ 10 23%
Total 45
Phản xạ Pre-A1 25 56%
A1 20 44%
Total 45
GRAND TOTAL 250

VIII. Testing & Validation

A. Pre-Launch Testing

Test with 10 Beta Users:

  1. 3 người mất gốc hoàn toàn (Pre-A1)
  2. 3 người có chút kiến thức (A1)
  3. 2 người khá tốt (A2+)
  4. 2 người giỏi (B1+)

Metrics to Track:

  • Average completion time per profile
  • Gate transition rates
  • Prescription distribution
  • User feedback on difficulty
  • Emotional response to UI copy

B. Quality Assurance Checklist

  • All 250 questions reviewed by English teacher
  • Audio recordings clear and accurate
  • Image assets appropriate and clear
  • Thresholds validated with sample data
  • Gate logic produces expected results
  • UI copy reviewed for empathy
  • Mobile responsive on iOS/Android
  • Mic permission flow tested
  • Edge cases handled gracefully
  • Data persists correctly

C. Success Metrics (Post-Launch)

Metric Target Measurement
Completion rate > 85% % who finish all 4 gates
Average duration 6-8 min Median completion time
Prescription distribution Balanced Should see mix of all 5 types
User sentiment Positive Post-test survey (1-5 scale)
Technical errors < 2% % tests with API failures

IX. Implementation Roadmap

Phase 1: Question Bank Creation (Week 1-2)

  • Create 100 Mù questions (images + definitions)
  • Record 60 Điếc audio files
  • Create 45 Câm pronunciation items
  • Create 45 Phản xạ flashcards/audio
  • Review all content with native speaker

Phase 2: Backend API (Week 2-3)

  • Implement adaptive test engine
  • Build gate logic with thresholds
  • Create prescription algorithm
  • Setup Azure Speech integration for Câm
  • Database schema + migrations

Phase 3: Frontend UI (Week 3-4)

  • Test flow screens (4 gates)
  • Results display (medical report style)
  • Prescription reveal screen
  • Mic permission + audio playback
  • Mobile responsive design

Phase 4: Testing & Refinement (Week 4-5)

  • Internal testing (team)
  • Beta testing (10 users)
  • Refine thresholds based on data
  • Fix bugs and edge cases
  • Polish UI copy

Phase 5: Launch (Week 6)

  • Deploy to production
  • Monitor metrics
  • Collect user feedback
  • Iterate based on real data

X. Open Questions & Future Iterations

Questions for User Research

  1. Is the medical metaphor (Mù/Điếc/Câm) clear and not offensive?
  2. Does the "not suitable" message for advanced users feel good?
  3. Is 5-10 minutes the right length?
  4. Should we show progress bar during test?

Future Enhancements (V2)

  • AI-generated question variants (hybrid approach)
  • Video-based questions for Câm (facial recognition)
  • Accent detection (North/South Vietnam)
  • Peer comparison (anonymized)
  • Gamification elements in monthly checks

Research Needed

  • Validate thresholds with 100+ users (adjust if needed)
  • A/B test different UI approaches for results
  • Study correlation between test results and 120-day completion
  • Analyze which prescription types have best outcomes

Appendix A: Example Test Flow (Full Walkthrough)

User Profile: Người mất gốc, học từ cấp 2-cấp 3 nhưng quên hết

START TEST

Gate 1: Mù (2.5 phút)

Questions 1-3 (Pre-A1 level):

  • Q1: [Image: apple] → Correct (✓)
  • Q2: Match "teacher" → Correct (✓)
  • Q3: [Image: cat] → Correct (✓)

System: 3 consecutive correct → increase to Pre-A1+

Questions 4-6 (Pre-A1+ level):

  • Q4: [Image: chair] → Correct (✓)
  • Q5: Match "beautiful" → Wrong (✗)
  • Q6: [Image: door] → Correct (✓)

Questions 7-10 (Pre-A1+ level maintained):

  • Q7-10: Mixed results (2 correct, 2 wrong)

Result: 7/10 correct = 70% → Severity: Nhẹ

Gate 1 decision: Score ≥ 60% → Full test for Gate 2


Gate 2: Điếc (2.5 phút)

Questions 1-3 (Pre-A1 level, slow audio):

  • Q1: Hear "apple" → Choose image → Correct (✓)
  • Q2: Discrimination: ship/sheep → Wrong (✗)
  • Q3: Hear "cat" → Choose image → Correct (✓)

Questions 4-9 (Pre-A1 maintained):

  • Q4-9: Mixed results (3 correct, 3 wrong)

Result: 5/9 correct = 56% → Severity: Trung Bình

Gate 2 decision: Score 55-65% range → Proceed to Câm with normal questions


Gate 3: Câm (2 phút)

Mù OK + Điếc OK → 3 questions

Question 1: Pronounce "apple"

  • User speaks into mic
  • Azure Speech score: 72/100
  • Result: Good (✓)

Question 2: Read sentence "I like coffee"

  • User reads
  • Azure Speech score: 65/100
  • Result: Fair (✓)

Question 3: Pronounce "beautiful"

  • User speaks
  • Azure Speech score: 55/100
  • Result: Fair (✓)

Result: 3/3 attempted, avg score 64 → Severity: Trung Bình


Gate 4: Phản Xạ (1.5 phút)

Foundation moderate → 4 questions with countdown

Question 1: Flash [apple image 2s] → Choose word in 3s

  • Response time: 2.1s → Correct (✓)

Question 2: Audio "cat" → Choose image in 3s

  • Response time: 2.8s → Correct (✓)

Question 3: Flash [chair image 2s] → Choose word in 3s

  • Response time: 3.5s (timeout) → Wrong (✗)

Question 4: Audio "dog" → Choose image in 3s

  • Response time: 1.8s → Correct (✓)

Result: 3/4 correct = 75%, but avg time 2.55s → Severity: Nhẹ


RESULTS CALCULATION

test_results = {
    "Mù": {
        "correct_pct": 70,
        "severity": "Nhẹ",
        "score": 30  # 100 - 70
    },
    "Điếc": {
        "correct_pct": 56,
        "severity": "Trung bình",
        "score": 44  # 100 - 56
    },
    "Câm": {
        "correct_pct": 64,
        "severity": "Trung bình",
        "score": 36  # 100 - 64
    },
    "Phản xạ": {
        "correct_pct": 75,
        "severity": "Nhẹ",
        "score": 25  # 100 - 75
    }
}

# No severe diseases
# Highest score: Điếc (44)
prescription = "RX_DIEC"
focus = ["Điếc"]
duration = 60  # days

RESULTS SCREEN (UI)

┌─────────────────────────────────────────────────┐
│  Kết Quả Chẩn Đoán Của Bạn                     │
├─────────────────────────────────────────────────┤
│                                                  │
│  Cảm ơn bạn đã hoàn thành test! Chúng tôi     │
│  đã hiểu được điểm mạnh và điểm cần cải       │
│  thiện của bạn.                                 │
│                                                  │
├─────────────────────────────────────────────────┤
│                                                  │
│  📚 TỪ VỰNG (Mù)                       [Nhẹ]   │
│  Bạn có vốn từ vựng cơ bản khá tốt!          │
│  → Chúng tôi sẽ giúp bạn mở rộng thêm         │
│                                                  │
│  👂 NGHE HIỂU (Điếc)          [Trung bình] ⚠️  │
│  Bạn cần cải thiện khả năng nghe              │
│  → Chúng tôi sẽ tập trung vào kỹ năng này    │
│                                                  │
│  🗣️ PHÁT ÂM (Câm)          [Trung bình]        │
│  Bạn phát âm được, nhưng cần luyện thêm       │
│  → Chúng tôi sẽ cải thiện độ rõ ràng          │
│                                                  │
│  ⚡ PHẢN XẠ                           [Nhẹ]     │
│  Phản xạ của bạn khá tốt!                     │
│  → Chúng tôi sẽ giúp bạn nhanh hơn nữa        │
│                                                  │
├─────────────────────────────────────────────────┤
│                                                  │
│  💊 ĐƠN THUỐC CHO BẠN                          │
│                                                  │
│  👂 "Đơn Luyện Nghe Nền Tảng"                 │
│                                                  │
│  Trong 60 ngày, chúng tôi sẽ:                 │
│  • Luyện nghe 1,000 câu thông dụng            │
│  • Phân biệt âm khó (ship/sheep, bad/bed)     │
│  • Nghe hiểu podcast đơn giản                  │
│                                                  │
│  [Button: Bắt Đầu Ngay →]                     │
│                                                  │
└─────────────────────────────────────────────────┘

Total Duration: 8.5 phút (trong khung 5-10 phút ✓)


Appendix B: Technical Integration Checklist

Frontend Components Needed

  • DiagnosisTestContainer.tsx - Main test orchestrator
  • GateMu.tsx - Mù test component
  • GateDiec.tsx - Điếc test component (audio playback)
  • GateCam.tsx - Câm test component (mic recording)
  • GatePhanXa.tsx - Phản xạ test component (countdown)
  • TestResults.tsx - Results display
  • PrescriptionReveal.tsx - Prescription screen
  • ProgressBar.tsx - Test progress indicator
  • AudioPlayer.tsx - Reusable audio component
  • MicRecorder.tsx - Reusable mic recording component

Backend API Endpoints

  • POST /api/v1/diagnosis/start - Initialize test session
  • POST /api/v1/diagnosis/answer - Submit answer for question
  • GET /api/v1/diagnosis/next-question - Get next adaptive question
  • POST /api/v1/diagnosis/complete - Finalize test, calculate prescription
  • GET /api/v1/diagnosis/results/{test_id} - Retrieve results
  • POST /api/v1/pronunciation/score - Azure Speech scoring
  • GET /api/v1/question-bank/random - Get random question by criteria

External Service Integration

  • Azure Speech API (pronunciation scoring)
  • Azure Blob Storage (audio files, images)
  • Supabase Auth (user identification)
  • Supabase PostgreSQL (data persistence)

Environment Variables

AZURE_SPEECH_KEY=
AZURE_SPEECH_REGION=
AZURE_STORAGE_CONNECTION_STRING=
SUPABASE_URL=
SUPABASE_ANON_KEY=

References & Related Documents

  • definitions.md: Single source of truth cho tất cả constants và enums
  • don-mu-vocabulary.md: Chi tiết lộ trình học từ vựng 120 ngày (cho RX_MU)
  • database-schema.md: Schema database cho user_diagnosis_results và prescription types
  • ai-coach-behavior.md: AI Coach behavior sau khi nhận kết quả chẩn đoán
  • user-flow.md: UI/UX flow cho màn hình test và results
  • gamification.md: Milestones và streak system liên quan đến tiến độ sau chẩn đoán

Document Version: 1.1 Last Updated: 2026-01-09 Next Review: After beta testing (Week 5)

Contributors: Founder + Claude Code Status: ✅ Design Complete - Ready for Implementation