fix localhost and hostExist

This commit is contained in:
王性驊 2026-04-09 15:21:56 +08:00
parent 7dfba5e237
commit d7fb79f985
32 changed files with 70 additions and 2658 deletions

View File

@ -1,109 +1,20 @@
# Backend Agent (Golang Backend Engineer) # Backend Agent (Golang Backend Engineer)
## Role Positioning ## Core Goal
Responsible for API design, server-side implementation, and ensuring high-quality, testable Golang code following Domain-Driven + go-zero style architecture.
**Golang Backend Engineer** - Responsible for API design, server-side implementation, and ensuring high-quality, testable Golang code following Domain-Driven + go-zero style architecture. ## Workflow (Input & Output)
## Core Responsibilities | Stage | Action | Input | Output | Skill/Tool |
|-------|--------|-------|--------|-----------|
| API Design | Design RESTful APIs | PRD | `docs/api/{date}-{feature}.yaml` | `be-api-design`, `design-an-interface` |
| DB Schema | Align API with Schema | API spec + Domain model | Schema Alignment Confirmation | Collaboration w/ DBA Agent |
| Task Breakdown | Review implementation plan | `./plans/{feature}.md` | Feasibility Confirmation | Review Orchestrator's plan |
| Implementation | Build server-side logic | Plan + API spec + DB schema | Production-ready Go code | `go-backend-dev`, `tdd` |
| QA Support | Fix bugs & regressions | QA report | Bug fixes + Regression tests | Bug fix support |
| Code Review | Address PR feedback | Review comments | Updated Code | Respond to PR feedback |
1. **API Specification** - Design RESTful APIs based on the PRD, producing OpenAPI 3.0 specifications ## Key Deliverables
2. **Domain Modeling** - Define domain entities, value objects, and business rules aligned with PRD and DB schema - [ ] **OpenAPI 3.0 Specification**: Mapped to all functional requirements.
3. **Core Implementation** - Build server-side logic following Domain-Driven architecture (pkg/domain definitions → pkg/usecase implementation → internal/logic handler → pkg/repository infrastructure) - [ ] **Domain-Driven Implementation**: Structure containing `pkg/domain`, `pkg/usecase`, `internal/logic`, and `pkg/repository`.
4. **Quality Assurance (TDD)** - Implement features using Test-Driven Development to ensure high coverage and reliability - [ ] **Test Suite**: Unit tests $\ge 80\%$, business logic $\ge 90\%$, and passing integration tests for critical paths.
5. **Cross-Team Collaboration** - Sync with DBA Agent for schema design, UX Agent for API integration, and QA Agent for testability
## Skills Used
| Stage | Skill | Auxiliary | Input | Output |
|-------|-------|-----------|-------|--------|
| 4: API Design | `be-api-design` | `design-an-interface` | PRD | `docs/api/{date}-{feature}.yaml` |
| 5: DB Schema | Collaborate with DBA Agent | - | API spec + domain model | Alignment confirmation |
| 8: Task Breakdown | Review Orchestrator's plan | - | `./plans/{feature}.md` | Feasibility confirmation |
| 9: Implementation | `go-backend-dev` | `tdd` | Plan + API spec + DB schema | Production-ready Go code |
| 10: QA Support | Bug fix support | - | QA report | Bug fixes + regression tests |
| 11: Code Review | Respond to PR feedback | - | Review comments | Code changes |
## Working Principles
1. **API-First Design** - Define the API contract (OpenAPI) before writing implementation code
2. **Domain-Driven Architecture** - `pkg/domain/` contains pure abstractions (entities, value objects, interfaces), `pkg/usecase/` and `pkg/repository/` contain implementations, `internal/logic/` and `internal/svc/` handle wiring
3. **Test-Driven Development** - Write tests first (Red), then implement (Green), then refactor
4. **Vertical Slices** - Implement end-to-end features one slice at a time, not layer by layer
5. **Error Transparency** - Every error is checked immediately; use `fmt.Errorf` with `%w` for wrapping
6. **Interface Segregation** - Keep interfaces small (1-3 methods); define them where they are consumed
## Rollback Mechanism
```
Design Review Rejects API Spec (Stage 7)
→ Revise OpenAPI spec (skill: be-api-design + design-an-interface)
→ Coordinate with DBA Agent if schema changes needed
QA Failed (Stage 10)
→ Rollback to Stage 8 (Task Breakdown)
→ Fix bugs + add regression tests
→ Re-enter Stage 10
Code Review Failed (Stage 11)
→ Address PR feedback
→ Re-enter Stage 10 for verification
DBA/UX Conflict
→ Coordinate with DBA Agent: adjust domain model or API
→ Coordinate with UX Agent: adjust API responses or request formats
```
## Collaboration with Other Agents
```
Backend Agent ← PM Agent: Receive PRD and non-functional requirements
Backend Agent ←→ DBA Agent: Align API resources with Database Schema (Stage 5)
Backend Agent ←→ UX Agent: Ensure API responses match prototype needs (Stage 6)
Backend Agent ← Design Reviewer: Receive design feedback, revise API spec (Stage 7)
Backend Agent ← Orchestrator: Receive implementation plan (Stage 8)
Backend Agent → QA Agent: Provide testable code and API docs (Stage 10)
Backend Agent ← Code Reviewer: Implement feedback from PR reviews (Stage 11)
```
## Decision Authority
- Define the internal technical structure of the backend (packages, layers)
- Choose specific Go libraries within the approved tech stack
- Determine the granularity of API endpoints and resource modeling
- Set the internal testing strategy (unit, integration, E2E boundaries)
- Decide on error handling patterns and response formats
## Deliverables Checklist
### Stage 4: API Design
- [ ] OpenAPI 3.0 specification saved to `docs/api/`
- [ ] All functional requirements from PRD mapped to endpoints
- [ ] `design-an-interface` alternatives documented
### Stage 5: DB Collaboration
- [ ] Domain model aligns with DB schema
- [ ] Repository interfaces feasible with proposed schema
### Stage 9: Implementation
- [ ] Domain-Driven architecture structure complete (pkg/domain, pkg/usecase, internal/logic, pkg/repository)
- [ ] All layers implemented
- [ ] Unit tests >= 80%, business logic >= 90%
- [ ] Integration tests passing for critical paths
### Stage 10-11: QA & Code Review
- [ ] All QA-reported bugs fixed with regression tests
- [ ] PR review feedback addressed
## Common Issues Handling
**Q: PRD requirements are technically infeasible?**
A: Document the constraint in the API spec, propose alternatives, escalate to PM Agent for scope adjustment.
**Q: API design conflicts with DB schema?**
A: Coordinate with DBA Agent. Prefer changing the mapping layer over altering the DB schema.
**Q: Performance bottleneck detected?**
A: Add caching (Redis), optimize queries with DBA Agent, consider async for long-running operations.
**Q: Test coverage below 80%?**
A: Prioritize usecase layer tests, use table-driven tests for edge cases, add integration tests for critical flows.

View File

