# 🗃️ 查詢歷史快取系統 - 功能規格計劃
**專案**: DramaLing 英語學習平台
**功能**: 查詢歷史記錄與智能快取系統
**文檔版本**: v1.0
**建立日期**: 2025-01-18
**核心概念**: 將技術快取包裝為用戶查詢歷史,提升體驗透明度
---
## 🎯 **核心設計理念**
### **從「快取機制」到「查詢歷史」**
| 技術實現 | 用戶概念 | 實際意義 |
|----------|----------|----------|
| Cache Hit | 查詢過的句子 | "您之前查詢過這個句子" |
| Cache Miss | 新句子查詢 | "正在為您分析新句子..." |
| Word Cache | 查詢過的詞彙 | "您之前查詢過這個詞彙" |
| API Call | 即時查詢 | "正在為您查詢詞彙資訊..." |
### **使用者場景**
```
場景1: 句子查詢
用戶輸入: "Hello world"
第1次: "正在分析..." (3-5秒) → 存入查詢歷史
第2次: "您之前查詢過,立即顯示" (<200ms)
場景2: 詞彙查詢
句子: "The apple"
點擊 "The": "正在查詢..." → 存入詞彙查詢歷史
新句子: "The orange"
點擊 "The": "您之前查詢過,立即顯示" → 從歷史載入
```
---
## 📋 **技術規格設計**
## 🎯 **A. 句子查詢歷史系統**
### **A1. 當前實現改造**
**現有**: `SentenceAnalysisCache` (技術導向命名)
**改為**: 保持技術實現,改變用戶訊息
#### **API 回應訊息改造**
**檔案**: `/backend/DramaLing.Api/Controllers/AIController.cs:547`
```csharp
// 當前 (技術導向)
return Ok(new {
Success = true,
Data = cachedResult,
Message = "句子分析完成(快取)", // ❌ 技術術語
Cached = true,
CacheHit = true
});
// 改為 (用戶導向)
return Ok(new {
Success = true,
Data = cachedResult,
Message = "您之前查詢過這個句子,立即為您顯示結果", // ✅ 用戶友善
FromHistory = true, // ✅ 更直觀的欄位名
QueryDate = cachedAnalysis.CreatedAt,
TimesQueried = cachedAnalysis.AccessCount
});
```
### **A2. 前端顯示改造**
**檔案**: `/frontend/app/generate/page.tsx`
```typescript
// 查詢歷史狀態顯示
{queryStatus && (
{queryStatus.fromHistory ? (
<>
🗃️
查詢歷史 (第{queryStatus.timesQueried}次)
首次查詢: {formatDate(queryStatus.queryDate)}
>
) : (
<>
🔍
新句子分析中...
>
)}
)}
```
---
## 🎯 **B. 詞彙查詢歷史系統**
### **B1. 新增詞彙查詢快取表**
```sql
-- 用戶詞彙查詢歷史表
CREATE TABLE UserVocabularyQueryHistory (
Id UNIQUEIDENTIFIER PRIMARY KEY,
UserId UNIQUEIDENTIFIER NOT NULL, -- 用戶ID (未來用戶系統)
Word NVARCHAR(100) NOT NULL, -- 查詢的詞彙
WordLowercase NVARCHAR(100) NOT NULL, -- 小寫版本 (查詢鍵)
-- 查詢結果快取
AnalysisResult NVARCHAR(MAX) NOT NULL, -- JSON 格式的分析結果
Translation NVARCHAR(200) NOT NULL, -- 快速存取的翻譯
Definition NVARCHAR(500) NOT NULL, -- 快速存取的定義
-- 查詢上下文
FirstQueriedInSentence NVARCHAR(1000), -- 首次查詢時的句子語境
LastQueriedInSentence NVARCHAR(1000), -- 最後查詢時的句子語境
-- 查詢歷史統計
FirstQueriedAt DATETIME2 NOT NULL, -- 首次查詢時間
LastQueriedAt DATETIME2 NOT NULL, -- 最後查詢時間
QueryCount INT DEFAULT 1, -- 查詢次數
-- 系統欄位
CreatedAt DATETIME2 NOT NULL,
UpdatedAt DATETIME2 NOT NULL,
-- 索引優化
INDEX IX_UserVocabularyQueryHistory_UserId_Word (UserId, WordLowercase),
INDEX IX_UserVocabularyQueryHistory_LastQueriedAt (LastQueriedAt),
-- 暫時不設定外鍵,因為用戶系統還未完全實現
-- FOREIGN KEY (UserId) REFERENCES Users(Id)
);
```
### **B2. 詞彙查詢服務重構**
**檔案**: `/backend/DramaLing.Api/Services/VocabularyQueryService.cs`
```csharp
public interface IVocabularyQueryService
{
Task QueryWordAsync(string word, string sentence, Guid? userId = null);
Task> GetUserQueryHistoryAsync(Guid userId, int limit = 50);
}
public class VocabularyQueryService : IVocabularyQueryService
{
private readonly DramaLingDbContext _context;
private readonly IGeminiService _geminiService;
private readonly ILogger _logger;
public async Task QueryWordAsync(string word, string sentence, Guid? userId = null)
{
var wordLower = word.ToLower();
var mockUserId = userId ?? Guid.Parse("00000000-0000-0000-0000-000000000001"); // 模擬用戶
// 1. 檢查用戶的詞彙查詢歷史
var queryHistory = await _context.UserVocabularyQueryHistory
.FirstOrDefaultAsync(h => h.UserId == mockUserId && h.WordLowercase == wordLower);
if (queryHistory != null)
{
// 更新查詢統計
queryHistory.LastQueriedAt = DateTime.UtcNow;
queryHistory.LastQueriedInSentence = sentence;
queryHistory.QueryCount++;
await _context.SaveChangesAsync();
// 返回歷史查詢結果
var historicalAnalysis = JsonSerializer.Deserialize