dramaling-vocab-learning/note/智能複習/智能複習系統-技術規格書.md

295 lines
7.7 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.

# 智能複習系統 - 技術規格書 (TSD)
**目標讀者**: 後端開發工程師、系統架構師
**版本**: 1.0
**日期**: 2025-09-25
---
## 🏗️ **系統架構**
### **核心服務**
```
┌─────────────────────┐
│ 復習記錄 API │
└─────────┬───────────┘
┌─────▼─────┐
│ 輸入驗證層 │
└─────┬─────┘
┌───────▼────────┐
│ SpacedRepetition │
│ Service │
│ ┌─────────────┐ │
│ │ 逾期檢測 │ │
│ │ 間隔計算 │ │
│ │ 熟悉度更新 │ │
│ └─────────────┘ │
└───────┬────────┘
┌─────▼─────┐
│ 數據持久化 │
└───────────┘
```
### **關鍵類別設計**
#### **SpacedRepetitionService**
```csharp
public class SpacedRepetitionService
{
public ReviewResult ProcessReview(ReviewRequest request)
{
// 1. 計算逾期天數 (明確時間基準)
var actualReviewDate = DateTime.Now.Date; // 復習行為當日
var overdueDays = (actualReviewDate - request.NextReviewDate.Date).Days;
// 2. 應用記憶衰減
var adjustedMastery = ApplyMemoryDecay(request.CurrentMastery, overdueDays);
// 3. 計算新間隔
var newInterval = CalculateNewInterval(
request.CurrentInterval,
request.IsCorrect,
request.ConfidenceLevel,
overdueDays
);
// 4. 更新基礎熟悉程度 (存入資料庫)
var newBaseMastery = CalculateMasteryLevel(
request.TimesCorrect + (request.IsCorrect ? 1 : 0),
request.TotalReviews + 1,
newInterval
);
return new ReviewResult
{
NewInterval = newInterval,
NextReviewDate = actualReviewDate.AddDays(newInterval), // 以復習當日為基準
BaseMasteryLevel = newBaseMastery, // 基礎熟悉度
CurrentMasteryLevel = newBaseMastery, // 剛復習完,兩者相等
IsOverdue = overdueDays > 0,
OverdueDays = Math.Max(0, overdueDays)
};
}
/// <summary>
/// 計算當前熟悉度 (實時計算,不存資料庫)
/// </summary>
public int CalculateCurrentMasteryLevel(Flashcard flashcard)
{
var daysSinceLastReview = (DateTime.Now.Date - flashcard.LastReviewDate.Date).Days;
// 如果沒有時間經過,返回基礎熟悉度
if (daysSinceLastReview <= 0)
return flashcard.BaseMasteryLevel;
// 應用記憶衰減
return ApplyMemoryDecay(flashcard.BaseMasteryLevel, daysSinceLastReview);
}
}
```
---
## 🔌 **API 設計**
### **POST /api/flashcards/{id}/review**
#### **請求格式**
```json
{
"isCorrect": boolean,
"confidenceLevel": number, // 1-5, 翻卡題必須
"questionType": "flipcard" | "multiple_choice" | "fill_blank"
}
```
#### **響應格式**
```json
{
"success": true,
"data": {
"newInterval": 15,
"nextReviewDate": "2025-10-10",
"baseMasteryLevel": 65, // 基礎熟悉度 (存資料庫)
"currentMasteryLevel": 65, // 當前熟悉度 (實時計算)
"isOverdue": false,
"overdueDays": 0
}
}
```
### **GET /api/flashcards/{id}**
#### **響應格式**
```json
{
"success": true,
"data": {
"id": 123,
"word": "apple",
"definition": "蘋果",
"baseMasteryLevel": 75, // 基礎熟悉度 (資料庫值)
"currentMasteryLevel": 68, // 當前熟悉度 (考慮衰減)
"lastReviewDate": "2025-09-20",
"nextReviewDate": "2025-10-04",
"currentInterval": 14,
"timesCorrect": 8,
"totalReviews": 10,
"isOverdue": true,
"overdueDays": 1
}
}
```
#### **錯誤響應**
```json
{
"success": false,
"error": {
"code": "VALUE_OUT_OF_RANGE",
"message": "信心程度必須在 1-5 範圍內",
"field": "confidenceLevel"
}
}
```
---
## 🛡️ **安全與驗證**
### **輸入驗證規則**
```csharp
public class ReviewRequestValidator : AbstractValidator<ReviewRequest>
{
public ReviewRequestValidator()
{
RuleFor(x => x.IsCorrect).NotNull();
RuleFor(x => x.ConfidenceLevel)
.InclusiveBetween(1, 5)
.When(x => x.QuestionType == "flipcard");
RuleFor(x => x.QuestionType)
.Must(BeValidQuestionType)
.WithMessage("questionType 必須是 flipcard, multiple_choice 或 fill_blank");
}
}
```
### **錯誤處理策略**
- **4xx 錯誤**: 客戶端輸入錯誤,返回詳細錯誤訊息
- **5xx 錯誤**: 服務器錯誤,記錄日誌並返回通用錯誤訊息
- **資料庫錯誤**: 重試機制最多3次重試
---
## 💾 **資料庫設計**
### **資料表更新**
```sql
-- 現有 Flashcards 表需要的欄位
ALTER TABLE Flashcards ADD COLUMN
LastReviewDate DATETIME, -- 上次實際復習日期
BaseMasteryLevel INT DEFAULT 0, -- 基礎熟悉度 (上次復習時的值)
OverdueCount INT DEFAULT 0, -- 逾期次數統計
ConsecutiveOverdue INT DEFAULT 0; -- 連續逾期次數
-- 注意: CurrentMasteryLevel 不存資料庫,透過 API 實時計算
```
### **索引優化**
```sql
-- 提升查詢到期詞卡的性能
CREATE INDEX IX_Flashcards_NextReviewDate
ON Flashcards(NextReviewDate, UserId);
-- 提升逾期統計查詢性能
CREATE INDEX IX_Flashcards_OverdueStats
ON Flashcards(LastReviewDate, NextReviewDate);
```
---
## ⚙️ **配置管理**
### **appsettings.json 配置**
```json
{
"SpacedRepetition": {
"GrowthFactors": {
"ShortTerm": 1.8,
"MediumTerm": 1.4,
"LongTerm": 1.2,
"VeryLongTerm": 1.1
},
"OverduePenalties": {
"Light": 0.9, // 1-3天
"Medium": 0.75, // 4-7天
"Heavy": 0.5, // 8-30天
"Extreme": 0.3 // >30天
},
"MemoryDecayRate": 0.05, // 每天5%衰減
"MaxInterval": 365
}
}
```
---
## 🔍 **監控與日誌**
### **關鍵指標監控**
```csharp
public class ReviewMetrics
{
[Counter("reviews_processed_total")]
public static readonly Counter ReviewsProcessed;
[Histogram("review_calculation_duration_ms")]
public static readonly Histogram CalculationDuration;
[Histogram("mastery_calculation_duration_ms")]
public static readonly Histogram MasteryCalculationDuration;
[Gauge("overdue_reviews_current")]
public static readonly Gauge OverdueReviews;
[Counter("mastery_calculations_total")]
public static readonly Counter MasteryCalculations;
}
```
### **日誌記錄**
- **INFO**: 正常復習記錄
- **WARN**: 逾期復習、異常參數
- **ERROR**: 計算失敗、資料庫錯誤
---
## 🚀 **部署需求**
### **性能要求**
- **API 響應時間**: P95 < 100ms
- **並發處理**: 支援 1000+ 同時用戶
- **資料庫連線**: 連線池最大 50 連線
### **環境配置**
- **.NET 8+** 運行環境
- **SQLite/PostgreSQL** 資料庫
- **Memory/Redis** 緩存 (可選)
### **部署檢查清單**
- [ ] 資料庫遷移腳本執行
- [ ] 配置文件更新
- [ ] 監控指標接入
- [ ] 日誌收集配置
- [ ] 性能測試通過
---
**實施時間**: 2-3個工作日
**測試時間**: 1個工作日
**上線影響**: 零停機時間部署