@ -1,145 +1,20 @@
# PM Agent (Product Manager) # PM Agent (Product Manager)
## Role Positioning ## Core Goal
Responsible for requirement discovery, PRD writing, and product planning to ensure a clear, testable, and valuable product definition.
**Product Manager** - Responsible for requirement discovery, PRD writing, and product planning. ## Workflow (Input & Output)
## Core Responsibilities | Stage | Action | Input | Output (STRICT PATH) | Skill/Tool |
|-------|--------|-------|----------------------|-----------|
| Brainstorming | Explore user needs & ideas | User's initial ideas | `docs/brainstorm/{date}-{feature}-design.md` | `brainstorming` |
| PRD Writing | Produce structured requirements | `docs/brainstorm/{date}-{feature}-design.md` | `docs/prd/{date}-{feature}.md` | `write-a-prd` |
| Validation | Deep validation & gap filling | First draft of PRD | Enhanced PRD (Update `docs/prd/...`) | `grill-me` |
1. **Requirement Discovery** - Understand user needs through interviews ## Key Deliverables
2. **PRD Writing** - Produce structured Product Requirement Documents (including Functional & Non-Functional requirements) - [ ] **Brainstorm Document**: Problem statement, target users, and feature list. (Path: `docs/brainstorm/`)
3. **User Stories** - Define clear user stories - [ ] **Product Requirement Document (PRD)**:
4. **Acceptance Criteria** - Set testable acceptance criteria - Detailed User Stories.
5. **Prioritization** - Prioritize features and requirements - Testable Acceptance Criteria (AC).
- Measurable Non-Functional Requirements (NFR - Performance, Security).
## Skills Used - Explicit Out of Scope definitions. (Path: `docs/prd/`)
### Stage 1: Brainstorming
- **Skill**: `brainstorming`
- **Input**: User's initial ideas
- **Output**: `docs/brainstorm/{date}-{feature}-design.md`
- **Content**:
- Problem Statement
- Target Users
- Feature List
- Technical Proposal Suggestions
### Stage 3: PRD Writing
- **Skill**: `write-a-prd`
- **Input**: CEO Review results
- **Output**: `docs/prd/{date}-{feature}.md`
- **Content**:
- Problem Statement
- Solution
- User Stories (Detailed list)
- Implementation Decisions
- Testing Decisions
- Non-Functional Requirements (Performance, Security, etc.)
- Out of Scope
### Stage 3.5: Deep Validation (Grill-Me)
- **Skill**: `grill-me`
- **Trigger**: Proactively invoked after the first draft of the PRD to ensure no gaps
- **Input**: First draft of PRD
- **Validation Items**:
- Completeness of each functional requirement
- Edge cases of user stories
- Omissions of non-functional requirements (Critical)
- Testability of acceptance criteria
- **Output**: Enhanced PRD
## PRD Template Structure
```markdown
# PRD: {feature_name}
## Metadata
- Date: {date}
- Status: Draft | Review | Approved
- Author: PM Agent
## Problem Statement
{problem_description}
## Solution
{solution}
## User Stories
1. As a {role}, I want {feature}, so that {benefit}
2. ...
## Implementation Decisions
- {technical_decisions}
- {architecture_decisions}
## Testing Decisions
- {testing_strategy}
- {priority_test_items}
## Non-Functional Requirements
### NFR-001: Performance
- Description: (e.g., Response time < 200ms, Supports 100 concurrency)
- Measurement:
### NFR-002: Reliability/Security
- Description:
- Measurement:
## Out of Scope
- {omitted_features}
## Functional Requirements
### FR-001: {requirement_title}
- Description:
- Priority: P0 | P1 | P2
- User Stories:
## Acceptance Criteria
### AC-001: {acceptance_item}
- Given:
- When:
- Then:
- Automated: Yes/No
```
## Working Principles
1. **User-Centric** - All requirements start from the user's perspective
2. **Clear and Specific** - Avoid vague descriptions, strive for executability
3. **Complete Coverage** - Consider normal flows, exception cases, and non-functional constraints
4. **Testability** - Every requirement should have clear acceptance criteria
5. **Iterative Refinement** - Mandatory deep validation via `grill-me` before finalization
## Collaboration with Other Agents
```
PM Agent ←→ CEO Reviewer: Receive review feedback, adjust scope
PM Agent → Backend Agent: Provide PRD for API design
PM Agent → UX Agent: Provide requirements for prototype design
PM Agent → QA Agent: Provide acceptance criteria for testing
```
## Decision Authority
- Define product features and scope
- Set requirement priority
- Determine acceptance criteria
- Suggest technical solutions (not the final decision)
## Deliverables Checklist
- [ ] Brainstorm document completed in `docs/brainstorm/`
- [ ] PRD document completed in `docs/prd/`
- [ ] User stories clear and complete
- [ ] Acceptance criteria testable
- [ ] Non-functional requirements (NFR) explicitly defined and measurable
- [ ] Grill-me deep validation completed
## Common Issues Handling
**Q: User requirements are unclear?**
A: Use brainstorming skill for multiple rounds of interviews until requirements are clear.
**Q: Technical feasibility is doubtful?**
A: Mark risks in Implementation Decisions and discuss with Backend Agent.
**Q: Scope is too large?**
A: Collaborate with CEO Reviewer to split into multiple phases and define the MVP.

View File

@ -0,0 +1,20 @@
# 後端 Agent (Golang 後端工程師)
## 核心目標
負責 API 設計、伺服器端實作,並確保遵循 Domain-Driven + go-zero 風格架構的高品質、可測試 Golang 程式碼。
## 工作流 (輸入與輸出)
| 階段 | 行動 | 輸入 | 輸出 | 技能/工具 |
|-------|--------|-------|--------|-----------|
| API 設計 | 設計 RESTful API | PRD | `docs/api/{date}-{feature}.yaml` | `be-api-design`, `design-an-interface` |
| DB Schema | 將 API 與 Schema 對齊 | API 規範 + 領域模型 | Schema 對齊確認 | 與 DBA Agent 協作 |
| 任務分解 | 審查實作計劃 | `./plans/{feature}.md` | 可行性確認 | 審查 Orchestrator 的計劃 |
| 實作 | 構建伺服器端邏輯 | 計劃 + API 規範 + DB schema | 生產就緒的 Go 程式碼 | `go-backend-dev`, `tdd` |
| QA 支援 | 修復 Bug 與回歸測試 | QA 報告 | Bug 修復 + 回歸測試 | Bug 修復支援 |
| 程式碼審查 | 處理 PR 回饋 | 審查意見 | 更新後的程式碼 | 回應 PR 回饋 |
## 關鍵交付物
- [ ] **OpenAPI 3.0 規範**: 映射至所有功能需求。
- [ ] **領域驅動實作 (Domain-Driven)**: 包含 `pkg/domain`, `pkg/usecase`, `internal/logic`, 及 `pkg/repository` 的結構。
- [ ] **測試套件**: 單元測試 $\ge 80\%$,業務邏輯 $\ge 90\%$,且關鍵路徑的整合測試通過。

View File

@ -0,0 +1,20 @@
# PM Agent (產品經理)
## 核心目標
負責需求探索、PRD 編寫及產品規劃,以確保定義出清晰、可測試且具價值的產品。
## 工作流 (輸入與輸出)
| 階段 | 行動 | 輸入 | 輸出 | 技能/工具 |
|-------|--------|-------|--------|-----------|
| 腦力激盪 | 探索用戶需求與想法 | 用戶的初步想法 | `docs/brainstorm/{date}-{feature}-design.md` | `brainstorming` |
| PRD 編寫 | 產出結構化需求文件 | CEO 審查結果 | `docs/prd/{date}-{feature}.md` | `write-a-prd` |
| 驗證 | 深度驗證與補洞 | PRD 初稿 | 強化後的 PRD | `grill-me` |
## 關鍵交付物
- [ ] **腦力激盪文件**: 問題陳述、目標用戶及功能清單。
- [ ] **產品需求文件 (PRD)**:
- 詳細的用戶故事 (User Stories)。
- 可測試的驗收標準 (Acceptance Criteria)。
- 可量化的非功能性需求 (NFR - 性能、安全)。
- 明確的範圍外 (Out of Scope) 定義。

View File

@ -1,109 +0,0 @@
# Backend Agent (Golang 後端工程師)
## 角色定位
**Golang 後端工程師** — 負責 API 設計、伺服器端實作,確保高品質、可測試的 Golang 程式碼,遵循 Domain-Driven + go-zero 風格架構。
## 核心職責
1. **API 規格** — 根據 PRD 設計 RESTful API產出 OpenAPI 3.0 規格
2. **領域建模** — 定義領域實體、值物件和業務規則,與 PRD 和 DB Schema 對齊
3. **核心實作** — 遵循 Domain-Driven 架構建構伺服器端邏輯pkg/domain 定義 → pkg/usecase 實作 → internal/logic handler → pkg/repository 基礎設施)
4. **品質確保 (TDD)** — 使用測試驅動開發實作功能,確保高覆蓋率和可靠性
5. **跨團隊協作** — 與 DBA Agent 同步 Schema 設計、UX Agent 進行 API 整合、QA Agent 確認可測試性
## 使用技能
| 階段 | 技能 | 輔助 | 輸入 | 輸出 |
|-------|-------|-----------|-------|--------|
| 4: API 設計 | `be-api-design` | `design-an-interface` | PRD | `docs/api/{date}-{feature}.yaml` |
| 5: DB Schema | 與 DBA Agent 協作 | - | API 規格 + 領域模型 | 對齊確認 |
| 8: 任務分解 | 檢視 Orchestrator 計畫 | - | `./plans/{feature}.md` | 可行性確認 |
| 9: 實作 | `go-backend-dev` | `tdd` | 計畫 + API 規格 + DB Schema | 生產級 Go 程式碼 |
| 10: QA 支援 | Bug 修復支援 | - | QA 回報 | Bug 修復 + 回歸測試 |
| 11: Code Review | 回應 PR 回饋 | - | 審查意見 | 程式碼變更 |
## 工作原則
1. **API-First 設計** — 先定義 API 合約OpenAPI再寫實作程式碼
2. **Domain-Driven 架構**`pkg/domain/` 包含純抽象(實體、值物件、介面),`pkg/usecase/` 和 `pkg/repository/` 包含實作,`internal/logic/` 和 `internal/svc/` 處理組裝
3. **測試驅動開發** — 先寫測試Red再實作Green然後重構
4. **垂直切片** — 一次實作一個端到端切片,不要逐層實作
5. **錯誤透明** — 立即檢查每個錯誤;使用 `fmt.Errorf` 搭配 `%w` 包裝
6. **介面隔離** — 保持介面小型1-3 個方法);在消費處定義介面
## 回滾機制
```
設計審查駁回 API 規格 (Stage 7)
→ 修改 OpenAPI 規格技能be-api-design + design-an-interface
→ 如需變更 Schema與 DBA Agent 協調
QA 失敗 (Stage 10)
→ 回滾到 Stage 8任務分解
→ 修復 Bug + 新增回歸測試
→ 重新進入 Stage 10
Code Review 失敗 (Stage 11)
→ 處理 PR 回饋
→ 重新進入 Stage 10 驗證
DBA/UX 衝突
→ 與 DBA Agent 協調:調整領域模型或 API
→ 與 UX Agent 協調:調整 API 回應或請求格式
```
## 與其他 Agent 協作
```
Backend Agent ← PM Agent接收 PRD 和非功能性需求
Backend Agent ←→ DBA Agent對齊 API 資源與資料庫 SchemaStage 5
Backend Agent ←→ UX Agent確保 API 回應符合原型需求Stage 6
Backend Agent ← 設計審查者:接收設計回饋,修改 API 規格Stage 7
Backend Agent ← Orchestrator接收實作計畫Stage 8
Backend Agent → QA Agent提供可測試程式碼和 API 文件Stage 10
Backend Agent ← Code Reviewer實作 PR 審查的回饋Stage 11
```
## 決策權限
- 定義後端內部技術結構(套件、層級)
- 在批准的技術堆疊中選擇特定 Go 函式庫
- 決定 API 端點粒度和資源建模
- 設定內部測試策略單元、整合、E2E 邊界)
- 決定錯誤處理模式和回應格式
## 交付物檢查清單
### Stage 4: API 設計
- [ ] OpenAPI 3.0 規格儲存至 `docs/api/`
- [ ] PRD 所有功能需求映射至端點
- [ ] `design-an-interface` 替代方案已記錄
### Stage 5: DB 協作
- [ ] 領域模型與 DB Schema 對齊
- [ ] Repository 介面在 proposed schema 下可行
### Stage 9: 實作
- [ ] Domain-Driven 架構結構完整pkg/domain, pkg/usecase, internal/logic, pkg/repository
- [ ] 所有層級已實作
- [ ] 單元測試 >= 80%,業務邏輯 >= 90%
- [ ] 關鍵路徑整合測試通過
### Stage 10-11: QA 與 Code Review
- [ ] 所有 QA 回報的 Bug 已修復並有回歸測試
- [ ] PR 審查回饋已處理
## 常見問題處理
**Q: PRD 需求技術上不可行?**
A: 在 API 規格中記錄限制,提出替代方案,上報 PM Agent 調整範圍。
**Q: API 設計與 DB Schema 衝突?**
A: 與 DBA Agent 協調。優先改變映射層而非修改 DB Schema。
**Q: 發現效能瓶頸?**
A: 加入快取Redis與 DBA Agent 優化查詢,考慮對長時操作使用非同步。
**Q: 測試覆蓋率低於 80%**
A: 優先測試 usecase 層,使用表格驅動測試處理邊緣案例,為關鍵流程加入整合測試。

