317 lines
9.6 KiB
Markdown
317 lines
9.6 KiB
Markdown
# 複習系統後端驅動架構重構計劃
|
||
|
||
## 專案概述
|
||
|
||
### 問題現狀
|
||
1. **邏輯錯誤**:完成一個測驗就標記詞卡完成,但實際還有其他測驗未完成
|
||
2. **架構問題**:前端管理複習會話狀態,容易出現數據不一致
|
||
3. **UI問題**:雙進度條視覺效果不佳,用戶希望整合為分段式進度條
|
||
4. **維護困難**:複習邏輯散落在前端各處,調試和維護困難
|
||
|
||
### 解決方案
|
||
將複習會話狀態管理移至後端,實現真正的後端驅動架構,同時優化進度條UI設計。
|
||
|
||
## 技術架構設計
|
||
|
||
### 後端架構
|
||
|
||
#### 1. 數據模型設計
|
||
|
||
```csharp
|
||
// 學習會話實體
|
||
public class StudySession
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
public DateTime StartedAt { get; set; }
|
||
public DateTime? CompletedAt { get; set; }
|
||
public SessionStatus Status { get; set; }
|
||
public List<StudyCard> Cards { get; set; } = new();
|
||
public int CurrentCardIndex { get; set; }
|
||
public string? CurrentTestType { get; set; }
|
||
public int TotalTests { get; set; }
|
||
public int CompletedTests { get; set; }
|
||
}
|
||
|
||
// 詞卡學習進度
|
||
public class StudyCard
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid StudySessionId { get; set; }
|
||
public Guid FlashcardId { get; set; }
|
||
public string Word { get; set; } = string.Empty;
|
||
public List<string> PlannedTests { get; set; } = new();
|
||
public List<TestResult> CompletedTests { get; set; } = new();
|
||
public bool IsCompleted => CompletedTests.Count >= PlannedTests.Count;
|
||
public int Order { get; set; }
|
||
|
||
// 導航屬性
|
||
public StudySession StudySession { get; set; }
|
||
public Flashcard Flashcard { get; set; }
|
||
}
|
||
|
||
// 測驗結果實體
|
||
public class TestResult
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid StudyCardId { get; set; }
|
||
public string TestType { get; set; } = string.Empty;
|
||
public bool IsCorrect { get; set; }
|
||
public string? UserAnswer { get; set; }
|
||
public int? ConfidenceLevel { get; set; } // 1-5, 用於翻卡記憶
|
||
public int ResponseTimeMs { get; set; }
|
||
public DateTime CompletedAt { get; set; }
|
||
|
||
// 導航屬性
|
||
public StudyCard StudyCard { get; set; }
|
||
}
|
||
|
||
// 會話狀態枚舉
|
||
public enum SessionStatus
|
||
{
|
||
Active, // 進行中
|
||
Completed, // 已完成
|
||
Paused, // 暫停
|
||
Abandoned // 放棄
|
||
}
|
||
```
|
||
|
||
#### 2. 服務層設計
|
||
|
||
```csharp
|
||
// 學習會話服務介面
|
||
public interface IStudySessionService
|
||
{
|
||
Task<StudySessionDto> StartSessionAsync(Guid userId);
|
||
Task<CurrentTestDto> GetCurrentTestAsync(Guid sessionId);
|
||
Task<SubmitTestResponseDto> SubmitTestAsync(Guid sessionId, SubmitTestRequestDto request);
|
||
Task<NextTestDto> GetNextTestAsync(Guid sessionId);
|
||
Task<ProgressDto> GetProgressAsync(Guid sessionId);
|
||
Task<CompleteSessionResponseDto> CompleteSessionAsync(Guid sessionId);
|
||
}
|
||
|
||
// 測驗模式選擇服務
|
||
public interface IReviewModeSelector
|
||
{
|
||
List<string> GetPlannedTests(string userCEFRLevel, string wordCEFRLevel);
|
||
string GetNextTestType(StudyCard card);
|
||
}
|
||
```
|
||
|
||
#### 3. API端點設計
|
||
|
||
```csharp
|
||
[Route("api/study/sessions")]
|
||
public class StudySessionController : ControllerBase
|
||
{
|
||
// 開始學習會話
|
||
[HttpPost("start")]
|
||
public async Task<ActionResult<StudySessionDto>> StartSession()
|
||
|
||
// 獲取當前測驗
|
||
[HttpGet("{sessionId}/current-test")]
|
||
public async Task<ActionResult<CurrentTestDto>> GetCurrentTest(Guid sessionId)
|
||
|
||
// 提交測驗結果
|
||
[HttpPost("{sessionId}/submit-test")]
|
||
public async Task<ActionResult<SubmitTestResponseDto>> SubmitTest(Guid sessionId, SubmitTestRequestDto request)
|
||
|
||
// 獲取下一個測驗
|
||
[HttpGet("{sessionId}/next-test")]
|
||
public async Task<ActionResult<NextTestDto>> GetNextTest(Guid sessionId)
|
||
|
||
// 獲取詳細進度
|
||
[HttpGet("{sessionId}/progress")]
|
||
public async Task<ActionResult<ProgressDto>> GetProgress(Guid sessionId)
|
||
|
||
// 結束會話
|
||
[HttpPut("{sessionId}/complete")]
|
||
public async Task<ActionResult<CompleteSessionResponseDto>> CompleteSession(Guid sessionId)
|
||
}
|
||
```
|
||
|
||
### 前端架構
|
||
|
||
#### 1. 服務層重構
|
||
|
||
```typescript
|
||
// 學習會話服務
|
||
class StudySessionService {
|
||
async startSession(): Promise<StudySessionResponse> {
|
||
return await this.post('/api/study/sessions/start');
|
||
}
|
||
|
||
async getCurrentTest(sessionId: string): Promise<CurrentTestResponse> {
|
||
return await this.get(`/api/study/sessions/${sessionId}/current-test`);
|
||
}
|
||
|
||
async submitTest(sessionId: string, result: TestResult): Promise<SubmitTestResponse> {
|
||
return await this.post(`/api/study/sessions/${sessionId}/submit-test`, result);
|
||
}
|
||
|
||
async getNextTest(sessionId: string): Promise<NextTestResponse> {
|
||
return await this.get(`/api/study/sessions/${sessionId}/next-test`);
|
||
}
|
||
|
||
async getProgress(sessionId: string): Promise<ProgressResponse> {
|
||
return await this.get(`/api/study/sessions/${sessionId}/progress`);
|
||
}
|
||
|
||
async completeSession(sessionId: string): Promise<CompleteSessionResponse> {
|
||
return await this.put(`/api/study/sessions/${sessionId}/complete`);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. React組件簡化
|
||
|
||
```typescript
|
||
// 簡化的 LearnPage 組件
|
||
function LearnPage() {
|
||
const [session, setSession] = useState<StudySession | null>(null);
|
||
const [currentTest, setCurrentTest] = useState<CurrentTest | null>(null);
|
||
const [progress, setProgress] = useState<Progress | null>(null);
|
||
|
||
// 簡化的狀態管理 - 只保留UI相關狀態
|
||
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null);
|
||
const [showResult, setShowResult] = useState(false);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
|
||
// 簡化的邏輯
|
||
const handleStartSession = async () => {
|
||
const newSession = await studyService.startSession();
|
||
setSession(newSession);
|
||
loadCurrentTest(newSession.id);
|
||
};
|
||
|
||
const handleSubmitAnswer = async (result: TestResult) => {
|
||
await studyService.submitTest(session.id, result);
|
||
loadNextTest();
|
||
};
|
||
}
|
||
```
|
||
|
||
## 實施計劃
|
||
|
||
### 階段一:後端擴展 (預計2-3天)
|
||
|
||
#### Day 1: 數據模型和遷移
|
||
- [ ] 創建 StudySession, StudyCard, TestResult 實體
|
||
- [ ] 創建資料庫遷移
|
||
- [ ] 更新 DbContext
|
||
|
||
#### Day 2: 服務層實現
|
||
- [ ] 實現 StudySessionService
|
||
- [ ] 實現 ReviewModeSelector
|
||
- [ ] 單元測試
|
||
|
||
#### Day 3: API控制器
|
||
- [ ] 實現 StudySessionController
|
||
- [ ] API集成測試
|
||
- [ ] Swagger文檔更新
|
||
|
||
### 階段二:前端重構 (預計2天)
|
||
|
||
#### Day 4: 服務層和狀態管理
|
||
- [ ] 創建 StudySessionService
|
||
- [ ] 重構 LearnPage 組件
|
||
- [ ] 移除複雜的本地狀態
|
||
|
||
#### Day 5: UI組件優化
|
||
- [ ] 簡化測驗組件
|
||
- [ ] 更新導航邏輯
|
||
- [ ] 錯誤處理優化
|
||
|
||
### 階段三:進度條美化 (預計1天)
|
||
|
||
#### Day 6: 分段式進度條
|
||
- [ ] 設計 SegmentedProgressBar 組件
|
||
- [ ] 實現詞卡分段顯示
|
||
- [ ] 添加hover tooltip功能
|
||
- [ ] 響應式布局優化
|
||
|
||
### 階段四:測試與部署 (預計1天)
|
||
|
||
#### Day 7: 完整測試
|
||
- [ ] 端到端學習流程測試
|
||
- [ ] 進度追蹤準確性驗證
|
||
- [ ] 性能測試
|
||
- [ ] 用戶體驗測試
|
||
|
||
## 數據流程圖
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[用戶開始學習] --> B[POST /sessions/start]
|
||
B --> C[後端創建StudySession]
|
||
C --> D[後端規劃詞卡測驗]
|
||
D --> E[返回會話信息]
|
||
E --> F[GET /sessions/{id}/current-test]
|
||
F --> G[後端返回當前測驗]
|
||
G --> H[前端顯示測驗UI]
|
||
H --> I[用戶完成測驗]
|
||
I --> J[POST /sessions/{id}/submit-test]
|
||
J --> K[後端記錄結果]
|
||
K --> L{該詞卡測驗完成?}
|
||
L -->|否| M[GET /sessions/{id}/next-test]
|
||
L -->|是| N[後端計算SM2並更新]
|
||
N --> O{所有詞卡完成?}
|
||
O -->|否| M
|
||
O -->|是| P[PUT /sessions/{id}/complete]
|
||
M --> G
|
||
P --> Q[學習完成]
|
||
```
|
||
|
||
## 關鍵優勢
|
||
|
||
### 可靠性提升
|
||
- ✅ 數據一致性:狀態存在資料庫,不怕頁面刷新
|
||
- ✅ 錯誤恢復:會話可暫停和恢復
|
||
- ✅ 邏輯正確:只有完成所有測驗才標記詞卡完成
|
||
|
||
### 維護性改善
|
||
- ✅ 業務邏輯集中:複習邏輯在後端統一管理
|
||
- ✅ 前端簡化:專注UI渲染和用戶互動
|
||
- ✅ 測試友好:API可獨立測試
|
||
|
||
### 用戶體驗優化
|
||
- ✅ 進度條美化:分段式設計更直觀
|
||
- ✅ 響應速度:減少前端複雜計算
|
||
- ✅ 數據准確:實時同步學習進度
|
||
|
||
## 風險評估與應對
|
||
|
||
### 風險點
|
||
1. **數據遷移風險**:現有學習記錄可能需要轉換
|
||
2. **API性能風險**:頻繁API調用可能影響響應速度
|
||
3. **向下兼容風險**:可能影響現有功能
|
||
|
||
### 應對措施
|
||
1. **分階段部署**:先在測試環境驗證,再逐步上線
|
||
2. **數據備份**:重構前完整備份現有數據
|
||
3. **性能監控**:實施API性能監控和優化
|
||
4. **回滾方案**:保留舊版本代碼,必要時快速回滾
|
||
|
||
## 成功標準
|
||
|
||
### 功能標準
|
||
- [ ] 詞卡必須完成所有預定測驗才能標記為完成
|
||
- [ ] 學習進度準確追蹤和顯示
|
||
- [ ] 支持會話暫停和恢復
|
||
- [ ] 分段式進度條正確顯示詞卡分佈
|
||
|
||
### 性能標準
|
||
- [ ] API響應時間 < 500ms
|
||
- [ ] 頁面載入時間 < 2s
|
||
- [ ] 學習流程無明顯卡頓
|
||
|
||
### 用戶體驗標準
|
||
- [ ] 學習流程直觀流暢
|
||
- [ ] 進度顯示清晰準確
|
||
- [ ] 錯誤處理友好
|
||
|
||
---
|
||
|
||
**創建時間**: 2025-09-26
|
||
**負責人**: Claude Code
|
||
**預計完成**: 2025-10-03 (7個工作天) |