@vincent119/go-copilot-rules 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,374 @@
1
+ ---
2
+ name: go-ddd
3
+ description: |
4
+ Go DDD 架構設計規範:領域驅動設計 (Domain-Driven Design)、Bounded Context(限界上下文)、
5
+ Aggregate Root(聚合根)、Repository Pattern、Shared Kernel(共用核心)、依賴注入整合。
6
+
7
+ **適用場景**:設計微服務架構、規劃專案目錄結構、實作 DDD 分層、定義領域模型、
8
+ 拆分 Bounded Context、設計 Repository 介面。
9
+
10
+ **關鍵字**:DDD, domain driven design, bounded context, aggregate, entity, value object,
11
+ repository pattern, domain layer, application layer, infrastructure layer, delivery layer,
12
+ 目錄結構, 專案架構, 微服務, monolith to microservices
13
+ ---
14
+
15
+ # Go DDD 架構設計規範
16
+
17
+ > **相關 Skills**:本規範需搭配 `go-dependency-injection` 與 `go-domain-events`
18
+
19
+ ---
20
+
21
+ ## 目錄結構
22
+
23
+ ```bash
24
+ .
25
+ ├── cmd/
26
+ │ └── <app>/main.go # 進入點:只負責載入 configs、初始化 internal/infra (DB/Redis) 並啟動依賴注入
27
+ ├── api/ # 對外契約:OpenAPI (Swagger)、Protobuf 定義與產生的程式碼
28
+ ├── configs/ # 設定檔:config.yaml, env.example
29
+ ├── internal/ # 核心邏輯:外部無法 import
30
+ │ ├── <service>/ # 業務服務【Bounded Context】
31
+ │ │ ├── domain/ # 領域層:Entity, VO, Repository Interface (純業務,禁 SQL/JSON)
32
+ │ │ ├── application/ # 應用層:Use Case 流程編排,依賴 domain interface
33
+ │ │ ├── infra/ # 實作層:Repository Impl (SQL/GORM), JWT 實作, 外部 API 呼叫
34
+ │ │ ├── delivery/ # 介面層:HTTP Handlers, gRPC Services, DTO 定義
35
+ │ │ └── di.go # 依賴注入 (Google Wire or Fx)
36
+ │ ├── infra/ # 【全域基礎設施】
37
+ │ │ ├── database/ # DB 連線池初始化 (MySQL, Postgres)
38
+ │ │ ├── cache/ # Redis, Memcached 客戶端
39
+ │ │ └── logger/ # 結構化日誌 (Zap/Slog) 配置
40
+ │ └── pkg/ # 【Shared Kernel】跨 Bounded Context 的共用領域抽象(例:Money、DomainError)
41
+ │ # 僅限「跨 Bounded Context 皆成立」的抽象
42
+ │ # 禁止放入特定 service 的規則或流程
43
+ ├── pkg/ # 【通用工具】uuid, retry, stringutils (完全不含業務邏輯)
44
+ ├── migrations/ # Database Migration 檔案(詳見 go-database Skill)
45
+ ├── scripts/ # 腳本:DB Migration, Makefile 輔助腳本
46
+ ├── deployments/ # Kubernetes、Helm Chart 與部署相關檔案
47
+ │ ├── helm/ # Helm charts
48
+ │ └── kustomization/ # Kustomize overlays
49
+ ├── docs/ # swagger.yaml, 架構設計文件
50
+ ├── documents/ # 專案文件
51
+ │ ├── en/ # 專案相關文件(需求規格、設計文件、SOP)
52
+ │ └── zh/ # 專案相關文件(需求規格、設計文件、SOP)
53
+ ├── test/ # 整合測試與測試資料 (fixtures) 黑箱 / 整合測試,禁止直接測 domain 私有狀態
54
+ ├── Dockerfile # Multi-stage build
55
+ ├── Makefile # 常用指令 (make wire, make test, make lint)
56
+ ├── .dockerignore # Docker build 忽略清單(排除編譯輸出、暫存檔與測試資料)
57
+ ├── .gitignore # Git 忽略清單(node_modules、vendor、log、tmp 等)
58
+ ├── .golangci.yml # 靜態分析與 Linter 設定(統一風格與品質門檻)
59
+ ├── README.md # 專案說明:目的、架構、建置步驟、測試與部署指引
60
+ ├── LICENSE # 授權條款;內部專案可標註版權與使用限制
61
+ ├── go.mod # Go 模組定義與依賴版本管理
62
+ └── go.sum # 依賴模組驗證雜湊清單(確保可重建性)
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 架構總覽(Architecture Overview)
68
+
69
+ ### 核心原則
70
+
71
+ 本專案採用 **領域驅動設計(Domain-Driven Design, DDD)** 作為核心架構方法,並僅在最外層以 MVC 作為介面實作模式,兩者責任邊界清楚、互不混用。
72
+
73
+ - 每一項業務能力皆建模為一個獨立的 **限界上下文(Bounded Context)**,並置於 `internal/<service>/` 目錄下
74
+ - 業務規則集中於 **領域層(Domain Layer)**,與任何框架或基礎設施實作完全解耦
75
+ - **MVC 僅應用於交付層(Delivery Layer)**,用於處理對外介面(HTTP / gRPC)
76
+ - 基礎設施相關關注點(資料庫、快取、日誌等)皆透過 **依賴注入(Dependency Injection)** 進行解耦與提供
77
+ - MVC 僅作為 Delivery Layer 的實作模式之一,不構成系統核心架構
78
+
79
+ ### 演進路徑
80
+
81
+ 此架構能確保系統具備長期可維護性、可測試性,並可在不破壞核心業務模型的前提下,平順演進自單體架構至微服務架構。
82
+
83
+ ---
84
+
85
+ ## Shared Kernel(共用核心)使用規範
86
+
87
+ > Shared Kernel 位於 `internal/pkg/`,存放跨 Bounded Context 通用的領域抽象。
88
+
89
+ ### ✅ 適合放入的內容
90
+
91
+ | 類型 | 範例 |
92
+ |------|------|
93
+ | Value Objects | `Money`, `Email`, `PhoneNumber`, `Address` |
94
+ | Domain Error | `DomainError`, `ValidationError`, `NotFoundError` |
95
+ | 通用介面 | `Clock`, `UUIDGenerator`(用於測試注入) |
96
+ | 規格抽象 | `Specification<T>` pattern 基底 |
97
+
98
+ ### ❌ 禁止放入的內容
99
+
100
+ | 類型 | 原因 |
101
+ |------|------|
102
+ | 特定 BC 的 Entity/Aggregate | 造成 BC 間耦合 |
103
+ | 業務流程編排(Use Case) | 違反 BC 邊界獨立性 |
104
+ | 框架耦合的實作(如 GORM Model) | 應放 Infra 層 |
105
+ | 可變狀態或 Singleton | 難以測試與併行安全 |
106
+
107
+ ### 變更流程
108
+
109
+ 1. 修改 Shared Kernel 需所有**相依 BC 負責人同意**
110
+ 2. 變更需附**影響範圍分析**(列出受影響的 BC)
111
+ 3. **向下相容**變更可直接合併;破壞性變更需升版並遷移計畫
112
+
113
+ ### 設計原則
114
+
115
+ - **最小化**:只放真正跨 BC 通用的抽象
116
+ - **不可變**:Value Objects 設計為 immutable
117
+ - **無副作用**:Shared Kernel 內的邏輯不應有 I/O 或外部依賴
118
+
119
+ ---
120
+
121
+ ## 分層職責說明
122
+
123
+ ### Domain Layer(領域層)
124
+
125
+ **位置**:`internal/<service>/domain/`
126
+
127
+ **職責**:
128
+ - 定義 Entity(實體)、Value Object(值物件)、Aggregate Root(聚合根)
129
+ - 定義 Repository Interface(輸出埠)
130
+ - 包含核心業務邏輯與不變條件(Invariant)
131
+ - **完全不依賴**框架、資料庫、HTTP、JSON
132
+
133
+ **範例**:
134
+ ```go
135
+ // internal/order/domain/order.go
136
+ package domain
137
+
138
+ import "time"
139
+
140
+ // Order 訂單聚合根
141
+ type Order struct {
142
+ id string
143
+ customerID string
144
+ items []OrderItem
145
+ totalAmount Money
146
+ status OrderStatus
147
+ createdAt time.Time
148
+ }
149
+
150
+ // PlaceOrder 建立訂單(工廠方法)
151
+ func PlaceOrder(customerID string, items []OrderItem) (*Order, error) {
152
+ if len(items) == 0 {
153
+ return nil, ErrEmptyOrder
154
+ }
155
+
156
+ order := &Order{
157
+ id: generateID(),
158
+ customerID: customerID,
159
+ items: items,
160
+ status: OrderStatusPending,
161
+ createdAt: time.Now().UTC(),
162
+ }
163
+
164
+ order.calculateTotal()
165
+ return order, nil
166
+ }
167
+
168
+ // Repository 輸出埠(interface 定義在 Domain,實作在 Infra)
169
+ type Repository interface {
170
+ Save(ctx context.Context, order *Order) error
171
+ FindByID(ctx context.Context, id string) (*Order, error)
172
+ }
173
+ ```
174
+
175
+ ### Application Layer(應用層)
176
+
177
+ **位置**:`internal/<service>/application/`
178
+
179
+ **職責**:
180
+ - Use Case 流程編排(呼叫多個 Repository、Domain Service)
181
+ - 事務管理(Transaction)
182
+ - 對外介面(Input Port)
183
+ - 依賴 Domain Interface,不依賴具體實作
184
+
185
+ **範例**:
186
+ ```go
187
+ // internal/order/application/create_order_usecase.go
188
+ package application
189
+
190
+ type CreateOrderUseCase struct {
191
+ repo domain.Repository
192
+ eventBus EventBus
193
+ }
194
+
195
+ func (uc *CreateOrderUseCase) Execute(ctx context.Context, input CreateOrderInput) error {
196
+ // 1. 建立領域模型
197
+ order, err := domain.PlaceOrder(input.CustomerID, input.Items)
198
+ if err != nil {
199
+ return fmt.Errorf("place order: %w", err)
200
+ }
201
+
202
+ // 2. 持久化
203
+ if err := uc.repo.Save(ctx, order); err != nil {
204
+ return fmt.Errorf("save order: %w", err)
205
+ }
206
+
207
+ // 3. 發布領域事件
208
+ uc.eventBus.Publish(ctx, OrderCreatedEvent{OrderID: order.ID()})
209
+
210
+ return nil
211
+ }
212
+ ```
213
+
214
+ ### Infrastructure Layer(基礎設施層)
215
+
216
+ **位置**:`internal/<service>/infra/`
217
+
218
+ **職責**:
219
+ - Repository 實作(SQL、GORM、Redis)
220
+ - 外部 API 呼叫
221
+ - JWT 驗證實作
222
+ - Message Queue 發送
223
+
224
+ **範例**:
225
+ ```go
226
+ // internal/order/infra/order_repository.go
227
+ package infra
228
+
229
+ import (
230
+ "gorm.io/gorm"
231
+ "myapp/internal/order/domain"
232
+ )
233
+
234
+ type OrderRepositoryImpl struct {
235
+ db *gorm.DB
236
+ }
237
+
238
+ func (r *OrderRepositoryImpl) Save(ctx context.Context, order *domain.Order) error {
239
+ // 將領域模型轉為 GORM 模型
240
+ model := toGORMModel(order)
241
+ return r.db.WithContext(ctx).Create(model).Error
242
+ }
243
+
244
+ func (r *OrderRepositoryImpl) FindByID(ctx context.Context, id string) (*domain.Order, error) {
245
+ var model OrderModel
246
+ if err := r.db.WithContext(ctx).First(&model, "id = ?", id).Error; err != nil {
247
+ if errors.Is(err, gorm.ErrRecordNotFound) {
248
+ return nil, domain.ErrOrderNotFound
249
+ }
250
+ return nil, err
251
+ }
252
+ return toDomainModel(&model), nil
253
+ }
254
+ ```
255
+
256
+ ### Delivery Layer(交付層)
257
+
258
+ **位置**:`internal/<service>/delivery/`
259
+
260
+ **職責**:
261
+ - HTTP Handlers、gRPC Services
262
+ - 請求驗證、DTO 轉換
263
+ - 呼叫 Application Layer Use Case
264
+
265
+ **範例**:
266
+ ```go
267
+ // internal/order/delivery/http/order_handler.go
268
+ package http
269
+
270
+ type OrderHandler struct {
271
+ createOrderUC *application.CreateOrderUseCase
272
+ }
273
+
274
+ // CreateOrder 處理 HTTP 請求
275
+ // @Summary 建立訂單
276
+ // @Router /orders [post]
277
+ func (h *OrderHandler) CreateOrder(c *gin.Context) {
278
+ var req CreateOrderRequest
279
+ if err := c.ShouldBindJSON(&req); err != nil {
280
+ c.JSON(400, gin.H{"error": err.Error()})
281
+ return
282
+ }
283
+
284
+ input := application.CreateOrderInput{
285
+ CustomerID: req.CustomerID,
286
+ Items: toUseCaseItems(req.Items),
287
+ }
288
+
289
+ if err := h.createOrderUC.Execute(c.Request.Context(), input); err != nil {
290
+ c.JSON(500, gin.H{"error": err.Error()})
291
+ return
292
+ }
293
+
294
+ c.JSON(201, gin.H{"message": "order created"})
295
+ }
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Bounded Context 設計準則
301
+
302
+ ### 識別 BC 的標準
303
+
304
+ 1. **獨立的業務能力**:訂單管理、使用者管理、支付處理
305
+ 2. **不同的語言術語**:Order vs Payment vs Shipment
306
+ 3. **獨立的團隊擁有權**:不同團隊維護不同 BC
307
+ 4. **可獨立部署**:未來拆分成微服務時的單位
308
+
309
+ ### BC 之間的通訊
310
+
311
+ | 通訊方式 | 適用場景 | 實作 |
312
+ |----------|----------|------|
313
+ | **同步 API 呼叫** | 強一致性需求 | HTTP / gRPC |
314
+ | **非同步事件** | 最終一致性可接受 | Message Queue(NATS、Kafka) |
315
+ | **Shared Database** | ❌ **禁止** | 造成耦合 |
316
+
317
+ ### 跨 BC 資料訪問
318
+
319
+ **原則**:每個 BC 擁有自己的資料庫 Schema 或 Table Prefix
320
+
321
+ **正確做法**:
322
+ ```go
323
+ // ✅ 透過 API 呼叫其他 BC
324
+ func (uc *CreateOrderUseCase) Execute(ctx context.Context, input CreateOrderInput) error {
325
+ // 呼叫 User BC 的 API 驗證使用者
326
+ user, err := uc.userClient.GetUser(ctx, input.CustomerID)
327
+ if err != nil {
328
+ return fmt.Errorf("get user: %w", err)
329
+ }
330
+
331
+ // ...訂單邏輯
332
+ }
333
+ ```
334
+
335
+ **錯誤做法**:
336
+ ```go
337
+ // ❌ 直接查詢其他 BC 的資料表
338
+ func (r *OrderRepo) GetUserName(ctx context.Context, userID string) (string, error) {
339
+ var name string
340
+ // 錯誤:跨越 BC 邊界直接查詢 users 表
341
+ r.db.Raw("SELECT name FROM users WHERE id = ?", userID).Scan(&name)
342
+ return name, nil
343
+ }
344
+ ```
345
+
346
+ ---
347
+
348
+ ## 檢查清單
349
+
350
+ **Domain Layer**
351
+ - [ ] 無 `import` 任何框架(GORM、Gin、gRPC)
352
+ - [ ] 無 JSON/YAML tags
353
+ - [ ] Repository 定義為 Interface
354
+ - [ ] Entity 方法包含業務邏輯驗證
355
+
356
+ **Application Layer**
357
+ - [ ] Use Case 依賴 Domain Interface
358
+ - [ ] 無直接 `import` Infrastructure 實作
359
+ - [ ] 事務邊界清晰
360
+
361
+ **Infrastructure Layer**
362
+ - [ ] Repository 實作不洩漏到 Domain
363
+ - [ ] GORM Model 與 Domain Entity 分離
364
+ - [ ] 錯誤轉換為 Domain Error
365
+
366
+ **Delivery Layer**
367
+ - [ ] HTTP Handler 不直接操作 Domain Entity
368
+ - [ ] DTO 與 Domain Model 分離
369
+ - [ ] 驗證在此層完成
370
+
371
+ **Bounded Context**
372
+ - [ ] 每個 BC 有獨立的資料庫 Schema/Prefix
373
+ - [ ] BC 之間透過 API 或事件通訊
374
+ - [ ] 無跨 BC 的直接資料庫查詢