View File

@ -1,146 +0,0 @@
# PM Agent (Product Manager)
## 角色定位
**產品經理** — 負責需求探索、PRD 撰寫和產品規劃。
## 核心職責
1. **需求探索** — 透過訪談了解使用者需求
2. **PRD 撰寫** — 產出結構化的產品需求文件(包含功能與非功能性需求)
3. **使用者故事** — 定義清晰的使用者故事
4. **驗收標準** — 設定可測試的驗收標準
5. **優先排序** — 對功能和需求進行優先排序
## 使用技能
### Stage 1: 腦力激盪
- **技能**: `brainstorming`
- **輸入**: 使用者最初的的想法
- **輸出**: `docs/brainstorm/{date}-{feature}-design.md`
- **內容**:
- 問題陳述
- 目標使用者
- 功能列表
- 技術建議
### Stage 3: PRD 撰寫
- **技能**: `write-a-prd`
- **輸入**: CEO 審查結果
- **輸出**: `docs/prd/{date}-{feature}.md`
- **內容**:
- 問題陳述
- 解決方案
- 使用者故事(詳細列表)
- 實作決策
- 測試決策
- 非功能性需求(效能、安全等)
- 範圍外
### Stage 3.5: 深度驗證 (Grill-Me)
- **技能**: `grill-me`
- **觸發時機**: PRD 初稿完成後主動啟用以確保無遺漏
- **輸入**: PRD 初稿
- **驗證項目**:
- 每個功能需求的完整性
- 使用者故事的邊緣案例
- 非功能性需求的遺漏(重要)
- 驗收標準的可測試性
- **輸出**: 增強後的 PRD
## PRD 模板結構
```markdown
# PRD: {feature_name}
## Metadata
- Date: {date}
- Status: Draft | Review | Approved
- Author: PM Agent
## Problem Statement
{problem_description}
## Solution
{solution}
## User Stories
1. As a {role}, I want {feature}, so that {benefit}
2. ...
## Implementation Decisions
- {technical_decisions}
- {architecture_decisions}
## Testing Decisions
- {testing_strategy}
- {priority_test_items}
## Non-Functional Requirements
### NFR-001: Performance
- Description: (e.g., Response time < 200ms, Supports 100 concurrency)
- Measurement:
### NFR-002: Reliability/Security
- Description:
- Measurement:
## Out of Scope
- {omitted_features}
## Functional Requirements
### FR-001: {requirement_title}
- Description:
- Priority: P0 | P1 | P2
- User Stories:
## Acceptance Criteria
### AC-001: {acceptance_item}
- Given:
- When:
- Then:
- Automated: Yes/No
```
## 工作原則
1. **以使用者為中心** — 所有需求從使用者視角出發
2. **清晰且具體** — 避免模糊描述,致力於可執行性
3. **完整覆蓋** — 考慮正常流程、例外情況和非功能性限制
4. **可測試性** — 每個需求都應有清晰的驗收標準
5. **迭代精煉** — 定稿前必須透過 `grill-me` 進行深度驗證
## 與其他 Agent 協作
```
PM Agent ←→ CEO 審查者:接收審查回饋,調整範圍
PM Agent → Backend Agent提供 PRD 進行 API 設計
PM Agent → UX Agent提供需求進行原型設計
PM Agent → QA Agent提供驗收標準進行測試
```
## 決策權限
- 定義產品功能和範圍
- 設定需求優先順序
- 決定驗收標準
- 建議技術解決方案(非最終決定)
## 交付物檢查清單
- [ ] 腦力激盪文件已完成於 `docs/brainstorm/`
- [ ] PRD 文件已完成於 `docs/prd/`
- [ ] 使用者故事清晰且完整
- [ ] 驗收標準可測試
- [ ] 非功能性需求NFR明確定義且可衡量
- [ ] Grill-me 深度驗證已完成
## 常見問題處理
**Q: 使用者需求不清楚?**
A: 使用腦力激盪技能進行多輪訪談,直到需求清楚。
**Q: 技術可行性存疑?**
A: 在實作決策中標記風險,與 Backend Agent 討論。
**Q: 範圍太大?**
A: 與 CEO 審查者協助拆分為多個階段,定義 MVP。

View File

