dramaling-app/docs/04_technical/01_architecture/backend-api-separation-plan.md

1017 lines
30 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.

# 後端API架構分離計劃
**文件版本**: 1.0
**建立日期**: 2025-09-10
**更新日期**: 2025-09-10
**負責人**: Drama Ling 開發團隊
## 📋 概述
由於Drama Ling需要同時支援移動端App和Web端應用現有的單一後端API架構將面臨以下挑戰
- 移動端和Web端資料需求差異
- 認證方式和安全要求不同
- 效能優化需求各異
- 維護和擴展複雜度增加
本文件提出後端API分離的架構方案和實施計劃。
## 🎯 目標
### 主要目標
1. **API專業化**: 為移動端和Web端提供專門優化的API
2. **提升效能**: 減少不必要的資料傳輸,提升回應速度
3. **簡化維護**: 降低不同端點間的耦合度
4. **增強安全**: 針對不同平台實施適當的安全策略
5. **支援擴展**: 為未來微服務架構奠定基礎
### 成功指標
- API回應時間減少30%以上
- 移動端資料傳輸量減少50%
- 代碼維護複雜度降低
- 支援獨立部署和擴展
## 🏗 架構方案
### 方案一: API Gateway + 微服務分離 (推薦)
```mermaid
graph TB
MA[Mobile App] --> AG[API Gateway]
WA[Web App] --> AG
AG --> AUTH[Authentication Service]
AG --> USER[User Service]
AG --> VOCAB[Vocabulary Service]
AG --> LEARN[Learning Service]
AG --> PROG[Progress Service]
AUTH --> DB1[(Auth DB)]
USER --> DB2[(User DB)]
VOCAB --> DB3[(Vocabulary DB)]
LEARN --> DB4[(Learning DB)]
PROG --> DB5[(Progress DB)]
```
#### 優勢
- 🎯 **高度專業化**: 每個服務專注特定功能
- 🚀 **獨立擴展**: 可根據負載獨立擴展服務
- 🔒 **安全隔離**: 服務間隔離,降低安全風險
- 🛠 **技術選型靈活**: 不同服務可選用不同技術
- 👥 **團隊分工**: 支援多團隊並行開發
#### 挑戰
- 複雜度較高,需要服務發現和配置管理
- 分散式系統的一致性問題
- 運維複雜度增加
### 方案二: 單體 + 多端點適配 (階段性)
```mermaid
graph TB
MA[Mobile App] --> ME[/api/v1/mobile]
WA[Web App] --> WE[/api/v1/web]
ME --> BS[Backend Service]
WE --> BS
BS --> SL[Shared Logic Layer]
BS --> MH[Mobile Handler]
BS --> WH[Web Handler]
SL --> DB[(Database)]
```
#### 優勢
- 🏃‍♂️ **快速實施**: 在現有架構基礎上調整
- 🔧 **維護簡單**: 單一部署單位
- 💰 **成本較低**: 無需額外的基礎設施
- 🧪 **風險可控**: 漸進式改進
#### 挑戰
- 單體應用的擴展限制
- 不同端點間仍有耦合
- 長期維護複雜度仍然較高
## 📊 API差異化設計
### 移動端API特點
```json
{
"endpoint": "/api/v1/mobile/vocabulary/{id}",
"response": {
"word": "confidence",
"phonetic": "/ˈkɒnfɪdəns/",
"definition": "信心",
"audio_url": "https://cdn.dramaling.com/audio/confidence.mp3",
"last_reviewed": "2025-09-10T10:30:00Z"
},
"features": [
"精簡資料結構",
"支援離線緩存",
"增量同步",
"推播通知",
"JWT認證"
]
}
```
### Web端API特點
```json
{
"endpoint": "/api/v1/web/vocabulary/{id}",
"response": {
"word": "confidence",
"phonetic": "/ˈkɒnfɪdəns/",
"definitions": {
"primary": "信心;自信心;把握",
"secondary": ["確信", "秘密", "信賴"]
},
"examples": [
{
"sentence": "She spoke with great confidence during the presentation.",
"translation": "她在簡報中表現出很大的自信。"
}
],
"synonyms": ["assurance", "self-assurance", "poise"],
"etymology": "來自拉丁語 confidentia",
"usage_frequency": 0.85,
"difficulty_level": "intermediate",
"related_words": ["confident", "confidential"],
"learning_analytics": {
"total_reviews": 15,
"success_rate": 0.87,
"avg_response_time": 2.3
}
},
"features": [
"完整資料結構",
"即時互動",
"豐富的學習分析",
"SEO友好",
"Session認證"
]
}
```
### 認證策略差異
#### 移動端認證
```csharp
[ApiController]
[Route("api/v1/mobile/[controller]")]
[Authorize(AuthenticationSchemes = "JwtBearer")]
public class MobileVocabularyController : ControllerBase
{
// JWT Token + Refresh Token
// 生物識別支援
// OAuth2.0 整合
}
```
#### Web端認證
```csharp
[ApiController]
[Route("api/v1/web/[controller]")]
[Authorize(AuthenticationSchemes = "Cookie,OpenIdConnect")]
public class WebVocabularyController : ControllerBase
{
// Session + Cookie
// Social Login (Google, Facebook)
// CSRF Protection
}
```
## 🚀 實施計劃
### Phase 1: 基礎分離 (4週)
**目標**: 建立移動端和Web端分離的API端點
#### Week 1: 路由分離
- [ ] 建立 `/api/v1/mobile/*` 路由結構
- [ ] 建立 `/api/v1/web/*` 路由結構
- [ ] 實現路由中介軟體和版本控制
- [ ] 測試基本路由功能
#### Week 2: 控制器分離
- [ ] 複製現有控制器為Mobile和Web版本
- [ ] 實現MobileBaseController和WebBaseController
- [ ] 調整回應格式和資料結構
- [ ] 單元測試覆蓋
#### Week 3: 資料模型差異化
- [ ] 建立MobileDto和WebDto資料傳輸物件
- [ ] 實現AutoMapper配置
- [ ] 調整序列化設定
- [ ] API文件生成
#### Week 4: 認證系統調整
- [ ] 實現JWT認證for移動端
- [ ] 保持Session認證for Web端
- [ ] 測試認證流程
- [ ] 效能基準測試
### Phase 2: 功能優化 (6週)
**目標**: 針對不同平台優化API功能
#### Week 5-6: 移動端優化
- [ ] 實現離線支援和增量同步
- [ ] 優化資料傳輸量和壓縮
- [ ] 推播通知整合
- [ ] 移動端特有功能開發
#### Week 7-8: Web端優化
- [ ] 實現即時互動功能
- [ ] 豐富學習分析資料
- [ ] SEO優化和Open Graph支援
- [ ] Web端專屬功能開發
#### Week 9-10: 效能和安全優化
- [ ] API快取策略實施
- [ ] 安全性強化(CORS, CSRF, Rate Limiting)
- [ ] 監控和日誌系統
- [ ] 負載測試和調優
### Phase 3: 微服務準備 (8週)
**目標**: 為未來微服務架構做準備
#### Week 11-12: 服務邊界定義
- [ ] 識別和定義服務邊界
- [ ] 資料庫分離規劃
- [ ] API Gateway選型和POC
- [ ] 服務發現機制設計
#### Week 13-16: 核心服務提取
- [ ] 提取User Service
- [ ] 提取Vocabulary Service
- [ ] 提取Learning Service
- [ ] 服務間通信機制
#### Week 17-18: 整合和測試
- [ ] API Gateway整合
- [ ] 端到端測試
- [ ] 效能測試和調優
- [ ] 生產環境部署準備
## 🛠 技術實現
### .NET Core 實現範例
#### 1. 路由結構
```csharp
// Program.cs
app.MapControllerRoute(
name: "mobile-api",
pattern: "api/v1/mobile/{controller}/{action=Index}/{id?}");
app.MapControllerRoute(
name: "web-api",
pattern: "api/v1/web/{controller}/{action=Index}/{id?}");
```
#### 2. 基礎控制器
```csharp
// MobileBaseController.cs
[ApiController]
[Route("api/v1/mobile/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public abstract class MobileBaseController : ControllerBase
{
protected readonly ILogger Logger;
protected readonly IMapper Mapper;
protected MobileBaseController(ILogger logger, IMapper mapper)
{
Logger = logger;
Mapper = mapper;
}
protected IActionResult MobileSuccess<T>(T data, string message = null)
{
return Ok(new MobileApiResponse<T>
{
Data = data,
Message = message,
Timestamp = DateTimeOffset.UtcNow,
Success = true
});
}
}
// WebBaseController.cs
[ApiController]
[Route("api/v1/web/[controller]")]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public abstract class WebBaseController : ControllerBase
{
protected readonly ILogger Logger;
protected readonly IMapper Mapper;
protected WebBaseController(ILogger logger, IMapper mapper)
{
Logger = logger;
Mapper = mapper;
}
protected IActionResult WebSuccess<T>(T data, object meta = null)
{
return Ok(new WebApiResponse<T>
{
Data = data,
Meta = meta,
Links = GenerateHATEOASLinks(),
Timestamp = DateTimeOffset.UtcNow
});
}
}
```
#### 3. 專業化控制器
```csharp
// Mobile Vocabulary Controller
public class MobileVocabularyController : MobileBaseController
{
private readonly IVocabularyService _vocabularyService;
public MobileVocabularyController(
ILogger<MobileVocabularyController> logger,
IMapper mapper,
IVocabularyService vocabularyService)
: base(logger, mapper)
{
_vocabularyService = vocabularyService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetVocabulary(int id)
{
var vocabulary = await _vocabularyService.GetByIdAsync(id);
var mobileDto = Mapper.Map<MobileVocabularyDto>(vocabulary);
return MobileSuccess(mobileDto);
}
[HttpGet("sync")]
public async Task<IActionResult> SyncVocabulary([FromQuery] DateTime? lastSync)
{
var changes = await _vocabularyService.GetChangesAsync(lastSync);
var mobileDtos = Mapper.Map<List<MobileVocabularyDto>>(changes);
return MobileSuccess(new
{
Vocabularies = mobileDtos,
LastSyncTime = DateTimeOffset.UtcNow,
HasMore = changes.Count >= 50
});
}
}
// Web Vocabulary Controller
public class WebVocabularyController : WebBaseController
{
private readonly IVocabularyService _vocabularyService;
private readonly ILearningAnalyticsService _analyticsService;
public WebVocabularyController(
ILogger<WebVocabularyController> logger,
IMapper mapper,
IVocabularyService vocabularyService,
ILearningAnalyticsService analyticsService)
: base(logger, mapper)
{
_vocabularyService = vocabularyService;
_analyticsService = analyticsService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetVocabulary(int id)
{
var vocabulary = await _vocabularyService.GetByIdAsync(id);
var analytics = await _analyticsService.GetVocabularyAnalyticsAsync(id);
var webDto = Mapper.Map<WebVocabularyDto>(vocabulary);
webDto.LearningAnalytics = Mapper.Map<LearningAnalyticsDto>(analytics);
return WebSuccess(webDto, new {
Related = await _vocabularyService.GetRelatedWordsAsync(id),
Recommendations = await _vocabularyService.GetRecommendationsAsync(id)
});
}
[HttpGet("search")]
public async Task<IActionResult> SearchVocabulary(
[FromQuery] string query,
[FromQuery] int page = 1,
[FromQuery] int size = 20,
[FromQuery] string[] filters = null)
{
var result = await _vocabularyService.SearchAsync(query, page, size, filters);
var webDtos = Mapper.Map<List<WebVocabularyDto>>(result.Items);
return WebSuccess(webDtos, new
{
Pagination = new
{
Page = page,
Size = size,
Total = result.Total,
Pages = (int)Math.Ceiling((double)result.Total / size)
},
Filters = await _vocabularyService.GetAvailableFiltersAsync(),
Aggregations = result.Aggregations
});
}
}
```
#### 4. 資料傳輸物件 (DTOs)
```csharp
// Mobile DTOs - 精簡結構
public class MobileVocabularyDto
{
public int Id { get; set; }
public string Word { get; set; }
public string Phonetic { get; set; }
public string Definition { get; set; }
public string AudioUrl { get; set; }
public DateTimeOffset LastReviewed { get; set; }
public int ReviewCount { get; set; }
public double MasteryLevel { get; set; }
}
public class MobileApiResponse<T>
{
public T Data { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
// Web DTOs - 豐富結構
public class WebVocabularyDto
{
public int Id { get; set; }
public string Word { get; set; }
public string Phonetic { get; set; }
public DefinitionDto Definitions { get; set; }
public List<ExampleDto> Examples { get; set; }
public List<string> Synonyms { get; set; }
public List<string> Antonyms { get; set; }
public string Etymology { get; set; }
public double UsageFrequency { get; set; }
public string DifficultyLevel { get; set; }
public List<string> RelatedWords { get; set; }
public LearningAnalyticsDto LearningAnalytics { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
}
public class WebApiResponse<T>
{
public T Data { get; set; }
public object Meta { get; set; }
public Dictionary<string, string> Links { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
```
## 📈 效能考量
### 移動端優化策略
1. **資料壓縮**: 使用Gzip/Brotli壓縮
2. **增量同步**: 僅傳輸變更資料
3. **快取策略**: 積極的客戶端快取
4. **分頁載入**: 小批次資料載入
5. **連接複用**: HTTP/2 多工處理
### Web端優化策略
1. **快取分層**: Redis + Memory + CDN
2. **資料預載**: 相關資料預先載入
3. **即時更新**: WebSocket/SignalR
4. **搜尋優化**: ElasticSearch整合
5. **圖片優化**: WebP格式和響應式圖片
## 🔒 安全性設計
### 共同安全措施
- HTTPS強制執行
- API版本控制
- 輸入驗證和清理
- 輸出編碼
- 安全標頭設定
### 移動端專屬
- JWT Token安全存儲
- Certificate Pinning
- Root Detection
- API密鑰混淆
- 生物識別整合
### Web端專屬
- CSRF保護
- XSS防護
- Content Security Policy
- Session管理
- Same-Site Cookie
## 📊 監控和分析
### 關鍵指標 (KPIs)
1. **效能指標**
- API回應時間 (P95 < 200ms)
- 錯誤率 (< 0.1%)
- 吞吐量 (TPS)
2. **使用者體驗**
- 移動端資料傳輸量
- Web端頁面載入時間
- 離線功能可用性
3. **業務指標**
- API使用率
- 功能採用率
- 使用者滿意度
### 監控工具
- **Application Insights**: .NET應用監控
- **Prometheus + Grafana**: 指標收集和視覺化
- **ELK Stack**: 日誌分析
- **Postman/Newman**: API測試自動化
## 🚦 風險管理
### 技術風險
| 風險 | 機率 | 影響 | 緩解措施 |
|------|------|------|----------|
| 服務間通信複雜度 | | | 使用成熟的API Gateway解決方案 |
| 資料一致性問題 | | | 實施Saga模式和補償事務 |
| 效能退化 | | | 充分的效能測試和監控 |
| 安全漏洞 | | | 安全掃描和滲透測試 |
### 業務風險
| 風險 | 機率 | 影響 | 緩解措施 |
|------|------|------|----------|
| 開發時程延遲 | | | 分階段實施降低每階段風險 |
| 使用者體驗下降 | | | 充分的使用者測試 |
| 維護成本增加 | | | 自動化部署和監控 |
## 📝 後續步驟
### 立即行動項目
1. [ ] **技術評估**: 評估現有程式碼庫分離可行性
2. [ ] **團隊培訓**: 微服務架構和API設計最佳實踐
3. [ ] **工具準備**: 開發測試部署工具鏈建立
4. [ ] **原型開發**: 建立MVP驗證架構可行性
### 決策點
1. **Week 4**: Phase 1完成度評估決定是否進入Phase 2
2. **Week 10**: 效能和安全性評估決定微服務遷移時機
3. **Week 18**: 全面評估決定生產環境部署策略
## 📚 詞彙學習系統API實施計畫
### 階段一核心詞彙API開發 (Week 1-3)
#### 1.1 資料庫架構建立
```sql
-- 詞彙基礎表設計 (基於database-schema.md)
CREATE TABLE vocabulary_bank (
vocab_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
word VARCHAR(100) NOT NULL,
phonetic VARCHAR(200),
part_of_speech VARCHAR(50),
definition_en TEXT,
definition_native JSONB,
category VARCHAR(50),
difficulty_level VARCHAR(10),
frequency_rank INTEGER,
audio_url TEXT,
example_sentences JSONB,
synonyms JSONB,
antonyms JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(word, part_of_speech)
);
-- 用戶詞彙進度表
CREATE TABLE user_vocabulary_progress (
progress_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(user_id) ON DELETE CASCADE,
vocab_id UUID REFERENCES vocabulary_bank(vocab_id) ON DELETE CASCADE,
mastery_level VARCHAR(20) DEFAULT 'learning',
mastery_score INTEGER DEFAULT 0,
review_count INTEGER DEFAULT 0,
correct_count INTEGER DEFAULT 0,
ease_factor DECIMAL(4,2) DEFAULT 2.50,
interval_days INTEGER DEFAULT 1,
next_review_date DATE,
first_encountered TIMESTAMPTZ DEFAULT NOW(),
last_reviewed TIMESTAMPTZ,
UNIQUE(user_id, vocab_id)
);
```
#### 1.2 核心服務層實現
```csharp
// IVocabularyService 介面設計
public interface IVocabularyService
{
// 基本詞彙CRUD
Task<VocabularyDto> GetByIdAsync(Guid vocabId);
Task<PagedResult<VocabularyDto>> GetVocabularyListAsync(VocabularyFilter filter);
Task<List<VocabularyDto>> SearchVocabularyAsync(string query, int limit = 20);
// 用戶學習進度
Task<UserVocabularyProgressDto> GetUserProgressAsync(Guid userId, Guid vocabId);
Task UpdateProgressAsync(Guid userId, UpdateProgressRequest request);
Task<List<VocabularyDto>> GetDueForReviewAsync(Guid userId);
// 間隔重複演算法
Task<SpacedRepetitionResult> ProcessReviewResultAsync(
Guid userId, Guid vocabId, ReviewQuality quality);
// 學習分析
Task<LearningAnalyticsDto> GetLearningAnalyticsAsync(Guid userId);
}
// 間隔重複演算法實現
public class SpacedRepetitionService : ISpacedRepetitionService
{
public SpacedRepetitionResult CalculateNextReview(
double easeFactor, int interval, ReviewQuality quality)
{
// SuperMemo SM-2 算法實現
var newEaseFactor = Math.Max(1.3, easeFactor +
(0.1 - (5 - (int)quality) * (0.08 + (5 - (int)quality) * 0.02)));
int newInterval = quality switch
{
ReviewQuality.Again => 1,
ReviewQuality.Hard => (int)(interval * 1.2),
ReviewQuality.Good => (int)(interval * newEaseFactor),
ReviewQuality.Easy => (int)(interval * newEaseFactor * 1.3),
_ => 1
};
return new SpacedRepetitionResult
{
NextInterval = newInterval,
NewEaseFactor = newEaseFactor,
NextReviewDate = DateTime.UtcNow.AddDays(newInterval)
};
}
}
```
#### 1.3 API控制器實現
```csharp
// 移動端詞彙API控制器
[ApiController]
[Route("api/v1/mobile/vocabulary")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class MobileVocabularyController : MobileBaseController
{
private readonly IVocabularyService _vocabularyService;
[HttpGet("daily-review")]
public async Task<ActionResult<MobileApiResponse<List<MobileVocabularyDto>>>> GetDailyReview()
{
var userId = GetCurrentUserId();
var vocabularyList = await _vocabularyService.GetDueForReviewAsync(userId);
var mobileDtos = Mapper.Map<List<MobileVocabularyDto>>(vocabularyList);
return MobileSuccess(mobileDtos);
}
[HttpPost("{vocabId}/review")]
public async Task<ActionResult<MobileApiResponse<ReviewResultDto>>> SubmitReview(
Guid vocabId, [FromBody] SubmitReviewRequest request)
{
var userId = GetCurrentUserId();
var result = await _vocabularyService.ProcessReviewResultAsync(
userId, vocabId, request.Quality);
return MobileSuccess(new ReviewResultDto
{
NextReviewDate = result.NextReviewDate,
MasteryLevelChange = result.MasteryLevelChange,
PointsEarned = result.PointsEarned
});
}
[HttpGet("search")]
public async Task<ActionResult<MobileApiResponse<List<MobileVocabularyDto>>>> Search(
[FromQuery] string query, [FromQuery] int limit = 10)
{
var results = await _vocabularyService.SearchVocabularyAsync(query, limit);
var mobileDtos = Mapper.Map<List<MobileVocabularyDto>>(results);
return MobileSuccess(mobileDtos);
}
}
// Web端詞彙API控制器
[ApiController]
[Route("api/v1/web/vocabulary")]
[Authorize]
public class WebVocabularyController : WebBaseController
{
[HttpGet("{id}")]
public async Task<ActionResult<WebApiResponse<WebVocabularyDto>>> GetVocabulary(Guid id)
{
var vocabulary = await _vocabularyService.GetByIdAsync(id);
var webDto = Mapper.Map<WebVocabularyDto>(vocabulary);
return WebSuccess(webDto, new {
RelatedWords = await _vocabularyService.GetRelatedWordsAsync(id),
LearningTips = await _vocabularyService.GetLearningTipsAsync(id),
UsageExamples = await _vocabularyService.GetUsageExamplesAsync(id)
});
}
[HttpGet("analytics")]
public async Task<ActionResult<WebApiResponse<LearningAnalyticsDto>>> GetAnalytics(
[FromQuery] DateTime? from, [FromQuery] DateTime? to)
{
var userId = GetCurrentUserId();
var analytics = await _vocabularyService.GetLearningAnalyticsAsync(
userId, from, to);
return WebSuccess(analytics);
}
}
```
### 階段二:智能學習功能 (Week 4-6)
#### 2.1 AI驅動的詞彙推薦系統
```csharp
public interface IVocabularyRecommendationService
{
Task<List<VocabularyDto>> GetPersonalizedRecommendationsAsync(
Guid userId, int count = 10);
Task<List<VocabularyDto>> GetContextualVocabularyAsync(
string context, DifficultyLevel level);
Task<List<VocabularyDto>> GetRelatedVocabularyAsync(Guid vocabId);
}
public class AIVocabularyRecommendationService : IVocabularyRecommendationService
{
private readonly IOpenAIService _openAiService;
private readonly IVocabularyRepository _vocabularyRepo;
public async Task<List<VocabularyDto>> GetPersonalizedRecommendationsAsync(
Guid userId, int count = 10)
{
// 獲取用戶學習歷史和偏好
var userProfile = await GetUserLearningProfileAsync(userId);
// 使用GPT-4o-mini分析用戶需求
var prompt = $@"
Based on user learning profile:
- Current level: {userProfile.Level}
- Weak categories: {string.Join(',', userProfile.WeakCategories)}
- Interests: {string.Join(',', userProfile.Interests)}
Recommend 10 vocabulary words that would be most beneficial
for this learner's progression.";
var aiResponse = await _openAiService.GetCompletionAsync(prompt);
// 解析AI回應並匹配資料庫詞彙
return await MatchWordsFromDatabase(aiResponse, count);
}
}
```
#### 2.2 自適應複習系統
```csharp
public class AdaptiveReviewService : IAdaptiveReviewService
{
public async Task<AdaptiveReviewSession> CreateReviewSessionAsync(Guid userId)
{
var dueWords = await _vocabularyService.GetDueForReviewAsync(userId);
var userStats = await GetUserStatisticsAsync(userId);
// 根據用戶表現調整複習策略
var strategy = DetermineReviewStrategy(userStats);
// 智能排序複習詞彙
var optimizedOrder = OptimizeReviewOrder(dueWords, strategy);
return new AdaptiveReviewSession
{
SessionId = Guid.NewGuid(),
UserId = userId,
Words = optimizedOrder,
Strategy = strategy,
EstimatedDuration = CalculateEstimatedDuration(optimizedOrder.Count)
};
}
private ReviewStrategy DetermineReviewStrategy(UserStatistics stats)
{
// 基於用戶統計數據選擇最佳複習策略
if (stats.AccuracyRate < 0.7)
return ReviewStrategy.Reinforcement; // 加強練習
else if (stats.ReviewStreak > 7)
return ReviewStrategy.Challenging; // 挑戰模式
else
return ReviewStrategy.Balanced; // 平衡模式
}
}
```
### 階段三:高級分析與遊戲化 (Week 7-9)
#### 3.1 學習分析API
```csharp
[ApiController]
[Route("api/v1/mobile/vocabulary/analytics")]
public class MobileVocabularyAnalyticsController : MobileBaseController
{
[HttpGet("dashboard")]
public async Task<ActionResult<MobileApiResponse<DashboardData>>> GetDashboard()
{
var userId = GetCurrentUserId();
var data = new DashboardData
{
TodayProgress = await _analyticsService.GetTodayProgressAsync(userId),
WeeklyStreak = await _analyticsService.GetWeeklyStreakAsync(userId),
MasteryDistribution = await _analyticsService.GetMasteryDistributionAsync(userId),
RecentAchievements = await _analyticsService.GetRecentAchievementsAsync(userId)
};
return MobileSuccess(data);
}
[HttpGet("progress-chart")]
public async Task<ActionResult<MobileApiResponse<ProgressChartData>>> GetProgressChart(
[FromQuery] ChartPeriod period = ChartPeriod.Month)
{
var userId = GetCurrentUserId();
var chartData = await _analyticsService.GetProgressChartDataAsync(userId, period);
return MobileSuccess(chartData);
}
}
```
#### 3.2 遊戲化系統整合
```csharp
public interface IVocabularyGamificationService
{
Task<AchievementResult> CheckAchievementsAsync(Guid userId, LearningActivity activity);
Task<List<BadgeDto>> GetUserBadgesAsync(Guid userId);
Task<LeaderboardPosition> GetLeaderboardPositionAsync(Guid userId);
Task<int> CalculateExperiencePointsAsync(ReviewResult result);
}
public class VocabularyGamificationService : IVocabularyGamificationService
{
public async Task<int> CalculateExperiencePointsAsync(ReviewResult result)
{
var basePoints = result.Quality switch
{
ReviewQuality.Again => 1,
ReviewQuality.Hard => 3,
ReviewQuality.Good => 5,
ReviewQuality.Easy => 8,
_ => 0
};
// 連續正確答案加成
var streakMultiplier = Math.Min(result.StreakCount / 5.0 + 1, 2.0);
// 詞彙難度加成
var difficultyMultiplier = result.Difficulty switch
{
"A1" => 1.0,
"A2" => 1.2,
"B1" => 1.5,
"B2" => 1.8,
"C1" => 2.0,
"C2" => 2.5,
_ => 1.0
};
return (int)(basePoints * streakMultiplier * difficultyMultiplier);
}
}
```
### 階段四:效能優化與快取 (Week 10-12)
#### 4.1 Redis快取策略
```csharp
public class CachedVocabularyService : IVocabularyService
{
private readonly IVocabularyService _baseService;
private readonly IRedisCache _cache;
public async Task<VocabularyDto> GetByIdAsync(Guid vocabId)
{
var cacheKey = $"vocabulary:{vocabId}";
var cached = await _cache.GetAsync<VocabularyDto>(cacheKey);
if (cached != null)
return cached;
var vocabulary = await _baseService.GetByIdAsync(vocabId);
await _cache.SetAsync(cacheKey, vocabulary, TimeSpan.FromHours(6));
return vocabulary;
}
public async Task<List<VocabularyDto>> GetDueForReviewAsync(Guid userId)
{
var cacheKey = $"user:{userId}:due-review";
var cached = await _cache.GetAsync<List<VocabularyDto>>(cacheKey);
if (cached != null)
return cached;
var dueWords = await _baseService.GetDueForReviewAsync(userId);
await _cache.SetAsync(cacheKey, dueWords, TimeSpan.FromMinutes(15));
return dueWords;
}
}
```
#### 4.2 資料庫查詢優化
```sql
-- 高效能索引設計
CREATE INDEX CONCURRENTLY idx_user_vocab_due_review
ON user_vocabulary_progress(user_id, next_review_date)
WHERE next_review_date <= CURRENT_DATE;
CREATE INDEX CONCURRENTLY idx_vocabulary_search
ON vocabulary_bank USING gin(to_tsvector('english', word || ' ' || definition_en));
-- 用戶學習統計物化視圖
CREATE MATERIALIZED VIEW user_vocabulary_stats AS
SELECT
user_id,
COUNT(*) as total_words,
COUNT(*) FILTER (WHERE mastery_level = 'mastered') as mastered_count,
AVG(mastery_score) as average_mastery,
COUNT(*) FILTER (WHERE last_reviewed >= CURRENT_DATE - INTERVAL '7 days') as weekly_reviews
FROM user_vocabulary_progress
GROUP BY user_id;
CREATE UNIQUE INDEX ON user_vocabulary_stats(user_id);
```
### 詞彙學習API端點總結
#### 移動端API端點
| 端點 | 方法 | 描述 | 快取策略 |
|------|------|------|----------|
| `/api/v1/mobile/vocabulary/daily-review` | GET | 獲取每日複習詞彙 | 15分鐘 |
| `/api/v1/mobile/vocabulary/{id}/review` | POST | 提交複習結果 | 無快取 |
| `/api/v1/mobile/vocabulary/search` | GET | 詞彙搜尋 | 30分鐘 |
| `/api/v1/mobile/vocabulary/recommendations` | GET | 個人化推薦 | 1小時 |
| `/api/v1/mobile/vocabulary/analytics/dashboard` | GET | 學習儀表板 | 10分鐘 |
#### Web端API端點
| 端點 | 方法 | 描述 | 快取策略 |
|------|------|------|----------|
| `/api/v1/web/vocabulary/{id}` | GET | 詞彙詳細資訊 | 6小時 |
| `/api/v1/web/vocabulary/analytics` | GET | 學習分析報告 | 30分鐘 |
| `/api/v1/web/vocabulary/batch` | GET | 批量詞彙資料 | 1小時 |
| `/api/v1/web/vocabulary/export` | POST | 匯出學習資料 | 無快取 |
### 實施優先級
#### 高優先級 (Week 1-6)
1. 基礎詞彙CRUD API
2. 用戶學習進度追蹤
3. 間隔重複演算法
4. 移動端基礎API
#### 中優先級 (Week 7-9)
1. AI推薦系統
2. 學習分析功能
3. 遊戲化元素
4. Web端豐富功能
#### 低優先級 (Week 10-12)
1. 效能優化
2. 進階快取策略
3. 資料匯出功能
4. 管理後台API
---
**最後更新**: 2025-09-10
**版本**: 1.1 - 新增詞彙學習系統實施計畫
**維護者**: Drama Ling 開發團隊