SDD 流程模擬
本文以對話方式模擬一個完整的規格驅動開發(SDD)流程,展示如何使用 Claude Code + OpenSpec 框架進行從需求到交付的端到端協作。
參與者
| 角色 | 職責 | 主要工具 |
|---|---|---|
| PM | 需求定義、驗收標準 | OpenSpec proposal |
| UX | 使用者體驗設計、互動規格 | Figma + Figma Make + Claude Code |
| BE | API 設計、後端實作審查 | OpenAPI + Claude Code |
| FE | 前端實作審查、元件整合 | Claude Code + Design System |
| ADM | 流程協調、品質關卡、跨角色協調 | OpenSpec + Claude Code |
| Agent | 規格生成、程式碼實作 | Claude Code |
| QA | 測試策略、驗收測試 | Test framework + Claude Code |
備註: ADM(Agentic Development Master)是傳統 Scrum Master 角色的演進。在 SDD 工作流程中,ADM 專注於協調 AI-人類協作、確保規格品質,以及促進跨職能協調。
情境
功能需求: 在電商平台新增「商品願望清單」功能,讓使用者可以儲存商品並在個人檔案頁面查看願望清單。
階段 1:需求種子(PM)
背景
PM 從利益關係人處收到業務需求,並建立需求種子文件。種子應該由 PM 根據實際回饋撰寫,而不是由 AI 自動生成。
PM(Alice): 收集使用者回饋並撰寫種子文件
「根據客服工單和調查的使用者回饋,我已經為願望清單功能起草了需求種子。」
<!-- requirements/product-wishlist.md -->
---
title: 商品願望清單功能
author: PM-Alice
created: 2026-04-15
status: seed
---
# 商品願望清單功能
## 業務背景
使用者希望能夠儲存他們感興趣的商品,以便未來做購買決定。這是我們 Q1 使用者調查中第三大熱門需求(1,247 票)。
### 問題陳述
- 使用者經常在多次造訪後才決定購買,但無法追蹤先前瀏覽的商品
- 客服工單顯示每月約 200 件「如何找回之前看過的商品」詢問
- 競品分析:主要競爭對手均已提供此功能
### 預期效益
- 提升回訪率:預估增加 15% 回訪使用者
- 提升轉換率:願望清單使用者轉換率預估較一般使用者高 2.3 倍
- 降低客服負擔:減少相關工單約 80%
## 目標使用者
- 主要:已註冊會員,有明確購買意圖但需要時間考慮
- 次要:瀏覽型使用者,用於收集感興趣商品
## 使用情境
### 情境 1:加入願望清單
使用者 Amy 在瀏覽商品頁時看到一雙喜歡的鞋子,但想等薪水入帳再購買。她點擊愛心按鈕將商品加入願望清單,系統顯示「已加入願望清單」提示。
### 情境 2:查看願望清單
兩週後 Amy 登入帳號,進入個人檔案頁面點擊「我的願望清單」,看到之前收藏的鞋子。她注意到價格從 $2,800 降到 $2,380,決定立即購買。
### 情境 3:未登入使用者
訪客 Bob 瀏覽商品時想加入願望清單,點擊愛心後系統顯示登入提示。登入成功後,該商品自動加入願望清單。
### 情境 4:商品已下架
使用者 Carol 查看願望清單時,發現某商品顯示「已無法購買」標籤。她可以選擇移除該商品或保留作為參考。
## 業務規則
- 每位使用者願望清單上限:500 件商品
- 願望清單為私人資料,不對外公開
- 商品下架後保留在願望清單中 90 天,之後自動移除
- 價格變動通知:降價超過 10% 時發送 Email 通知(需使用者開啟通知設定)
## 驗收標準
- [ ] 未認證使用者點擊願望清單時導向登入,登入後自動加入
- [ ] 已認證使用者可以即時加入/移除願望清單
- [ ] 願望清單頁面支援分頁載入(每頁 20 件)
- [ ] 無法購買的商品在願望清單中以視覺標示區分
- [ ] 顯示商品加入時價格與目前價格的比較
- [ ] 願望清單為空時顯示引導文案
## 排除範圍(本次不做)
- 願望清單分享功能
- 願望清單分類/資料夾
- 多個願望清單
- 降價推播通知(僅 Email)PM(Alice): 「我已經提交這份種子供團隊審查,再進行精煉會議。」
要點
種子文件應該由人類根據實際利益關係人回饋撰寫,而不是由 AI 從簡短提示自動生成。AI 傾向於幻覺出沒有被要求的「完整」功能集。PM 擁有需求定義的責任。
階段 1 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 需求種子文件 | requirements/product-wishlist.md | PM |
階段 2:種子審查會議(ADM + 所有團隊成員)
背景
在精煉會議之前,ADM 召集所有團隊成員進行種子審查會議(實體或線上)。這確保每個人都理解範圍,並能當面提出疑慮。
ADM(Frank): 召開種子審查會議
「各位,我們開始願望清單功能的種子審查。請針對以下面向提出意見:
- 需求的清晰度
- 遺漏的驗收標準
- 潛在的技術疑慮
- 範圍的適當性」
BE(Bob):
「需求提到『價格變動』——我們需要即時價格追蹤,還是只顯示目前價格與加入時的價格比較?」
FE(Carol):
「對於『即時加入/移除』——我們應該澄清這是指 UI 上的樂觀更新嗎?」
UX(Diana):
「沒有提到空狀態。當使用者的願望清單是空的時候應該顯示什麼?」
QA(Eve):
「邊界案例:當願望清單中的商品從目錄中完全刪除時會發生什麼?」
ADM(Frank): 提出與現有功能的關係
「等一下,我們需要確認一件事。目前系統已經有『商品收藏』功能,這個願望清單跟收藏有什麼關係?」
PM(Alice):
「好問題。『商品收藏』是舊版功能,只是簡單的收藏列表。這次的願望清單有價格追蹤、降價提醒等進階功能。」
BE(Bob):
「那我們需要決定:是擴充現有收藏功能,還是建立全新的願望清單服務?如果是後者,舊的收藏功能要怎麼處理?」
ADM(Frank):
「這影響範圍可能超出本次需求。Alice,我們需要在提案中明確這點。選項有:
- 擴充現有收藏功能,加入新功能
- 建立新服務,保留舊收藏功能
- 建立新服務,逐步淘汰舊收藏功能並提供遷移路徑」
PM(Alice):
「我傾向選項 3。但需要跟產品團隊確認淘汰時程。我會在種子中加入這個決策點。」
ADM(Frank): 總結會議發現
「好的發現,團隊。Alice,請根據今天的討論更新種子,特別是與現有收藏功能的關係。我會將這些記錄為精煉會議的討論項目。」
PM(Alice): 根據會議回饋更新種子
<!-- requirements/product-wishlist.md(審查後更新)-->
---
title: 商品願望清單功能
author: PM-Alice
created: 2026-04-15
status: seed
reviewed: 2026-04-16
---
# 商品願望清單功能
## 業務背景
使用者希望能夠儲存他們感興趣的商品,以便未來做購買決定。這是我們 Q1 使用者調查中第三大熱門需求(1,247 票)。
### 問題陳述
- 使用者經常在多次造訪後才決定購買,但無法追蹤先前瀏覽的商品
- 客服工單顯示每月約 200 件「如何找回之前看過的商品」詢問
- 競品分析:主要競爭對手均已提供此功能
### 預期效益
- 提升回訪率:預估增加 15% 回訪使用者
- 提升轉換率:願望清單使用者轉換率預估較一般使用者高 2.3 倍
- 降低客服負擔:減少相關工單約 80%
## 目標使用者
- 主要:已註冊會員,有明確購買意圖但需要時間考慮
- 次要:瀏覽型使用者,用於收集感興趣商品
## 使用情境
### 情境 1:加入願望清單
使用者 Amy 在瀏覽商品頁時看到一雙喜歡的鞋子,但想等薪水入帳再購買。她點擊愛心按鈕將商品加入願望清單,系統顯示「已加入願望清單」提示。
### 情境 2:查看願望清單並發現降價
兩週後 Amy 登入帳號,進入個人檔案頁面點擊「我的願望清單」,看到之前收藏的鞋子。她注意到價格從 $2,800 降到 $2,380,決定立即購買。
### 情境 3:未登入使用者
訪客 Bob 瀏覽商品時想加入願望清單,點擊愛心後系統顯示登入提示。登入成功後,該商品自動加入願望清單。
### 情境 4:商品已下架
使用者 Carol 查看願望清單時,發現某商品顯示「已無法購買」標籤。她可以選擇移除該商品或保留作為參考。
### 情境 5:商品完全刪除
使用者 David 的願望清單中有一件商品被賣家完全刪除。系統自動移除該商品並在下次登入時顯示通知:「您的願望清單中有 1 件商品已不存在」。
## 業務規則
- 每位使用者願望清單上限:500 件商品
- 願望清單為私人資料,不對外公開
- 商品下架後保留在願望清單中 90 天,之後自動移除
- 商品完全刪除時立即從願望清單移除並通知使用者
- 價格變動通知:降價超過 10% 時發送 Email 通知(需使用者開啟通知設定)
## 驗收標準
- [ ] 未認證使用者點擊願望清單時導向登入,登入後自動加入
- [ ] 已認證使用者可以即時加入/移除願望清單(樂觀 UI 更新)
- [ ] 願望清單頁面支援分頁載入(每頁 20 件)
- [ ] 無法購買的商品在願望清單中以視覺標示區分
- [ ] 顯示商品加入時價格與目前價格的比較
- [ ] 已刪除的商品從願望清單中移除並通知
- [ ] 願望清單為空時顯示引導文案
## 與現有功能的關係
- 現有功能:商品收藏(簡單列表,無價格追蹤)
- 決策:建立新願望清單服務,逐步淘汰舊收藏功能
- 遷移計畫:待產品團隊確認淘汰時程
## 排除範圍(本次不做)
- 願望清單分享功能
- 願望清單分類/資料夾
- 多個願望清單
- 降價推播通知(僅 Email)
## 待討論問題(精煉會議)
- 空狀態設計細節
- 價格變動通知頻率上限
- 舊收藏功能遷移路徑與時程要點
精煉前的種子審查會議能及早發現模糊和邊界案例。每個角色帶來他們的觀點:BE 問資料、FE 問互動、UX 問狀態、QA 問邊界案例。ADM 確保團隊考慮與現有功能的關係,避免功能重疊或遺漏淘汰計畫。同步會議讓團隊能即時討論和澄清,比非同步留言更有效率。
階段 2 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 更新後的種子文件 | requirements/product-wishlist.md | PM |
階段 3:提案生成與審查(PM + ADM + 團隊)
背景
種子審查完成後,PM 使用種子作為 /openspec:proposal 的輸入,讓 Agent 生成正式提案。團隊隨後一起審查 Agent 的產出。
3.1 PM 生成提案
PM(Alice): 開啟 Claude Code
claude "根據 requirements/product-wishlist.md 種子文件,
使用 /openspec:proposal 生成正式提案"Agent: 生成提案草稿
<!-- openspec/changes/wishlist-feature/proposal.md -->
---
id: wishlist-feature
title: 商品願望清單功能
status: draft
owner: PM-Alice
created: 2026-04-16
---
# 商品願望清單功能
## 概述
為電商平台新增商品願望清單功能,讓使用者可以儲存感興趣的商品。
## 變更範圍
### 後端變更
| 檔案 | 變更類型 | 說明 |
|------|----------|------|
| `services/wishlist/` | 新增 | 願望清單微服務 |
| `api/wishlist.yaml` | 新增 | API 規格 |
### 前端變更
| 檔案 | 變更類型 | 說明 |
|------|----------|------|
| `components/WishlistButton/` | 新增 | 願望清單按鈕元件 |
| `pages/wishlist/` | 新增 | 願望清單頁面 |
## 驗收標準
(繼承自種子文件)3.2 團隊逐行審查提案
ADM(Frank): 召開提案審查會議,投影提案內容
「各位,Agent 已經根據種子生成了提案草稿。我們現在逐行審查,有問題直接請 Agent 修改。」
ADM(Frank): 「先看『概述』區塊...」
PM(Alice):
「概述太簡略了。應該加上業務價值說明。」
ADM(Frank): 即時請 Agent 修改
claude "更新提案的概述區塊,加入業務價值說明:
這是 Q1 調查第三大需求,預期提升使用者黏著度和轉換率"Agent: 即時更新提案
ADM(Frank): 「好,繼續看『變更範圍』...」
BE(Bob):
「後端變更建議使用獨立的願望清單微服務,避免與商品服務耦合。請 Agent 補充這個架構決策。」
ADM(Frank): 即時請 Agent 修改
claude "更新變更範圍的後端變更,
說明使用獨立微服務架構,並加入架構決策說明"FE(Carol):
「前端變更缺少樂觀更新的技術需求說明。」
UX(Diana):
「我有個問題:願望清單動畫要用什麼模式?」
ADM(Frank): 「好問題。Carol 和 Diana,你們的意見?」
FE(Carol): 「建議遵循現有的『加入購物車』互動模式,保持一致性。」
ADM(Frank): 「還有一個重要議題:舊收藏功能的處理。」
BE(Bob):
「如果要淘汰舊收藏功能,我們需要在提案中加入:資料遷移計畫、API 相容性策略、淘汰時程。」
PM(Alice):
「我已經跟產品團隊確認過,他們同意 6 個月後淘汰舊功能。我們需要在這期間維持兩個系統並行。」
FE(Carol):
「前端需要加入遷移提示,引導使用者從舊收藏移動到新願望清單。這可能超出本次需求範圍。」
ADM(Frank): 「好,這是範圍外變動。我們記錄為後續任務,但提案需要說明相依性。」
ADM(Frank): 彙整修改請求
claude "更新提案:
1. 前端變更加入樂觀更新技術需求
2. 新增技術決策區塊,記錄:
- BE:獨立微服務架構
- FE:樂觀更新模式
- UX:遵循加入購物車動畫模式
3. 新增範圍確認區塊:
- MVP 不包含:願望清單分類、分享願望清單
- MVP 包含:加入/移除、清單檢視、降價提醒
4. 新增與現有功能關係區塊:
- 舊功能:商品收藏(將於 6 個月後淘汰)
- 資料遷移:自動將舊收藏匯入新願望清單
- 範圍外後續任務:遷移提示 UI、舊 API 廢棄公告"Agent: 更新所有規格
ADM(Frank): 「提案已更新完成。各位確認一下最終版本...沒問題的話,Diana 和 Bob 請在週末前完成你們的規格。」
要點
逐行審查讓團隊能即時發現問題並請 Agent 修正。審查時必須確認與現有功能的關係:是否擴充、是否淘汰、是否有範圍外的相依變動。這些決策都應記錄在提案中,範圍外任務則記錄為後續工作。
階段 3 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| OpenSpec 提案 | openspec/changes/wishlist-feature/proposal.md | PM + Agent |
階段 4:API First 設計(BE + Agent + 團隊審查)
背景
API First 設計流程。根據階段 3 產生的 OpenSpec 提案,BE 依照 API 設計原則請 Agent 產生 OpenAPI 文件,並提交到 API 管理平台(Git-based)供團隊審查。
4.1 BE 產生 API 規格
BE(Bob): 開啟 Claude Code
「根據提案中的需求,我需要設計願望清單 API。」
claude "根據 openspec/changes/wishlist-feature/proposal.md,
依照我們的 API 設計原則(RESTful、一致性命名、分頁標準)
建立 OpenAPI 3.0 規格,包含:
- GET /wishlist(分頁)
- POST /wishlist(加入商品)
- DELETE /wishlist/{productId}(移除商品)
包含帶有降價指示器的 WishlistItem schema。"Agent: 生成 OpenAPI 規格
# specs/api/wishlist-api.yaml
openapi: 3.0.3
info:
title: Wishlist API
version: 1.0.0
description: 商品願望清單 API
paths:
/api/v1/wishlist:
get:
summary: 取得願望清單
operationId: getWishlist
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/WishlistResponse'
post:
summary: 加入願望清單
operationId: addToWishlist
requestBody:
content:
application/json:
schema:
type: object
required:
- productId
properties:
productId:
type: string
responses:
'201':
description: 加入成功
/api/v1/wishlist/{productId}:
delete:
summary: 從願望清單移除
operationId: removeFromWishlist
parameters:
- name: productId
in: path
required: true
schema:
type: string
responses:
'204':
description: 移除成功
components:
schemas:
WishlistResponse:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/WishlistItem'
pagination:
$ref: '#/components/schemas/Pagination'
WishlistItem:
type: object
properties:
productId:
type: string
productName:
type: string
imageUrl:
type: string
currentPrice:
type: number
originalPrice:
type: number
priceDropped:
type: boolean
isAvailable:
type: boolean
addedAt:
type: string
format: date-time4.2 提交到 API 管理平台
BE(Bob): 提交 API 規格到 Git-based API 管理平台
git add specs/api/wishlist-api.yaml
git commit -m "feat(api): add wishlist API specification"
git push origin feature/wishlist-apiBE(Bob): 「API 規格已提交,請 ADM 安排審查會議。」
4.3 團隊逐行審查 API 規格
ADM(Frank): 召開 API 審查會議(實體或線上),投影 API 規格
「各位,包括 Alice,我們來逐行審查願望清單 API 規格。有問題直接請 Agent 修改。」
ADM(Frank): 「先看 GET /wishlist endpoint...」
PM(Alice):
「分頁參數沒問題。但我想確認,刪除商品的通知機制會在哪裡處理?」
BE(Bob):
「刪除商品的通知會透過事件驅動架構處理,不在這個 API 範圍內。我請 Agent 在 API 文件加上備註說明。」
ADM(Frank): 即時請 Agent 修改
claude "在 wishlist-api.yaml 的 info.description 加入備註:
刪除商品通知透過事件驅動架構處理,不在此 API 範圍"ADM(Frank): 「繼續看 WishlistItem schema...」
FE(Carol):
「priceDropped 布林值很好用。但 addedAt 欄位的格式需要明確說明是 ISO 8601。」
ADM(Frank): 即時請 Agent 修改
claude "更新 WishlistItem schema 的 addedAt 欄位,
加入 example 說明 ISO 8601 格式"QA(Eve):
「缺少錯誤回應的 schema,這會影響測試設計。」
ADM(Frank): 即時請 Agent 修改
claude "新增 ErrorResponse schema,並在所有 endpoint 加入
400、401、404、500 的錯誤回應定義"Agent: 更新所有規格
UX(Diana):
「API 能支援空狀態和分頁載入的 UI 需求。我這邊沒問題。」
ADM(Frank): 「API 規格更新完成。各位確認最終版本...」
BE(Bob): 確認後合併
git commit -m "feat(api): finalize wishlist API after review"
git push && gh pr merge --squash要點
逐行審查 API 規格讓團隊能即時發現問題並請 Agent 修正。PM 確保 API 滿足業務需求,FE 確保回應格式可用,QA 確保錯誤處理完整。所有修改在會議中完成,避免來回修改。
階段 4 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| OpenAPI 規格 | specs/api/wishlist-api.yaml | BE + Agent |
階段 5:UX 設計(UX + Agent)
背景
有了確定的 API 契約,UX 設計使用者體驗,並建立詳細的互動規格,這些規格將指導 AI 實作和人工審查。
5.1 UX 設計線框圖
UX(Diana): 設計願望清單功能的 UI
「根據 API 規格和提案需求,我需要設計:
- 商品卡片上的願望清單按鈕(愛心圖示)
- 個人檔案中的願望清單頁面(格狀佈局)
- 空狀態畫面」
Diana: 完成線框圖設計後,記錄互動規格
5.2 UX 標註驗收標準
UX(Diana): 開啟 Claude Code
「根據我的線框圖和已確定的 API 規格,我需要建立帶有驗收標準的互動規格。」
claude "為願望清單按鈕和格狀元件建立 UX 互動規格。
參考 specs/api/wishlist-api.yaml 的回應格式。
包含 Given/When/Then 情境:
- 加入願望清單(已認證)
- 加入願望清單(未認證)
- 從願望清單移除"Agent: 生成互動規格
<!-- specs/ux/wishlist-interaction.md -->
---
title: 願望清單互動規格
type: ux-spec
api-ref: specs/api/wishlist-api.yaml
components:
- WishlistButton
- WishlistGrid
- EmptyState
---
# 願望清單互動規格
## 願望清單按鈕互動
### 狀態定義
| 狀態 | 視覺效果 | 行為 |
|------|----------|------|
| 未儲存 | 空心愛心 | 點擊時填滿動畫 |
| 已儲存 | 實心愛心(紅色) | 點擊時縮小淡出動畫 |
| 載入中 | 愛心 + 轉圈 | 點擊停用 |
### 驗收標準(Given/When/Then)
**情境:使用者將商品加入願望清單**
- Given:使用者已認證且商品不在願望清單中
- When:使用者點擊願望清單按鈕
- Then:按鈕立即顯示已儲存狀態(樂觀更新)
- And:「已加入願望清單」吐司訊息出現
- And:背景呼叫 POST /api/v1/wishlist
**情境:未認證使用者嘗試儲存**
- Given:使用者未認證
- When:使用者點擊願望清單按鈕
- Then:登入模態視窗出現
- And:成功登入後,商品自動儲存UX(Diana): 「好的。讓我對照線框圖審查這份規格...狀態定義相符,API 參考也正確。我會把這份規格提交到儲存庫。」
要點
UX 規格參考已確定的 API 規格,確保前端互動與後端契約一致。Given/When/Then 格式使其可被機器解析,並可直接用於測試生成。
階段 5 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 線框圖 / 設計稿 | Figma | UX |
| UX 互動規格 | specs/ux/wishlist-interaction.md | UX + Agent |
階段 6:實作(Agent + FE/BE 審查)
背景
有了核准的提案,Agent 根據規格實作程式碼。人工審查者(BE/FE)驗證是否符合規格和最佳實踐。
6.1 後端實作
ADM(Frank): 「Bob,提案已核准。請指導 Agent 進行後端實作。」
BE(Bob): 開啟 Claude Code
claude "根據 openspec/changes/wishlist-feature/proposal.md
使用 /openspec:apply 實作後端 API"Agent: 生成後端實作
// services/wishlist/wishlist.service.ts
import { Injectable } from '@nestjs/common';
import { WishlistRepository } from './wishlist.repository';
@Injectable()
export class WishlistService {
constructor(private readonly repository: WishlistRepository) {}
async getWishlist(userId: string, page: number, limit: number) {
const items = await this.repository.findByUserId(userId, {
skip: (page - 1) * limit,
take: limit,
});
const total = await this.repository.countByUserId(userId);
return {
items: items.map(this.toWishlistItem),
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
};
}
async addToWishlist(userId: string, productId: string) {
const existing = await this.repository.findOne(userId, productId);
if (existing) {
return existing;
}
return this.repository.create({ userId, productId });
}
async removeFromWishlist(userId: string, productId: string) {
await this.repository.delete(userId, productId);
}
}6.2 BE 審查
BE(Bob): 審查 Agent 產出的程式碼
「讓我看看 WishlistService 的實作...getWishlist 方法有正確實作分頁邏輯,addToWishlist 有處理重複加入的情況。不過我注意到缺少快取策略,這在高流量時會有效能問題。」
BE(Bob): 「核心實作符合 API 規格。我會開一個後續任務處理快取優化。核准合併。」
6.3 前端實作
ADM(Frank): 「Carol,後端準備好了。請指導 Agent 進行前端實作。」
FE(Carol): 開啟 Claude Code
claude "根據 specs/ux/wishlist-interaction.md
使用設計系統的 Button 和 Card 元件實作前端元件"Agent: 生成前端實作
// components/WishlistButton/WishlistButton.tsx
import { useState, useCallback } from 'react';
import { Heart } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useWishlist } from '@/hooks/useWishlist';
import { useAuth } from '@/hooks/useAuth';
import { cn } from '@/lib/utils';
interface WishlistButtonProps {
productId: string;
className?: string;
}
export function WishlistButton({ productId, className }: WishlistButtonProps) {
const { isAuthenticated, openLoginModal } = useAuth();
const { isInWishlist, toggle, isLoading } = useWishlist(productId);
const [isAnimating, setIsAnimating] = useState(false);
const handleClick = useCallback(async () => {
if (!isAuthenticated) {
openLoginModal({ onSuccess: () => toggle() });
return;
}
setIsAnimating(true);
await toggle();
setTimeout(() => setIsAnimating(false), 300);
}, [isAuthenticated, toggle, openLoginModal]);
return (
<Button
variant="ghost"
size="icon"
onClick={handleClick}
disabled={isLoading}
className={cn(
'transition-transform',
isAnimating && 'scale-125',
className
)}
aria-label={isInWishlist ? '從願望清單移除' : '加入願望清單'}
>
<Heart
className={cn(
'h-5 w-5 transition-colors',
isInWishlist ? 'fill-red-500 text-red-500' : 'text-gray-400'
)}
/>
</Button>
);
}6.4 FE 審查
FE(Carol): 對照 UX 規格審查程式碼
「WishlistButton 的狀態切換邏輯正確,樂觀更新有實作。aria-label 也有加上,符合無障礙標準。不過我發現缺少 API 失敗時的錯誤狀態處理,這會影響使用者體驗。」
FE(Carol): 「核心互動符合 UX 規格。我請 Agent 補上錯誤處理後就可以合併。」
要點
人工審查是必要的。Agent 快速生成程式碼,但人類驗證是否正確符合規格,並捕捉 Agent 可能遺漏的邊界案例。
階段 6 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 後端程式碼 | services/wishlist/ | Agent + BE |
| 前端程式碼 | components/WishlistButton/ | Agent + FE |
階段 7:測試(QA + Agent)
背景
QA 從規格生成測試案例並執行。UX 規格中的 Given/When/Then 格式直接對應到測試情境。
7.1 QA 請求 Agent 生成測試
ADM(Frank): 「Eve,實作完成了。請生成並執行 E2E 測試。」
QA(Eve): 開啟 Claude Code
claude "根據 proposal.md 和 wishlist-interaction.md
生成 E2E 測試案例"Agent: 生成測試案例
// tests/e2e/wishlist.spec.ts
import { test, expect } from '@playwright/test';
test.describe('商品願望清單功能', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/products/test-product-1');
});
test('已認證使用者可以將商品加入願望清單', async ({ page }) => {
// Given:使用者已認證
await page.evaluate(() => {
localStorage.setItem('token', 'test-token');
});
await page.reload();
// When:點擊願望清單按鈕
const wishlistBtn = page.getByLabel('加入願望清單');
await wishlistBtn.click();
// Then:按鈕顯示已儲存狀態
await expect(wishlistBtn).toHaveAttribute('aria-label', '從願望清單移除');
// And:成功吐司訊息出現
await expect(page.getByText('已加入願望清單')).toBeVisible();
});
test('未認證使用者點擊願望清單時看到登入模態視窗', async ({ page }) => {
// Given:使用者未認證
await page.evaluate(() => {
localStorage.removeItem('token');
});
// When:點擊願望清單按鈕
await page.getByLabel('加入願望清單').click();
// Then:登入模態視窗出現
await expect(page.getByRole('dialog')).toBeVisible();
await expect(page.getByText('請登入')).toBeVisible();
});
test('願望清單顯示降價指示器', async ({ page }) => {
// Given:使用者有已降價的願望清單商品
await page.goto('/wishlist');
// Then:降價標籤可見
await expect(page.getByText('價格已降')).toBeVisible();
});
});7.2 QA 執行測試
QA(Eve): 「執行 E2E 測試中...」
npx playwright test tests/e2e/wishlist.spec.ts
# 結果
Running 3 tests using 1 worker
✓ 已認證使用者可以將商品加入願望清單 (1.2s)
✓ 未認證使用者點擊願望清單時看到登入模態視窗 (0.8s)
✓ 願望清單顯示降價指示器 (0.9s)
3 passed (3.5s)QA(Eve): 「所有測試通過。功能符合驗收標準。」
ADM(Frank): 「太好了。讓我們進行部署。」
要點
測試從規格生成,確保它們驗證的是實際需求。Given/When/Then 格式從需求到測試建立了直接的可追溯性。
階段 7 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| E2E 測試案例 | tests/e2e/wishlist.spec.ts | Agent + QA |
| 測試報告 | CI/CD 系統 | QA |
階段 8:歸檔(PM + ADM + Agent)
背景
成功部署後,提案被歸檔。這更新了單一事實來源並建立了審計軌跡。
8.1 PM 請求歸檔
PM(Alice): 「功能已上線並在生產環境驗證完成。是時候歸檔了。」
claude "願望清單功能通過所有測試並已部署,
使用 /openspec:archive 歸檔這個變更"8.2 Agent 執行歸檔
Agent: 執行歸檔流程
# Agent 執行歸檔流程
1. 更新提案狀態為 archived
2. 將規格合併到 specs/ 目錄
3. 更新 CHANGELOG.md
4. 建立 git tag<!-- openspec/changes/wishlist-feature/proposal.md -->
---
status: archived
archived_at: 2026-04-26
deployed_version: v2.3.0
---ADM(Frank): 「歸檔完成。團隊辛苦了。願望清單功能現在是我們生產規格的一部分了。」
階段 8 產出工件:
| 工件 | 位置 | 負責人 |
|---|---|---|
| 歸檔後的提案 | openspec/archive/wishlist-feature/ | Agent |
| 合併後的規格 | specs/ 目錄 | Agent |
| CHANGELOG 更新 | CHANGELOG.md | Agent |
完整工件清單
| 階段 | 工件 | 位置 | 負責人 |
|---|---|---|---|
| 1 | 需求種子文件 | requirements/ | PM |
| 2 | 更新後的種子文件 | requirements/ | PM |
| 3 | OpenSpec 提案 | openspec/changes/ | PM + Agent |
| 4 | OpenAPI 規格 | specs/api/ | BE + Agent |
| 5 | 線框圖 / 設計稿 | Figma | UX |
| 5 | UX 互動規格 | specs/ux/ | UX + Agent |
| 6 | 後端程式碼 | services/ | Agent + BE |
| 6 | 前端程式碼 | components/ | Agent + FE |
| 7 | E2E 測試案例 | tests/e2e/ | Agent + QA |
| 8 | 歸檔後的提案 | openspec/archive/ | Agent |
| 8 | 合併後的規格 | specs/ | Agent |
流程摘要
Agentic Development Master(ADM)的角色
ADM 作為 SDD 交響樂團的指揮:
| 傳統 Scrum Master | Agentic Development Master |
|---|---|
| 主持儀式 | 協調 AI-人類協作 |
| 移除阻礙 | 確保規格品質與完整性 |
| 追蹤速度 | 監控 AI 產出品質關卡 |
| 指導團隊 Scrum | 指導團隊脈絡工程 |
| 保護團隊免受干擾 | 協調跨角色交接 |