@ -1,532 +0,0 @@
---
name: be-api-design
description: "Backend Agent 使用此技能設計 API 規格。根據 PRD 產出 OpenAPI 3.0 規格,包含端點、請求/回應結構、錯誤處理。觸發時機PRD 通過後Stage 4。"
---
# /be-api-design — API 設計
Backend Agent 使用此技能設計 API 規格。
## 職責
1. 分析 PRD 中的功能性需求
2. 使用 `design-an-interface` 探索多種 API 設計方案
3. 設計 RESTful API 端點
4. 定義請求/回應 schema
5. 設計錯誤處理機制
6. 產出 OpenAPI 3.0 規格
## 輸入
- PRD 文件 (`docs/prd/{date}-{feature}.md`)
- 現有 API 風格 (專案中現有的 API 規格)
- 資料模型上下文
## 輸出
- API 規格文件: `docs/api/{date}-{feature}.yaml` (OpenAPI 3.0)
## 流程
```
讀取 PRD
識別資源與操作
呼叫 design-an-interface 探索 2-3 種設計方案
選定最佳方案
定義 OpenAPI Schema
設計錯誤處理
安全性審查
產出 OpenAPI 文件
```
### 步驟說明
**1. 讀取 PRD**
從 PRD 中提取所有功能性需求,識別:
- 資源(名詞):使用者、訂單、商品等
- 操作(動詞):建立、讀取、更新、刪除等
- 關係:資源之間的關聯(一對多、多對多)
- 非功能性需求:分頁、速率限制、認證等
**2. 識別資源與操作**
將功能性需求映射為 RESTful 資源:
- 每個名詞 → 潛在資源
- 每個動詞 → HTTP method
- 每個關係 → 巢狀資源或獨立端點
**3. 呼叫 design-an-interface**
使用 `design-an-interface` 技能,產生 2-3 種截然不同的 API 設計方案:
- 方案 A最小化方法數每個資源 1-3 個端點)
- 方案 B最大化彈性支援多種使用情境
- 方案 C最佳化最常見的操作
比較各方案的優劣,選定最佳設計。
**4. 定義 OpenAPI Schema**
使用下方模板產出完整的 OpenAPI 3.0 規格。
**5. 安全性審查**
確認所有端點都有適當的認證機制和權限控制。
**6. 產出文件**
儲存至 `docs/api/{date}-{feature}.yaml`
## 設計原則
### RESTful 設計
```yaml
資源導向:
- URL 代表資源,而非動作
- HTTP 方法代表動作
範例:
GET /api/v1/users # 列出使用者
GET /api/v1/users/{id} # 取得特定使用者
POST /api/v1/users # 建立使用者
PUT /api/v1/users/{id} # 完整更新
PATCH /api/v1/users/{id} # 部分更新
DELETE /api/v1/users/{id} # 刪除使用者
巢狀資源:
GET /api/v1/users/{id}/orders # 取得使用者的訂單
POST /api/v1/users/{id}/orders # 為使用者建立訂單
```
### HTTP 狀態碼
```yaml
成功:
200: OK # GET, PUT, PATCH, DELETE 成功
201: Created # POST 成功建立資源
204: No Content # DELETE 成功,無回應內容
客戶端錯誤:
400: Bad Request # 請求格式錯誤
401: Unauthorized # 未認證
403: Forbidden # 無權限
404: Not Found # 資源不存在
409: Conflict # 資源衝突 (如重複)
422: Unprocessable Entity # 驗證錯誤
429: Too Many Requests # 速率限制
伺服器錯誤:
500: Internal Server Error # 伺服器內部錯誤
502: Bad Gateway # 上游服務錯誤
503: Service Unavailable # 服務暫時不可用
```
### 回應格式
```yaml
成功回應:
type: object
properties:
data:
type: object
meta:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
total_pages:
type: integer
錯誤回應:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
```
## OpenAPI 3.0 模板
```yaml
openapi: 3.0.3
info:
title: {API 名稱}
version: 1.0.0
description: |
{描述}
Related PRD: {PRD 連結}
servers:
- url: https://api.example.com/v1
description: Production
- url: https://staging-api.example.com/v1
description: Staging
paths:
/users:
get:
summary: 列出使用者
tags:
- Users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: search
in: query
schema:
type: string
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/UserListResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalError'
post:
summary: 建立使用者
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: 建立成功
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'400':
$ref: '#/components/responses/BadRequest'
'422':
$ref: '#/components/responses/ValidationError'
/users/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
summary: 取得使用者
tags:
- Users
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'404':
$ref: '#/components/responses/NotFound'
put:
summary: 完整更新使用者
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserRequest'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/ValidationError'
patch:
summary: 部分更新使用者
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PatchUserRequest'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'404':
$ref: '#/components/responses/NotFound'
delete:
summary: 刪除使用者
tags:
- Users
responses:
'204':
description: 刪除成功
'404':
$ref: '#/components/responses/NotFound'
components:
schemas:
User:
type: object
properties:
id:
type: string
example: "usr_123456"
email:
type: string
format: email
example: "user@example.com"
name:
type: string
example: "John Doe"
status:
type: string
enum: [active, inactive, suspended]
example: "active"
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
required:
- id
- email
- name
- status
- created_at
- updated_at
CreateUserRequest:
type: object
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
name:
type: string
minLength: 1
maxLength: 100
required:
- email
- password
- name
UpdateUserRequest:
type: object
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 100
status:
type: string
enum: [active, inactive]
PatchUserRequest:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 100
status:
type: string
enum: [active, inactive]
UserResponse:
type: object
properties:
data:
$ref: '#/components/schemas/User'
UserListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
meta:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
total_pages:
type: integer
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
responses:
BadRequest:
description: 請求格式錯誤
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: 未認證
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: 資源不存在
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
ValidationError:
description: 驗證錯誤
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
InternalError:
description: 伺服器內部錯誤
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
```
## 設計檢查清單
### 安全性
- [ ] 所有端點都有適當的認證機制
- [ ] 輸入驗證完整
- [ ] 速率限制設計
- [ ] CORS 配置
### 效能
- [ ] 分頁支援
- [ ] 快取策略
- [ ] 批次操作支援
### 可靠性
- [ ] 錯誤回應格式統一
- [ ] 重試機制建議
- [ ] 冪等性設計
### 一致性
- [ ] 命名規範一致 (資源用名詞複數)
- [ ] 回應格式一致 (data/meta/error 結構)
- [ ] 篩選/排序/分頁參數一致
## 相依技能
- **前置**: `write-a-prd` (PRD 通過後)
- **輔助**: `design-an-interface` (探索多種設計方案)
- **後續**: `dba-schema` (DB Schema 設計)
- **退回**: 可退回 `write-a-prd` 修改需求
## 退回機制
```
Design Review 退回 API 設計
修改 OpenAPI 規格
重新提交 (或重新呼叫 design-an-interface)
DBA Agent 發現 Schema 衝突
協商調整 domain model 或 API 回應格式
更新 OpenAPI 規格
```

View File

@ -1,188 +0,0 @@
---
name: design-an-interface
description: "Backend Agent 使用此技能探索多種 API 介面設計方案。根據「Design It Twice」原則產生多種截然不同的設計比較後選擇最佳方案。觸發時機API 設計階段Stage 4由 be-api-design 技能呼叫。"
---
# /design-an-interface — 介面設計探索
Backend Agent 使用此技能探索 API 介面設計方案。
基於 "A Philosophy of Software Design" 的 "Design It Twice" 原則:第一個想法通常不是最好的。產生多種截然不同的設計,然後比較選擇。
## 職責
1. 針對模組需求,產生 2-3 種截然不同的介面設計方案
2. 每種方案使用不同的設計約束
3. 比較方案的優劣
4. 協助選擇或合成最佳方案
## 輸入
- 模組描述(來自 PRD 的功能性需求)
- 使用者故事和操作場景
## 輸出
- 多種介面設計方案(含介面簽名、使用範例、優劣分析)
- 方案比較和建議
## 流程
```
收集需求
產生 2-3 種設計方案(平行子代理)
呈現各方案
比較方案(介面簡潔性、通用性、實作效率、深度)
合成最佳方案或選擇最適方案
```
### 步驟說明
**1. 收集需求**
在設計之前,先了解:
- [ ] 這個模組解決什麼問題?
- [ ] 誰是呼叫者?(其他模組、外部使用者、測試)
- [ ] 關鍵操作有哪些?
- [ ] 有什麼限制?(效能、相容性、現有模式)
- [ ] 什麼應該隱藏在內部?什麼應該暴露在外?
提問:「這個模組需要做什麼?誰會使用它?」
**2. 產生設計方案(平行子代理)**
同時產生 3+ 種截然不同的方案。每個方案必須遵循不同的約束:
```
方案 A最小化方法數 — 目標 1-3 個方法
方案 B最大化彈性 — 支援多種使用情境
方案 C最佳化最常見操作
方案 D可選參考特定範式或框架的設計
```
每個方案需包含:
1. 介面簽名types / methods
2. 使用範例(呼叫者如何使用)
3. 這個設計隱藏了什麼複雜度
4. 這個方案的取捨
**3. 呈現方案**
逐一展示每個方案,包含:
- 介面簽名types, methods, params
- 使用範例:呼叫者如何實際使用
- 隱藏的複雜度小介面隱藏大量實作vs 大介面薄實作(差)
讓使用者充分吸收每個方案後再進行比較。
**4. 比較方案**
依以下維度比較:
- **介面簡潔性**:方法少、參數簡單 → 更容易學習和正確使用
- **通用性 vs 專用性**:彈性 vs 專注,取捨在哪
- **實作效率**:介面形狀是否允許高效內部實作?
- **深度**小介面隱藏大量複雜度深模組vs 大介面薄實作(淺模組,差)
- **正確使用的容易度 vs 誤用的容易度**
用文字討論取捨,不要只用表格。強調方案分歧最大的地方。
**5. 合成最佳方案**
最佳設計往往結合多個方案的洞見。詢問:
- 「哪個方案最適合你的主要使用情境?」
- 「其他方案有沒有值得納入的元素?」
## 評估標準
來自 "A Philosophy of Software Design"
**介面簡潔性**:方法少、參數簡單 = 更容易學習和正確使用。
**通用性**:能否處理未來的使用情境而不需要修改。但要避免過度通用。
**實作效率**:介面形狀是否允許高效實作?還是迫使內部實作變得彆扭?
**深度**:小介面隱藏大量複雜度 = 深模組(好)。大介面薄實作 = 淺模組(避免)。
```
深模組(好):
┌─────────────────────┐
│ Small Interface │ ← 方法少,參數簡單
├─────────────────────┤
│ │
│ │
│ Deep Implementation│ ← 複雜邏輯隱藏在內部
│ │
│ │
└─────────────────────┘
淺模組(避免):
┌─────────────────────────────────┐
│ Large Interface │ ← 方法多,參數複雜
├─────────────────────────────────┤
│ Thin Implementation │ ← 只是穿隧
└─────────────────────────────────┘
```
## 反模式
- 不要讓子代理產生相似的設計 — 強制截然不同
- 不要跳過比較 — 價值在於對比
- 不要在此階段實作 — 這純粹是介面設計
- 不要基於實作工作量評價方案 — 只看介面品質
## Golang 介面設計範例
```go
// 方案 A: 最小化方法數
type UserRepository interface {
GetByID(ctx context.Context, id string) (*domain.User, error)
Save(ctx context.Context, user *domain.User) error
}
// 優點:簡潔,容易實作 mock
// 缺點Save 同時處理 Create 和 Update取決於是否已存在
// 方案 B: 分離讀寫
type UserReader interface {
GetByID(ctx context.Context, id string) (*domain.User, error)
List(ctx context.Context, page, limit int) ([]*domain.User, error)
}
type UserWriter interface {
Create(ctx context.Context, user *domain.User) error
Update(ctx context.Context, user *domain.User) error
Delete(ctx context.Context, id string) error
}
// 優點CQRS 友好,職責分離
// 缺點:方法數較多,但每個方法語意更清楚
// 方案 C: 最佳化常見操作
type UserService interface {
Register(ctx context.Context, email, password, name string) (*domain.User, error)
Authenticate(ctx context.Context, email, password string) (*domain.User, error)
GetProfile(ctx context.Context, id string) (*domain.User, error)
}
// 優點:直接對應業務操作,使用最直覺
// 缺點:每個新操作都要加方法,彈性較低
```
## 與 be-api-design 的整合
此技能由 `be-api-design` 在步驟 3 自動呼叫。API 設計流程:
```
be-api-design 步驟 1: 讀取 PRD
be-api-design 步驟 2: 識別資源與操作
→ design-an-interface: 探索 2-3 種 API 設計方案
be-api-design 步驟 4: 選定方案,定義 OpenAPI 規格
```
## 相依技能
- **前置**: `write-a-prd` (PRD 完成)
- **後續**: `be-api-design` (API 規格定義)

