dramaling-vocab-learning/複習系統設計工具重構規格.md

696 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# 複習系統設計工具重構規格
## 📋 現況問題分析
### 當前 review-design 頁面的問題
**檔案**: `/frontend/app/review-design/page.tsx`
#### ❌ **問題 1: 靜態組件展示**
```typescript
// 當前實作:只是靜態展示不同測驗組件
const [activeTab, setActiveTab] = useState('FlipMemoryTest')
// 問題:無法模擬真實的複習流程
return <FlipMemoryTest cardData={staticData} onAnswer={logOnly} />
```
**後果**:
- 無法測試真實的 Store 協作
- 無法驗證答題→進度更新→下一題的完整流程
- 不能測試錯誤處理和邊界情況
#### ❌ **問題 2: 測試資料寫死**
```typescript
// 當前實作:直接 import 靜態 JSON
import exampleData from './example-data.json'
// 問題:無法動態切換或重置測試場景
const cardData = exampleData[currentCardIndex]
```
**後果**:
- 無法測試空資料狀態
- 無法測試資料載入失敗情況
- 無法快速切換不同測試場景
#### ❌ **問題 3: 缺乏真實性**
```typescript
// 當前實作:簡化的回調函數
const handleAnswer = (answer: string) => {
addLog(`答案: ${answer}`) // 只是記錄,不做真實處理
}
// 問題:無法測試真實的 Store 狀態更新
```
**後果**:
- 進度條不會真實更新
- Store 狀態不會改變
- 無法發現狀態同步問題
## 🎯 重構設計規格
### 目標:打造**專業的複習系統開發工具**
#### 核心需求:
1. **真實模擬**: 完整模擬生產環境的複習流程
2. **動態資料**: 可動態匯入、重置、切換測試資料
3. **狀態監控**: 即時顯示所有 Store 狀態
4. **調試功能**: 提供開發者需要的調試工具
## 🏗️ 新架構設計
### 整體頁面架構
```
複習系統設計工具
├── 控制面板 (ControlPanel)
│ ├── 資料管理區
│ │ ├── 匯入測試資料按鈕
│ │ ├── 重置 Store 狀態按鈕
│ │ ├── 切換測試資料集下拉選單
│ │ └── Store 狀態重置按鈕
│ ├── 模擬控制區
│ │ ├── 開始複習模擬按鈕
│ │ ├── 暫停/繼續按鈕
│ │ └── 結束模擬按鈕
│ └── 快速測試區
│ ├── 單一組件測試模式
│ └── 完整流程測試模式
├── 複習模擬器 (ReviewSimulator)
│ ├── 真實的 ReviewRunner 組件
│ ├── 真實的進度條和導航
│ └── 真實的狀態管理
└── 調試面板 (DebugPanel)
├── Store 狀態監控 (即時)
├── 答題歷史記錄
├── 性能指標顯示
└── 錯誤日誌
```
### 1. 資料管理系統設計
#### 動態資料匯入機制
```typescript
interface TestDataManager {
// 測試資料集管理
availableDatasets: TestDataset[]
currentDataset: TestDataset | null
// 動態操作
importDataset(dataset: TestDataset): void
resetStores(): void
switchDataset(datasetId: string): void
// 預定義場景
loadScenario(scenario: TestScenario): void
}
// 測試場景定義
type TestScenario =
| 'empty' // 空資料測試
| 'single-card' // 單詞卡測試
| 'full-session' // 完整會話測試
| 'error-cases' // 錯誤情況測試
| 'performance' // 性能測試
```
#### 測試資料結構
```typescript
interface TestDataset {
id: string
name: string
description: string
flashcards: MockFlashcard[]
scenarios: {
completedTests?: CompletedTest[]
userProfile?: UserProfile
errorConditions?: ErrorCondition[]
}
}
```
### 2. 真實複習模擬器設計
#### 完整Store整合
```typescript
const ReviewSimulator = () => {
// 使用真實的 Store不是模擬
const reviewSession = useReviewSessionStore()
const testQueue = useTestQueueStore()
const testResult = useTestResultStore()
const reviewData = useReviewDataStore()
const reviewUI = useReviewUIStore()
// 真實的初始化流程
const initializeSimulation = async (dataset: TestDataset) => {
// 1. 重置所有 Store
reviewSession.resetSession()
testQueue.resetQueue()
testResult.resetScore()
reviewData.resetData()
// 2. 載入測試資料到 ReviewDataStore
reviewData.setDueCards(dataset.flashcards)
// 3. 觸發真實的佇列初始化
testQueue.initializeTestQueue(dataset.flashcards, dataset.scenarios.completedTests || [])
// 4. 設置第一張卡片
if (dataset.flashcards.length > 0) {
reviewSession.setCurrentCard(dataset.flashcards[0])
}
}
return (
<div className="review-simulator">
{/* 使用真實的 ReviewRunner不是模擬組件 */}
<ReviewRunner />
</div>
)
}
```
#### 真實進度追蹤
```typescript
// 真實的進度條,連接到真實 Store
const RealProgressTracker = () => {
const { testItems, currentTestIndex, completedTests } = useTestQueueStore()
const { score } = useTestResultStore()
// 真實計算,不是模擬
const progress = testItems.length > 0 ? (completedTests / testItems.length) * 100 : 0
const accuracy = score.total > 0 ? (score.correct / score.total) * 100 : 0
return (
<div className="real-progress-tracker">
<div className="progress-stats">
<span>進度: {completedTests}/{testItems.length} ({progress.toFixed(1)}%)</span>
<span>正確率: {score.correct}/{score.total} ({accuracy.toFixed(1)}%)</span>
</div>
<div className="progress-bar">
<div
className="progress-fill bg-blue-500 h-2 rounded transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
</div>
)
}
```
### 3. 調試面板設計
#### Store 狀態即時監控
```typescript
const StoreMonitor = () => {
// 即時監控所有 Store 狀態
const sessionState = useReviewSessionStore()
const queueState = useTestQueueStore()
const resultState = useTestResultStore()
const dataState = useReviewDataStore()
const uiState = useReviewUIStore()
return (
<div className="store-monitor">
<div className="store-section">
<h4>Session Store</h4>
<pre className="store-state">
{JSON.stringify({
mounted: sessionState.mounted,
currentCard: sessionState.currentCard?.id,
mode: sessionState.mode,
isLoading: sessionState.isLoading,
error: sessionState.error
}, null, 2)}
</pre>
</div>
<div className="store-section">
<h4>Queue Store</h4>
<pre className="store-state">
{JSON.stringify({
totalTests: queueState.testItems.length,
currentIndex: queueState.currentTestIndex,
currentMode: queueState.currentMode,
completedCount: queueState.testItems.filter(t => t.isCompleted).length,
skippedCount: queueState.testItems.filter(t => t.isSkipped).length
}, null, 2)}
</pre>
</div>
<div className="store-section">
<h4>Result Store</h4>
<pre className="store-state">
{JSON.stringify(resultState.score, null, 2)}
</pre>
</div>
</div>
)
}
```
### 4. 操作控制面板設計
#### 資料管理控制
```typescript
const DataControlPanel = () => {
const [selectedDataset, setSelectedDataset] = useState<string>('')
const predefinedDatasets = [
{
id: 'basic',
name: '基礎詞彙 (5張卡)',
description: 'A1-A2 等級詞彙,適合基礎測試'
},
{
id: 'advanced',
name: '進階詞彙 (10張卡)',
description: 'B2-C1 等級詞彙,測試複雜邏輯'
},
{
id: 'mixed',
name: '混合難度 (15張卡)',
description: '各等級混合,測試自適應算法'
},
{
id: 'error-test',
name: '錯誤情況測試',
description: '包含異常資料,測試錯誤處理'
}
]
return (
<div className="data-control-panel">
<div className="control-section">
<h3>測試資料管理</h3>
<select
value={selectedDataset}
onChange={(e) => setSelectedDataset(e.target.value)}
>
<option value="">選擇測試資料集...</option>
{predefinedDatasets.map(dataset => (
<option key={dataset.id} value={dataset.id}>
{dataset.name}
</option>
))}
</select>
<div className="action-buttons">
<button onClick={() => importDataset(selectedDataset)}>
匯入資料
</button>
<button onClick={resetAllStores}>
重置 Store
</button>
<button onClick={clearAllData}>
清空資料
</button>
</div>
</div>
<div className="current-dataset-info">
{currentDataset && (
<div className="dataset-info">
<h4>當前資料集: {currentDataset.name}</h4>
<p>{currentDataset.description}</p>
<p>詞卡數量: {currentDataset.flashcards.length}</p>
</div>
)}
</div>
</div>
)
}
```
### 5. 模擬控制器設計
#### 複習流程控制
```typescript
const SimulationController = () => {
const [isSimulating, setIsSimulating] = useState(false)
const [simulationSpeed, setSimulationSpeed] = useState(1)
const simulationControls = {
// 開始完整複習模擬
startFullSimulation: async () => {
setIsSimulating(true)
await initializeRealReviewSession()
},
// 暫停模擬
pauseSimulation: () => {
setIsSimulating(false)
},
// 單步執行 (逐題測試)
stepThrough: async () => {
await processNextTest()
updateDebugInfo()
},
// 快速完成 (自動答題)
autoComplete: async () => {
while (!isAllTestsCompleted()) {
await autoAnswerCurrentTest()
await waitFor(1000 / simulationSpeed)
}
}
}
return (
<div className="simulation-controller">
<div className="simulation-status">
<span className={`status-indicator ${isSimulating ? 'active' : 'inactive'}`}>
{isSimulating ? '模擬進行中' : '模擬暫停'}
</span>
</div>
<div className="control-buttons">
<button onClick={simulationControls.startFullSimulation}>
開始完整模擬
</button>
<button onClick={simulationControls.stepThrough}>
單步執行
</button>
<button onClick={simulationControls.autoComplete}>
自動完成
</button>
<button onClick={simulationControls.pauseSimulation}>
暫停模擬
</button>
</div>
<div className="simulation-settings">
<label>
模擬速度:
<input
type="range"
min="0.1"
max="3"
step="0.1"
value={simulationSpeed}
onChange={(e) => setSimulationSpeed(Number(e.target.value))}
/>
{simulationSpeed}x
</label>
</div>
</div>
)
}
```
### 6. 調試工具增強
#### 測驗佇列視覺化
```typescript
const QueueVisualizer = () => {
const { testItems, currentTestIndex } = useTestQueueStore()
return (
<div className="queue-visualizer">
<h4>測驗佇列狀態</h4>
<div className="queue-timeline">
{testItems.map((test, index) => (
<div
key={test.id}
className={`queue-item ${
index === currentTestIndex ? 'current' :
test.isCompleted ? 'completed' :
test.isSkipped ? 'skipped' :
test.isIncorrect ? 'incorrect' : 'pending'
}`}
>
<div className="test-info">
<span className="test-type">{test.testType}</span>
<span className="word">{test.word}</span>
<span className="priority">P{test.priority}</span>
</div>
</div>
))}
</div>
</div>
)
}
```
#### 答題歷史追蹤
```typescript
const AnswerHistoryTracker = () => {
const [answerHistory, setAnswerHistory] = useState<AnswerRecord[]>([])
const trackAnswer = useCallback((answer: AnswerRecord) => {
setAnswerHistory(prev => [...prev, {
...answer,
timestamp: new Date(),
responseTime: answer.responseTime,
isCorrect: answer.isCorrect
}])
}, [])
return (
<div className="answer-history">
<h4>答題歷史</h4>
<div className="history-list">
{answerHistory.map((record, index) => (
<div key={index} className="history-item">
<span className="timestamp">{record.timestamp.toLocaleTimeString()}</span>
<span className="test-type">{record.testType}</span>
<span className="word">{record.word}</span>
<span className={`result ${record.isCorrect ? 'correct' : 'incorrect'}`}>
{record.isCorrect ? '✓' : '✗'}
</span>
<span className="response-time">{record.responseTime}ms</span>
</div>
))}
</div>
</div>
)
}
```
## 🎛️ 操作流程設計
### 理想的使用流程
#### 1. 初始狀態 (空白畫面)
```
┌─────────────────────────────────┐
│ 複習系統設計工具 │
├─────────────────────────────────┤
│ │
│ 🔧 控制面板 │
│ ┌───────────────────────────┐ │
│ │ 📁 測試資料管理 │ │
│ │ ○ 選擇資料集... │ │
│ │ [ 匯入資料 ] [ 重置 ] │ │
│ └───────────────────────────┘ │
│ │
│ 💭 當前狀態: 無資料 │
│ 📊 Store 狀態: 空 │
└─────────────────────────────────┘
```
#### 2. 匯入資料後
```
┌─────────────────────────────────┐
│ 🎯 模擬控制 │
│ [ 開始完整模擬 ] │
│ [ 單步執行 ] [ 自動完成 ] │
├─────────────────────────────────┤
│ 📊 即時狀態監控 │
│ TestQueue: 15 items loaded │
│ Current: flip-memory (0/15) │
│ Score: 0/0 (0%) │
└─────────────────────────────────┘
```
#### 3. 模擬進行中
```
┌─────────────────────────────────┐
│ 🎮 複習模擬器 │
│ ┌─ 真實 ReviewRunner ─────┐ │
│ │ [Progress: 3/15 ████▒▒] │ │
│ │ │ │
│ │ 當前測驗: 翻卡記憶 │ │
│ │ 詞卡: "elaborate" │ │
│ │ [ 信心度選擇: 1-5 ] │ │
│ │ │ │
│ │ [ 跳過 ] [ 繼續 ] │ │
│ └─────────────────────────┘ │
├─────────────────────────────────┤
│ 🐛 調試面板 (即時更新) │
│ TestQueue: item 3→4 │
│ Score: 2✓ 1✗ (66.7%) │
│ LastAnswer: "elaborate" ✓ │
└─────────────────────────────────┘
```
### 3. 測試資料集設計
#### 預定義資料集範例
```json
{
"datasets": [
{
"id": "basic-flow",
"name": "基礎流程測試",
"description": "測試完整的答題→進度更新→下一題流程",
"flashcards": [
{
"id": "test-1",
"word": "hello",
"definition": "A greeting",
"cefr": "A1"
}
],
"scenarios": {
"completedTests": [],
"userProfile": {
"level": "A2",
"preferences": {}
}
}
},
{
"id": "error-handling",
"name": "錯誤處理測試",
"description": "測試各種錯誤情況的處理",
"flashcards": [],
"scenarios": {
"errorConditions": [
"api_failure",
"invalid_answer",
"network_timeout"
]
}
}
]
}
```
### 4. 開發者工作流程
#### 典型調試場景
```typescript
// 場景 1: 測試新測驗類型
1. 選擇「單一組件測試」模式
2. 匯入「基礎詞彙」資料集
3. 選擇特定測驗類型 ( sentence-fill)
4. 逐步測試答題邏輯
5. 檢查 Store 狀態變化
6. 驗證UI反饋正確性
// 場景 2: 測試完整流程
1. 選擇「完整流程測試」模式
2. 匯入「混合難度」資料集
3. 開始自動模擬
4. 監控進度條更新
5. 檢查佇列重排邏輯
6. 驗證會話完成處理
// 場景 3: 測試錯誤處理
1. 選擇「錯誤情況測試」模式
2. 觸發各種錯誤條件
3. 驗證錯誤邊界處理
4. 檢查錯誤恢復機制
```
## 🔧 技術實施細節
### Store 重置機制
```typescript
const resetAllStores = () => {
// 重置所有複習相關 Store
const { resetSession } = useReviewSessionStore.getState()
const { resetQueue } = useTestQueueStore.getState()
const { resetScore } = useTestResultStore.getState()
const { resetData } = useReviewDataStore.getState()
resetSession()
resetQueue()
resetScore()
resetData()
console.log('✅ 所有 Store 已重置')
}
```
### 真實資料注入
```typescript
const injectTestData = async (dataset: TestDataset) => {
// 模擬真實的資料載入流程
const { setDueCards, setLoadingCards } = useReviewDataStore.getState()
setLoadingCards(true)
// 模擬API延遲
await new Promise(resolve => setTimeout(resolve, 500))
setDueCards(dataset.flashcards)
setLoadingCards(false)
console.log(`✅ 已匯入 ${dataset.flashcards.length} 張測試詞卡`)
}
```
### 自動答題機器人
```typescript
const createAnswerBot = () => {
return {
// 自動產生正確答案
generateCorrectAnswer: (cardData: any, testType: string): string => {
switch (testType) {
case 'vocab-choice':
case 'vocab-listening':
return cardData.word
case 'sentence-fill':
return cardData.word
case 'sentence-reorder':
case 'sentence-listening':
return cardData.example
default:
return ''
}
},
// 自動產生錯誤答案 (用於測試錯誤處理)
generateIncorrectAnswer: (cardData: any, testType: string): string => {
// 故意產生錯誤答案來測試錯誤處理邏輯
return 'incorrect_answer_' + Math.random().toString(36).substr(2, 9)
}
}
}
```
## 📊 成功指標
### 工具效能指標
- **資料匯入時間**: < 1秒
- **Store 重置時間**: < 0.5秒
- **狀態監控更新**: 即時 (< 100ms)
- **模擬流程完成**: 15張卡片 < 30秒
### 開發者體驗指標
- **問題發現時間**: 從數小時縮短到數分鐘
- **UI設計驗證**: 即時預覽和調整
- **邏輯調試效率**: 提升 80%+
- **回歸測試**: 自動化場景測試
## 🎯 總結
這個重構將把 `review-design` **靜態組件展示**升級為**專業的複習系統開發工具**提供
1. **真實性**: 完全模擬生產環境行為
2. **靈活性**: 動態資料管理和場景切換
3. **可觀測性**: 完整的狀態監控和調試信息
4. **自動化**: 自動測試和驗證功能
**這樣的工具將大幅提升複習功能的開發和調試效率!** 🛠
---
*規格版本: v1.0*
*設計目標: 專業複習系統開發工具*
*預計實施時間: 2-3 *