246 lines
6.0 KiB
Markdown
246 lines
6.0 KiB
Markdown
# 智能複習系統 - 技術規格書 (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 newMastery = CalculateMasteryLevel(
|
||
request.TimesCorrect + (request.IsCorrect ? 1 : 0),
|
||
request.TotalReviews + 1,
|
||
newInterval
|
||
);
|
||
|
||
return new ReviewResult
|
||
{
|
||
NewInterval = newInterval,
|
||
NextReviewDate = actualReviewDate.AddDays(newInterval), // 以復習當日為基準
|
||
MasteryLevel = newMastery,
|
||
IsOverdue = overdueDays > 0,
|
||
OverdueDays = Math.Max(0, overdueDays)
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔌 **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",
|
||
"masteryLevel": 65,
|
||
"isOverdue": false,
|
||
"overdueDays": 0
|
||
}
|
||
}
|
||
```
|
||
|
||
#### **錯誤響應**
|
||
```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, -- 上次實際復習日期
|
||
OverdueCount INT DEFAULT 0, -- 逾期次數統計
|
||
ConsecutiveOverdue INT DEFAULT 0; -- 連續逾期次數
|
||
```
|
||
|
||
### **索引優化**
|
||
```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;
|
||
|
||
[Gauge("overdue_reviews_current")]
|
||
public static readonly Gauge OverdueReviews;
|
||
}
|
||
```
|
||
|
||
### **日誌記錄**
|
||
- **INFO**: 正常復習記錄
|
||
- **WARN**: 逾期復習、異常參數
|
||
- **ERROR**: 計算失敗、資料庫錯誤
|
||
|
||
---
|
||
|
||
## 🚀 **部署需求**
|
||
|
||
### **性能要求**
|
||
- **API 響應時間**: P95 < 100ms
|
||
- **並發處理**: 支援 1000+ 同時用戶
|
||
- **資料庫連線**: 連線池最大 50 連線
|
||
|
||
### **環境配置**
|
||
- **.NET 8+** 運行環境
|
||
- **SQLite/PostgreSQL** 資料庫
|
||
- **Memory/Redis** 緩存 (可選)
|
||
|
||
### **部署檢查清單**
|
||
- [ ] 資料庫遷移腳本執行
|
||
- [ ] 配置文件更新
|
||
- [ ] 監控指標接入
|
||
- [ ] 日誌收集配置
|
||
- [ ] 性能測試通過
|
||
|
||
---
|
||
|
||
**實施時間**: 2-3個工作日
|
||
**測試時間**: 1個工作日
|
||
**上線影響**: 零停機時間部署 |