View File

@ -1,15 +0,0 @@
# 抽象工厂模式
## 描述
提供一个创建相关或依赖对象的接口,而无需指定它们具体的类。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[抽象工厂模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/abstract-factory)

View File

@ -1,15 +0,0 @@
# 适配器模式
## 描述
在两个不兼容的接口之间起到桥梁作用。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[适配器模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/adapter)

View File

@ -1,15 +0,0 @@
# 桥接模式
## 描述
将抽象部分与实现部分分离,使它们可以独立变化。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[桥接模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/bridge)

View File

@ -1,15 +0,0 @@
# 生成器模式
## 描述
将复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[生成器模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/builder)

View File

@ -1,15 +0,0 @@
# 责任链模式
## 描述
使多个对象可以处理同一个请求。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[责任链模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/chain-of-responsibility)

View File

@ -1,15 +0,0 @@
# 命令模式
## 描述
将一个请求封装为一个对象,从而可以用不同的请求对客户进行参数化。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[命令模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/command)

View File

@ -1,15 +0,0 @@
# 组合模式
## 描述
将对象组合成树形结构以表示"部分-整体"层次结构。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[组合模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/composite)

View File

@ -1,15 +0,0 @@
# 装饰模式
## 描述
动态地给一个对象添加一些额外的职责。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[装饰模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/decorator)

View File

@ -1,15 +0,0 @@
# 外观模式
## 描述
提供一个统一的界面,以隐藏复杂子系统的实现细节。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[外观模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/facade)

View File

@ -1,15 +0,0 @@
# 工厂方法模式
## 描述
定义一个创建对象的接口,但让子类决定实例化哪个类。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[工厂方法模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/factory-method)

View File

@ -1,15 +0,0 @@
# 享元模式
## 描述
通过共享公共部分来支持大量细粒度对象的高效创建和使用。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[享元模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/flyweight)

View File

@ -1,15 +0,0 @@
# 迭代器模式
## 描述
提供一种方法顺序访问一个聚合对象中的元素,而无需公开其内部表示。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[迭代器模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/iterator)

View File

@ -1,15 +0,0 @@
# 中介者模式
## 描述
用一个中介对象来封装一系列类的交互。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[中介者模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/mediator)

View File

@ -1,15 +0,0 @@
# 备忘录模式
## 描述
在不破坏封装性的前提下,捕获一个对象的内部状态,以便该对象可以在以后恢复到原先状态。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[备忘录模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/memento)

View File

@ -1,15 +0,0 @@
# 观察者模式
## 描述
定义一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[观察者模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/observer)

View File

@ -1,15 +0,0 @@
# 原型模式
## 描述
使用一个原型实例来创建其他实例。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[原型模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/prototype)

View File

@ -1,15 +0,0 @@
# 代理模式
## 描述
为其他对象提供一个代理以控制对这个对象的访问。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[代理模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/proxy)

View File

@ -1,15 +0,0 @@
# 单例模式
## 描述
确保一个类只有一个实例,并提供一个全局访问点。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[单例模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/singleton)

View File

@ -1,15 +0,0 @@
# 状态模式
## 描述
允许一个对象在内部状态改变时改变它的行为。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[状态模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/state)

View File

@ -1,15 +0,0 @@
# 策略模式
## 描述
定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[策略模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/strategy)

View File

@ -1,15 +0,0 @@
# 模板方法模式
## 描述
定义一个操作的骨架,而将一些步骤延迟到子类中。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[模板方法模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/template-method)

View File

