GlobalHub API (中央匯入與分發服務)
📋 基本資訊
- 專案路徑:
liongroup/liontech/lionglobal/b2c/globalhubapi - GitLab URL: https://gitlab.com/liongroup/liontech/lionglobal/b2c/globalhubapi
- 專案類型: 後端 API (.NET)
- 定位: 中央層 - 產品匯入與分發服務
- 最後更新: 2026-02-07
📖 專案描述
GlobalHub API 是基於 .NET 10 建構的中央層後端服務,採用領域驅動設計 (Domain-Driven Design, DDD) 與整潔架構 (Clean Architecture) 原則開發。
架構定位
中央層 (Central)
├─ SERP API (外部供應商)
├─ GlobalHub API (本專案) ← 中央匯入與分發服務
└─ GlobalHub ← 中央 B2C 前台
區域層 (Regions: TW, US, JP)
├─ ProductsAPI ← 接收同步
├─ ProductBackend
└─ 區域 B2C 前台
核心職責 ⭐
A. 上游同步 (SERP → GlobalHub)
- 從 SERP API 匯入產品資料(團體旅遊、票券)
- 資料驗證與轉換
- AI 資料豐富化(多語言翻譯、描述優化)
- 儲存到中央資料庫
B. 下游同步 (GlobalHub → 各區域)
- 推送產品到 ProductsAPI (TW/US/JP)
- 區域化資料轉換
- 批次同步與錯誤處理
C. 中央產品展示
- 提供 GlobalHub 前台所需的產品 API
🏗️ 專案架構
目錄結構
globalhubapi/
├── src/
│ ├── Domain/ # 領域層 (業務邏輯核心)
│ │ ├── Product/ # 產品領域模型
│ │ │ ├── Product.cs
│ │ │ ├── ProductTranslation.cs
│ │ │ ├── ProductPrice.cs
│ │ │ ├── ImportJob.cs
│ │ │ └── RegionSyncLog.cs
│ │ ├── Domain.csproj
│ │ └── bin/, obj/
│ ├── Application/ # 應用層 (用例/業務流程)
│ │ ├── Abstractions/ # 介面定義
│ │ ├── Products/ # 產品相關用例
│ │ │ ├── Import/ # SERP 匯入邏輯
│ │ │ │ ├── ImportProductsCommand.cs
│ │ │ │ └── ImportProductsCommandHandler.cs
│ │ │ └── Sync/ # 區域同步邏輯
│ │ │ ├── SyncToRegionCommand.cs
│ │ │ └── SyncToRegionCommandHandler.cs
│ │ ├── Application.csproj
│ │ └── bin/, obj/
│ ├── Infrastructure/ # 基礎設施層 (外部依賴)
│ │ ├── Database/ # 資料庫設定
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── Configurations/
│ │ ├── Migrations/ # EF Core 遷移
│ │ ├── BackgroundJobs/ # Hangfire 背景任務
│ │ │ ├── ImportProductsJob.cs
│ │ │ └── RegionSyncJob.cs
│ │ ├── ExternalServices/ # 外部服務
│ │ │ ├── SerpApiClient.cs # SERP API 客戶端
│ │ │ └── RegionApiClient.cs # 區域 API 客戶端
│ │ ├── Infrastructure.csproj
│ │ └── bin/, obj/
│ ├── Presentation/
│ │ └── Web.Api/ # Web API 層
│ │ ├── Endpoints/
│ │ │ ├── Products/ # 產品端點
│ │ │ ├── Import/ # 匯入端點
│ │ │ ├── Sync/ # 同步端點
│ │ │ └── Webhooks/ # Webhook 端點
│ │ └── Program.cs
│ └── SharedKernel/ # 共享核心
│ ├── Entity.cs
│ ├── Error.cs
│ ├── ErrorType.cs
│ ├── IDomainEvent.cs
│ ├── Result.cs
│ ├── ValidationError.cs
│ └── SharedKernel.csproj
├── .vscode/ # VS Code 設定
├── .github/ # GitHub 專用資源
│ ├── instructions/ # 架構最佳實踐指南
│ ├── prompts/ # 開發 Prompts
│ └── agents/ # AI Agent 設定
├── GlobalHubApi.sln # Visual Studio 方案檔
├── Directory.Build.props # MSBuild 全域屬性
├── Directory.Packages.props # NuGet 套件版本管理
├── global.json # .NET SDK 版本
├── Dockerfile # Docker 容器化
├── .gitlab-ci.yml # GitLab CI/CD
└── README.md
技術棧詳細
後端框架
- .NET 10 - 最新版 .NET (ASP.NET Core)
- Entity Framework Core - ORM 框架
- PostgreSQL - 關聯式資料庫(中央資料庫)
背景任務
- Hangfire - 分散式背景任務處理
錯誤處理與重試
- Polly - 重試策略與斷路器
監控
- Prometheus - 指標收集
- Serilog + Seq - 結構化日誌
架構模式
- DDD (Domain-Driven Design) - 領域驅動設計
- Clean Architecture - 整潔架構(依賴反轉)
- CQRS - 命令查詢職責分離(部分實作)
容器化
- Docker - 容器化部署
🔌 API 文件
主要端點
上游同步 (SERP 匯入)
| 方法 | 端點 | 說明 | 回傳狀態 |
|---|---|---|---|
POST | /api/products/import | 啟動 SERP 匯入任務 | 202 Accepted, 400 BadRequest |
GET | /api/products/import/{jobId} | 查詢匯入任務狀態 | 200 OK, 404 NotFound |
POST | /api/webhooks/serp | 接收 SERP Webhook 事件 | 200 OK, 401 Unauthorized |
下游同步 (分發到區域)
| 方法 | 端點 | 說明 | 回傳狀態 |
|---|---|---|---|
POST | /api/sync/regions | 同步到所有區域 | 202 Accepted |
POST | /api/sync/regions/{code} | 同步到特定區域 (TW/US/JP) | 202 Accepted, 404 NotFound |
GET | /api/sync/regions/{code}/status | 查詢區域同步狀態 | 200 OK |
監控與健康檢查
| 方法 | 端點 | 說明 | 回傳狀態 |
|---|---|---|---|
GET | /health | 服務健康檢查 | 200 OK, 503 Unavailable |
GET | /health/sync | 同步機制健康檢查 | 200 OK, 503 Unavailable |
GET | /hangfire | Hangfire Dashboard | - |
API 設計原則
- 非同步優先 - 長時間操作立即回傳
202 Accepted,提供 Job ID 追蹤 - Result Pattern - 使用
Result<T>處理錯誤,避免例外影響效能 - 冪等性 - 重複呼叫不會造成重複處理
- 領域事件 - 使用 Domain Events 處理副作用
💾 資料模型
Domain Layer
Product Domain
public class Product : Entity
{
public Guid Id { get; set; }
public string ExternalProductId { get; set; } // SERP Product ID
public string SupplierId { get; set; } // "SERP"
// 基本資訊
public string Name { get; set; }
public string Description { get; set; }
public ProductType ProductType { get; set; }
// 多語言內容
public List<ProductTranslation> Translations { get; set; }
// 多幣別價格
public List<ProductPrice> Prices { get; set; }
// AI 豐富化
public string? EnrichedDescription { get; set; }
public List<string>? Tags { get; set; }
// 時間戳記
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public class ImportJob : Entity
{
public Guid Id { get; set; }
public string SupplierId { get; set; }
public ImportJobStatus Status { get; set; }
public ImportTrigger Trigger { get; set; }
public int TotalProcessed { get; set; }
public int SuccessCount { get; set; }
public int FailedCount { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? CompletedAt { get; set; }
}
public class RegionSyncLog : Entity
{
public Guid Id { get; set; }
public string RegionCode { get; set; } // TW, US, JP
public int ProductCount { get; set; }
public int SuccessCount { get; set; }
public int FailedCount { get; set; }
public SyncStatus Status { get; set; }
public DateTime StartedAt { get; set; }
public DateTime? CompletedAt { get; set; }
}
SharedKernel
核心共享元件:
// 基礎實體
public abstract class Entity
{
public Guid Id { get; protected set; }
}
// Result Pattern (錯誤處理)
public class Result<T>
{
public bool IsSuccess { get; }
public T Value { get; }
public Error Error { get; }
}
// 錯誤定義
public record Error(string Code, string Description, ErrorType Type);
// 領域事件介面
public interface IDomainEvent
{
Guid Id { get; }
DateTime OccurredOn { get; }
}
🔄 同步機制
上游同步:SERP → GlobalHub
觸發方式:
- Webhook (即時) - SERP 推送產品變更事件 ⭐ 優先
- 定時輪詢 - Hangfire Recurring Jobs
- 全量同步: 每天凌晨 2:00 AM
- 增量同步: 每小時
- 價格同步: 每 15 分鐘
- 手動觸發 - 管理員手動執行
處理流程:
SERP API
↓ HTTP/JSON
SerpApiClient
↓ 驗證
SerpProductMapper
↓ 轉換
ProductEnrichmentService (AI)
↓ 豐富化
ImportProductsJob (Hangfire)
↓ 批次儲存
中央 PostgreSQL
下游同步:GlobalHub → 各區域
觸發方式:
- 定時排程 - Hangfire Recurring Jobs
- TW: 每 30 分鐘
- US: 每天凌晨 3:00 AM
- JP: 每天凌晨 4:00 AM
- Webhook 觸發 - SERP 事件後自動推送
- 手動觸發 - 管理員手動同步
處理流程:
GlobalHub API (RegionSyncService)
↓ 批次處理 (50個/批)
├─ TW: POST /api/products/sync-from-globalhub
├─ US: POST /api/products/sync-from-globalhub
└─ JP: POST /api/products/sync-from-globalhub
↓
ProductsAPI (各區域)
↓ 冪等性處理
├─ 儲存 PostgreSQL
└─ 同步 Elasticsearch
詳細設計: GlobalHub 同步架構
🔗 相關專案
上游整合
| 專案 | 關係 | 說明 |
|---|---|---|
| SERP API | 外部供應商 | 提供旅遊產品資料 |
中央層專案
| 專案 | 關係 | 說明 |
|---|---|---|
| globalhub | 前端 (中央) | 消費 GlobalHub API 的中央前台 |
區域層專案
| 專案 | 關係 | 說明 |
|---|---|---|
| productsapi | 下游服務 (區域) | 接收同步的產品資料 |
| productbackend | 管理後台 (區域) | 區域產品內容管理 |
🚀 開發指南
環境需求
- .NET 10 SDK
- PostgreSQL (本地或 Docker)
- IDE: Visual Studio 2022 / Rider / VS Code
本地執行
-
確保資料庫設定
檢查
appsettings.json中的Database連線字串:{
"ConnectionStrings": {
"Database": "Host=localhost;Port=5432;Database=globalhubdb;Username=postgres;Password=yourpassword"
},
"Regions": {
"TW": {
"ApiUrl": "https://tw.productsapi.liontravel.com",
"ApiKey": "tw_api_key_here"
}
}
} -
執行專案
dotnet run --project src/Presentation/Web.Api/Web.Api.csproj -
執行 Migrations
dotnet ef database update --project src/Infrastructure
Docker 執行
-
建構映像檔
docker build -t globalhubapi . -
啟動容器
docker run -d -p 8080:8080 --name globalhubapi \
-e ConnectionStrings__Database="Host=host.docker.internal;Port=5432;Database=globalhubdb;Username=postgres;Password=yourpassword" \
globalhubapi
測試
dotnet test
🏛️ 架構層次
1. Domain Layer (領域層)
- 無外部依賴 - 純業務邏輯
- 實體與值物件 - Product, ImportJob, RegionSyncLog
- 領域事件 - ProductImported, ProductSynced
2. Application Layer (應用層)
- 用例實作 - 產品匯入、區域同步
- CQRS Handlers - 命令與查詢處理器
- 介面定義 - Repository、Service 介面
3. Infrastructure Layer (基礎設施層)
- 資料庫實作 - EF Core DbContext
- 外部服務 - SERP API Client, Region API Client
- 背景任務 - Hangfire Jobs (Import, Sync)
4. Presentation Layer (展示層)
- Web API - ASP.NET Core Minimal API
- DTO - 資料傳輸物件
- 驗證 - FluentValidation
🔄 背景任務 (Hangfire)
支援的任務
上游同步
- SERP 全量同步 - 每天凌晨 2:00 AM
- SERP 增量同步 - 每小時
- SERP 價格同步 - 每 15 分鐘
下游同步
- TW 區域同步 - 每 30 分鐘
- US 區域同步 - 每天凌晨 3:00 AM
- JP 區域同步 - 每天凌晨 4:00 AM
Hangfire Dashboard
存取 /hangfire 查看任務執行狀態、重試記錄、失敗日誌。
📊 監控與告警
Prometheus Metrics
globalhub_serp_sync_total{status}- SERP 同步總次數globalhub_region_sync_total{region,status}- 區域同步總次數globalhub_sync_duration_seconds{sync_type}- 同步耗時globalhub_last_sync_timestamp{source}- 最後同步時間
健康檢查
GET /health- 服務整體健康GET /health/sync- 同步機制健康(檢查 SERP 與各區域)
告警規則
- SERP 同步失敗率 > 10%
- SERP 同步超過 1 小時未執行
- 區域同步失敗
- 同步時間 P95 > 5 分鐘
📝 CI/CD 流程
.gitlab-ci.yml 支援以下階段:
- Build - 編譯專案
- Test - 執行單元測試與整合測試
- Publish - 建置 Docker 映像檔並推送到 Registry
- Deploy - 部署到目標環境
🎯 設計決策
為何選擇 Clean Architecture?
- 可測試性 - 業務邏輯獨立於框架
- 可維護性 - 清晰的層次分離
- 可擴展性 - 易於替換基礎設施組件
為何使用 Hangfire?
- 可靠性 - 任務持久化,伺服器重啟不丟失
- 監控 - 內建 Dashboard
- 易用性 - .NET 原生整合
為何採用 Result Pattern?
- 效能 - 避免例外拋出的效能成本
- 明確性 - 強制處理錯誤情況
- 型別安全 - 編譯期檢查
為何雙向同步架構?
- 中央採購 - 統一從 SERP 取得產品
- 區域運營 - 各區域獨立管理與銷售
- 資料主權 - 區域資料留在區域資料庫
🔐 安全性
- 輸入驗證 - FluentValidation
- SQL Injection 防護 - EF Core 參數化查詢
- API Key 驗證 - Webhook 簽章驗證
- 敏感資料 - 使用 User Secrets / 環境變數
📚 相關文件
- 系統總覽
- GlobalHub 同步架構 ⭐ 完整同步設計
- ProductsAPI
- 任務清單