skills/go-ddd/SKILL.md
Go DDD 架構設計規範:領域驅動設計 (Domain-Driven Design)、Bounded Context(限界上下文)、 Aggregate Root(聚合根)、Repository Pattern、Shared Kernel(共用核心)、依賴注入整合。 **適用場景**:設計微服務架構、規劃專案目錄結構、實作 DDD 分層、定義領域模型、 拆分 Bounded Context、設計 Repository 介面。
npx skillsauth add vincent119/ai-rules-kit go-dddInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
相關 Skills:本規範需搭配
go-dependency-injection與go-domain-events
.
├── cmd/
│ └── <app>/main.go # 進入點:只負責載入 configs、初始化 internal/infra (DB/Redis) 並啟動依賴注入
├── api/ # 對外契約:OpenAPI (Swagger)、Protobuf 定義與產生的程式碼
├── configs/ # 設定檔:config.yaml, env.example
├── internal/ # 核心邏輯:外部無法 import
│ ├── <service>/ # 業務服務【Bounded Context】
│ │ ├── domain/ # 領域層:Entity, VO, Repository Interface (純業務,禁 SQL/JSON)
│ │ ├── application/ # 應用層:Use Case 流程編排,依賴 domain interface
│ │ ├── infra/ # 實作層:Repository Impl (SQL/GORM), JWT 實作, 外部 API 呼叫
│ │ ├── delivery/ # 介面層:HTTP Handlers, gRPC Services, DTO 定義
│ │ └── di.go # 依賴注入 (Google Wire or Fx)
│ ├── infra/ # 【全域基礎設施】
│ │ ├── database/ # DB 連線池初始化 (MySQL, Postgres)
│ │ ├── cache/ # Redis, Memcached 客戶端
│ │ └── logger/ # 結構化日誌 (Zap/Slog) 配置
│ └── pkg/ # 【Shared Kernel】跨 Bounded Context 的共用領域抽象(例:Money、DomainError)
│ # 僅限「跨 Bounded Context 皆成立」的抽象
│ # 禁止放入特定 service 的規則或流程
├── pkg/ # 【通用工具】uuid, retry, stringutils (完全不含業務邏輯)
├── migrations/ # Database Migration 檔案(詳見 go-database Skill)
├── scripts/ # 腳本:DB Migration, Makefile 輔助腳本
├── deployments/ # Kubernetes、Helm Chart 與部署相關檔案
│ ├── helm/ # Helm charts
│ └── kustomization/ # Kustomize overlays
├── docs/ # swagger.yaml, 架構設計文件
├── documents/ # 專案文件
│ ├── en/ # 專案相關文件(需求規格、設計文件、SOP)
│ └── zh/ # 專案相關文件(需求規格、設計文件、SOP)
├── test/ # 整合測試與測試資料 (fixtures) 黑箱 / 整合測試,禁止直接測 domain 私有狀態
├── Dockerfile # Multi-stage build
├── Makefile # 常用指令 (make wire, make test, make lint)
├── .dockerignore # Docker build 忽略清單(排除編譯輸出、暫存檔與測試資料)
├── .gitignore # Git 忽略清單(node_modules、vendor、log、tmp 等)
├── .golangci.yml # 靜態分析與 Linter 設定(統一風格與品質門檻)
├── README.md # 專案說明:目的、架構、建置步驟、測試與部署指引
├── LICENSE # 授權條款;內部專案可標註版權與使用限制
├── go.mod # Go 模組定義與依賴版本管理
└── go.sum # 依賴模組驗證雜湊清單(確保可重建性)
本專案採用 領域驅動設計(Domain-Driven Design, DDD) 作為核心架構方法,並僅在最外層以 MVC 作為介面實作模式,兩者責任邊界清楚、互不混用。
internal/<service>/ 目錄下此架構能確保系統具備長期可維護性、可測試性,並可在不破壞核心業務模型的前提下,平順演進自單體架構至微服務架構。
Shared Kernel 位於
internal/pkg/,存放跨 Bounded Context 通用的領域抽象。
| 類型 | 範例 |
|------|------|
| Value Objects | Money, Email, PhoneNumber, Address |
| Domain Error | DomainError, ValidationError, NotFoundError |
| 通用介面 | Clock, UUIDGenerator(用於測試注入) |
| 規格抽象 | Specification<T> pattern 基底 |
| 類型 | 原因 | |------|------| | 特定 BC 的 Entity/Aggregate | 造成 BC 間耦合 | | 業務流程編排(Use Case) | 違反 BC 邊界獨立性 | | 框架耦合的實作(如 GORM Model) | 應放 Infra 層 | | 可變狀態或 Singleton | 難以測試與併行安全 |
位置:internal/<service>/domain/
職責:
範例:
// internal/order/domain/order.go
package domain
import "time"
// Order 訂單聚合根
type Order struct {
id string
customerID string
items []OrderItem
totalAmount Money
status OrderStatus
createdAt time.Time
}
// PlaceOrder 建立訂單(工廠方法)
func PlaceOrder(customerID string, items []OrderItem) (*Order, error) {
if len(items) == 0 {
return nil, ErrEmptyOrder
}
order := &Order{
id: generateID(),
customerID: customerID,
items: items,
status: OrderStatusPending,
createdAt: time.Now().UTC(),
}
order.calculateTotal()
return order, nil
}
// Repository 輸出埠(interface 定義在 Domain,實作在 Infra)
type Repository interface {
Save(ctx context.Context, order *Order) error
FindByID(ctx context.Context, id string) (*Order, error)
}
位置:internal/<service>/application/
職責:
範例:
// internal/order/application/create_order_usecase.go
package application
type CreateOrderUseCase struct {
repo domain.Repository
eventBus EventBus
}
func (uc *CreateOrderUseCase) Execute(ctx context.Context, input CreateOrderInput) error {
// 1. 建立領域模型
order, err := domain.PlaceOrder(input.CustomerID, input.Items)
if err != nil {
return fmt.Errorf("place order: %w", err)
}
// 2. 持久化
if err := uc.repo.Save(ctx, order); err != nil {
return fmt.Errorf("save order: %w", err)
}
// 3. 發布領域事件
uc.eventBus.Publish(ctx, OrderCreatedEvent{OrderID: order.ID()})
return nil
}
位置:internal/<service>/infra/
職責:
範例:
// internal/order/infra/order_repository.go
package infra
import (
"gorm.io/gorm"
"myapp/internal/order/domain"
)
type OrderRepositoryImpl struct {
db *gorm.DB
}
func (r *OrderRepositoryImpl) Save(ctx context.Context, order *domain.Order) error {
// 將領域模型轉為 GORM 模型
model := toGORMModel(order)
return r.db.WithContext(ctx).Create(model).Error
}
func (r *OrderRepositoryImpl) FindByID(ctx context.Context, id string) (*domain.Order, error) {
var model OrderModel
if err := r.db.WithContext(ctx).First(&model, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, domain.ErrOrderNotFound
}
return nil, err
}
return toDomainModel(&model), nil
}
位置:internal/<service>/delivery/
職責:
範例:
// internal/order/delivery/http/order_handler.go
package http
type OrderHandler struct {
createOrderUC *application.CreateOrderUseCase
}
// CreateOrder 處理 HTTP 請求
// @Summary 建立訂單
// @Router /orders [post]
func (h *OrderHandler) CreateOrder(c *gin.Context) {
var req CreateOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
input := application.CreateOrderInput{
CustomerID: req.CustomerID,
Items: toUseCaseItems(req.Items),
}
if err := h.createOrderUC.Execute(c.Request.Context(), input); err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, gin.H{"message": "order created"})
}
| 通訊方式 | 適用場景 | 實作 | |----------|----------|------| | 同步 API 呼叫 | 強一致性需求 | HTTP / gRPC | | 非同步事件 | 最終一致性可接受 | Message Queue(NATS、Kafka) | | Shared Database | ❌ 禁止 | 造成耦合 |
原則:每個 BC 擁有自己的資料庫 Schema 或 Table Prefix
正確做法:
// ✅ 透過 API 呼叫其他 BC
func (uc *CreateOrderUseCase) Execute(ctx context.Context, input CreateOrderInput) error {
// 呼叫 User BC 的 API 驗證使用者
user, err := uc.userClient.GetUser(ctx, input.CustomerID)
if err != nil {
return fmt.Errorf("get user: %w", err)
}
// ...訂單邏輯
}
錯誤做法:
// ❌ 直接查詢其他 BC 的資料表
func (r *OrderRepo) GetUserName(ctx context.Context, userID string) (string, error) {
var name string
// 錯誤:跨越 BC 邊界直接查詢 users 表
r.db.Raw("SELECT name FROM users WHERE id = ?", userID).Scan(&name)
return name, nil
}
Domain Layer
import 任何框架(GORM、Gin、gRPC)Application Layer
import Infrastructure 實作Infrastructure Layer
Delivery Layer
Bounded Context
tools
基於 SLA/SLO 量化評估事故影響的計算模型與業務影響矩陣。適用於「SLA 影響」、「SLO 違反」、「影響評估」、「營收損失估算」、「Error Budget」、「可用性計算」、「事故成本評估」等量化事故業務影響的任務。強化 impact-assessor 的評估能力。注意:事故原因分析與改善規劃不在此技能範圍內。
research
根因分析(RCA)方法論詳細指南。提供 5 Whys、Fishbone 圖、Fault Tree Analysis、變更分析等結構化 RCA 技術,以及認知偏誤防範清單。適用於「根因分析」、「RCA」、「5 Whys」、「魚骨圖」、「Fault Tree」、「原因分析方法論」、「變更分析」等事故原因分析任務。強化 root-cause-investigator 的分析能力。注意:時間軸重建與改善規劃不在此技能範圍內。
testing
事故事後分析(Postmortem)完整流程。協調 7 個執行階段:資訊收集 → 時間軸重建 → 根因分析 → 影響評估 → 改善規劃 → 報告審查 → 整合報告,最終產出完整的 Postmortem 報告。適用於「寫事故報告」、「post-incident 分析」、「RCA 報告」、「事故時間軸整理」、「建立改善措施」等請求。注意:即時 Incident Response(on-call)、監控系統設定、告警配置不在此技能範圍內。
content-media
投影片版面模式庫。提供 20 種投影片類型的最佳版面配置、格線系統、色彩與字型設計 Token。適用於「投影片版面」、「Slide Layout」、「設計系統」、「格線」、「字型」、「色彩規範」等投影片視覺設計任務。強化 visual-designer 的設計能力。注意:PPT/Keynote 檔案直接輸出不在此技能範圍內。