# 系統整合與部署規格 ## 📋 **文件資訊** - **文件名稱**: 系統整合與部署規格 - **版本**: v2.0 - **建立日期**: 2025-01-25 - **最後更新**: 2025-01-25 - **負責團隊**: DramaLing DevOps團隊 - **適用系統**: AI句子分析功能全棧系統 --- ## 🏗️ **系統架構圖** ### **整體架構** ``` ┌─────────────────┐ HTTP/JSON ┌──────────────────┐ Gemini API ┌─────────────────┐ │ │ Request │ │ Request │ │ │ Frontend │ ──────────────► │ Backend API │ ──────────────► │ Google Gemini │ │ (Next.js) │ │ (.NET Core) │ │ AI Service │ │ Port 3000 │ ◄────────────── │ Port 5008 │ ◄────────────── │ │ │ │ Response │ │ Response │ │ └─────────────────┘ └──────────────────┘ └─────────────────┘ │ │ │ │ ▼ ▼ ┌─────────────────┐ ┌──────────────────┐ │ Local Storage │ │ SQLite Database │ │ - user_level │ │ - Cache Data │ │ - auth_token │ │ - Usage Stats │ └─────────────────┘ └──────────────────┘ ``` ### **數據流向** ```mermaid sequenceDiagram participant U as 用戶 participant F as 前端(3000) participant B as 後端(5008) participant G as Gemini API participant D as 資料庫 U->>F: 1. 輸入英文句子 U->>F: 2. 點擊「分析句子」 F->>F: 3. 驗證輸入(≤300字符) F->>F: 4. 讀取userLevel (localStorage) F->>B: 5. POST /api/ai/analyze-sentence B->>B: 6. 輸入驗證和處理 B->>G: 7. 調用Gemini API G->>B: 8. 返回AI分析結果 B->>B: 9. 解析和格式化數據 B->>D: 10. 記錄使用統計 (可選) B->>F: 11. 返回結構化分析結果 F->>F: 12. 計算個人化統計 F->>F: 13. 渲染詞彙標記和統計卡片 F->>U: 14. 顯示完整分析結果 ``` --- ## 🔄 **前後端整合規格** ### **API整合詳細設計** #### **前端請求實現** ```typescript // 位置: frontend/app/generate/page.tsx const handleAnalyzeSentence = async () => { try { const response = await fetch('http://localhost:5008/api/ai/analyze-sentence', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${getAuthToken()}` // 可選 }, body: JSON.stringify({ inputText: textInput, analysisMode: 'full', options: { includeGrammarCheck: true, includeVocabularyAnalysis: true, includeTranslation: true, includeIdiomDetection: true, includeExamples: true } }) }); if (!response.ok) { throw new Error(`API請求失敗: ${response.status}`); } const result = await response.json(); handleAnalysisResult(result.data); } catch (error) { handleAnalysisError(error); } }; ``` #### **數據處理邏輯** ```typescript // 前端個人化統計計算 const calculateVocabularyStats = (vocabularyAnalysis, idioms, userLevel) => { const userIndex = CEFR_LEVELS.indexOf(userLevel); let simple = 0, moderate = 0, difficult = 0; Object.values(vocabularyAnalysis).forEach(word => { const wordIndex = CEFR_LEVELS.indexOf(word.difficultyLevel); if (userIndex > wordIndex) simple++; else if (userIndex === wordIndex) moderate++; else difficult++; }); return { simpleCount: simple, moderateCount: moderate, difficultCount: difficult, idiomCount: idioms.length }; }; ``` ### **錯誤處理整合** #### **前端錯誤處理** ```typescript const handleAnalysisError = (error) => { console.error('Analysis error:', error); // 顯示用戶友善的錯誤訊息 if (error.message.includes('timeout')) { setErrorMessage('分析服務繁忙,請稍後再試'); } else if (error.message.includes('network')) { setErrorMessage('網路連接問題,請檢查網路狀態'); } else { setErrorMessage('分析過程中發生錯誤,請稍後再試'); } // 提供降級體驗 setFallbackAnalysisView(textInput); }; ``` #### **後端錯誤映射** ```csharp // 位置: backend/Controllers/AIController.cs private ApiErrorResponse CreateErrorResponse(string code, string message, object? details, string requestId) { var userFriendlyMessage = code switch { "INVALID_INPUT" => "輸入格式不正確,請檢查文本內容", "AI_SERVICE_ERROR" => "AI分析服務暫時不可用,請稍後重試", "RATE_LIMIT_EXCEEDED" => "請求過於頻繁,請稍候再試", "TIMEOUT" => "分析超時,請嘗試較短的句子", _ => "系統暫時不可用,請稍後重試" }; return new ApiErrorResponse { Success = false, Error = new ApiError { Code = code, Message = userFriendlyMessage, Details = details, Suggestions = GetSuggestionsForError(code) }, RequestId = requestId, Timestamp = DateTime.UtcNow }; } ``` --- ## 🔧 **開發環境配置** ### **環境準備** #### **必要軟體** ```yaml 開發工具: - Node.js: >= 18.0.0 - .NET SDK: >= 8.0.0 - Git: >= 2.40.0 - VSCode: 最新版本 瀏覽器支援: - Chrome: >= 90 (開發調試用) - Safari: >= 14 (測試用) - Firefox: >= 88 (測試用) 可選工具: - Docker: >= 20.0 (容器化部署) - Redis: >= 6.0 (本地快取測試) - Postman: API測試 ``` #### **環境變數配置** ```bash # 後端環境變數 export GEMINI_API_KEY="your-gemini-api-key" export ASPNETCORE_ENVIRONMENT="Development" export DRAMALING_DB_CONNECTION="Data Source=dramaling_test.db" # 前端環境變數 (可選) export NEXT_PUBLIC_API_URL="http://localhost:5008" export NEXT_PUBLIC_ENVIRONMENT="development" ``` ### **啟動流程** #### **開發環境啟動腳本** ```bash #!/bin/bash # 位置: start-development.sh echo "🚀 啟動 DramaLing 開發環境..." # 1. 檢查必要軟體 check_prerequisites() { command -v node >/dev/null 2>&1 || { echo "需要安裝 Node.js"; exit 1; } command -v dotnet >/dev/null 2>&1 || { echo "需要安裝 .NET SDK"; exit 1; } } # 2. 啟動後端 API (Port 5008) start_backend() { echo "🔧 啟動後端 API..." cd backend/DramaLing.Api dotnet restore dotnet run & BACKEND_PID=$! echo "後端 PID: $BACKEND_PID" } # 3. 啟動前端 (Port 3000) start_frontend() { echo "🎨 啟動前端..." cd ../../frontend npm install npm run dev & FRONTEND_PID=$! echo "前端 PID: $FRONTEND_PID" } # 4. 健康檢查 health_check() { echo "🏥 執行健康檢查..." sleep 10 # 檢查後端 if curl -f http://localhost:5008/health >/dev/null 2>&1; then echo "✅ 後端服務正常" else echo "❌ 後端服務異常" fi # 檢查前端 if curl -f http://localhost:3000 >/dev/null 2>&1; then echo "✅ 前端服務正常" else echo "❌ 前端服務異常" fi } # 執行啟動流程 check_prerequisites start_backend start_frontend health_check echo "🎉 開發環境啟動完成!" echo "前端: http://localhost:3000" echo "後端API: http://localhost:5008" echo "API文檔: http://localhost:5008/swagger" ``` --- ## 🧪 **測試整合策略** ### **整合測試架構** #### **API整合測試** ```csharp [TestFixture] public class AIAnalysisIntegrationTests : IClassFixture> { private readonly WebApplicationFactory _factory; private readonly HttpClient _client; [SetUp] public void Setup() { _client = _factory.CreateClient(); } [Test] public async Task AnalyzeSentence_EndToEnd_ReturnsValidResponse() { // Arrange var request = new { inputText = "She just join the team, so let's cut her some slack.", analysisMode = "full" }; // Act var response = await _client.PostAsJsonAsync("/api/ai/analyze-sentence", request); // Assert response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); Assert.That(result.Success, Is.True); Assert.That(result.Data.VocabularyAnalysis.Count, Is.GreaterThan(0)); Assert.That(result.Data.SentenceMeaning, Is.Not.Empty); Assert.That(result.Data.Idioms.Count, Is.GreaterThan(0)); } } ``` #### **前端E2E測試** ```typescript // 使用 Playwright 或 Cypress describe('AI Analysis E2E Flow', () => { test('complete analysis workflow', async ({ page }) => { // 1. 導航到分析頁面 await page.goto('http://localhost:3000/generate'); // 2. 輸入測試句子 await page.fill('[data-testid="text-input"]', 'She just join the team, so let\'s cut her some slack.'); // 3. 點擊分析按鈕 await page.click('[data-testid="analyze-button"]'); // 4. 等待分析完成 await page.waitForSelector('[data-testid="analysis-result"]', { timeout: 10000 }); // 5. 驗證結果 await expect(page.locator('[data-testid="grammar-correction"]')).toBeVisible(); await expect(page.locator('[data-testid="vocabulary-analysis"]')).toBeVisible(); await expect(page.locator('[data-testid="idioms-section"]')).toBeVisible(); await expect(page.locator('[data-testid="statistics-cards"]')).toBeVisible(); // 6. 測試詞彙點擊 await page.click('[data-testid="word-she"]'); await expect(page.locator('[data-testid="vocab-popup"]')).toBeVisible(); }); }); ``` ### **性能測試整合** #### **負載測試配置** ```yaml # 使用 k6 或 JMeter 負載測試場景: - 正常負載: 100 用戶,持續 10 分鐘 - 壓力測試: 500 用戶,持續 5 分鐘 - 尖峰測試: 1000 用戶,持續 2 分鐘 性能指標: - 回應時間P95: < 5秒 - 錯誤率: < 1% - 吞吐量: > 100 RPS - 資源使用: CPU < 80%, Memory < 70% ``` --- ## 🚀 **部署架構** ### **環境配置** #### **開發環境 (Development)** ```yaml 基礎設施: - 本地開發機器 - SQLite 資料庫 - In-Memory 快取 - Gemini API (測試金鑰) 配置特點: - 詳細日誌輸出 - 熱重載支援 - Swagger API 文檔 - CORS 寬鬆政策 ``` #### **測試環境 (Staging)** ```yaml 基礎設施: - 雲端虛擬機 或 Docker 容器 - PostgreSQL 資料庫 - Redis 快取 - Gemini API (測試金鑰) 配置特點: - 生產環境模擬 - 效能監控啟用 - 自動化測試整合 - 安全掃描 ``` #### **生產環境 (Production)** ```yaml 基礎設施: - Kubernetes 叢集 或 雲端服務 - PostgreSQL 高可用性叢集 - Redis 叢集 - Gemini API (生產金鑰) - CDN 和負載均衡 配置特點: - 高可用性 (99.9%+) - 自動擴容 - 全面監控和告警 - 災難恢復機制 ``` ### **容器化部署** #### **Docker Compose 配置** ```yaml # docker-compose.yml version: '3.8' services: # 後端 API 服務 backend: build: context: ./backend/DramaLing.Api dockerfile: Dockerfile ports: - "5008:5008" environment: - ASPNETCORE_ENVIRONMENT=Production - GEMINI_API_KEY=${GEMINI_API_KEY} - ConnectionStrings__DefaultConnection=${DB_CONNECTION} depends_on: - database - redis healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5008/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s # 前端服務 frontend: build: context: ./frontend dockerfile: Dockerfile ports: - "3000:3000" environment: - NEXT_PUBLIC_API_URL=http://backend:5008 depends_on: - backend # 資料庫服務 database: image: postgres:15-alpine environment: - POSTGRES_DB=dramaling - POSTGRES_USER=${DB_USER} - POSTGRES_PASSWORD=${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" # 快取服務 redis: image: redis:7-alpine ports: - "6379:6379" volumes: - redis_data:/data volumes: postgres_data: redis_data: ``` #### **Kubernetes 部署配置** ```yaml # k8s-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: dramaling-backend spec: replicas: 3 selector: matchLabels: app: dramaling-backend template: metadata: labels: app: dramaling-backend spec: containers: - name: backend image: dramaling/backend:latest ports: - containerPort: 5008 env: - name: GEMINI_API_KEY valueFrom: secretKeyRef: name: ai-secrets key: gemini-api-key - name: ConnectionStrings__DefaultConnection valueFrom: configMapKeyRef: name: app-config key: db-connection resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health port: 5008 initialDelaySeconds: 30 periodSeconds: 30 readinessProbe: httpGet: path: /health port: 5008 initialDelaySeconds: 5 periodSeconds: 5 ``` --- ## 📊 **監控與可觀測性** ### **日誌整合** #### **結構化日誌配置** ```json // appsettings.Production.json { "Serilog": { "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.ApplicationInsights"], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning", "DramaLing": "Information" } }, "WriteTo": [ { "Name": "Console", "Args": { "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}" } }, { "Name": "ApplicationInsights", "Args": { "instrumentationKey": "{ApplicationInsights:InstrumentationKey}" } } ], "Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"] } } ``` #### **前端錯誤追蹤** ```typescript // 錯誤邊界和監控 class ErrorBoundary extends React.Component { componentDidCatch(error, errorInfo) { // 發送錯誤到監控服務 console.error('React Error Boundary:', error, errorInfo); // 可選:整合 Sentry 或其他錯誤追蹤服務 if (typeof window !== 'undefined' && window.gtag) { window.gtag('event', 'exception', { description: error.toString(), fatal: false }); } } } ``` ### **健康檢查系統** #### **深度健康檢查** ```csharp public class SystemHealthCheck : IHealthCheck { private readonly IGeminiService _geminiService; private readonly DramaLingDbContext _dbContext; public async Task CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { var checks = new Dictionary(); // 檢查資料庫連接 try { await _dbContext.Database.CanConnectAsync(cancellationToken); checks["database"] = HealthStatus.Healthy; } catch (Exception ex) { checks["database"] = HealthStatus.Unhealthy; } // 檢查 AI 服務 try { var isHealthy = await _geminiService.HealthCheckAsync(); checks["gemini_api"] = isHealthy ? HealthStatus.Healthy : HealthStatus.Degraded; } catch (Exception ex) { checks["gemini_api"] = HealthStatus.Unhealthy; } // 檢查記憶體使用 var memoryUsage = GC.GetTotalMemory(false); checks["memory"] = memoryUsage < 500_000_000 ? HealthStatus.Healthy : HealthStatus.Degraded; var overallStatus = checks.Values.All(s => s == HealthStatus.Healthy) ? HealthStatus.Healthy : checks.Values.Any(s => s == HealthStatus.Unhealthy) ? HealthStatus.Unhealthy : HealthStatus.Degraded; return new HealthCheckResult(overallStatus, description: $"System health: {string.Join(", ", checks.Select(c => $"{c.Key}:{c.Value}"))}", data: checks.ToDictionary(c => c.Key, c => (object)c.Value.ToString())); } } ``` --- ## 🔒 **安全整合** ### **HTTPS 配置** ```yaml 開發環境: - HTTP: localhost:3000, localhost:5008 - 自簽證書: dotnet dev-certs https --trust 生產環境: - HTTPS: 強制重定向 - TLS 1.3: 最低版本要求 - HSTS: 嚴格傳輸安全 - 證書: Let's Encrypt 或企業CA ``` ### **CORS 政策** ```csharp // 開發環境 CORS 配置 services.AddCors(options => { options.AddPolicy("Development", policy => { policy.WithOrigins("http://localhost:3000", "http://localhost:3001") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); options.AddPolicy("Production", policy => { policy.WithOrigins("https://dramaling.com", "https://app.dramaling.com") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); ``` --- ## 📈 **監控整合** ### **應用程式監控** #### **關鍵指標儀表板** ```yaml 業務指標: - 每日分析次數 - 用戶活躍度 - 功能使用分佈 - AI分析成功率 技術指標: - API回應時間分佈 - 資料庫查詢性能 - 記憶體和CPU使用 - 錯誤率和異常統計 用戶體驗指標: - 頁面載入時間 - 首次內容繪製 (FCP) - 最大內容繪製 (LCP) - 累積佈局偏移 (CLS) ``` #### **告警配置** ```yaml 嚴重告警: - API 錯誤率 > 5% (5分鐘內) - 回應時間P95 > 10秒 (5分鐘內) - 服務不可用 > 2分鐘 - 資料庫連接失敗 警告告警: - CPU 使用率 > 80% (10分鐘內) - 記憶體使用率 > 85% (10分鐘內) - AI API 調用失敗率 > 10% - 磁碟空間不足 < 10% ``` --- ## 🔧 **故障排除指南** ### **常見問題和解決方案** #### **連接問題** ```yaml 問題: CORS 錯誤 症狀: "Access to fetch blocked by CORS policy" 解決: 檢查後端 CORS 設定,確認前端域名在允許清單 問題: 連接被拒絕 症狀: "Connection refused" 或 "ECONNREFUSED" 解決: 確認後端服務正在運行,檢查埠號是否正確 問題: 超時錯誤 症狀: "Request timeout" 或響應超過 30 秒 解決: 檢查 AI API 金鑰,網路連接,增加超時設定 ``` #### **資料問題** ```yaml 問題: AI 回應格式錯誤 症狀: "Cannot read property 'vocabularyAnalysis' of undefined" 解決: 檢查 Gemini API 回應格式,更新錯誤處理邏輯 問題: 詞彙分析為空 症狀: 分析結果不包含詞彙資訊 解決: 檢查 AI Prompt 設計,確認輸入文本有效 問題: 統計數字不一致 症狀: 統計卡片數字與實際標記不符 解決: 檢查前端統計計算邏輯,確認分類算法正確 ``` ### **調試工具** #### **開發調試指令** ```bash # 檢查服務狀態 curl -I http://localhost:5008/health curl -I http://localhost:3000 # 測試 API 端點 curl -X POST http://localhost:5008/api/ai/analyze-sentence \ -H "Content-Type: application/json" \ -d '{"inputText":"Test sentence","analysisMode":"full"}' # 檢查日誌 docker logs dramaling-backend docker logs dramaling-frontend # 檢查資源使用 docker stats top -p $(pgrep dotnet) ``` #### **生產監控指令** ```bash # 健康檢查 kubectl get pods -l app=dramaling kubectl describe pod dramaling-backend-xxx # 查看日誌 kubectl logs -f deployment/dramaling-backend kubectl logs -f deployment/dramaling-frontend # 性能監控 kubectl top pods kubectl top nodes ``` --- ## 📋 **部署檢查清單** ### **部署前檢查** - [ ] 所有測試通過 (單元、整合、E2E) - [ ] 安全掃描無嚴重漏洞 - [ ] 性能基準測試達標 - [ ] 配置檔案正確設定 - [ ] 環境變數和金鑰配置完成 - [ ] 資料庫遷移腳本準備 - [ ] 監控和告警配置完成 - [ ] 回滾計劃準備 ### **部署後驗證** - [ ] 健康檢查端點回應正常 - [ ] API 功能端到端測試通過 - [ ] 前端頁面載入和功能正常 - [ ] 監控指標顯示正常 - [ ] 日誌記錄正確產生 - [ ] 告警機制測試正常 - [ ] 負載測試驗證性能 - [ ] 安全掃描確認無新漏洞 --- ## 🔄 **CI/CD 流程** ### **持續整合流程** ```yaml 觸發條件: - 主分支推送 (main) - Pull Request 建立 - 標籤建立 (v*.*.*) 建置步驟: 1. 程式碼檢出 2. 依賴安裝 3. 靜態分析 (ESLint, SonarQube) 4. 單元測試執行 5. 測試覆蓋率檢查 6. 安全掃描 7. 建置 Docker 映像 8. 整合測試執行 部署條件: - 所有測試通過 - 程式碼覆蓋率 > 80% - 安全掃描通過 - 人工審核批准 (生產部署) ``` ### **持續部署流程** ```yaml 測試環境自動部署: - 主分支每次推送自動部署 - 自動執行煙霧測試 - 通知團隊部署狀態 生產環境部署: - 手動觸發或定期發布 - 藍綠部署或滾動更新 - 自動回滾機制 - 部署後監控和驗證 ``` --- **文件版本**: v2.0 **DevOps負責人**: DramaLing DevOps團隊 **最後更新**: 2025-01-25 **下次審查**: 2025-02-25 **關聯文件**: - 《AI句子分析功能產品需求規格》- 產品需求和用戶故事 - 《AI分析API技術實現規格》- API設計和技術實現 - 《AI驅動產品後端技術架構指南》- 架構設計指導原則