SDD 流程模擬(純 API)
本文模擬當需求來自外部 API 整合,不涉及 UI/UX 時的規格驅動開發流程。這類需求通常包括:第三方系統整合、合作夥伴 API、Webhook 接收、內部服務間通訊等。
參與者
| 角色 | 職責 | 主要工具 |
|---|---|---|
| PM | 需求定義、驗收標準、合作夥伴溝通 | OpenSpec proposal |
| BE | API 設計、後端實作審查 | OpenAPI + Claude Code |
| ADM | 流程協調、品質關卡、跨角色協調 | OpenSpec + Claude Code |
| Agent | 規格生成、程式碼實作 | Claude Code |
| QA | 測試策略、API 測試、整合測試 | Test framework + Claude Code |
備註: 純 API 流程中,UX 和 FE 角色不參與。流程更精簡,專注於 API 契約設計和後端實作。
情境
功能需求: 為合作夥伴提供庫存同步 API,讓合作夥伴系統可以即時查詢商品庫存狀態,並接收庫存變動通知。
階段 1:需求種子(PM)
背景
PM 從合作夥伴或業務單位收到 API 整合需求,並建立需求種子文件。外部 API 需求通常有明確的技術規格要求。
PM(Alice): 收集合作夥伴需求並撰寫種子文件
「合作夥伴 TechMart 需要即時庫存同步 API,用於他們的電商平台。我已經整理了需求種子。」
<!-- requirements/partner-inventory-api.md -->
---
title: 合作夥伴庫存同步 API
author: PM-Alice
created: 2026-04-15
status: seed
requester: TechMart Inc.
type: external-api
---
# 合作夥伴庫存同步 API
## 業務背景
合作夥伴 TechMart 需要即時同步我們的商品庫存,以避免超賣和庫存不一致問題。這是 Q2 合作夥伴計畫的核心需求。
### 問題陳述
- TechMart 目前透過每日 FTP 檔案同步庫存,時效性差導致超賣問題
- 過去 3 個月因庫存不同步造成 47 筆訂單取消,客訴 23 件
- TechMart 是我們第三大銷售通路,月銷售額約 $2.5M
### 預期效益
- 消除超賣問題:預期將訂單取消率從 2.3% 降至 0.1%
- 提升合作夥伴滿意度:TechMart 承諾 API 上線後增加 20% 商品上架量
- 建立標準化合作夥伴整合模式:未來可快速複製給其他合作夥伴
## 合作夥伴資訊
- 公司名稱:TechMart Inc.
- 技術聯絡人:John Smith (john.smith@techmart.com)
- 系統環境:Java 17, Spring Boot
- 預期流量:尖峰時段每分鐘約 500-800 次查詢
## 使用情境
### 情境 1:即時庫存查詢
TechMart 的商品頁面載入時,系統呼叫我們的 API 查詢該商品目前庫存數量,並顯示「有貨」或「缺貨」狀態給消費者。
### 情境 2:批次庫存同步
TechMart 每小時執行排程任務,批次查詢所有上架商品(約 5,000 件)的庫存狀態,更新其內部資料庫。
### 情境 3:庫存變動即時通知
當我們的倉庫出貨導致某商品庫存低於安全水位(10 件)時,系統透過 Webhook 通知 TechMart,TechMart 可即時在頁面顯示「即將售完」提示。
### 情境 4:商品售完通知
當商品庫存歸零時,系統發送 Webhook 通知 TechMart,TechMart 自動將該商品標記為「暫時缺貨」。
### 情境 5:Webhook 接收失敗
TechMart 的 Webhook 接收端暫時無法連線,我們的系統自動重試(指數退避),最多重試 5 次。若仍失敗則記錄並發送告警郵件給 TechMart 技術聯絡人。
## 業務規則
- 庫存數量為即時數據,更新延遲不超過 30 秒
- 庫存狀態分類:in_stock(>10)、low_stock(1-10)、out_of_stock(0)
- 每個合作夥伴配發獨立 API Key
- 速率限制依合作夥伴等級設定(TechMart 為 Premium:1000 req/min)
## 驗收標準
- [ ] API 使用 API Key 認證(Header: X-API-Key)
- [ ] 單次查詢支援最多 100 個商品
- [ ] 回應時間 < 200ms(P95)
- [ ] Webhook 在庫存變動後 5 秒內發送
- [ ] Webhook 重試機制:指數退避,最多 5 次
- [ ] 提供沙盒環境供整合測試
- [ ] 提供完整 OpenAPI 3.0 規格文件
## 排除範圍(本次不做)
- 價格同步 API
- 訂單同步 API
- 商品資訊同步 API
- 多倉庫庫存查詢(僅總庫存)PM(Alice): 「我已經提交種子供團隊審查。」
要點
外部 API 需求通常有明確的技術約束和 SLA 要求。PM 需要與合作夥伴確認這些細節,並在種子文件中明確記錄。
階段 1 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 需求種子文件 | requirements/partner-inventory-api.md | PM |
階段 2:種子審查會議(ADM + BE + QA)
背景
純 API 流程的種子審查會議精簡為 ADM、BE、QA 參與。重點在於 API 設計可行性和測試策略。
ADM(Frank): 召開種子審查會議
「各位,我們開始合作夥伴庫存 API 的種子審查。這是純 API 需求,不涉及 UI。」
BE(Bob):
「200ms P95 回應時間有挑戰。批次查詢 100 個商品需要快取策略。另外,Webhook 的重試機制需要定義清楚。」
QA(Eve):
「需要確認 Webhook 的冪等性如何驗證。另外,速率限制的具體數值是多少?」
PM(Alice):
「速率限制我跟 TechMart 確認過,他們預估每分鐘最多 1000 次請求。Webhook 冪等性透過 event_id 實現。」
ADM(Frank): 提出與現有功能的關係
「等等,我們目前已經有內部的庫存查詢 API 供前端使用。這次的合作夥伴 API 跟現有 API 是什麼關係?」
BE(Bob):
「現有的內部 API 是
/api/v1/products/{id}/stock,單筆查詢,沒有批次功能,也沒有認證機制。我們有幾個選項:
- 擴充現有 API 加入批次和認證
- 建立獨立的合作夥伴 API 層
- 重構現有 API,統一內外部使用」
PM(Alice):
「考慮到合作夥伴有不同的 SLA 需求和速率限制,我建議選項 2,建立獨立的合作夥伴 API 層。但底層可以共用庫存服務。」
ADM(Frank):
「這樣的話,我們需要確認:現有內部 API 是否需要調整?未來是否考慮統一?這些可能超出本次範圍。」
QA(Eve):
「如果底層共用庫存服務,那效能測試需要考慮內外部 API 同時使用的場景。」
ADM(Frank): 總結會議發現
「好的。Alice,請更新種子加入速率限制、冪等性細節,以及與現有內部 API 的關係。Bob,請評估共用庫存服務的技術方案。」
PM(Alice): 根據會議回饋更新種子
<!-- requirements/partner-inventory-api.md(審查後更新)-->
---
title: 合作夥伴庫存同步 API
author: PM-Alice
created: 2026-04-15
status: seed
reviewed: 2026-04-16
requester: TechMart Inc.
type: external-api
---
# 合作夥伴庫存同步 API
## 業務背景
合作夥伴 TechMart 需要即時同步我們的商品庫存,以避免超賣和庫存不一致問題。
### 問題陳述
- TechMart 目前透過每日 FTP 檔案同步庫存,時效性差導致超賣問題
- 過去 3 個月因庫存不同步造成 47 筆訂單取消,客訴 23 件
- TechMart 是我們第三大銷售通路,月銷售額約 $2.5M
### 預期效益
- 消除超賣問題:預期將訂單取消率從 2.3% 降至 0.1%
- 提升合作夥伴滿意度:TechMart 承諾 API 上線後增加 20% 商品上架量
- 建立標準化合作夥伴整合模式:未來可快速複製給其他合作夥伴
## 合作夥伴資訊
- 公司名稱:TechMart Inc.
- 技術聯絡人:John Smith (john.smith@techmart.com)
- 系統環境:Java 17, Spring Boot
- 預期流量:尖峰時段每分鐘約 500-800 次查詢
## 使用情境
### 情境 1:即時庫存查詢
TechMart 的商品頁面載入時,系統呼叫我們的 API 查詢該商品目前庫存數量,並顯示「有貨」或「缺貨」狀態給消費者。
### 情境 2:批次庫存同步
TechMart 每小時執行排程任務,批次查詢所有上架商品(約 5,000 件)的庫存狀態,更新其內部資料庫。
### 情境 3:庫存變動即時通知
當我們的倉庫出貨導致某商品庫存低於安全水位(10 件)時,系統透過 Webhook 通知 TechMart,TechMart 可即時在頁面顯示「即將售完」提示。
### 情境 4:商品售完通知
當商品庫存歸零時,系統發送 Webhook 通知 TechMart,TechMart 自動將該商品標記為「暫時缺貨」。
### 情境 5:Webhook 接收失敗
TechMart 的 Webhook 接收端暫時無法連線,我們的系統自動重試(指數退避),最多重試 5 次。若仍失敗則記錄並發送告警郵件給 TechMart 技術聯絡人。
## 業務規則
- 庫存數量為即時數據,更新延遲不超過 30 秒
- 庫存狀態分類:in_stock(>10)、low_stock(1-10)、out_of_stock(0)
- 每個合作夥伴配發獨立 API Key
- 速率限制依合作夥伴等級設定(TechMart 為 Premium:1000 req/min)
- Webhook 透過 event_id 確保冪等性
## 驗收標準
- [ ] API 使用 API Key 認證(Header: X-API-Key)
- [ ] 單次查詢支援最多 100 個商品
- [ ] 回應時間 < 200ms(P95)
- [ ] Webhook 在庫存變動後 5 秒內發送
- [ ] 速率限制:1000 requests/min per API Key
- [ ] Webhook 透過 event_id 確保冪等性
- [ ] Webhook 失敗重試:指數退避,最多 5 次
- [ ] 提供沙盒環境供整合測試
## 與現有功能的關係
- 現有功能:內部庫存查詢 API(`/api/v1/products/{id}/stock`,單筆查詢,無認證)
- 決策:建立獨立合作夥伴 API 層,底層共用庫存服務
- 範圍外考量:未來可能統一內外部 API
## 排除範圍(本次不做)
- 價格同步 API
- 訂單同步 API
- 商品資訊同步 API
- 多倉庫庫存查詢(僅總庫存)
## 待討論問題(精煉會議)
- 快取策略選型(Redis vs. 本地快取)
- Webhook 簽名驗證機制
- 共用庫存服務的效能影響評估要點
純 API 流程的審查更專注於技術可行性、效能需求和測試策略。ADM 確保團隊考慮與現有 API 的關係,決定是擴充、獨立建置或統一重構。BE 和 QA 的意見對 API 設計至關重要。
階段 2 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 更新後的種子文件 | requirements/partner-inventory-api.md | PM |
階段 3:提案生成與審查(PM + ADM + BE + QA)
背景
PM 使用種子作為輸入生成提案,團隊逐行審查並即時修改。
3.1 PM 生成提案
PM(Alice): 開啟 Claude Code
claude "根據 requirements/partner-inventory-api.md 種子文件,
使用 /openspec:proposal 生成正式提案"Agent: 生成提案草稿
<!-- openspec/changes/partner-inventory-api/proposal.md -->
---
id: partner-inventory-api
title: 合作夥伴庫存同步 API
status: draft
owner: PM-Alice
created: 2026-04-16
type: external-api
---
# 合作夥伴庫存同步 API
## 概述
為合作夥伴提供庫存同步 API,包含查詢端點和 Webhook 通知機制。
## 變更範圍
### 後端變更
| 檔案 | 變更類型 | 說明 |
|------|----------|------|
| `services/partner-api/` | 新增 | 合作夥伴 API 服務 |
| `api/partner-inventory.yaml` | 新增 | OpenAPI 規格 |
| `services/webhook/` | 修改 | 新增庫存變動事件 |
### 基礎設施變更
| 項目 | 變更類型 | 說明 |
|------|----------|------|
| Redis 快取 | 新增 | 庫存查詢快取層 |
| API Gateway | 修改 | 新增速率限制規則 |
## 驗收標準
(繼承自種子文件)3.2 團隊逐行審查提案
ADM(Frank): 召開提案審查會議,投影提案內容
「各位,我們逐行審查提案。有問題直接請 Agent 修改。」
ADM(Frank): 「先看『概述』區塊...」
PM(Alice):
「概述需要加上合作夥伴名稱和商業價值。」
ADM(Frank): 即時請 Agent 修改
claude "更新提案概述,加入:
- 合作夥伴:TechMart Inc.
- 商業價值:Q2 合作夥伴計畫核心需求,預期帶來 15% 訂單增長"ADM(Frank): 「繼續看『變更範圍』...」
BE(Bob):
「快取策略建議用 Redis Cluster,需要加入架構決策說明。另外,Webhook 服務需要加入簽名驗證機制。」
ADM(Frank): 即時請 Agent 修改
claude "更新提案:
1. 基礎設施變更加入 Redis Cluster 架構決策
2. Webhook 服務加入 HMAC-SHA256 簽名驗證機制說明"QA(Eve):
「需要加入測試策略區塊,包含效能測試和整合測試計畫。另外,既然底層共用庫存服務,效能測試要包含內外部 API 併發場景。」
ADM(Frank): 「還有一個重點:與現有內部 API 的關係。」
BE(Bob):
「我們決定建立獨立的合作夥伴 API 層,但共用底層庫存服務。提案需要說明這個架構決策,以及對現有內部 API 的影響。」
PM(Alice):
「現有內部 API 目前不需要修改。但長期來看,我們可能會統一內外部 API。這應該列為範圍外的後續考量。」
ADM(Frank): 「好,我們把這些都記錄下來。」
ADM(Frank): 即時請 Agent 修改
claude "更新提案:
1. 新增測試策略區塊:
- 效能測試:驗證 200ms P95 回應時間
- 併發測試:內外部 API 同時使用場景
- 整合測試:Webhook 端對端驗證
- 沙盒環境:獨立測試資料集
2. 新增與現有功能關係區塊:
- 現有功能:內部庫存查詢 API(不修改)
- 架構決策:獨立合作夥伴 API 層,共用底層庫存服務
- 範圍外後續考量:未來可能統一內外部 API"Agent: 更新所有規格
ADM(Frank): 「提案更新完成。各位確認最終版本...」
要點
純 API 提案審查重點在於架構決策、效能保證和測試策略。審查時必須確認與現有 API 的關係:是否擴充、是否獨立建置、是否共用底層服務。範圍外的後續考量也應記錄,方便未來規劃。
階段 3 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| OpenSpec 提案 | openspec/changes/partner-inventory-api/proposal.md | PM + Agent |
階段 4:API First 設計(BE + Agent + 團隊審查)
背景
這是純 API 流程的核心階段。BE 設計完整的 OpenAPI 規格,包含認證、錯誤處理、Webhook 規格。
4.1 BE 產生 API 規格
BE(Bob): 開啟 Claude Code
claude "根據 openspec/changes/partner-inventory-api/proposal.md,
建立完整的 OpenAPI 3.0 規格,包含:
- GET /partner/v1/inventory(批次查詢)
- POST /partner/v1/webhooks(註冊 Webhook)
- DELETE /partner/v1/webhooks/{id}(取消註冊)
- Webhook payload 規格
- 認證和速率限制說明
- 錯誤回應定義"Agent: 生成 OpenAPI 規格
# specs/api/partner-inventory-api.yaml
openapi: 3.0.3
info:
title: Partner Inventory API
version: 1.0.0
description: |
合作夥伴庫存同步 API
## 認證
所有請求需要在 Header 中包含 `X-API-Key`
## 速率限制
- 1000 requests/min per API Key
- 超過限制回傳 429 Too Many Requests
## Webhook 簽名
Webhook 請求包含 `X-Signature` header,使用 HMAC-SHA256 簽名
servers:
- url: https://api.example.com
description: Production
- url: https://sandbox-api.example.com
description: Sandbox
security:
- ApiKeyAuth: []
paths:
/partner/v1/inventory:
post:
summary: 批次查詢庫存
operationId: batchGetInventory
description: 查詢多個商品的庫存狀態,最多 100 個商品
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- product_ids
properties:
product_ids:
type: array
items:
type: string
maxItems: 100
example: ["SKU001", "SKU002", "SKU003"]
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/InventoryResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/RateLimited'
/partner/v1/webhooks:
post:
summary: 註冊 Webhook
operationId: registerWebhook
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookRegistration'
responses:
'201':
description: 註冊成功
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookResponse'
/partner/v1/webhooks/{webhookId}:
delete:
summary: 取消 Webhook 註冊
operationId: unregisterWebhook
parameters:
- name: webhookId
in: path
required: true
schema:
type: string
responses:
'204':
description: 取消成功
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
schemas:
InventoryResponse:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/InventoryItem'
timestamp:
type: string
format: date-time
InventoryItem:
type: object
properties:
product_id:
type: string
quantity:
type: integer
status:
type: string
enum: [in_stock, low_stock, out_of_stock]
updated_at:
type: string
format: date-time
WebhookRegistration:
type: object
required:
- url
- events
properties:
url:
type: string
format: uri
events:
type: array
items:
type: string
enum: [inventory.updated, inventory.low_stock, inventory.out_of_stock]
secret:
type: string
description: 用於簽名驗證的密鑰
WebhookPayload:
type: object
properties:
event_id:
type: string
format: uuid
description: 冪等性識別碼
event_type:
type: string
timestamp:
type: string
format: date-time
data:
$ref: '#/components/schemas/InventoryItem'
responses:
BadRequest:
description: 請求格式錯誤
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: 認證失敗
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: 超過速率限制
headers:
Retry-After:
schema:
type: integer
description: 建議重試等待秒數
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Error:
type: object
properties:
code:
type: string
message:
type: string
request_id:
type: string4.2 提交到 API 管理平台
BE(Bob): 提交 API 規格
git add specs/api/partner-inventory-api.yaml
git commit -m "feat(api): add partner inventory API specification"
git push origin feature/partner-inventory-api4.3 團隊逐行審查 API 規格
ADM(Frank): 召開 API 審查會議,投影 API 規格
「各位,我們逐行審查合作夥伴庫存 API 規格。」
ADM(Frank): 「先看認證和速率限制說明...」
PM(Alice):
「說明很清楚。但需要加入 API Key 如何申請的流程說明。」
ADM(Frank): 即時請 Agent 修改
claude "在 info.description 加入 API Key 申請流程說明"ADM(Frank): 「繼續看批次查詢端點...」
QA(Eve):
「maxItems: 100 的驗證錯誤訊息需要定義。超過 100 個商品時回傳什麼?」
ADM(Frank): 即時請 Agent 修改
claude "在 BadRequest 回應中加入 example,
說明超過 100 個商品時的錯誤訊息格式"BE(Bob):
「Webhook payload 缺少重試次數欄位。合作夥伴需要知道這是第幾次重試。」
ADM(Frank): 即時請 Agent 修改
claude "在 WebhookPayload 加入 retry_count 欄位,
type: integer,description: 重試次數,0 表示首次發送"Agent: 更新所有規格
ADM(Frank): 「API 規格更新完成。各位確認...」
BE(Bob): 確認後合併
git commit -m "feat(api): finalize partner inventory API after review"
git push && gh pr merge --squash要點
外部 API 規格需要特別注意認證機制、錯誤處理、速率限制說明。這些對合作夥伴整合至關重要。
階段 4 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| OpenAPI 規格 | specs/api/partner-inventory-api.yaml | BE + Agent |
階段 5:實作(Agent + BE 審查)
背景
純 API 流程只有後端實作,沒有前端。重點在於 API 實作符合規格和效能要求。
5.1 後端實作
ADM(Frank): 「Bob,API 規格已核准。請指導 Agent 進行實作。」
BE(Bob): 開啟 Claude Code
claude "根據 openspec/changes/partner-inventory-api/proposal.md
和 specs/api/partner-inventory-api.yaml
使用 /openspec:apply 實作後端 API"Agent: 生成後端實作
// services/partner-api/inventory.controller.ts
import { Controller, Post, Body, UseGuards } from '@nestjs/common';
import { ApiKeyGuard } from '@/guards/api-key.guard';
import { RateLimitGuard } from '@/guards/rate-limit.guard';
import { InventoryService } from './inventory.service';
import { BatchInventoryDto } from './dto/batch-inventory.dto';
@Controller('partner/v1')
@UseGuards(ApiKeyGuard, RateLimitGuard)
export class InventoryController {
constructor(private readonly inventoryService: InventoryService) {}
@Post('inventory')
async batchGetInventory(@Body() dto: BatchInventoryDto) {
if (dto.product_ids.length > 100) {
throw new BadRequestException({
code: 'BATCH_SIZE_EXCEEDED',
message: 'Maximum 100 products per request',
});
}
const items = await this.inventoryService.batchGet(dto.product_ids);
return {
items,
timestamp: new Date().toISOString(),
};
}
}// services/partner-api/inventory.service.ts
import { Injectable } from '@nestjs/common';
import { RedisService } from '@/services/redis.service';
import { InventoryRepository } from './inventory.repository';
@Injectable()
export class InventoryService {
private readonly CACHE_TTL = 30; // 30 seconds
constructor(
private readonly redis: RedisService,
private readonly repository: InventoryRepository,
) {}
async batchGet(productIds: string[]) {
const cached = await this.redis.mget(
productIds.map(id => `inventory:${id}`)
);
const missingIds = productIds.filter((_, i) => !cached[i]);
if (missingIds.length > 0) {
const fresh = await this.repository.findByIds(missingIds);
// Cache the fresh data
const pipeline = this.redis.pipeline();
fresh.forEach(item => {
pipeline.setex(
`inventory:${item.product_id}`,
this.CACHE_TTL,
JSON.stringify(item)
);
});
await pipeline.exec();
}
return this.mergeResults(productIds, cached, missingIds);
}
}5.2 BE 審查
BE(Bob): 審查 Agent 產出的程式碼
「讓我看看實作...API 參數驗證正確,快取邏輯使用 Redis pipeline 優化批次操作,符合效能需求。但我發現缺少 Circuit Breaker 模式,當 Redis 不可用時需要降級處理。」
BE(Bob): 請 Agent 補充
claude "補充 Circuit Breaker 模式,
當 Redis 不可用時直接查詢資料庫,並加入健康檢查端點"BE(Bob): 「核心實作符合 API 規格。Circuit Breaker 補充後核准合併。」
要點
純 API 實作審查重點在於效能優化、錯誤處理和可靠性設計。外部 API 需要更高的穩定性標準。
階段 5 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 後端程式碼 | services/partner-api/ | Agent + BE |
階段 6:測試(QA + Agent)
背景
純 API 流程的測試重點在於 API 契約測試、效能測試和整合測試。
6.1 QA 請求 Agent 生成測試
ADM(Frank): 「Eve,實作完成了。請生成 API 測試。」
QA(Eve): 開啟 Claude Code
claude "根據 specs/api/partner-inventory-api.yaml
生成以下測試:
1. API 契約測試(驗證回應符合 OpenAPI 規格)
2. 效能測試(驗證 200ms P95)
3. Webhook 整合測試"Agent: 生成測試案例
// tests/api/partner-inventory.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Partner Inventory API', () => {
const API_KEY = process.env.TEST_API_KEY;
const BASE_URL = process.env.API_BASE_URL;
test('batch inventory query returns correct format', async ({ request }) => {
const response = await request.post(`${BASE_URL}/partner/v1/inventory`, {
headers: { 'X-API-Key': API_KEY },
data: { product_ids: ['SKU001', 'SKU002'] },
});
expect(response.status()).toBe(200);
const body = await response.json();
expect(body).toHaveProperty('items');
expect(body).toHaveProperty('timestamp');
expect(body.items[0]).toHaveProperty('product_id');
expect(body.items[0]).toHaveProperty('quantity');
expect(body.items[0]).toHaveProperty('status');
});
test('rejects requests exceeding 100 products', async ({ request }) => {
const productIds = Array.from({ length: 101 }, (_, i) => `SKU${i}`);
const response = await request.post(`${BASE_URL}/partner/v1/inventory`, {
headers: { 'X-API-Key': API_KEY },
data: { product_ids: productIds },
});
expect(response.status()).toBe(400);
const body = await response.json();
expect(body.code).toBe('BATCH_SIZE_EXCEEDED');
});
test('returns 401 without API key', async ({ request }) => {
const response = await request.post(`${BASE_URL}/partner/v1/inventory`, {
data: { product_ids: ['SKU001'] },
});
expect(response.status()).toBe(401);
});
test('returns 429 when rate limited', async ({ request }) => {
// Send requests until rate limited
const requests = Array.from({ length: 1100 }, () =>
request.post(`${BASE_URL}/partner/v1/inventory`, {
headers: { 'X-API-Key': API_KEY },
data: { product_ids: ['SKU001'] },
})
);
const responses = await Promise.all(requests);
const rateLimited = responses.filter(r => r.status() === 429);
expect(rateLimited.length).toBeGreaterThan(0);
});
});// tests/performance/inventory-load.spec.ts
import { check } from 'k6';
import http from 'k6/http';
export const options = {
stages: [
{ duration: '30s', target: 100 },
{ duration: '1m', target: 100 },
{ duration: '30s', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<200'], // 200ms P95
},
};
export default function () {
const response = http.post(
`${__ENV.API_BASE_URL}/partner/v1/inventory`,
JSON.stringify({ product_ids: ['SKU001', 'SKU002', 'SKU003'] }),
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': __ENV.API_KEY,
},
}
);
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
}6.2 QA 執行測試
QA(Eve): 「執行 API 測試和效能測試...」
# API 契約測試
npx playwright test tests/api/partner-inventory.spec.ts
# 結果
Running 4 tests using 1 worker
✓ batch inventory query returns correct format (0.8s)
✓ rejects requests exceeding 100 products (0.3s)
✓ returns 401 without API key (0.2s)
✓ returns 429 when rate limited (5.2s)
4 passed (6.5s)
# 效能測試
k6 run tests/performance/inventory-load.spec.ts
# 結果
✓ http_req_duration.............: avg=45ms p(95)=156ms
✓ checks.......................: 100.00%QA(Eve): 「所有測試通過。P95 回應時間 156ms,符合 200ms 要求。」
要點
外部 API 測試需要驗證契約符合性、效能 SLA 和錯誤處理。效能測試應在接近生產的環境執行。
階段 6 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| API 測試案例 | tests/api/partner-inventory.spec.ts | Agent + QA |
| 效能測試案例 | tests/performance/inventory-load.spec.ts | Agent + QA |
| 測試報告 | CI/CD 系統 | QA |
階段 7:歸檔(PM + ADM + Agent)
背景
成功部署後,提案被歸檔,並將 API 文件發布給合作夥伴。
7.1 PM 請求歸檔
PM(Alice): 「API 已部署並通過所有測試。準備歸檔並通知合作夥伴。」
claude "合作夥伴庫存 API 通過所有測試並已部署,
使用 /openspec:archive 歸檔這個變更,
並生成合作夥伴整合文件"7.2 Agent 執行歸檔
Agent: 執行歸檔流程
# Agent 執行歸檔流程
1. 更新提案狀態為 archived
2. 將 API 規格合併到 specs/ 目錄
3. 生成合作夥伴整合指南
4. 更新 CHANGELOG.md
5. 建立 git tagADM(Frank): 「歸檔完成。Alice,請將整合文件和沙盒存取憑證發送給 TechMart。」
PM(Alice): 「收到。我會安排與 TechMart 的整合對接會議。」
階段 7 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 歸檔後的提案 | openspec/archive/partner-inventory-api/ | Agent |
| 合併後的規格 | specs/ 目錄 | Agent |
| 合作夥伴整合指南 | docs/partner/ | Agent |
| CHANGELOG 更新 | CHANGELOG.md | Agent |
完整工件清單
| 階段 | 工件 | 位置 | 負責人 |
|---|---|---|---|
| 1 | 需求種子文件 | requirements/ | PM |
| 2 | 更新後的種子文件 | requirements/ | PM |
| 3 | OpenSpec 提案 | openspec/changes/ | PM + Agent |
| 4 | OpenAPI 規格 | specs/api/ | BE + Agent |
| 5 | 後端程式碼 | services/ | Agent + BE |
| 6 | API 測試案例 | tests/api/ | Agent + QA |
| 6 | 效能測試案例 | tests/performance/ | Agent + QA |
| 7 | 歸檔後的提案 | openspec/archive/ | Agent |
| 7 | 合作夥伴整合指南 | docs/partner/ | Agent |
| 7 | 合併後的規格 | specs/ | Agent |
流程摘要
與完整 SDD 流程的差異
| 面向 | 完整 SDD 流程 | 純 API 流程 |
|---|---|---|
| 參與角色 | PM, UX, BE, FE, ADM, QA | PM, BE, ADM, QA |
| 階段數量 | 8 階段 | 7 階段(跳過 UX 設計) |
| 設計產出 | OpenAPI + UX 規格 | 僅 OpenAPI |
| 實作範圍 | 後端 + 前端 | 僅後端 |
| 測試重點 | E2E + 效能 | API 契約 + 效能 |
| 額外考量 | UI/UX 一致性 | 外部整合、SLA、文件 |
相關文件
- SDD 流程模擬(完整) - 包含 UI/UX 的完整流程
- 工作流程框架 - 完整工作流程文件
- API 設計流程 - API 設計詳細流程