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

16 KiB
Raw Blame History

後端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 + 微服務分離 (推薦)

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)]

優勢

  • 🎯 高度專業化: 每個服務專注特定功能
  • 🚀 獨立擴展: 可根據負載獨立擴展服務
  • 🔒 安全隔離: 服務間隔離,降低安全風險
  • 🛠 技術選型靈活: 不同服務可選用不同技術
  • 👥 團隊分工: 支援多團隊並行開發

挑戰

  • 複雜度較高,需要服務發現和配置管理
  • 分散式系統的一致性問題
  • 運維複雜度增加

方案二: 單體 + 多端點適配 (階段性)

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特點

{
  "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特點

{
  "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認證"
  ]
}

認證策略差異

移動端認證

[ApiController]
[Route("api/v1/mobile/[controller]")]
[Authorize(AuthenticationSchemes = "JwtBearer")]
public class MobileVocabularyController : ControllerBase
{
    // JWT Token + Refresh Token
    // 生物識別支援
    // OAuth2.0 整合
}

Web端認證

[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. 路由結構

// 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. 基礎控制器

// 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. 專業化控制器

// 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)

// 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> [{"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"}]