586 lines
16 KiB
Markdown
586 lines
16 KiB
Markdown
# 後端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"}] |