Skip to content

SDD 流程模擬(純 API)

本文模擬當需求來自外部 API 整合,不涉及 UI/UX 時的規格驅動開發流程。這類需求通常包括:第三方系統整合、合作夥伴 API、Webhook 接收、內部服務間通訊等。

參與者

角色職責主要工具
PM需求定義、驗收標準、合作夥伴溝通OpenSpec proposal
BEAPI 設計、後端實作審查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,用於他們的電商平台。我已經整理了需求種子。」

markdown
<!-- 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.mdPM

階段 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,單筆查詢,沒有批次功能,也沒有認證機制。我們有幾個選項:

  1. 擴充現有 API 加入批次和認證
  2. 建立獨立的合作夥伴 API 層
  3. 重構現有 API,統一內外部使用」

PM(Alice):

「考慮到合作夥伴有不同的 SLA 需求和速率限制,我建議選項 2,建立獨立的合作夥伴 API 層。但底層可以共用庫存服務。」

ADM(Frank):

「這樣的話,我們需要確認:現有內部 API 是否需要調整?未來是否考慮統一?這些可能超出本次範圍。」

QA(Eve):

「如果底層共用庫存服務,那效能測試需要考慮內外部 API 同時使用的場景。」

ADM(Frank): 總結會議發現

「好的。Alice,請更新種子加入速率限制、冪等性細節,以及與現有內部 API 的關係。Bob,請評估共用庫存服務的技術方案。」

PM(Alice): 根據會議回饋更新種子

markdown
<!-- 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.mdPM

階段 3:提案生成與審查(PM + ADM + BE + QA)

背景

PM 使用種子作為輸入生成提案,團隊逐行審查並即時修改。

3.1 PM 生成提案

PM(Alice): 開啟 Claude Code

bash
claude "根據 requirements/partner-inventory-api.md 種子文件,
使用 /openspec:proposal 生成正式提案"

Agent: 生成提案草稿

markdown
<!-- 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 修改

bash
claude "更新提案概述,加入:
- 合作夥伴:TechMart Inc.
- 商業價值:Q2 合作夥伴計畫核心需求,預期帶來 15% 訂單增長"

ADM(Frank): 「繼續看『變更範圍』...」

BE(Bob):

「快取策略建議用 Redis Cluster,需要加入架構決策說明。另外,Webhook 服務需要加入簽名驗證機制。」

ADM(Frank): 即時請 Agent 修改

bash
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 修改

bash
claude "更新提案:
1. 新增測試策略區塊:
   - 效能測試:驗證 200ms P95 回應時間
   - 併發測試:內外部 API 同時使用場景
   - 整合測試:Webhook 端對端驗證
   - 沙盒環境:獨立測試資料集
2. 新增與現有功能關係區塊:
   - 現有功能:內部庫存查詢 API(不修改)
   - 架構決策:獨立合作夥伴 API 層,共用底層庫存服務
   - 範圍外後續考量:未來可能統一內外部 API"

Agent: 更新所有規格

ADM(Frank): 「提案更新完成。各位確認最終版本...」

要點

純 API 提案審查重點在於架構決策、效能保證和測試策略。審查時必須確認與現有 API 的關係:是否擴充、是否獨立建置、是否共用底層服務。範圍外的後續考量也應記錄,方便未來規劃。

階段 3 產出工件:

工件位置負責人
OpenSpec 提案openspec/changes/partner-inventory-api/proposal.mdPM + Agent

階段 4:API First 設計(BE + Agent + 團隊審查)

背景

這是純 API 流程的核心階段。BE 設計完整的 OpenAPI 規格,包含認證、錯誤處理、Webhook 規格。

4.1 BE 產生 API 規格

BE(Bob): 開啟 Claude Code

bash
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 規格

yaml
# 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: string

4.2 提交到 API 管理平台

BE(Bob): 提交 API 規格

bash
git add specs/api/partner-inventory-api.yaml
git commit -m "feat(api): add partner inventory API specification"
git push origin feature/partner-inventory-api

4.3 團隊逐行審查 API 規格

ADM(Frank): 召開 API 審查會議,投影 API 規格