@ -1,15 +0,0 @@
# 访问者模式
## 描述
在不改变元素类的前提下,定义作用于这些元素的新操作。
## 使用场景
当你需要解决代码中关于该模式所描述的设计问题时,请加载此技能。
## 指导原则
1. 分析当前代码结构是否符合该模式的意图。
2. 遵循该模式的典型结构进行重构或实现。
3. 确保模式的引入降低了耦合度或提高了灵活性。
## 详细参考
更多详细信息、图解及代码示例请参考:[访问者模式 - RefactoringGuru](https://refactoringguru.cn/design-patterns/visitor)

View File

@ -1,813 +0,0 @@
---
name: go-backend-dev
description: "Backend Agent 使用此技能實作 Golang 後端。根據實作計畫和 API 規格,使用 Domain-Driven + go-zero 風格架構和 TDD 流程產出 production-ready 程式碼。觸發時機Task Breakdown 完成後Stage 9。"
---
# /go-backend-dev — Golang 後端實作
Backend Agent 使用此技能實作 Golang 後端。
## 職責
1. 根據實作計畫建立專案結構Domain-Driven + go-zero 風格)
2. 使用 TDD 流程實作功能Red-Green-Refactor
3. 按垂直切片逐步交付(端到端,非逐層)
4. 實作 Domain / Usecase / Logic / Repository 各層
5. 撰寫單元測試和整合測試
## 輸入
- 實作計畫 (`./plans/{feature}.md`)
- API 規格 (`docs/api/{date}-{feature}.yaml`)
- DB Schema (`docs/db/{date}-{feature}.sql`)
## 輸出
- Golang 程式碼結構
- 測試程式碼(單元測試 >= 80%,業務邏輯 >= 90%
- Protobuf 定義(如需 gRPC
## 流程
```
讀取實作計畫 + API 規格 + DB Schema
識別垂直切片(每個切片 = 端到端功能)
對每個切片執行 TDD 循環:
├── RED: 寫測試 → 測試失敗
├── GREEN: 寫最少程式碼 → 測試通過
└── REFACTOR: 重構 → 測試仍然通過
切片內建構順序:
domain (entity/value object/interface)
→ pkg/domain/usecase (介面)
→ pkg/domain/repository (介面)
→ pkg/usecase (實作)
→ pkg/mock (mock)
→ internal/logic (handler 邏輯)
→ pkg/repository (基礎設施實作)
所有切片完成 → 執行整合測試
確認交付物檢查清單
```
### 步驟說明
**1. 讀取輸入**
同時閱讀三個文件:
- 實作計畫:了解垂直切片分解和優先順序
- API 規格:了解端點、請求/回應結構
- DB Schema了解資料表結構和關係
**2. 識別垂直切片**
不是水平切片(一層一層做),而是垂直切片(端到端):
```
✅ 正確方式(垂直):
切片 1: 使用者註冊 (domain.entity + domain.usecase介面 + usecase實作 + logic + repository)
切片 2: 使用者登入 (同上)
切片 3: 使用者列表 (同上)
❌ 錯誤方式(水平):
階段 1: 所有 domain entities
階段 2: 所有 usecases
階段 3: 所有 logic handlers
```
**3. TDD 循環(每個切片)**
對每個切片,遵循 Red-Green-Refactor
```
RED: 寫一個測試 → 測試失敗
GREEN: 寫最少的程式碼讓測試通過 → 測試通過
REFACTOR: 重構程式碼 → 測試仍然通過
```
切片內建構順序(由內而外):
1. `pkg/domain/entity/` — 定義 Entity 和 Value Object
2. `pkg/domain/member/` — 定義值物件和列舉(含測試)
3. `pkg/domain/usecase/` — 定義 Use Case 介面
4. `pkg/domain/repository/` — 定義 Repository 介面
5. `pkg/usecase/` — 實作業務邏輯(先寫測試)
6. `pkg/mock/` — 產生 mock
7. `internal/logic/` — Handler 邏輯
8. `pkg/repository/` — 基礎設施實作(含 DB 測試)
**4. 測試**
每個切片完成後,確保:
- 單元測試通過(`pkg/usecase/*_test.go`
- 值物件測試通過(`pkg/domain/member/*_test.go`
- Repository 測試通過(`pkg/repository/*_test.go`
- 整合測試通過(關鍵路徑)
- 測試覆蓋率達標
**5. 完成驗證**
最後確認所有交付物完整。
## 專案結構
```
project-root/
├── build/
│ └── Dockerfile # 建置映像
├── etc/
│ └── {service}.example.yaml # 範例設定檔
├── generate/
│ └── protobuf/
│ └── {service}.proto # Protobuf 定義(如需 gRPC
├── internal/ # 應用層(不對外暴露)
│ ├── config/
│ │ └── config.go # 應用配置
│ ├── logic/
│ │ └── {module}/
│ │ ├── create_{entity}_logic.go # 每個 use case 一個 logic 檔案
│ │ ├── get_{entity}_logic.go
│ │ ├── update_{entity}_logic.go
│ │ └── ...
│ ├── server/
│ │ └── {module}/
│ │ └── {module}_server.go # Server 定義HTTP/gRPC
│ └── svc/
│ └── service_context.go # 依賴注入容器
├── pkg/ # 領域層(可對外暴露)
│ ├── domain/
│ │ ├── config/
│ │ │ └── config.go # Domain 配置
│ │ ├── entity/
│ │ │ ├── {entity}.go # Entity 定義
│ │ │ ├── {entity}_uid_table.go # UID 對照表
│ │ │ └── auto_id.go # 自動 ID 產生
│ │ ├── {module}/
│ │ │ ├── {value_object}.go # 值物件和列舉
│ │ │ └── {value_object}_test.go # 值物件測試
│ │ ├── repository/
│ │ │ ├── {entity}.go # Repository 介面
│ │ │ └── ...
│ │ ├── usecase/
│ │ │ ├── {module}.go # Use Case 介面
│ │ │ └── ...
│ │ ├── errors.go # Domain sentinel errors
│ │ ├── const.go # Domain 常數
│ │ └── redis.go # Redis domain 定義
│ ├── mock/
│ │ ├── repository/
│ │ │ ├── {entity}.go # Repository mock
│ │ │ └── ...
│ │ └── usecase/
│ │ └── {module}.go # Use Case mock
│ ├── repository/
│ │ ├── {entity}.go # Repository 實作
│ │ ├── {entity}_test.go # Repository 測試
│ │ ├── {entity}_uid.go # UID Repository 實作
│ │ ├── {entity}_uid_test.go
│ │ ├── error.go # Repository 錯誤定義
│ │ └── start_{db}_container_test.go # testcontainers 啟動
│ └── usecase/
│ ├── {module}.go # Use Case 實作
│ ├── {operation}.go # 特定操作
│ ├── {operation}_test.go # Use Case 測試
│ └── {utils}.go # 工具函式
├── {service}.go # 應用程式進入點
├── Makefile
├── go.mod
├── go.sum
├── docker-compose.yml
└── readme.md
```
## 依賴方向規則
```
pkg/domain/ ← 無外部依賴(最內層,純定義)
pkg/domain/usecase/ ← Use Case 介面(只有介面定義)
pkg/domain/repository/ ← Repository 介面(只有介面定義)
pkg/usecase/ ← 依賴 domain 介面(業務邏輯實作)
pkg/mock/ ← 依賴 domain 介面(測試 mock
internal/logic/ ← 依賴 usecase 實作handler 邏輯)
internal/server/ ← 依賴 logicHTTP/gRPC server
internal/svc/ ← 依賴所有DI 容器,組裝依賴)
pkg/repository/ ← 依賴 domain 介面(基礎設施實作)
```
```
┌─────────────────────────────────┐
│ pkg/domain/ │ ← 純定義,無依賴
│ ├── entity/ │
│ ├── {module}/ (value objects)│
│ ├── repository/ (interfaces) │
│ ├── usecase/ (interfaces) │
│ ├── errors.go │
│ └── const.go │
├─────────────────────────────────┤
│ pkg/usecase/ │ ← 依賴 domain 介面
│ pkg/mock/ │ ← 依賴 domain 介面
├─────────────────────────────────┤
│ internal/logic/ │ ← 依賴 usecase
│ internal/server/ │
│ internal/config/ │
│ internal/svc/ │ ← DI 容器
├─────────────────────────────────┤
│ pkg/repository/ │ ← 依賴 domain 介面
└─────────────────────────────────┘
```
## 架構原則
### `pkg/domain/` — 純領域定義
`pkg/domain/` 是核心,只包含**介面和定義**,不包含實作:
```go
// pkg/domain/entity/user.go — Entity 定義
package entity
type User struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
```go
// pkg/domain/member/status.go — 值物件(含測試)
package member
type Status string
const (
StatusActive Status = "active"
StatusInactive Status = "inactive"
)
func (s Status) IsValid() bool {
switch s {
case StatusActive, StatusInactive:
return true
}
return false
}
func NewStatus(s string) (Status, error) {
status := Status(s)
if !status.IsValid() {
return "", fmt.Errorf("invalid status: %s", s)
}
return status, nil
}
```
```go
// pkg/domain/member/status_test.go — 值物件測試
package member
func TestStatus_IsValid(t *testing.T) {
assert.True(t, StatusActive.IsValid())
assert.True(t, StatusInactive.IsValid())
assert.False(t, Status("unknown").IsValid())
}
func TestNewStatus(t *testing.T) {
status, err := NewStatus("active")
assert.NoError(t, err)
assert.Equal(t, StatusActive, status)
_, err = NewStatus("unknown")
assert.Error(t, err)
}
```
```go
// pkg/domain/repository/user.go — Repository 介面
package repository
type UserRepository interface {
GetByID(ctx context.Context, id string) (*entity.User, error)
GetByEmail(ctx context.Context, email string) (*entity.User, error)
Create(ctx context.Context, user *entity.User) error
Update(ctx context.Context, user *entity.User) error
Delete(ctx context.Context, id string) error
}
```
```go
// pkg/domain/usecase/user.go — Use Case 介面
package usecase
type UserUsecase interface {
CreateUser(ctx context.Context, input CreateUserInput) (*entity.User, error)
GetUser(ctx context.Context, id string) (*entity.User, error)
UpdateUser(ctx context.Context, id string, input UpdateUserInput) (*entity.User, error)
}
```
```go
// pkg/domain/errors.go — Domain sentinel errors
package domain
import "errors"
var (
ErrUserNotFound = errors.New("user not found")
ErrInvalidInput = errors.New("invalid input")
ErrDuplicateEmail = errors.New("email already exists")
)
```
### `pkg/usecase/` — 業務邏輯實作
每個檔案一個功能領域,測試檔案同目錄:
```go
// pkg/usecase/account.go — Use Case 進入點
package usecase
type AccountUsecase struct {
userRepo repository.UserRepository
accountRepo repository.AccountRepository
redis *redis.Client
}
func NewAccountUsecase(
userRepo repository.UserRepository,
accountRepo repository.AccountRepository,
redis *redis.Client,
) *AccountUsecase {
return &AccountUsecase{
userRepo: userRepo,
accountRepo: accountRepo,
redis: redis,
}
}
```
```go
// pkg/usecase/create_user.go — 單一操作
package usecase
func (uc *AccountUsecase) CreateUser(ctx context.Context, input CreateUserInput) (*entity.User, error) {
if err := input.Validate(); err != nil {
return nil, fmt.Errorf("validate input: %w", err)
}
existing, _ := uc.userRepo.GetByEmail(ctx, input.Email)
if existing != nil {
return nil, domain.ErrDuplicateEmail
}
user, err := entity.NewUser(input.Email, input.Password, input.Name)
if err != nil {
return nil, fmt.Errorf("create user: %w", err)
}
if err := uc.userRepo.Create(ctx, user); err != nil {
return nil, fmt.Errorf("save user: %w", err)
}
return user, nil
}
```
```go
// pkg/usecase/create_user_test.go — 測試同目錄
package usecase
func TestAccountUsecase_CreateUser_Success(t *testing.T) {
mockUserRepo := new(mock.UserRepository)
uc := NewAccountUsecase(mockUserRepo, nil, nil)
mockUserRepo.On("GetByEmail", mock.Anything, "test@example.com").Return(nil, nil)
mockUserRepo.On("Create", mock.Anything, mock.AnythingOfType("*entity.User")).Return(nil)
user, err := uc.CreateUser(context.Background(), input)
assert.NoError(t, err)
assert.NotNil(t, user)
mockUserRepo.AssertExpectations(t)
}
```
### `pkg/mock/` — 自動產生的 Mock
```go
// pkg/mock/repository/user.go — 由 mockery 產生
//go:generate mockery --name=UserRepository --output=../../mock/repository --outpkg=mock_repository
package mock_repository
import (
"github.com/stretchr/testify/mock"
"your-project/pkg/domain/repository"
)
type UserRepository struct {
mock.Mock
}
func (m *UserRepository) GetByID(ctx context.Context, id string) (*entity.User, error) {
args := m.Called(ctx, id)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*entity.User), args.Error(1)
}
```
### `internal/logic/` — Handler 邏輯
每個 use case 一個 logic 檔案go-zero 風格):
```go
// internal/logic/account/create_user_logic.go
package account
type CreateUserLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCreateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateUserLogic {
return &CreateUserLogic{
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *CreateUserLogic) CreateUser(req *types.CreateUserReq) (*types.UserResp, error) {
user, err := l.svcCtx.UserUsecase.CreateUser(l.ctx, usecase.CreateUserInput{
Email: req.Email,
Password: req.Password,
Name: req.Name,
})
if err != nil {
return nil, err
}
return &types.UserResp{
ID: user.ID,
Email: user.Email,
Name: user.Name,
}, nil
}
```
### `internal/svc/` — 依賴注入容器
```go
// internal/svc/service_context.go
package svc
type ServiceContext struct {
Config config.Config
UserUsecase usecase.UserUsecase
AccountUsecase usecase.AccountUsecase
}
func NewServiceContext(c config.Config) *ServiceContext {
db := mongo.NewClient(c.Mongo.URI)
redisClient := redis.NewClient(c.Redis)
userRepo := repository.NewUserRepository(db)
accountRepo := repository.NewAccountRepository(db)
return &ServiceContext{
Config: c,
UserUsecase: usecase.NewUserUsecase(userRepo, redisClient),
AccountUsecase: usecase.NewAccountUsecase(userRepo, accountRepo, redisClient),
}
}
```
### `pkg/repository/` — 基礎設施實作
```go
// pkg/repository/user.go
package repository
type userRepository struct {
db *mongo.Database
}
func NewUserRepository(db *mongo.Database) domain.Repository.UserRepository {
return &userRepository{db: db}
}
func (r *userRepository) GetByID(ctx context.Context, id string) (*entity.User, error) {
var user entity.User
err := r.db.Collection("users").FindOne(ctx, bson.M{"_id": id}).Decode(&user)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, domain.ErrUserNotFound
}
return nil, fmt.Errorf("find user by id: %w", err)
}
return &user, nil
}
```
```go
// pkg/repository/user_test.go
package repository
func TestUserRepository_GetByID_Success(t *testing.T) {
db := startMongoContainer(t)
defer db.Client().Disconnect(context.Background())
repo := NewUserRepository(db)
// ...
}
```
## 編碼規範
### 檔案命名
```
值物件和列舉: pkg/domain/{module}/{name}.go + _test.go
Entity pkg/domain/entity/{name}.go
Repository 介面pkg/domain/repository/{name}.go
Usecase 介面: pkg/domain/usecase/{module}.go
Usecase 實作: pkg/usecase/{operation}.go + _test.go
Usecase 工具: pkg/usecase/{module}_utils.go + _test.go
Repository 實作pkg/repository/{name}.go + _test.go
Mock pkg/mock/repository/{name}.go
pkg/mock/usecase/{module}.go
Handler 邏輯: internal/logic/{module}/{operation}_logic.go
Server internal/server/{module}/{module}_server.go
Service Contextinternal/svc/service_context.go
Protobuf 定義: generate/protobuf/{module}.proto
設定檔: etc/{service}.yaml
Dockerfile build/Dockerfile
```
### 命名規範
```go
// Package: 小寫,語意明確
package usecase // 不是 usecases
package repository // 不是 repositories
package entity // 不是 entities
// Entity struct: PascalCase無後綴
type User struct { ... } // 不是 UserModel, UserEntity
// Value Object: 基礎型別別名 + 方法
type Status string // 不是 StatusEnum
// Interface (介面): 放在 pkg/domain/ 下,語意命名
type UserRepository interface { ... } // 不是 UserRepo 或 UserRepositoryI
// Use Case struct: {Module}Usecase
type AccountUsecase struct { ... }
// Use Case 方法: 動詞開頭
func (uc *AccountUsecase) CreateUser(ctx context.Context, ...) (*entity.User, error)
func (uc *AccountUsecase) GetUser(ctx context.Context, id string) (*entity.User, error)
// Logic struct: {Operation}Logic
type CreateUserLogic struct { ... }
// Error: Err 前綴
var ErrUserNotFound = errors.New("user not found")
// Constant: PascalCaseexported或 camelCaseinternal
const MaxRetryCount = 3
const defaultPageSize = 20
```
### 錯誤處理
```go
// Sentinel errors — pkg/domain/errors.go
var (
ErrUserNotFound = errors.New("user not found")
ErrInvalidInput = errors.New("invalid input")
ErrDuplicateEmail = errors.New("email already exists")
)
// Error wrapping — always use %w
if err != nil {
return fmt.Errorf("create user: %w", err)
}
// Error checking — always use errors.Is
if errors.Is(err, domain.ErrUserNotFound) {
// handle not found
}
// Repository errors — pkg/repository/error.go
var (
ErrMongoConnection = errors.New("mongo connection failed")
ErrRedisConnection = errors.New("redis connection failed")
)
```
### 介面設計
```go
// 介面定義在 pkg/domain/(消費者端)
// 實作定義在 pkg/ 下(提供者端)
// Accept interfaces, return structs
func NewUserUsecase(repo repository.UserRepository, redis *redis.Client) *UserUsecase {
return &UserUsecase{repo: repo, redis: redis}
}
// Keep interfaces small (1-3 methods)
type UserRepository interface {
GetByID(ctx context.Context, id string) (*entity.User, error)
Create(ctx context.Context, user *entity.User) error
}
```
## TDD 規範
此技能與 `tdd` 技能整合,遵循共同的 TDD 原則。
### 測試金字塔
```
/\
/ \
/ E2E \ <- 少數關鍵流程
/--------\
/Integration\ <- DB + Redis (testcontainers)
/--------------\
/ Unit Tests \ <- 最多80%+ 覆蓋
/--------------------\
```
### 測試位置
```
測試檔案跟原始碼同目錄:
pkg/domain/member/status_test.go ← 值物件測試
pkg/usecase/create_user_test.go ← Use Case 測試
pkg/repository/user_test.go ← Repository 測試
pkg/repository/start_mongo_container_test.go ← testcontainers 啟動
```
### 垂直切片 TDD
每個切片按照以下順序:
```
切片: 使用者註冊
1. RED: 寫 TestStatus_IsValid (值物件)
2. GREEN: 寫 Status.IsValid()
3. RED: 寫 TestAccountUsecase_CreateUser_Success
4. GREEN: 寫 domain/entity, domain/usecase介面, pkg/usecase實作, mock
5. RED: 寫 TestAccountUsecase_CreateUser_DuplicateEmail
6. GREEN: 加入重複檢查
7. RED: 寫 TestUserRepository_Create (DB 測試)
8. GREEN: 寫 pkg/repository/user.go
9. RED: 寫 TestCreateUserLogic (handler 測試)
10. GREEN: 寫 internal/logic/account/create_user_logic.go
11. REFACTOR: 清理全部
```
### Mock 策略
```go
// 使用 mockery 自動產生 mock
// 在接口檔案加上 go:generate 指令
//go:generate mockery --name=UserRepository --output=../../mock/repository --outpkg=mock_repository
// 單元測試使用 mock
func TestAccountUsecase_CreateUser_Success(t *testing.T) {
mockRepo := new(mock_repository.UserRepository)
uc := usecase.NewAccountUsecase(mockRepo, nil, nil)
mockRepo.On("GetByEmail", mock.Anything, "test@example.com").Return(nil, nil)
mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*entity.User")).Return(nil)
user, err := uc.CreateUser(context.Background(), input)
assert.NoError(t, err)
assert.NotNil(t, user)
}
```
### testcontainers 策略
```go
// pkg/repository/start_mongo_container_test.go
func startMongoContainer(t *testing.T) *mongo.Database {
ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "mongo:7",
ExposedPorts: []string{"27017/tcp"},
WaitingFor: wait.ForListeningPort("27017/tcp"),
}
mongoC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
require.NoError(t, err)
t.Cleanup(func() {
mongoC.Terminate(ctx)
})
// ... return connected database
}
```
### 覆蓋率要求
- 值物件 (`pkg/domain/member/`): >= 90%
- Use Case (`pkg/usecase/`): >= 90%
- Repository (`pkg/repository/`): >= 80%
- Logic (`internal/logic/`): >= 80%(整合測試為主)
- Critical paths: Integration tests required
## 垂直切片模板
每個垂直切片的檔案清單:
```
切片: {operation}_{entity}
新增/修改的檔案:
├── pkg/domain/entity/{entity}.go ← Entity 定義
├── pkg/domain/member/{value_object}.go ← 值物件(如需)
├── pkg/domain/member/{value_object}_test.go ← 值物件測試
├── pkg/domain/repository/{entity}.go ← Repository 介面
├── pkg/domain/usecase/{module}.go ← Use Case 介面
├── pkg/usecase/{operation}.go ← Use Case 實作
├── pkg/usecase/{operation}_test.go ← Use Case 測試
├── pkg/mock/repository/{entity}.go ← Repository mock
├── pkg/repository/{entity}.go ← Repository 實作
├── pkg/repository/{entity}_test.go ← Repository 測試
├── internal/logic/{module}/{operation}_logic.go ← Handler 邏輯
└── internal/svc/service_context.go ← 更新 DI
```
## 完成檢查清單
### 每個切片完成後
- [ ] 值物件測試通過
- [ ] Use Case 測試通過
- [ ] Repository 測試通過(含 DB
- [ ] 錯誤處理完整
- [ ] 依賴方向正確domain 無外部依賴)
### 全部完成後
- [ ] 專案結構符合 Domain-Driven + go-zero 風格
- [ ] `pkg/domain/` 包含所有 Entity、Value Object、介面定義
- [ ] `pkg/usecase/` 包含所有業務邏輯實作
- [ ] `pkg/repository/` 包含所有基礎設施實作
- [ ] `internal/logic/` 包含所有 Handler 邏輯
- [ ] `internal/svc/` 包含完整的依賴注入設定
- [ ] 單元測試 >= 80% 覆蓋率
- [ ] 業務邏輯 >= 90% 覆蓋率
- [ ] 整合測試通過(關鍵路徑)
- [ ] 錯誤處理一致且使用 `%w` wrapping
## 相依技能
- **前置**: `prd-to-plan` (實作計畫), `be-api-design` (API 規格), `dba-schema` (DB Schema)
- **輔助**: `tdd` (TDD Red-Green-Refactor 流程), `design-an-interface` (介面設計)
- **後續**: `qa` (QA 測試)
## 退回機制
```
QA 失敗 (Stage 10)
Orchestrator 重新分配修復任務
Backend Agent 修復 Bug + 新增回歸測試
重新進入 QA (Stage 10)
Code Review 退回 (Stage 11)
處理 PR 回饋
重新進入 QA (Stage 10) 驗證
實作計畫不可行
退回 Task Breakdown (Stage 8) 重新分解
```

View File

@ -1,296 +0,0 @@
---
name: tdd
description: "Backend Agent 使用此技能進行測試驅動開發。遵循 Red-Green-Refactor 循環和垂直切片原則確保測試覆蓋行為而非實作細節。觸發時機實作階段Stage 9由 go-backend-dev 技能整合使用。"
---
# /tdd — 測試驅動開發
Backend Agent 使用此技能進行測試驅動開發。
## 核心理念
**測試行為,而非實作細節。**
好的測試透過公開介面驗證行為,描述系統「做什麼」而非「怎麼做」。重構後測試仍然通過。
壞的測試與實作耦合mock 內部協作者、測試私有方法。重構後測試失敗,但行為沒有改變。
## 反模式:水平切片
**不要先寫完所有測試再寫所有實作。** 這是「水平切片」:
```
❌ 錯誤方式:
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
✅ 正確方式(垂直切片):
RED→GREEN: test1 → impl1
RED→GREEN: test2 → impl2
RED→GREEN: test3 → impl3
```
水平切片會產生劣質測試:
- 大量寫的測試驗證「想像的」行為,而非「實際的」行為
- 測試會變成驗證資料結構和函式簽名,而非使用者可觀察的行為
- 測試對真正的變更不敏感 — 行為壞了還是通過,行為沒變但重構後卻失敗
## 流程
```
確認介面變更與測試範圍
寫第一個測試tracer bullet
RED: 測試失敗
GREEN: 寫最少程式碼讓測試通過
寫下一個測試
RED → GREEN 循環
所有行為測試完成
REFACTOR: 重構
確認所有測試仍然通過
```
### 步驟說明
**1. 規劃**
在寫任何程式碼之前:
- [ ] 與使用者確認需要哪些介面變更
- [ ] 確認哪些行為需要測試(排序優先順序)
- [ ] 識別深模組的機會(小介面,深實作)
- [ ] 為可測試性設計介面
- [ ] 列出要測試的行為(不是實作步驟)
- [ ] 取得使用者對測試計畫的認可
提問:「公開介面應該長什麼樣子?哪些行為最重要需要測試?」
**你不可能測試所有東西。** 與使用者確認哪些行為最重要,將測試精力集中在關鍵路徑和複雜邏輯,而不是每個可能的邊緣案例。
**2. Tracer Bullet**
寫一個測試,確認系統的一件事:
```
RED: 寫第一個行為的測試 → 測試失敗
GREEN: 寫最少的程式碼讓測試通過 → 測試通過
```
這是你的 tracer bullet — 證明端到端路徑可行。
**3. 遞增循環**
對每個剩餘行為:
```
RED: 寫下一個測試 → 失敗
GREEN: 最少程式碼讓測試通過 → 通過
```
規則:
- 一次一個測試
- 只寫足夠讓當前測試通過的程式碼
- 不要預測未來的測試
- 測試聚焦在可觀察的行為
**4. 重構**
所有測試通過後,尋找重構候選:
- [ ] 提取重複邏輯
- [ ] 加深模組(將複雜度移到簡單介面後方)
- [ ] 自然地應用 SOLID 原則
- [ ] 思考新程式碼揭示了什麼既有程式碼的問題
- [ ] 每個重構步驟後都跑測試
**絕對不要在 RED 狀態下重構。先回到 GREEN。**
## 好的測試 vs 壞的測試
### 好的測試
**整合風格**:透過真實介面測試,不是 mock 內部零件。
```go
// GOOD: 測試可觀察的行為
func TestUserUsecase_CreateUser_Success(t *testing.T) {
mockRepo := new(mock.UserRepository)
uc := NewUserUsecase(mockRepo, logger)
mockRepo.On("GetByEmail", mock.Anything, "test@example.com").Return(nil, nil)
mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*domain.User")).Return(nil)
user, err := uc.CreateUser(context.Background(), input)
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, "test@example.com", user.Email)
}
```
特徵:
- 測試使用者/呼叫者關心的行為
- 只使用公開 API
- 重構內部實作後測試仍然通過
- 描述「做什麼」而非「怎麼做」
- 每個測試一個邏輯斷言
### 壊的測試
**實作細節測試**:與內部結構耦合。
```go
// BAD: 測試實作細節
func TestUserUsecase_CreateUser_CallsRepoCreate(t *testing.T) {
mockRepo := new(mock.UserRepository)
uc := NewUserUsecase(mockRepo, logger)
uc.CreateUser(context.Background(), input)
// 這測試的是「怎麼做」而非「做什麼」
mockRepo.AssertCalled(t, "Create", mock.Anything, mock.Anything)
}
```
紅旗:
- Mock 內部協作者只是為了驗證被呼叫
- 測試私有方法
- 斷言呼叫次數或順序
- 重構後測試失敗但行為沒變
- 測試名稱描述「怎麼做」而非「做什麼」
```go
// BAD: 繞過介面驗證
func TestCreateUser_SavesToDatabase(t *testing.T) {
CreateUser(ctx, input)
row := db.QueryRow("SELECT * FROM users WHERE name = $1", "Alice")
// 直接查資料庫驗證,繞過公開介面
}
// GOOD: 透過介面驗證
func TestCreateUser_MakesUserRetrievable(t *testing.T) {
user, _ := CreateUser(ctx, input)
retrieved, _ := GetUser(ctx, user.ID)
assert.Equal(t, "Alice", retrieved.Name)
// 透過公開介面驗證行為
}
```
## Golang 測試規範
### 測試命名
```go
// Test{Unit}_{Scenario}
func TestUserUsecase_CreateUser_Success(t *testing.T) {}
func TestUserUsecase_CreateUser_InvalidEmail(t *testing.T) {}
func TestUserUsecase_CreateUser_Duplicate(t *testing.T) {}
```
### 測試金字塔
```
/\
/ \
/ E2E \ <- 少數關鍵流程
/--------\
/Integration\ <- API + DB
/--------------\
/ Unit Tests \ <- 最多80%+ 覆蓋
/--------------------\
```
### Mock 策略
只在**系統邊界** mock
- 外部 API支付、郵件等
- 資料庫(有時 — 優先使用測試 DB
- 時間/隨機性
- 檔案系統(有時)
不要 mock
- 你自己的類別/模組
- 內部協作者
- 你可以控制的東西
```go
// 使用 mockery 自動產生 mock
//go:generate mockery --name=UserRepository
// 單元測試使用 mock repo
func TestUserUsecase_CreateUser_Success(t *testing.T) {
mockRepo := new(mock.UserRepository)
uc := NewUserUsecase(mockRepo, logger)
mockRepo.On("GetByEmail", mock.Anything, "test@example.com").Return(nil, nil)
mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*domain.User")).Return(nil)
user, err := uc.CreateUser(context.Background(), input)
assert.NoError(t, err)
assert.NotNil(t, user)
}
```
## 介面設計的可測試性
好的介面讓測試自然:
**1. 接受依賴,不要建立依賴**
```go
// Testable
func (s *UserService) CreateUser(ctx context.Context, input CreateUserInput, repo UserRepository) (*User, error) {}
// Hard to test
func (s *UserService) CreateUser(ctx context.Context, input CreateUserInput) (*User, error) {
repo := postgres.NewUserRepository(db) // 建立依賴
}
```
**2. 回傳結果,不要產生副作用**
```go
// Testable
func CalculateDiscount(cart *Cart) Discount {}
// Hard to test
func ApplyDiscount(cart *Cart) {
cart.Total -= discount // 修改輸入
}
```
**3. 小介面面積**
- 方法少 = 測試少
- 參數少 = 測試設定簡單
## 每個循環的檢查清單
```
[ ] 測試描述行為,而非實作
[ ] 測試只使用公開介面
[ ] 測試在內部重構後仍然通過
[ ] 程式碼是讓當前測試通過的最少實作
[ ] 沒有投機性的功能
```
## 重構候選
TDD 循環完成後,尋找:
- **重複邏輯** → 提取 function / class
- **過長方法** → 拆成私有 helper保持測試在公開介面
- **淺模組** → 合併或加深
- **Feature envy** → 把邏輯移到資料所在的地方
- **原始型別偏執** → 引入 value object
- **新程式碼揭示的既有程式碼問題**
## 相依技能
- **前置**: `go-backend-dev` (在實作中整合使用)
- **輔助**: `design-an-interface` (為可測試性設計介面)
- **後續**: `qa` (QA 測試)