711 lines
25 KiB
Markdown
711 lines
25 KiB
Markdown
# 詞彙生成與儲存系統規格
|
||
|
||
## 系統概述
|
||
|
||
DramaLing詞彙學習系統是一個基於AI的英語詞彙學習平台,主要功能包括詞彙生成、智能分析、儲存管理和學習追蹤。系統採用前後端分離架構,前端使用Next.js 14,後端使用.NET 8 Web API,資料庫使用SQLite + Entity Framework Core。
|
||
|
||
## 1. 詞彙生成功能規格
|
||
|
||
### 1.1 句子分析功能
|
||
|
||
#### 核心特性
|
||
- **AI分析引擎**: 使用Google Gemini API進行句子深度分析
|
||
- **多層次分析**: 包含詞彙分析、語法檢查、整句翻譯
|
||
- **個人化適配**: 根據用戶英語程度(A1-C2)調整分析深度
|
||
- **智能快取**: 使用快取機制避免重複AI調用
|
||
- **使用量追蹤**: 追蹤用戶查詢使用量並實施限制
|
||
|
||
#### API端點
|
||
- **端點**: `POST /api/ai/analyze-sentence`
|
||
- **功能**: 句子綜合分析
|
||
- **輸入參數** (AnalyzeSentenceRequest):
|
||
```json
|
||
{
|
||
"inputText": "string", // 用戶輸入的英文句子 (最多1000字元)
|
||
"userLevel": "string", // 用戶英語程度 (A1-C2, 預設A2)
|
||
"forceRefresh": boolean, // 是否強制重新分析
|
||
"analysisMode": "string" // 分析模式 ("full")
|
||
}
|
||
```
|
||
- **回應格式**:
|
||
```json
|
||
{
|
||
"success": boolean,
|
||
"data": {
|
||
"wordAnalysis": {
|
||
"[word]": {
|
||
"word": "string",
|
||
"translation": "string",
|
||
"definition": "string",
|
||
"partOfSpeech": "string",
|
||
"pronunciation": "string",
|
||
"isHighValue": boolean,
|
||
"difficultyLevel": "string" // CEFR等級
|
||
}
|
||
},
|
||
"sentenceMeaning": {
|
||
"translation": "string",
|
||
"explanation": "string"
|
||
},
|
||
"grammarCorrection": {
|
||
"hasErrors": boolean,
|
||
"originalText": "string",
|
||
"correctedText": "string",
|
||
"corrections": [
|
||
{
|
||
"errorType": "string",
|
||
"original": "string",
|
||
"corrected": "string",
|
||
"reason": "string"
|
||
}
|
||
]
|
||
},
|
||
"finalAnalysisText": "string",
|
||
"highValueWords": ["string"]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 快取機制 (SentenceAnalysisCache)
|
||
- **表名**: `SentenceAnalysisCache`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class SentenceAnalysisCache
|
||
{
|
||
public Guid Id { get; set; }
|
||
public string InputTextHash { get; set; } // SHA-256雜湊
|
||
public string InputText { get; set; } // 原始輸入文本
|
||
public string? CorrectedText { get; set; } // 修正後文本
|
||
public bool HasGrammarErrors { get; set; } // 是否有語法錯誤
|
||
public string? GrammarCorrections { get; set; } // JSON格式語法修正
|
||
public string AnalysisResult { get; set; } // JSON格式分析結果
|
||
public string? HighValueWords { get; set; } // JSON格式高價值詞彙
|
||
public string? PhrasesDetected { get; set; } // JSON格式檢測片語
|
||
public DateTime CreatedAt { get; set; }
|
||
public DateTime ExpiresAt { get; set; }
|
||
public int AccessCount { get; set; } // 存取次數
|
||
public DateTime? LastAccessedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 實現位置
|
||
- **前端**: `frontend/app/generate/page.tsx:29-100`
|
||
- **後端控制器**: `backend/DramaLing.Api/Controllers/AIController.cs`
|
||
- **服務層**: `backend/DramaLing.Api/Services/GeminiService.cs`
|
||
- **快取服務**: `backend/DramaLing.Api/Services/AnalysisCacheService.cs`
|
||
|
||
### 1.2 詞卡生成功能
|
||
|
||
#### 核心特性
|
||
- **智能萃取**: 支援詞彙萃取(vocabulary)和智能萃取(smart)兩種模式
|
||
- **批量生成**: 一次可生成1-20張詞卡
|
||
- **多元內容**: 包含單字、翻譯、定義、例句、同義詞、難度等級
|
||
- **測試模式**: 支援無認證的測試端點
|
||
|
||
#### API端點
|
||
- **端點**: `POST /api/ai/test/generate` (測試用,無需認證)
|
||
- **功能**: 生成詞卡
|
||
- **輸入參數** (GenerateCardsRequest):
|
||
```json
|
||
{
|
||
"inputText": "string", // 原始文本 (最多5000字元)
|
||
"extractionType": "string", // "vocabulary" | "smart"
|
||
"cardCount": number // 1-20
|
||
}
|
||
```
|
||
- **回應格式**:
|
||
```json
|
||
{
|
||
"success": boolean,
|
||
"data": {
|
||
"taskId": "guid",
|
||
"status": "completed",
|
||
"generatedCards": [
|
||
{
|
||
"word": "string",
|
||
"translation": "string",
|
||
"definition": "string",
|
||
"partOfSpeech": "string",
|
||
"pronunciation": "string",
|
||
"example": "string",
|
||
"exampleTranslation": "string",
|
||
"synonyms": ["string"],
|
||
"difficultyLevel": "string",
|
||
"score": number // AI生成評分
|
||
}
|
||
]
|
||
},
|
||
"message": "string"
|
||
}
|
||
```
|
||
|
||
#### 實現位置
|
||
- **前端**: `frontend/app/generate/page.tsx:114-151`
|
||
- **後端**: `backend/DramaLing.Api/Controllers/AIController.cs:42-100`
|
||
|
||
### 1.3 互動式詞彙查詢
|
||
|
||
#### 核心特性
|
||
- **點擊查詢**: 用戶可點擊句子中任意單字查看詳細資訊
|
||
- **即時分析**: 動態調用AI API獲取單字分析
|
||
- **高價值標示**: 自動標示高價值單字和片語
|
||
- **使用量計費**: 區分高價值(免費)和低價值(計費)詞彙
|
||
|
||
#### API端點
|
||
- **端點**: `POST /api/ai/query-word`
|
||
- **輸入參數** (QueryWordRequest):
|
||
```json
|
||
{
|
||
"word": "string", // 要查詢的單字
|
||
"sentence": "string", // 上下文句子
|
||
"analysisId": "guid?" // 分析ID (可選)
|
||
}
|
||
```
|
||
|
||
#### 使用量統計 (WordQueryUsageStats)
|
||
- **表名**: `WordQueryUsageStats`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class WordQueryUsageStats
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
public DateOnly Date { get; set; } // 日期
|
||
public int SentenceAnalysisCount { get; set; } // 句子分析次數
|
||
public int HighValueWordClicks { get; set; } // 高價值詞彙點擊(免費)
|
||
public int LowValueWordClicks { get; set; } // 低價值詞彙點擊(收費)
|
||
public int TotalApiCalls { get; set; } // 總API調用次數
|
||
public int UniqueWordsQueried { get; set; } // 查詢的獨特詞彙數
|
||
public DateTime CreatedAt { get; set; }
|
||
public DateTime UpdatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 實現位置
|
||
- **組件**: `frontend/components/ClickableTextV2.tsx`
|
||
- **前端邏輯**: `frontend/app/generate/page.tsx:402-421`
|
||
- **使用量服務**: `backend/DramaLing.Api/Services/UsageTrackingService.cs`
|
||
|
||
## 2. 詞彙儲存系統規格
|
||
|
||
### 2.1 資料庫架構
|
||
|
||
#### 2.1.1 用戶管理 (User)
|
||
- **表名**: `user_profiles`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class User
|
||
{
|
||
public Guid Id { get; set; }
|
||
public string Username { get; set; } // 用戶名 (唯一)
|
||
public string Email { get; set; } // 信箱 (唯一)
|
||
public string PasswordHash { get; set; } // 密碼雜湊
|
||
public string? DisplayName { get; set; } // 顯示名稱
|
||
public string? AvatarUrl { get; set; } // 頭像URL
|
||
public string SubscriptionType { get; set; } = "free"; // 訂閱類型
|
||
public Dictionary<string, object> Preferences { get; set; } // JSON偏好設定
|
||
|
||
// 個人化學習相關
|
||
public string EnglishLevel { get; set; } = "A2"; // 英語程度(A1-C2)
|
||
public DateTime LevelUpdatedAt { get; set; } // 程度更新時間
|
||
public bool IsLevelVerified { get; set; } = false; // 是否通過測試驗證
|
||
public string? LevelNotes { get; set; } // 程度設定備註
|
||
|
||
public DateTime CreatedAt { get; set; }
|
||
public DateTime UpdatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 2.1.2 詞卡實體 (Flashcard)
|
||
- **表名**: `flashcards`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class Flashcard
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; } // 所屬用戶
|
||
public Guid CardSetId { get; set; } // 所屬卡組
|
||
|
||
// 詞卡內容
|
||
[Required, MaxLength(255)]
|
||
public string Word { get; set; } // 單字
|
||
[Required]
|
||
public string Translation { get; set; } // 翻譯
|
||
[Required]
|
||
public string Definition { get; set; } // 定義
|
||
[MaxLength(50)]
|
||
public string? PartOfSpeech { get; set; } // 詞性
|
||
[MaxLength(255)]
|
||
public string? Pronunciation { get; set; } // 發音
|
||
public string? Example { get; set; } // 例句
|
||
public string? ExampleTranslation { get; set; } // 例句翻譯
|
||
|
||
// SM-2 間隔重複算法參數
|
||
public float EasinessFactor { get; set; } = 2.5f; // 難易度係數
|
||
public int Repetitions { get; set; } = 0; // 重複次數
|
||
public int IntervalDays { get; set; } = 1; // 間隔天數
|
||
public DateTime NextReviewDate { get; set; } // 下次複習日期
|
||
|
||
// 學習統計
|
||
[Range(0, 100)]
|
||
public int MasteryLevel { get; set; } = 0; // 掌握程度(0-100)
|
||
public int TimesReviewed { get; set; } = 0; // 複習次數
|
||
public int TimesCorrect { get; set; } = 0; // 正確次數
|
||
public DateTime? LastReviewedAt { get; set; } // 最後複習時間
|
||
|
||
// 狀態管理
|
||
public bool IsFavorite { get; set; } = false; // 是否收藏
|
||
public bool IsArchived { get; set; } = false; // 是否封存
|
||
[MaxLength(10)]
|
||
public string? DifficultyLevel { get; set; } // 難度等級(A1-C2)
|
||
|
||
public DateTime CreatedAt { get; set; }
|
||
public DateTime UpdatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 2.1.3 卡組實體 (CardSet)
|
||
- **表名**: `card_sets`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class CardSet
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; } // 所屬用戶
|
||
|
||
[Required, MaxLength(255)]
|
||
public string Name { get; set; } // 卡組名稱
|
||
public string? Description { get; set; } // 描述
|
||
[MaxLength(50)]
|
||
public string Color { get; set; } = "bg-blue-500"; // 顏色標籤
|
||
public int CardCount { get; set; } = 0; // 詞卡數量
|
||
public bool IsDefault { get; set; } = false; // 是否為預設卡組
|
||
|
||
public DateTime CreatedAt { get; set; }
|
||
public DateTime UpdatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 2.1.4 標籤系統 (Tag & FlashcardTag)
|
||
- **表名**: `tags`, `flashcard_tags`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class Tag
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
[Required, MaxLength(100)]
|
||
public string Name { get; set; } // 標籤名稱
|
||
[Required, MaxLength(50)]
|
||
public string Color { get; set; } // 標籤顏色
|
||
public int UsageCount { get; set; } = 0; // 使用次數
|
||
public DateTime CreatedAt { get; set; }
|
||
}
|
||
|
||
public class FlashcardTag // 多對多關聯表
|
||
{
|
||
public Guid FlashcardId { get; set; }
|
||
public Guid TagId { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 2.1.5 學習追蹤 (StudySession & StudyRecord)
|
||
- **表名**: `study_sessions`, `study_records`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class StudySession
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
[Required, MaxLength(50)]
|
||
public string SessionType { get; set; } // 學習模式
|
||
public DateTime StartedAt { get; set; } // 開始時間
|
||
public DateTime? EndedAt { get; set; } // 結束時間
|
||
public int TotalCards { get; set; } = 0; // 總詞卡數
|
||
public int CorrectCount { get; set; } = 0; // 正確數量
|
||
public int DurationSeconds { get; set; } = 0; // 持續時間(秒)
|
||
public int AverageResponseTimeMs { get; set; } = 0; // 平均回應時間(毫秒)
|
||
}
|
||
|
||
public class StudyRecord
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
public Guid FlashcardId { get; set; }
|
||
public Guid SessionId { get; set; }
|
||
[Required, MaxLength(50)]
|
||
public string StudyMode { get; set; } // 學習模式
|
||
public int QualityRating { get; set; } // 品質評分(0-5)
|
||
public int? ResponseTimeMs { get; set; } // 回應時間(毫秒)
|
||
public string? UserAnswer { get; set; } // 用戶答案
|
||
public bool IsCorrect { get; set; } // 是否正確
|
||
public DateTime StudiedAt { get; set; } // 學習時間
|
||
|
||
// SM-2算法歷史記錄
|
||
public float PreviousEasinessFactor { get; set; }
|
||
public int PreviousRepetitions { get; set; }
|
||
public int PreviousIntervalDays { get; set; }
|
||
public float NewEasinessFactor { get; set; }
|
||
public int NewRepetitions { get; set; }
|
||
public int NewIntervalDays { get; set; }
|
||
public DateTime NextReviewDate { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 2.1.6 錯誤回報 (ErrorReport)
|
||
- **表名**: `error_reports`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class ErrorReport
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
public Guid FlashcardId { get; set; }
|
||
[Required, MaxLength(100)]
|
||
public string ReportType { get; set; } // 錯誤類型
|
||
public string? Description { get; set; } // 描述
|
||
[MaxLength(50)]
|
||
public string? StudyMode { get; set; } // 學習模式
|
||
[Required, MaxLength(50)]
|
||
public string Status { get; set; } = "pending"; // 狀態
|
||
public string? AdminNotes { get; set; } // 管理員備註
|
||
public Guid? ResolvedBy { get; set; } // 解決者ID
|
||
public DateTime? ResolvedAt { get; set; } // 解決時間
|
||
public DateTime CreatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### 2.1.7 每日統計 (DailyStats)
|
||
- **表名**: `daily_stats`
|
||
- **主要欄位**:
|
||
```csharp
|
||
public class DailyStats
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Guid UserId { get; set; }
|
||
public DateOnly Date { get; set; } // 日期
|
||
public int WordsStudied { get; set; } = 0; // 學習單字數
|
||
public int WordsCorrect { get; set; } = 0; // 正確單字數
|
||
public int StudyTimeSeconds { get; set; } = 0; // 學習時間(秒)
|
||
public int SessionCount { get; set; } = 0; // 學習場次
|
||
public int CardsGenerated { get; set; } = 0; // 生成詞卡數
|
||
public int AiApiCalls { get; set; } = 0; // AI API調用次數
|
||
public DateTime CreatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
### 2.2 儲存服務API
|
||
|
||
#### 2.2.1 詞卡管理API
|
||
- **取得詞卡列表**: `GET /api/flashcards`
|
||
- **查詢參數**:
|
||
- `setId` (Guid?): 指定卡組ID
|
||
- `search` (string?): 搜尋關鍵字(詞彙/翻譯)
|
||
- `favoritesOnly` (bool): 僅顯示收藏
|
||
- `limit` (int): 限制數量(預設50,最多100)
|
||
- `offset` (int): 偏移量(分頁用)
|
||
- **回應格式**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"flashcards": [...],
|
||
"total": number,
|
||
"hasMore": boolean
|
||
}
|
||
}
|
||
```
|
||
- **實現位置**: `FlashcardsController.cs:58-135`
|
||
|
||
- **建立詞卡**: `POST /api/flashcards`
|
||
- **請求體** (CreateFlashcardRequest):
|
||
```json
|
||
{
|
||
"cardSetId": "guid?", // 可選,未指定則使用預設卡組
|
||
"word": "string", // 必填
|
||
"translation": "string", // 必填
|
||
"definition": "string", // 必填
|
||
"partOfSpeech": "string?",
|
||
"pronunciation": "string?",
|
||
"example": "string?",
|
||
"exampleTranslation": "string?"
|
||
}
|
||
```
|
||
- **自動功能**: 如無指定卡組,自動分配到預設卡組或創建新的預設卡組
|
||
- **實現位置**: `FlashcardsController.cs:137-200`
|
||
|
||
- **更新詞卡**: `PUT /api/flashcards/{id}`
|
||
- **請求體** (UpdateFlashcardRequest): 支援部分欄位更新
|
||
- **實現位置**: `FlashcardsController.cs:233-287`
|
||
|
||
- **刪除詞卡**: `DELETE /api/flashcards/{id}`
|
||
- **實現位置**: `FlashcardsController.cs:289-324`
|
||
|
||
- **切換收藏狀態**: `POST /api/flashcards/{id}/favorite`
|
||
- **功能**: 切換詞卡的收藏狀態
|
||
|
||
#### 2.2.2 卡組管理API
|
||
- **取得卡組列表**: `GET /api/cardsets`
|
||
- **回應**: 包含卡組基本資訊和詞卡數量統計
|
||
|
||
- **建立卡組**: `POST /api/cardsets`
|
||
- **請求體** (CreateCardSetRequest):
|
||
```json
|
||
{
|
||
"name": "string", // 必填
|
||
"description": "string?", // 可選
|
||
"isPublic": boolean // 可選,預設false
|
||
}
|
||
```
|
||
|
||
- **更新卡組**: `PUT /api/cardsets/{id}`
|
||
- **請求體** (UpdateCardSetRequest): 支援部分欄位更新
|
||
|
||
- **刪除卡組**: `DELETE /api/cardsets/{id}`
|
||
- **限制**: 無法刪除預設卡組
|
||
|
||
- **確保預設卡組**: `POST /api/cardsets/ensure-default`
|
||
- **功能**: 確保用戶有預設卡組,如無則自動創建
|
||
|
||
#### 2.2.3 前端服務層
|
||
- **檔案位置**: `frontend/lib/services/flashcards.ts`
|
||
- **核心介面**:
|
||
```typescript
|
||
export interface Flashcard {
|
||
id: string;
|
||
word: string;
|
||
translation: string;
|
||
definition: string;
|
||
partOfSpeech: string;
|
||
pronunciation: string;
|
||
example: string;
|
||
exampleTranslation?: string;
|
||
masteryLevel: number; // 0-100掌握程度
|
||
timesReviewed: number; // 複習次數
|
||
isFavorite: boolean; // 是否收藏
|
||
nextReviewDate: string; // 下次複習日期
|
||
createdAt: string;
|
||
cardSet: {
|
||
name: string;
|
||
color: string;
|
||
};
|
||
}
|
||
|
||
export interface CardSet {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
color: string;
|
||
cardCount: number; // 詞卡數量
|
||
createdAt: string;
|
||
updatedAt: string;
|
||
isDefault: boolean; // 是否為預設卡組
|
||
progress: number; // 學習進度
|
||
lastStudied: string; // 最後學習時間
|
||
tags: string[]; // 標籤
|
||
}
|
||
|
||
class FlashcardsService {
|
||
// 詞卡CRUD操作
|
||
async getFlashcards(cardSetId?: string): Promise<ApiResponse<{flashcards: Flashcard[]; total: number; hasMore: boolean}>>
|
||
async createFlashcard(data: CreateFlashcardRequest): Promise<ApiResponse<Flashcard>>
|
||
async updateFlashcard(id: string, data: Partial<CreateFlashcardRequest>): Promise<ApiResponse<Flashcard>>
|
||
async deleteFlashcard(id: string): Promise<ApiResponse<void>>
|
||
async toggleFavorite(id: string): Promise<ApiResponse<Flashcard>>
|
||
|
||
// 卡組CRUD操作
|
||
async getCardSets(): Promise<ApiResponse<{sets: CardSet[]}>>
|
||
async createCardSet(data: CreateCardSetRequest): Promise<ApiResponse<CardSet>>
|
||
async deleteCardSet(id: string): Promise<ApiResponse<void>>
|
||
async ensureDefaultCardSet(): Promise<ApiResponse<CardSet>>
|
||
}
|
||
```
|
||
|
||
#### 2.2.4 資料庫關聯與索引
|
||
- **外鍵關聯**:
|
||
- `flashcards.user_id` → `user_profiles.id` (CASCADE)
|
||
- `flashcards.card_set_id` → `card_sets.id` (CASCADE)
|
||
- `card_sets.user_id` → `user_profiles.id` (CASCADE)
|
||
- `flashcard_tags.flashcard_id` → `flashcards.id` (CASCADE)
|
||
- `flashcard_tags.tag_id` → `tags.id` (CASCADE)
|
||
|
||
- **重要索引**:
|
||
- `user_profiles`: email(UNIQUE), username(UNIQUE)
|
||
- `flashcards`: user_id, card_set_id
|
||
- `card_sets`: user_id
|
||
- `tags`: user_id
|
||
- `daily_stats`: (user_id, date)(UNIQUE)
|
||
- `SentenceAnalysisCache`: input_text_hash(UNIQUE), expires_at
|
||
|
||
## 3. 系統整合流程
|
||
|
||
### 3.1 完整學習流程
|
||
1. **用戶認證** → JWT Token驗證與用戶程度讀取
|
||
2. **句子輸入** → 用戶在生成頁面輸入英文句子(最多300字元)
|
||
3. **快取檢查** → 檢查是否已有分析結果快取
|
||
4. **AI分析** → 調用Gemini API進行句子深度分析
|
||
5. **結果快取** → 將分析結果儲存到`SentenceAnalysisCache`
|
||
6. **互動探索** → 用戶點擊單字查看詳細分析(使用量追蹤)
|
||
7. **詞卡生成** → 基於分析結果生成個人化詞卡
|
||
8. **儲存管理** → 詞卡儲存到預設或指定卡組
|
||
9. **學習追蹤** → 使用SM-2算法追蹤學習進度
|
||
|
||
### 3.2 資料流向圖
|
||
```
|
||
用戶請求 → JWT認證 → 程度檢查 → 輸入驗證 → 快取檢查 → AI API調用
|
||
↓
|
||
結果快取 → 使用量記錄 → 前端顯示 → 用戶互動 → 詞卡生成 → 資料庫儲存
|
||
↓
|
||
學習記錄 → SM-2更新 → 統計更新 → 進度追蹤
|
||
```
|
||
|
||
### 3.3 關鍵業務邏輯
|
||
|
||
#### 3.3.1 預設卡組管理
|
||
- 用戶首次創建詞卡時,系統自動創建名為「未分類」的預設卡組
|
||
- 預設卡組無法刪除,確保用戶始終有存放詞卡的地方
|
||
- 實現位置: `FlashcardsController.cs:33-56`
|
||
|
||
#### 3.3.2 SM-2間隔重複算法
|
||
- 基於用戶答題品質(0-5分)調整複習間隔
|
||
- 記錄詳細的學習歷史用於算法優化
|
||
- 實現位置: `backend/DramaLing.Api/Services/SM2Algorithm.cs`
|
||
|
||
#### 3.3.3 使用量限制機制
|
||
- 免費用戶3小時內最多5次句子分析
|
||
- 高價值詞彙點擊免費,低價值詞彙計費
|
||
- 實現位置: `UsageTrackingService.cs`
|
||
|
||
## 4. 技術架構
|
||
|
||
### 4.1 前端技術棧
|
||
- **框架**: Next.js 14 (App Router)
|
||
- **語言**: TypeScript
|
||
- **樣式**: Tailwind CSS
|
||
- **狀態管理**: React Hooks + Context API
|
||
- **HTTP客戶端**: Fetch API
|
||
- **認證**: JWT + localStorage
|
||
- **路由保護**: ProtectedRoute組件
|
||
|
||
### 4.2 後端技術棧
|
||
- **框架**: .NET 8 Web API
|
||
- **ORM**: Entity Framework Core 8.0
|
||
- **資料庫**: SQLite (開發)
|
||
- **認證**: JWT Bearer Token
|
||
- **AI服務**: Google Gemini API
|
||
- **快取**: 內建EF快取 + 自定義快取服務
|
||
- **日誌**: Microsoft.Extensions.Logging
|
||
|
||
### 4.3 資料庫設計特點
|
||
- **Snake_case命名**: 所有資料表和欄位使用snake_case
|
||
- **GUID主鍵**: 所有實體使用Guid作為主鍵
|
||
- **軟刪除**: 支援IsArchived標記而非硬刪除
|
||
- **審計欄位**: CreatedAt、UpdatedAt自動管理
|
||
- **JSON欄位**: 使用JSON存儲複雜結構(如Preferences)
|
||
|
||
### 4.4 API設計原則
|
||
- **RESTful風格**: 遵循REST慣例
|
||
- **統一回應格式**:
|
||
```json
|
||
{
|
||
"success": boolean,
|
||
"data": object,
|
||
"error": string,
|
||
"message": string,
|
||
"timestamp": datetime
|
||
}
|
||
```
|
||
- **認證保護**: 所有業務API需JWT認證
|
||
- **錯誤處理**: 統一錯誤處理中間件
|
||
- **請求驗證**: DataAnnotations + 自定義驗證
|
||
- **分頁支援**: 統一的limit/offset分頁機制
|
||
|
||
## 5. 效能與優化
|
||
|
||
### 5.1 快取策略
|
||
- **句子分析快取**:
|
||
- 使用SHA-256雜湊避重
|
||
- 設定過期時間(ExpiresAt)
|
||
- 記錄存取次數和最後存取時間
|
||
|
||
- **詞彙查詢快取**:
|
||
- 減少重複AI API調用
|
||
- 提升查詞響應速度
|
||
|
||
- **清理機制**:
|
||
- 定期清理過期快取
|
||
- 實現位置: `CacheCleanupService.cs`
|
||
|
||
### 5.2 效能監控
|
||
- **日常統計**: DailyStats記錄用戶活動指標
|
||
- **使用量追蹤**: WordQueryUsageStats追蹤API使用
|
||
- **錯誤報告**: ErrorReport系統收集問題回饋
|
||
|
||
### 5.3 限制與配額
|
||
- **免費用戶限制**:
|
||
- 句子分析: 3小時內最多5次
|
||
- 手動輸入: 最多300字元
|
||
- 詞卡生成: 一次最多20張
|
||
|
||
- **付費用戶**: 無限制使用
|
||
- **API速率限制**: 防止濫用攻擊
|
||
|
||
## 6. 安全性考量
|
||
|
||
### 6.1 認證與授權
|
||
- **JWT Token**: 包含用戶ID和過期時間
|
||
- **用戶隔離**: 所有資料按UserId嚴格隔離
|
||
- **端點保護**: [Authorize]屬性保護敏感API
|
||
- **測試端點**: 部分功能提供[AllowAnonymous]測試
|
||
|
||
### 6.2 資料安全
|
||
- **密碼安全**: BCrypt雜湊儲存
|
||
- **輸入驗證**: 前後端雙重驗證
|
||
- **SQL注入防護**: EF Core參數化查詢
|
||
- **XSS防護**: 自動HTML編碼
|
||
|
||
### 6.3 API安全
|
||
- **CORS設定**: 限制來源域名
|
||
- **請求大小限制**: 防止大檔案攻擊
|
||
- **錯誤資訊隱藏**: 生產環境隱藏敏感錯誤
|
||
|
||
## 7. 監控與維護
|
||
|
||
### 7.1 系統監控
|
||
- **健康檢查**: API健康狀態監控
|
||
- **效能指標**: 回應時間、吞吐量追蹤
|
||
- **錯誤追蹤**: 異常日誌和錯誤報告
|
||
- **資源監控**: 資料庫和儲存空間監控
|
||
|
||
### 7.2 維護策略
|
||
- **資料備份**: 定期資料庫備份機制
|
||
- **日誌清理**: 定期清理舊日誌和快取
|
||
- **版本控制**: Git版本管理和部署追蹤
|
||
- **文件更新**: 與程式碼同步更新文件
|
||
|
||
## 8. 未來擴展規劃
|
||
|
||
### 8.1 短期功能擴展
|
||
- **語音功能**: 整合Azure Speech Service
|
||
- **個人化推薦**: 基於學習歷史的智能推薦
|
||
- **社群功能**: 卡組分享和協作學習
|
||
- **多語言支援**: 擴展到其他語言學習
|
||
|
||
### 8.2 技術架構升級
|
||
- **資料庫升級**: 從SQLite遷移到PostgreSQL
|
||
- **快取優化**: 引入Redis分散式快取
|
||
- **微服務化**: 拆分AI服務和業務服務
|
||
- **容器化部署**: Docker + Kubernetes部署
|
||
|
||
### 8.3 擴展性考量
|
||
- **水平擴展**: 支援多實例負載平衡
|
||
- **資料分割**: 大規模用戶資料分割策略
|
||
- **CDN整合**: 靜態資源和多媒體加速
|
||
- **國際化**: 多地區部署和資料同步
|
||
|
||
---
|
||
|
||
**文件版本**: 2.0
|
||
**最後更新**: 2025-09-20
|
||
**維護者**: DramaLing開發團隊
|
||
**更新說明**: 基於實際程式碼架構重新整理,修正與系統實現的差距 |