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

586 lines
16 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**: 全面評估決定生產環境部署策略
---
**最後更新**: 2025-09-10
**版本**: 1.0 - 初始架構分離計劃
**維護者**: Drama Ling 開發團隊
<function_calls>
<invoke name="TodoWrite">
<parameter name="todos">[{"content": "\u64b0\u5beb\u5f8c\u7aef\u67b6\u69cb\u5206\u96e2\u8a08\u5283\u6587\u4ef6", "status": "completed", "activeForm": "\u64b0\u5beb\u5f8c\u7aef\u67b6\u69cb\u5206\u96e2\u8a08\u5283\u6587\u4ef6\u4e2d"}, {"content": "\u898f\u5283API Gateway\u5fae\u670d\u52d9\u67b6\u69cb", "status": "completed", "activeForm": "\u898f\u5283API Gateway\u5fae\u670d\u52d9\u67b6\u69cb\u4e2d"}, {"content": "\u8a2d\u8a08\u79fb\u52d5\u7aef\u548cWeb\u7aefAPI\u5dee\u7570\u5316", "status": "completed", "activeForm": "\u8a2d\u8a08\u79fb\u52d5\u7aef\u548cWeb\u7aefAPI\u5dee\u7570\u5316\u4e2d"}, {"content": "\u5236\u5b9a\u9077\u79fb\u6b65\u9a5f\u548c\u6642\u7a0b", "status": "in_progress", "activeForm": "\u5236\u5b9a\u9077\u79fb\u6b65\u9a5f\u548c\u6642\u7a0b\u4e2d"}]