dramaling-vocab-learning/docs/03_development/backend-api-development-pla...

726 lines
21 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.

# DramaLing 後端 API 開發計劃
## 1. 概述
### 1.1 計劃目的
本開發計劃旨在基於現有的詞卡管理 API 規格,完善和優化後端 API 實現,確保 API 功能完整性、效能和穩定性。
### 1.2 依賴文檔
> 📋 **參考文檔引用**
>
> 本開發計劃基於以下文檔制定:
>
> **🔧 API 規格文檔 (主要參考)**
> - [詞卡管理 API 規格](./api/flashcard-management-api.md) - API 介面定義和實現邏輯的完整規格
>
> **🏗️ 技術架構文檔**
> - [後端架構詳細說明](../04_technical/backend-architecture.md) - 了解 ASP.NET Core 架構約束和設計模式
> - [系統架構總覽](../04_technical/system-architecture.md) - 了解整體系統設計和技術棧
>
> **📋 需求規格文檔**
> - [詞卡管理功能產品需求規格](../01_requirement/詞卡管理功能產品需求規格.md) - 了解業務需求和用戶故事
### 1.3 當前狀態評估
根據 [詞卡管理 API 規格](./api/flashcard-management-api.md) 分析,目前後端 API 狀態:
#### ✅ **已完成的 API 端點**
-`GET /api/flashcards` - 取得詞卡列表 (含搜尋和收藏篩選)
-`GET /api/flashcards/{id}` - 取得單一詞卡
-`POST /api/flashcards` - 創建新詞卡 (含重複檢測)
-`PUT /api/flashcards/{id}` - 更新詞卡
-`DELETE /api/flashcards/{id}` - 刪除詞卡 (軟刪除)
-`POST /api/flashcards/{id}/favorite` - 切換收藏狀態
#### 🎯 **需要改進的項目**
- 🔄 搜尋功能擴展 (目前不支援例句搜尋)
- 🔄 進階篩選 API (CEFR 等級、詞性、掌握度)
- 🔄 批量操作 API (未來功能)
- 🔄 效能優化 (查詢索引、快取機制)
- 🔄 API 文檔生成 (Swagger 增強)
## 2. 開發任務清單
### 2.1 搜尋功能增強 (優先級:🔴 高)
#### 任務 1: 擴展搜尋範圍支援例句
**影響檔案**:
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 修改 GetFlashcards 方法
**當前實現**:
```csharp
// 目前搜尋邏輯 (第 53-59 行)
if (!string.IsNullOrEmpty(search))
{
query = query.Where(f =>
f.Word.Contains(search) ||
f.Translation.Contains(search) ||
(f.Definition != null && f.Definition.Contains(search)));
}
```
**改進實現**:
```csharp
// 擴展搜尋範圍,新增例句搜尋
if (!string.IsNullOrEmpty(search))
{
query = query.Where(f =>
f.Word.Contains(search) ||
f.Translation.Contains(search) ||
(f.Definition != null && f.Definition.Contains(search)) ||
(f.Example != null && f.Example.Contains(search)) ||
(f.ExampleTranslation != null && f.ExampleTranslation.Contains(search)));
}
```
**驗收標準**:
- [ ] 搜尋範圍包含例句 (Example) 和例句翻譯 (ExampleTranslation)
- [ ] 搜尋效能無明顯下降
- [ ] 搜尋結果準確性維持 100%
#### 任務 2: 新增進階篩選查詢參數
**影響檔案**:
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 修改 GetFlashcards 方法參數
**新增查詢參數**:
```csharp
[HttpGet]
public async Task<ActionResult> GetFlashcards(
[FromQuery] string? search = null,
[FromQuery] bool favoritesOnly = false,
[FromQuery] string? cefrLevel = null, // 新增: A1, A2, B1, B2, C1, C2
[FromQuery] string? partOfSpeech = null, // 新增: noun, verb, adjective, etc.
[FromQuery] string? masteryLevel = null // 新增: high, medium, low
)
```
**篩選邏輯實現**:
```csharp
// CEFR 等級篩選
if (!string.IsNullOrEmpty(cefrLevel))
{
query = query.Where(f => f.DifficultyLevel == cefrLevel);
}
// 詞性篩選
if (!string.IsNullOrEmpty(partOfSpeech))
{
query = query.Where(f => f.PartOfSpeech == partOfSpeech);
}
// 掌握度篩選
if (!string.IsNullOrEmpty(masteryLevel))
{
switch (masteryLevel.ToLower())
{
case "high":
query = query.Where(f => f.MasteryLevel >= 80);
break;
case "medium":
query = query.Where(f => f.MasteryLevel >= 60 && f.MasteryLevel < 80);
break;
case "low":
query = query.Where(f => f.MasteryLevel < 60);
break;
}
}
```
**驗收標準**:
- [ ] 支援 CEFR 等級篩選 (A1-C2)
- [ ] 支援詞性篩選 (noun, verb, adjective 等)
- [ ] 支援掌握度篩選 (high, medium, low)
- [ ] 多重篩選條件正確組合 (AND 邏輯)
### 2.2 效能優化 (優先級:🟡 中)
#### 任務 3: 資料庫查詢優化
**影響檔案**:
- `backend/DramaLing.Api/Data/DramaLingDbContext.cs` - 新增索引配置
**索引優化**:
```csharp
// 在 OnModelCreating 方法中新增索引
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 現有配置...
// 搜尋優化索引
modelBuilder.Entity<Flashcard>()
.HasIndex(f => f.Word)
.HasDatabaseName("IX_Flashcards_Word");
modelBuilder.Entity<Flashcard>()
.HasIndex(f => f.Translation)
.HasDatabaseName("IX_Flashcards_Translation");
// 複合查詢索引
modelBuilder.Entity<Flashcard>()
.HasIndex(f => new { f.UserId, f.IsArchived, f.IsFavorite })
.HasDatabaseName("IX_Flashcards_UserId_IsArchived_IsFavorite");
// CEFR 等級索引
modelBuilder.Entity<Flashcard>()
.HasIndex(f => f.DifficultyLevel)
.HasDatabaseName("IX_Flashcards_DifficultyLevel");
}
```
**查詢邏輯優化**:
```csharp
// 使用 AsNoTracking 提升查詢效能
var flashcards = await query
.AsNoTracking()
.OrderByDescending(f => f.CreatedAt)
.ToListAsync();
```
**驗收標準**:
- [ ] 新增適當的資料庫索引
- [ ] 查詢時間 < 200ms (1000+ 詞卡)
- [ ] 搜尋響應時間 < 100ms
#### 任務 4: 快取機制實現
**影響檔案**:
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 整合快取服務
- `backend/DramaLing.Api/Extensions/ServiceCollectionExtensions.cs` - 已有快取配置
**快取策略實現**:
```csharp
// 在 FlashcardsController 中使用快取
private readonly ICacheService _cacheService;
[HttpGet]
public async Task<ActionResult> GetFlashcards(...)
{
var cacheKey = $"flashcards:user:{userId}:search:{search}:favorites:{favoritesOnly}";
var cachedResult = await _cacheService.GetAsync<object>(cacheKey);
if (cachedResult != null)
{
return Ok(cachedResult);
}
// 執行資料庫查詢...
var result = new { Success = true, Data = ... };
// 快取結果 (30分鐘)
await _cacheService.SetAsync(cacheKey, result, TimeSpan.FromMinutes(30));
return Ok(result);
}
```
**驗收標準**:
- [ ] 詞卡列表查詢快取 30 分鐘
- [ ] 快取命中率 > 70%
- [ ] 快取失效機制正確 (CRUD 操作後清除)
### 2.3 API 增強功能 (優先級:🟡 中)
#### 任務 5: 新增批量操作 API
**影響檔案**:
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 新增批量操作端點
**新增 API 端點**:
```csharp
[HttpPost("batch/favorite")]
public async Task<ActionResult> BatchToggleFavorite([FromBody] BatchFavoriteRequest request)
{
try
{
var userId = GetUserId();
var flashcards = await _context.Flashcards
.Where(f => request.FlashcardIds.Contains(f.Id) && f.UserId == userId && !f.IsArchived)
.ToListAsync();
foreach (var flashcard in flashcards)
{
flashcard.IsFavorite = request.IsFavorite;
flashcard.UpdatedAt = DateTime.UtcNow;
}
await _context.SaveChangesAsync();
return Ok(new { Success = true, UpdatedCount = flashcards.Count });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in batch favorite operation");
return StatusCode(500, new { Success = false, Error = "批量操作失敗" });
}
}
[HttpDelete("batch")]
public async Task<ActionResult> BatchDelete([FromBody] BatchDeleteRequest request)
{
// 批量軟刪除實現
}
```
**新增 DTO 類別**:
```csharp
public class BatchFavoriteRequest
{
public List<Guid> FlashcardIds { get; set; } = new();
public bool IsFavorite { get; set; }
}
public class BatchDeleteRequest
{
public List<Guid> FlashcardIds { get; set; } = new();
}
```
**驗收標準**:
- [ ] 支援批量收藏/取消收藏
- [ ] 支援批量刪除 (軟刪除)
- [ ] 批量操作事務性 (全部成功或全部失敗)
- [ ] 操作日誌記錄完整
#### 任務 6: 統計資料 API
**影響檔案**:
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 新增統計端點
**新增統計 API**:
```csharp
[HttpGet("statistics")]
public async Task<ActionResult> GetStatistics()
{
try
{
var userId = GetUserId();
var stats = await _context.Flashcards
.Where(f => f.UserId == userId && !f.IsArchived)
.GroupBy(f => 1) // 單一群組用於統計
.Select(g => new
{
TotalCount = g.Count(),
FavoriteCount = g.Count(f => f.IsFavorite),
MasteredCount = g.Count(f => f.MasteryLevel >= 80),
LearningCount = g.Count(f => f.MasteryLevel >= 60 && f.MasteryLevel < 80),
NewCount = g.Count(f => f.MasteryLevel < 60),
CefrDistribution = g.GroupBy(f => f.DifficultyLevel)
.ToDictionary(cg => cg.Key, cg => cg.Count())
})
.FirstOrDefaultAsync();
return Ok(new { Success = true, Data = stats });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting flashcard statistics");
return StatusCode(500, new { Success = false, Error = "統計資料載入失敗" });
}
}
```
**驗收標準**:
- [ ] 提供詞卡總數、收藏數、掌握度分布統計
- [ ] 提供 CEFR 等級分布統計
- [ ] 統計資料準確性 100%
- [ ] 響應時間 < 200ms
### 2.4 錯誤處理增強 (優先級:🟡 中)
#### 任務 7: 標準化錯誤回應格式
**影響檔案**:
- `backend/DramaLing.Api/Models/DTOs/` - 新增錯誤回應 DTO
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 統一錯誤處理
**錯誤回應 DTO**:
```csharp
public class ApiErrorResponse
{
public bool Success { get; set; } = false;
public string Error { get; set; } = string.Empty;
public string? Details { get; set; }
public string? ErrorCode { get; set; }
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
}
public class ApiSuccessResponse<T>
{
public bool Success { get; set; } = true;
public T? Data { get; set; }
public string? Message { get; set; }
}
```
**統一錯誤處理**:
```csharp
// 基礎控制器類別
public abstract class BaseApiController : ControllerBase
{
protected ActionResult ApiError(string message, string? details = null, string? errorCode = null)
{
return BadRequest(new ApiErrorResponse
{
Error = message,
Details = details,
ErrorCode = errorCode
});
}
protected ActionResult ApiSuccess<T>(T data, string? message = null)
{
return Ok(new ApiSuccessResponse<T>
{
Data = data,
Message = message
});
}
}
```
**驗收標準**:
- [ ] 所有 API 端點使用統一錯誤格式
- [ ] 錯誤代碼標準化 ( FLASHCARD_NOT_FOUND)
- [ ] 錯誤訊息本地化 (中文)
- [ ] 詳細錯誤信息僅在開發環境顯示
### 2.5 認證與授權準備 (優先級:🟢 低)
#### 任務 8: 準備生產環境認證
**影響檔案**:
- `backend/DramaLing.Api/Controllers/FlashcardsController.cs` - 準備認證代碼
**實現內容**:
```csharp
// 保留現有測試模式,準備生產環境切換
private Guid GetUserId()
{
// 開發環境:使用固定測試用戶
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
{
return Guid.Parse("00000000-0000-0000-0000-000000000001");
}
// 生產環境:解析 JWT Token
var userIdString = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ??
User.FindFirst("sub")?.Value;
if (Guid.TryParse(userIdString, out var userId))
return userId;
throw new UnauthorizedAccessException("Invalid user ID in token");
}
// 準備生產環境控制器標註
// [Authorize] // 生產環境時啟用
[AllowAnonymous] // 開發環境暫時保持
public class FlashcardsController : BaseApiController
```
**驗收標準**:
- [ ] 開發環境認證邏輯保持不變
- [ ] 生產環境認證代碼已準備
- [ ] 環境切換機制正確
- [ ] JWT Token 解析邏輯完整
## 3. 資料庫改進
### 3.1 Entity Framework 優化
#### 任務 9: 新增資料庫索引遷移
**影響檔案**:
- `backend/DramaLing.Api/Data/DramaLingDbContext.cs` - 索引配置
- 新增 EF 遷移檔案
**遷移步驟**:
```bash
# 生成新的遷移
dotnet ef migrations add AddFlashcardSearchIndexes
# 更新資料庫
dotnet ef database update
```
**索引策略**:
- 單欄索引Word, Translation, DifficultyLevel, PartOfSpeech
- 複合索引(UserId, IsArchived, IsFavorite)
- 搜尋優化全文搜尋索引 (如果 SQLite 支援)
**驗收標準**:
- [ ] 索引正確創建
- [ ] 查詢計劃顯示索引使用
- [ ] 搜尋效能明顯提升
#### 任務 10: 資料驗證增強
**影響檔案**:
- `backend/DramaLing.Api/Models/DTOs/CreateFlashcardRequest.cs` - 新增驗證特性
**驗證規則**:
```csharp
public class CreateFlashcardRequest
{
[Required(ErrorMessage = "詞彙為必填項目")]
[StringLength(255, ErrorMessage = "詞彙長度不得超過 255 字元")]
public string Word { get; set; } = string.Empty;
[Required(ErrorMessage = "翻譯為必填項目")]
public string Translation { get; set; } = string.Empty;
[Required(ErrorMessage = "定義為必填項目")]
public string Definition { get; set; } = string.Empty;
[StringLength(255, ErrorMessage = "發音長度不得超過 255 字元")]
public string Pronunciation { get; set; } = string.Empty;
[RegularExpression("^(noun|verb|adjective|adverb|preposition|interjection)$",
ErrorMessage = "詞性必須為有效值")]
public string PartOfSpeech { get; set; } = "noun";
[Required(ErrorMessage = "例句為必填項目")]
public string Example { get; set; } = string.Empty;
public string? ExampleTranslation { get; set; }
[RegularExpression("^(A1|A2|B1|B2|C1|C2)$",
ErrorMessage = "CEFR 等級必須為有效值")]
public string? DifficultyLevel { get; set; } = "A2";
}
```
**驗收標準**:
- [ ] 所有輸入資料驗證完整
- [ ] 錯誤訊息本地化和友善
- [ ] 驗證失敗時返回具體錯誤信息
- [ ] 防止無效資料進入資料庫
## 4. API 文檔與測試
### 4.1 Swagger 文檔增強
#### 任務 11: 完善 API 文檔
**影響檔案**:
- `backend/DramaLing.Api/Extensions/ServiceCollectionExtensions.cs` - Swagger 配置
**Swagger 增強**:
```csharp
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() {
Title = "DramaLing API - 詞卡管理",
Version = "v1",
Description = "DramaLing 詞卡管理功能的完整 API 文檔"
});
// XML 註解檔案
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
// API 範例
c.SchemaFilter<ExampleSchemaFilter>();
});
```
**XML 註解增強**:
```csharp
/// <summary>
/// 取得用戶的詞卡列表,支援搜尋和篩選
/// </summary>
/// <param name="search">搜尋關鍵字,搜尋範圍:詞彙、翻譯、定義、例句</param>
/// <param name="favoritesOnly">僅顯示收藏詞卡</param>
/// <param name="cefrLevel">CEFR 難度等級篩選 (A1-C2)</param>
/// <param name="partOfSpeech">詞性篩選</param>
/// <param name="masteryLevel">掌握度篩選 (high/medium/low)</param>
/// <returns>詞卡列表和數量</returns>
[HttpGet]
public async Task<ActionResult> GetFlashcards(...)
```
**驗收標準**:
- [ ] Swagger UI 顯示完整 API 文檔
- [ ] 所有參數和回應格式有詳細說明
- [ ] 提供 API 使用範例
- [ ] 錯誤代碼和狀態碼說明完整
### 4.2 API 測試套件
#### 任務 12: 整合測試實現
**影響檔案**:
- 新增 `backend/DramaLing.Api.Tests/Controllers/FlashcardsControllerTests.cs`
**測試涵蓋範圍**:
```csharp
[TestClass]
public class FlashcardsControllerTests
{
[TestMethod]
public async Task GetFlashcards_WithSearch_ReturnsFilteredResults()
{
// 測試搜尋功能
}
[TestMethod]
public async Task CreateFlashcard_WithValidData_CreatesSuccessfully()
{
// 測試詞卡創建
}
[TestMethod]
public async Task CreateFlashcard_WithDuplicateWord_ReturnsDuplicateError()
{
// 測試重複詞卡檢測
}
[TestMethod]
public async Task GetFlashcards_WithCefrFilter_ReturnsCorrectLevel()
{
// 測試 CEFR 等級篩選
}
}
```
**驗收標準**:
- [ ] 所有 API 端點有對應測試
- [ ] 測試覆蓋率 > 80%
- [ ] 包含邊界條件和錯誤情況測試
- [ ] 測試可在 CI/CD 中自動執行
## 5. 實施時程
### 5.1 開發階段規劃
#### 第一階段:核心功能增強 (預估2-3小時)
1. **擴展搜尋功能** (45分鐘)
2. **新增進階篩選參數** (60分鐘)
3. **資料驗證增強** (45分鐘)
4. **測試和驗證** (30分鐘)
#### 第二階段:效能優化 (預估2-3小時)
5. **資料庫索引優化** (60分鐘)
6. **快取機制實現** (90分鐘)
7. **效能測試和調整** (30分鐘)
#### 第三階段API 增強 (預估3-4小時)
8. **批量操作 API** (120分鐘)
9. **統計資料 API** (90分鐘)
10. **Swagger 文檔完善** (30分鐘)
#### 第四階段:測試和部署準備 (預估2-3小時)
11. **整合測試實現** (120分鐘)
12. **生產環境認證準備** (60分鐘)
### 5.2 里程碑檢查點
#### 里程碑 1: 基礎功能完善 ✅
- 搜尋和篩選功能完整
- 資料驗證機制健全
- 基本測試通過
#### 里程碑 2: 效能達標 ✅
- 查詢響應時間 < 200ms
- 快取命中率 > 70%
- 無明顯效能瓶頸
#### 里程碑 3: API 完整性 ✅
- 所有計劃 API 端點實現
- Swagger 文檔完整
- 錯誤處理標準化
#### 里程碑 4: 生產準備 ✅
- 整合測試覆蓋率 > 80%
- 生產環境配置準備
- 部署文檔更新
## 6. 品質保證
### 6.1 程式碼審查檢查清單
#### API 設計檢查
- [ ] RESTful 設計原則遵循
- [ ] HTTP 狀態碼正確使用
- [ ] 回應格式標準化
- [ ] 查詢參數命名一致
#### 安全性檢查
- [ ] 輸入驗證完整
- [ ] SQL 注入防護
- [ ] 用戶資料隔離
- [ ] 敏感資訊保護
#### 效能檢查
- [ ] 查詢優化
- [ ] 索引使用合理
- [ ] 記憶體使用最佳化
- [ ] 併發處理安全
### 6.2 測試策略
> 📋 **測試策略參考**
> - [測試策略文檔](../04_testing/test-strategy.md) - 了解完整的測試方法和標準
#### 單元測試
- Controller 方法邏輯測試
- 資料驗證規則測試
- 錯誤處理機制測試
#### 整合測試
- API 端點完整流程測試
- 資料庫操作測試
- 快取機制測試
#### 效能測試
- 大量資料載入測試
- 並發請求壓力測試
- 記憶體洩漏檢測
## 7. 部署與監控
### 7.1 部署準備
#### 環境配置
```bash
# 生產環境變數
export ASPNETCORE_ENVIRONMENT=Production
export DRAMALING_DB_CONNECTION="Data Source=production.db"
export USE_INMEMORY_DB=false
```
#### 健康檢查
```csharp
// 增強健康檢查
services.AddHealthChecks()
.AddDbContextCheck<DramaLingDbContext>()
.AddCheck<CacheHealthCheck>("cache")
.AddCheck<ApiHealthCheck>("api");
```
### 7.2 監控指標
#### 關鍵效能指標 (KPI)
- API 響應時間平均值 < 200ms
- API 成功率 > 99.5%
- 資料庫連接健康度 > 99%
- 快取命中率 > 70%
#### 業務指標
- 每日 API 呼叫次數
- 詞卡創建成功率
- 搜尋查詢頻率
- 使用者活躍度
---
**計劃版本**: v1.0
**制定日期**: 2025-09-24
**預估完成時間**: 9-13小時 (分 4 個階段)
**負責開發**: 後端開發團隊
**審核負責**: 技術主管
> 📋 **開發前必讀文檔**
>
> **🔧 主要規格參考**
> - [詞卡管理 API 規格](./api/flashcard-management-api.md) - 開發的主要依據,包含所有 API 介面定義
>
> **🏗️ 架構約束**
> - [後端架構詳細說明](../04_technical/backend-architecture.md) - 必須遵循的技術架構約束
> - [系統架構總覽](../04_technical/system-architecture.md) - 了解整體系統設計脈絡
>
> **📋 業務需求**
> - [詞卡管理功能產品需求規格](../01_requirement/詞卡管理功能產品需求規格.md) - 理解業務需求和用戶期望