「各位,我們逐行審查合作夥伴庫存 API 規格。」

ADM(Frank): 「先看認證和速率限制說明...」

PM(Alice):

「說明很清楚。但需要加入 API Key 如何申請的流程說明。」

ADM(Frank): 即時請 Agent 修改

bash
claude "在 info.description 加入 API Key 申請流程說明"

ADM(Frank): 「繼續看批次查詢端點...」

QA(Eve):

「maxItems: 100 的驗證錯誤訊息需要定義。超過 100 個商品時回傳什麼?」

ADM(Frank): 即時請 Agent 修改

bash
claude "在 BadRequest 回應中加入 example,
說明超過 100 個商品時的錯誤訊息格式"

BE(Bob):

「Webhook payload 缺少重試次數欄位。合作夥伴需要知道這是第幾次重試。」

ADM(Frank): 即時請 Agent 修改

bash
claude "在 WebhookPayload 加入 retry_count 欄位,
type: integer,description: 重試次數,0 表示首次發送"

Agent: 更新所有規格

ADM(Frank): 「API 規格更新完成。各位確認...」

BE(Bob): 確認後合併

bash
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.yamlBE + Agent

階段 5:實作(Agent + BE 審查)

背景

純 API 流程只有後端實作,沒有前端。重點在於 API 實作符合規格和效能要求。

5.1 後端實作

ADM(Frank): 「Bob,API 規格已核准。請指導 Agent 進行實作。」

BE(Bob): 開啟 Claude Code

bash
claude "根據 openspec/changes/partner-inventory-api/proposal.md
和 specs/api/partner-inventory-api.yaml
使用 /openspec:apply 實作後端 API"

Agent: 生成後端實作

typescript
// 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(),
    };
  }
}
typescript
// 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 補充

bash
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

bash
claude "根據 specs/api/partner-inventory-api.yaml
生成以下測試:
1. API 契約測試(驗證回應符合 OpenAPI 規格)
2. 效能測試(驗證 200ms P95)
3. Webhook 整合測試"

Agent: 生成測試案例

typescript
// 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);
  });
});
typescript
// 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 測試和效能測試...」

bash
# 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.tsAgent + QA
效能測試案例tests/performance/inventory-load.spec.tsAgent + QA
測試報告CI/CD 系統QA

階段 7:歸檔(PM + ADM + Agent)

背景

成功部署後,提案被歸檔,並將 API 文件發布給合作夥伴。

7.1 PM 請求歸檔

PM(Alice): 「API 已部署並通過所有測試。準備歸檔並通知合作夥伴。」

bash
claude "合作夥伴庫存 API 通過所有測試並已部署,
使用 /openspec:archive 歸檔這個變更,
並生成合作夥伴整合文件"

7.2 Agent 執行歸檔

Agent: 執行歸檔流程

bash
# Agent 執行歸檔流程
1. 更新提案狀態為 archived
2. API 規格合併到 specs/ 目錄
3. 生成合作夥伴整合指南
4. 更新 CHANGELOG.md
5. 建立 git tag

ADM(Frank): 「歸檔完成。Alice,請將整合文件和沙盒存取憑證發送給 TechMart。」

PM(Alice): 「收到。我會安排與 TechMart 的整合對接會議。」

階段 7 產出工件:

工件位置負責人
歸檔後的提案openspec/archive/partner-inventory-api/Agent
合併後的規格specs/ 目錄Agent
合作夥伴整合指南docs/partner/Agent
CHANGELOG 更新CHANGELOG.mdAgent

完整工件清單

階段工件位置負責人
1需求種子文件requirements/PM
2更新後的種子文件requirements/PM
3OpenSpec 提案openspec/changes/PM + Agent
4OpenAPI 規格specs/api/BE + Agent
5後端程式碼services/Agent + BE
6API 測試案例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, QAPM, BE, ADM, QA
階段數量8 階段7 階段(跳過 UX 設計)
設計產出OpenAPI + UX 規格僅 OpenAPI
實作範圍後端 + 前端僅後端
測試重點E2E + 效能API 契約 + 效能
額外考量UI/UX 一致性外部整合、SLA、文件

相關文件