使用 Claude Code 進行開發不僅僅是「問 AI 寫程式碼」那麼簡單。真正高效的開發需要建立系統化的工作流程,從需求分析到部署上線,每個階段都有最佳實踐。本文將深入探討如何在軟體開發生命週期的各個階段充分發揮 Claude Code 的潛力。
🎯 為什麼需要標準化工作流程?
無流程 vs 有流程的對比
❌ 無流程開發(混亂模式):
使用者: "幫我寫個登入功能"
Claude: [寫了一些程式碼]
使用者: "欸不對,我要用 OAuth"
Claude: [重寫]
使用者: "忘了說,還要雙因素驗證"
Claude: [再改]
使用者: "糟糕,沒考慮到資料庫設計..."
...反覆修改,浪費大量時間...
結果:
• 程式碼品質不一致
• 缺少測試和文檔
• 頻繁返工
• 技術債累積
✅ 有流程開發(系統化模式):
階段 1: 需求分析 (15 分鐘)
→ 明確功能範圍
→ 識別技術限制
→ 規劃整體架構
階段 2: 設計規劃 (20 分鐘)
→ 資料庫設計
→ API 設計
→ 前端架構
階段 3: 開發實作 (60 分鐘)
→ 後端開發
→ 前端開發
→ 整合測試
階段 4: 測試部署 (30 分鐘)
→ 單元測試
→ 整合測試
→ 部署檢查
結果:
• 高品質、可維護的程式碼
• 完整的測試覆蓋
• 清晰的文檔
• 減少技術債
📋 標準開發流程總覽
完整的開發生命週期
┌────────────────────────────────────────────────────┐
│ Claude Code 開發生命週期 │
│ │
│ 1️⃣ 需求分析階段 (Requirements Analysis) │
│ ├─ 理解需求 │
│ ├─ 識別限制條件 │
│ ├─ 評估可行性 │
│ └─ 定義驗收標準 │
│ │
│ 2️⃣ 設計規劃階段 (Design & Planning) │
│ ├─ 架構設計 │
│ ├─ 資料庫設計 │
│ ├─ API 設計 │
│ └─ 任務分解 │
│ │
│ 3️⃣ 開發實作階段 (Implementation) │
│ ├─ 後端開發 │
│ ├─ 前端開發 │
│ ├─ 整合開發 │
│ └─ 程式碼審查 │
│ │
│ 4️⃣ 測試驗證階段 (Testing & Validation) │
│ ├─ 單元測試 │
│ ├─ 整合測試 │
│ ├─ E2E 測試 │
│ └─ 效能測試 │
│ │
│ 5️⃣ 部署上線階段 (Deployment) │
│ ├─ 部署前檢查 │
│ ├─ 部署執行 │
│ ├─ 監控驗證 │
│ └─ 文檔更新 │
│ │
│ 6️⃣ 維護優化階段 (Maintenance) │
│ ├─ Bug 修復 │
│ ├─ 效能優化 │
│ ├─ 功能增強 │
│ └─ 重構優化 │
└────────────────────────────────────────────────────┘
1️⃣ 需求分析階段
目標:充分理解並明確化需求
與 Claude Code 的對話流程:
1步驟 1: 初步需求描述
2────────────────────────────────────────
3
4使用者:
5"我需要在電商網站加入購物車功能"
6
7Claude 回應(引導式提問):
8"我來幫你分析購物車功能的需求。請回答以下問題:
9
10【功能範圍】
111. 需要哪些核心功能?
12 - 新增商品到購物車
13 - 修改商品數量
14 - 移除商品
15 - 清空購物車
16 - 其他?
17
182. 需要支援哪些特殊情境?
19 - 未登入使用者的購物車(臨時儲存)
20 - 多裝置同步
21 - 購物車有效期限
22 - 庫存檢查
23
24【技術限制】
253. 現有技術棧?
26 - 前端框架(React, Vue, Angular?)
27 - 後端語言(Node.js, Python, Java?)
28 - 資料庫(PostgreSQL, MongoDB?)
29 - 狀態管理(Redux, Zustand?)
30
314. 整合需求?
32 - 需要整合哪些現有功能?
33 - 有哪些 API 要串接?
34
35【限制條件】
365. 效能要求?
37 - 預期使用者數量
38 - 回應時間要求
39 - 併發處理需求
40
416. 安全性要求?
42 - 需要什麼層級的資料保護?
43 - 是否需要防止惡意操作?"
需求文檔範本:
1步驟 2: 整理需求文檔
2────────────────────────────────────────
3
4使用者提供詳細資訊後:
5
6"請根據我的回答,整理一份完整的需求文檔,
7包含功能需求、技術需求、限制條件和驗收標準"
8
9Claude 產出:
10
11# 購物車功能需求文檔
12
13## 1. 功能需求
14
15### 1.1 核心功能
16- **新增商品**: 使用者可將商品加入購物車
17 - 支援指定數量
18 - 支援選擇商品規格(顏色、尺寸)
19 - 即時更新購物車數量顯示
20
21- **修改數量**: 使用者可調整購物車中的商品數量
22 - 支援直接輸入數量
23 - 支援 +/- 按鈕調整
24 - 數量限制:1-99
25
26- **移除商品**: 使用者可從購物車移除商品
27 - 提供確認對話框
28 - 支援一鍵清空功能
29
30- **購物車查看**: 顯示購物車內容
31 - 商品資訊(名稱、圖片、價格、規格)
32 - 小計和總計
33 - 優惠折扣顯示
34
35### 1.2 進階功能
36- **臨時購物車**: 未登入使用者的購物車
37 - 使用 localStorage 暫存
38 - 登入後自動合併
39
40- **庫存檢查**: 即時檢查商品庫存
41 - 庫存不足時提示
42 - 自動調整到最大可購買數量
43
44- **購物車同步**: 多裝置購物車同步
45 - 登入使用者的購物車存在伺服器
46 - 裝置間即時同步
47
48## 2. 技術需求
49
50### 2.1 技術棧
51- **前端**: React 18 + TypeScript
52- **狀態管理**: Zustand
53- **後端**: Node.js + Express
54- **資料庫**: PostgreSQL
55- **快取**: Redis(購物車資料)
56
57### 2.2 API 設計
58```typescript
59// 購物車 API endpoints
60POST /api/cart/items // 新增商品
61PUT /api/cart/items/:id // 更新數量
62DELETE /api/cart/items/:id // 移除商品
63GET /api/cart // 取得購物車
64DELETE /api/cart // 清空購物車
65POST /api/cart/merge // 合併臨時購物車
2.3 資料庫設計
1-- 購物車資料表
2CREATE TABLE carts (
3 id UUID PRIMARY KEY,
4 user_id UUID REFERENCES users(id),
5 session_id VARCHAR(255), -- 未登入使用者
6 created_at TIMESTAMP,
7 updated_at TIMESTAMP
8);
9
10-- 購物車項目資料表
11CREATE TABLE cart_items (
12 id UUID PRIMARY KEY,
13 cart_id UUID REFERENCES carts(id),
14 product_id UUID REFERENCES products(id),
15 quantity INTEGER CHECK (quantity > 0 AND quantity <= 99),
16 variant_id UUID REFERENCES product_variants(id),
17 created_at TIMESTAMP,
18 updated_at TIMESTAMP,
19 UNIQUE(cart_id, product_id, variant_id)
20);
3. 限制條件
3.1 效能要求
- API 回應時間 < 200ms
- 支援 1000 併發請求
- 購物車最多 100 個商品
3.2 安全性要求
- API 需要認證(JWT)
- 防止 CSRF 攻擊
- 輸入驗證和淨化
- Rate limiting(每分鐘 60 請求)
3.3 相容性要求
- 支援現代瀏覽器(Chrome, Firefox, Safari, Edge)
- 移動裝置響應式設計
- 無障礙設計(WCAG 2.1 AA)
4. 驗收標準
4.1 功能驗收
- 使用者可以成功新增商品到購物車
- 購物車數量顯示正確
- 可以修改商品數量
- 可以移除商品
- 總金額計算正確
- 未登入使用者的購物車在登入後正確合併
- 庫存不足時正確提示
4.2 效能驗收
- 新增商品回應時間 < 200ms
- 頁面載入時間 < 1s
- 支援 1000 併發使用者
4.3 安全性驗收
- 未認證使用者無法存取他人購物車
- 輸入驗證正常運作
- XSS 和 CSRF 防護有效
5. 開發時程估算
- 資料庫設計與 API 開發: 2 天
- 前端元件開發: 3 天
- 整合與測試: 2 天
- 部署與文檔: 1 天
總計: 8 個工作天
### 需求確認檢查清單
```markdown
在進入設計階段前,確認以下項目:
功能需求
☐ 所有核心功能都已明確定義
☐ 邊界情況和例外情境已考慮
☐ 使用者體驗流程清晰
☐ 與現有功能的整合點已識別
技術需求
☐ 技術棧已確定
☐ 資料庫選擇已決定
☐ API 設計原則已定義
☐ 第三方服務整合需求明確
限制條件
☐ 效能要求已量化
☐ 安全性需求已明確
☐ 時間和資源限制已溝通
☐ 相容性要求已定義
驗收標準
☐ 功能驗收標準可測試
☐ 效能指標可量測
☐ 成功標準明確無歧義
2️⃣ 設計規劃階段
目標:設計可擴展、可維護的架構
使用 Plan Mode 進行架構設計:
1// 啟動 Plan Mode(適合複雜功能)
2
3使用者:
4"根據購物車需求文檔(docs/cart-requirements.md),
5進入 Plan Mode 設計完整的實作計畫"
6
7Claude 回應:
8"我將進入 Plan Mode 為購物車功能設計實作計畫。
9讓我先探索專案結構..."
10
11[Claude 使用 Plan Agent]
12• Glob 掃描專案結構
13• Read 讀取相關檔案(現有的 API、資料庫設計)
14• Grep 搜尋類似功能的實作參考
Plan Agent 產出的實作計畫:
1# 購物車功能實作計畫
2
3## 階段 1: 資料庫設計 (2 小時)
4
5### 1.1 Schema 設計
6檔案: `prisma/schema.prisma`
7
8```prisma
9model Cart {
10 id String @id @default(uuid())
11 userId String? @map("user_id")
12 sessionId String? @map("session_id")
13 items CartItem[]
14 createdAt DateTime @default(now()) @map("created_at")
15 updatedAt DateTime @updatedAt @map("updated_at")
16
17 user User? @relation(fields: [userId], references: [id])
18
19 @@index([userId])
20 @@index([sessionId])
21 @@map("carts")
22}
23
24model CartItem {
25 id String @id @default(uuid())
26 cartId String @map("cart_id")
27 productId String @map("product_id")
28 variantId String? @map("variant_id")
29 quantity Int
30 createdAt DateTime @default(now()) @map("created_at")
31 updatedAt DateTime @updatedAt @map("updated_at")
32
33 cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade)
34 product Product @relation(fields: [productId], references: [id])
35 variant ProductVariant? @relation(fields: [variantId], references: [id])
36
37 @@unique([cartId, productId, variantId])
38 @@index([cartId])
39 @@map("cart_items")
40}
1.2 Migration
1npx prisma migrate dev --name add_cart_tables
階段 2: 後端實作 (4 小時)
2.1 服務層
檔案: src/services/cartService.ts
功能:
getCart(userId, sessionId): 取得購物車addItem(cartId, productId, quantity, variantId): 新增商品updateItemQuantity(itemId, quantity): 更新數量removeItem(itemId): 移除商品clearCart(cartId): 清空購物車mergeCarts(userId, sessionId): 合併購物車validateStock(productId, quantity): 驗證庫存
2.2 API 層
檔案: src/api/cart/cartController.ts
Endpoints:
GET /api/cart→ getCart()POST /api/cart/items→ addItem()PUT /api/cart/items/:id→ updateItem()DELETE /api/cart/items/:id→ removeItem()DELETE /api/cart→ clearCart()POST /api/cart/merge→ mergeCarts()
2.3 中介層
檔案: src/middleware/cartMiddleware.ts
功能:
getOrCreateCart: 取得或建立購物車validateCartAccess: 驗證購物車存取權限checkStock: 檢查庫存
2.4 驗證層
檔案: src/validators/cartValidator.ts
驗證規則:
- 商品 ID 格式
- 數量範圍(1-99)
- Variant ID(如有)
階段 3: Redis 快取 (1 小時)
3.1 快取策略
檔案: src/services/cacheService.ts
快取內容:
- 購物車資料(TTL: 1 小時)
- 商品庫存(TTL: 5 分鐘)
快取 Key 設計:
cart:{userId}或cart:session:{sessionId}stock:{productId}
階段 4: 前端實作 (6 小時)
4.1 狀態管理
檔案: src/stores/cartStore.ts
使用 Zustand:
1interface CartStore {
2 cart: Cart | null;
3 isLoading: boolean;
4 error: string | null;
5
6 // Actions
7 fetchCart: () => Promise<void>;
8 addItem: (productId, quantity, variantId?) => Promise<void>;
9 updateQuantity: (itemId, quantity) => Promise<void>;
10 removeItem: (itemId) => Promise<void>;
11 clearCart: () => Promise<void>;
12}
4.2 元件開發
檔案結構:
src/components/Cart/
├── CartButton.tsx # 購物車圖示按鈕
├── CartDrawer.tsx # 購物車側邊欄
├── CartItem.tsx # 購物車項目
├── CartSummary.tsx # 購物車摘要
├── AddToCartButton.tsx # 加入購物車按鈕
└── EmptyCart.tsx # 空購物車狀態
4.3 API 整合
檔案: src/api/cartApi.ts
使用 axios:
1export const cartApi = {
2 getCart: () => api.get('/cart'),
3 addItem: (data) => api.post('/cart/items', data),
4 updateItem: (id, data) => api.put(`/cart/items/${id}`, data),
5 removeItem: (id) => api.delete(`/cart/items/${id}`),
6 clearCart: () => api.delete('/cart'),
7};
階段 5: 測試 (4 小時)
5.1 單元測試
cartService.test.ts: 服務層邏輯測試cartController.test.ts: API 層測試cartStore.test.ts: 狀態管理測試
5.2 整合測試
cart.integration.test.ts: API 整合測試- 測試完整的購物車流程
5.3 E2E 測試
cart.e2e.test.ts: 使用者操作流程測試
階段 6: 部署準備 (2 小時)
6.1 環境變數
1REDIS_URL=redis://localhost:6379
2DATABASE_URL=postgresql://...
6.2 部署檢查清單
- Migration 已執行
- Redis 連線正常
- API endpoints 測試通過
- 前端打包成功
- 環境變數已設定
6.3 文檔更新
- API 文檔(OpenAPI/Swagger)
- 使用者操作指南
- 開發者文檔
風險與注意事項
⚠️ 潛在風險:
併發購物車更新衝突 → 使用樂觀鎖定(Optimistic Locking)
Redis 快取與資料庫不一致 → 實作 Cache-Aside Pattern,設定適當 TTL
庫存超賣問題 → 在 checkout 時再次驗證庫存
大量商品導致購物車載入慢 → 實作分頁或虛擬捲動
總時程估算
- 階段 1 (資料庫): 2 小時
- 階段 2 (後端): 4 小時
- 階段 3 (快取): 1 小時
- 階段 4 (前端): 6 小時
- 階段 5 (測試): 4 小時
- 階段 6 (部署): 2 小時
總計: 19 小時 (約 2.5 個工作天)
**Plan Mode 的價值:**
✅ 使用 Plan Mode 的好處:
全面性規劃 • 考慮所有技術層面 • 識別潛在問題 • 規劃測試策略
結構化執行 • 明確的階段劃分 • 清晰的檔案組織 • 可追蹤的進度
團隊協作 • 可供審查的設計文檔 • 明確的任務分工 • 統一的實作標準
風險管理 • 提前識別風險 • 規劃應對策略 • 預估時程
## 3️⃣ 開發實作階段
### 目標:按計畫高效實作功能
**實作流程範例:後端開發**
```typescript
═══════════════════════════════════════════════════════
對話 1: 資料庫設計與 Migration
═══════════════════════════════════════════════════════
使用者:
"根據實作計畫(docs/cart-implementation-plan.md),
開始階段 1:資料庫設計。
請:
1. 更新 prisma/schema.prisma 加入 Cart 和 CartItem models
2. 產生 migration
3. 執行 migration
4. 驗證 schema"
Claude 執行:
├─ Read prisma/schema.prisma
├─ Edit 加入新的 models
├─ Bash: npx prisma migrate dev --name add_cart_tables
├─ Bash: npx prisma generate
└─ 回報執行結果
【使用 TodoWrite 追蹤進度】
✓ 完成: 設計 Cart 和 CartItem schema
✓ 完成: 建立 migration
✓ 完成: 執行 migration
⏳ 待處理: 實作 cartService
⏳ 待處理: 實作 API endpoints
...
═══════════════════════════════════════════════════════
對話 2: 服務層實作
═══════════════════════════════════════════════════════
使用者:
"實作 src/services/cartService.ts,包含計畫中的所有功能。
要求:
- 使用 Prisma Client
- 包含完整的錯誤處理
- 加入 JSDoc 註解
- 處理邊界情況(庫存不足、商品不存在等)"
Claude 執行:
├─ Read prisma/schema.prisma(了解 schema)
├─ Read src/services/userService.ts(參考現有服務模式)
├─ Write src/services/cartService.ts
└─ 加入完整的型別定義和錯誤處理
產出範例:
```typescript
// src/services/cartService.ts
import { PrismaClient } from '@prisma/client';
import { CartNotFoundError, InsufficientStockError } from '../errors';
const prisma = new PrismaClient();
export class CartService {
/**
* 取得購物車
* @param userId - 使用者 ID(已登入)
* @param sessionId - Session ID(未登入)
*/
async getCart(userId?: string, sessionId?: string) {
if (!userId && !sessionId) {
throw new Error('userId or sessionId is required');
}
let cart = await prisma.cart.findFirst({
where: userId ? { userId } : { sessionId },
include: {
items: {
include: {
product: true,
variant: true,
},
},
},
});
// 如果購物車不存在,建立新的
if (!cart) {
cart = await prisma.cart.create({
data: {
userId,
sessionId,
},
include: {
items: {
include: {
product: true,
variant: true,
},
},
},
});
}
return cart;
}
/**
* 新增商品到購物車
*/
async addItem(
cartId: string,
productId: string,
quantity: number,
variantId?: string
) {
// 驗證庫存
await this.validateStock(productId, quantity, variantId);
// 檢查是否已存在
const existingItem = await prisma.cartItem.findFirst({
where: {
cartId,
productId,
variantId: variantId || null,
},
});
if (existingItem) {
// 更新數量
return await prisma.cartItem.update({
where: { id: existingItem.id },
data: {
quantity: existingItem.quantity + quantity,
},
include: {
product: true,
variant: true,
},
});
} else {
// 新增項目
return await prisma.cartItem.create({
data: {
cartId,
productId,
variantId,
quantity,
},
include: {
product: true,
variant: true,
},
});
}
}
/**
* 驗證庫存
*/
private async validateStock(
productId: string,
quantity: number,
variantId?: string
) {
const product = await prisma.product.findUnique({
where: { id: productId },
include: {
variants: variantId ? { where: { id: variantId } } : false,
},
});
if (!product) {
throw new ProductNotFoundError(productId);
}
const stock = variantId
? product.variants[0]?.stock
: product.stock;
if (stock < quantity) {
throw new InsufficientStockError(
productId,
variantId,
stock,
quantity
);
}
}
// ... 其他方法
}
export const cartService = new CartService();
【Todo 更新】 ✓ 完成: 設計 Cart 和 CartItem schema ✓ 完成: 建立 migration ✓ 完成: 執行 migration ✓ 完成: 實作 cartService ✓ 🔄 進行中: 實作 API endpoints ⏳ 待處理: 實作測試 …
═══════════════════════════════════════════════════════ 對話 3: API Endpoints 實作 ═══════════════════════════════════════════════════════
使用者: “實作 src/api/cart/cartController.ts 和路由設定。
參考:
- 現有的 API 模式: src/api/products/productController.ts
- Express Router 設定: src/api/index.ts
要求:
- RESTful API 設計
- 使用 async/await
- 完整的錯誤處理
- 輸入驗證(使用 express-validator)”
Claude 執行: ├─ Read src/api/products/productController.ts(學習模式) ├─ Read src/api/index.ts(了解路由結構) ├─ Write src/api/cart/cartController.ts ├─ Write src/api/cart/cartRouter.ts ├─ Edit src/api/index.ts(加入購物車路由) └─ Write src/validators/cartValidator.ts
產出範例:
1// src/api/cart/cartController.ts
2import { Request, Response, NextFunction } from 'express';
3import { cartService } from '../../services/cartService';
4import { ApiError } from '../../errors';
5
6export class CartController {
7 /**
8 * GET /api/cart
9 * 取得使用者的購物車
10 */
11 async getCart(req: Request, res: Response, next: NextFunction) {
12 try {
13 const userId = req.user?.id;
14 const sessionId = req.session?.id;
15
16 const cart = await cartService.getCart(userId, sessionId);
17
18 res.json({
19 success: true,
20 data: cart,
21 });
22 } catch (error) {
23 next(error);
24 }
25 }
26
27 /**
28 * POST /api/cart/items
29 * 新增商品到購物車
30 */
31 async addItem(req: Request, res: Response, next: NextFunction) {
32 try {
33 const { productId, quantity, variantId } = req.body;
34 const userId = req.user?.id;
35 const sessionId = req.session?.id;
36
37 // 取得或建立購物車
38 const cart = await cartService.getCart(userId, sessionId);
39
40 // 新增商品
41 const item = await cartService.addItem(
42 cart.id,
43 productId,
44 quantity,
45 variantId
46 );
47
48 res.status(201).json({
49 success: true,
50 data: item,
51 });
52 } catch (error) {
53 next(error);
54 }
55 }
56
57 // ... 其他方法
58}
59
60export const cartController = new CartController();
1// src/api/cart/cartRouter.ts
2import { Router } from 'express';
3import { cartController } from './cartController';
4import { validateAddItem } from '../../validators/cartValidator';
5import { authMiddleware } from '../../middleware/auth';
6
7const router = Router();
8
9// 所有路由都需要認證(或 session)
10router.use(authMiddleware.optionalAuth);
11
12router.get('/', cartController.getCart);
13router.post('/items', validateAddItem, cartController.addItem);
14router.put('/items/:id', cartController.updateItem);
15router.delete('/items/:id', cartController.removeItem);
16router.delete('/', cartController.clearCart);
17router.post('/merge', authMiddleware.requireAuth, cartController.mergeCarts);
18
19export default router;
【Todo 更新】 ✓ 完成: 實作 cartService ✓ 完成: 實作 API endpoints ✓ 🔄 進行中: 撰寫測試 ⏳ 待處理: 實作前端 …
═══════════════════════════════════════════════════════ 對話 4: 測試撰寫 ═══════════════════════════════════════════════════════
使用者: “為 cartService 撰寫完整的單元測試。
測試框架: Jest 測試檔案: src/services/tests/cartService.test.ts
測試涵蓋:
- 正常流程
- 邊界情況
- 錯誤處理
- 併發情境
期望覆蓋率 > 90%”
Claude 執行: ├─ Read src/services/cartService.ts ├─ Read src/services/tests/userService.test.ts(參考測試模式) └─ Write src/services/tests/cartService.test.ts
產出範例:
1// src/services/__tests__/cartService.test.ts
2import { cartService } from '../cartService';
3import { prisma } from '../../lib/prisma';
4import {
5 ProductNotFoundError,
6 InsufficientStockError,
7} from '../../errors';
8
9// Mock Prisma
10jest.mock('../../lib/prisma', () => ({
11 prisma: {
12 cart: {
13 findFirst: jest.fn(),
14 create: jest.fn(),
15 },
16 cartItem: {
17 findFirst: jest.fn(),
18 create: jest.fn(),
19 update: jest.fn(),
20 },
21 product: {
22 findUnique: jest.fn(),
23 },
24 },
25}));
26
27describe('CartService', () => {
28 beforeEach(() => {
29 jest.clearAllMocks();
30 });
31
32 describe('getCart', () => {
33 it('should return existing cart for user', async () => {
34 const mockCart = {
35 id: 'cart-1',
36 userId: 'user-1',
37 items: [],
38 };
39
40 (prisma.cart.findFirst as jest.Mock).mockResolvedValue(mockCart);
41
42 const result = await cartService.getCart('user-1');
43
44 expect(result).toEqual(mockCart);
45 expect(prisma.cart.findFirst).toHaveBeenCalledWith({
46 where: { userId: 'user-1' },
47 include: expect.any(Object),
48 });
49 });
50
51 it('should create new cart if not exists', async () => {
52 (prisma.cart.findFirst as jest.Mock).mockResolvedValue(null);
53 (prisma.cart.create as jest.Mock).mockResolvedValue({
54 id: 'cart-2',
55 userId: 'user-2',
56 items: [],
57 });
58
59 const result = await cartService.getCart('user-2');
60
61 expect(result.id).toBe('cart-2');
62 expect(prisma.cart.create).toHaveBeenCalled();
63 });
64
65 it('should throw error if no userId or sessionId', async () => {
66 await expect(cartService.getCart()).rejects.toThrow();
67 });
68 });
69
70 describe('addItem', () => {
71 it('should add new item to cart', async () => {
72 const mockProduct = {
73 id: 'product-1',
74 stock: 10,
75 };
76
77 (prisma.product.findUnique as jest.Mock).mockResolvedValue(mockProduct);
78 (prisma.cartItem.findFirst as jest.Mock).mockResolvedValue(null);
79 (prisma.cartItem.create as jest.Mock).mockResolvedValue({
80 id: 'item-1',
81 productId: 'product-1',
82 quantity: 2,
83 });
84
85 const result = await cartService.addItem('cart-1', 'product-1', 2);
86
87 expect(result.quantity).toBe(2);
88 expect(prisma.cartItem.create).toHaveBeenCalled();
89 });
90
91 it('should update quantity if item exists', async () => {
92 const mockProduct = { id: 'product-1', stock: 10 };
93 const existingItem = {
94 id: 'item-1',
95 quantity: 3,
96 };
97
98 (prisma.product.findUnique as jest.Mock).mockResolvedValue(mockProduct);
99 (prisma.cartItem.findFirst as jest.Mock).mockResolvedValue(existingItem);
100 (prisma.cartItem.update as jest.Mock).mockResolvedValue({
101 ...existingItem,
102 quantity: 5,
103 });
104
105 const result = await cartService.addItem('cart-1', 'product-1', 2);
106
107 expect(result.quantity).toBe(5);
108 expect(prisma.cartItem.update).toHaveBeenCalled();
109 });
110
111 it('should throw InsufficientStockError when stock is low', async () => {
112 const mockProduct = {
113 id: 'product-1',
114 stock: 2,
115 };
116
117 (prisma.product.findUnique as jest.Mock).mockResolvedValue(mockProduct);
118
119 await expect(
120 cartService.addItem('cart-1', 'product-1', 5)
121 ).rejects.toThrow(InsufficientStockError);
122 });
123
124 it('should throw ProductNotFoundError for invalid product', async () => {
125 (prisma.product.findUnique as jest.Mock).mockResolvedValue(null);
126
127 await expect(
128 cartService.addItem('cart-1', 'invalid-id', 1)
129 ).rejects.toThrow(ProductNotFoundError);
130 });
131 });
132
133 // ... 更多測試
134});
【Todo 更新】 ✓ 完成: 實作 cartService ✓ 完成: 實作 API endpoints ✓ 完成: 撰寫 cartService 單元測試 ✓ 🔄 進行中: 撰寫 API 整合測試 ⏳ 待處理: 實作前端 …
### 前端開發流程
```typescript
═══════════════════════════════════════════════════════
對話 5: Zustand Store 實作
═══════════════════════════════════════════════════════
使用者:
"實作 src/stores/cartStore.ts,使用 Zustand 管理購物車狀態。
參考現有的 Store 模式: src/stores/authStore.ts
包含:
- 購物車狀態
- Loading 和 error 狀態
- 所有 CRUD 操作
- 樂觀更新(Optimistic Updates)"
Claude 產出:
```typescript
// src/stores/cartStore.ts
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { cartApi } from '../api/cartApi';
import type { Cart, CartItem } from '../types/cart';
interface CartStore {
// State
cart: Cart | null;
isLoading: boolean;
error: string | null;
// Actions
fetchCart: () => Promise<void>;
addItem: (productId: string, quantity: number, variantId?: string) => Promise<void>;
updateQuantity: (itemId: string, quantity: number) => Promise<void>;
removeItem: (itemId: string) => Promise<void>;
clearCart: () => Promise<void>;
reset: () => void;
}
export const useCartStore = create<CartStore>()(
devtools(
persist(
(set, get) => ({
// Initial state
cart: null,
isLoading: false,
error: null,
// Fetch cart
fetchCart: async () => {
set({ isLoading: true, error: null });
try {
const response = await cartApi.getCart();
set({ cart: response.data, isLoading: false });
} catch (error) {
set({
error: error.message,
isLoading: false,
});
}
},
// Add item with optimistic update
addItem: async (productId, quantity, variantId) => {
const previousCart = get().cart;
// Optimistic update
set((state) => ({
cart: state.cart
? {
...state.cart,
items: [
...state.cart.items,
{
id: 'temp-' + Date.now(),
productId,
quantity,
variantId,
product: null, // Will be filled by API
} as CartItem,
],
}
: null,
}));
try {
const response = await cartApi.addItem({
productId,
quantity,
variantId,
});
// Update with real data
await get().fetchCart();
} catch (error) {
// Rollback on error
set({ cart: previousCart, error: error.message });
}
},
// Update quantity
updateQuantity: async (itemId, quantity) => {
const previousCart = get().cart;
// Optimistic update
set((state) => ({
cart: state.cart
? {
...state.cart,
items: state.cart.items.map((item) =>
item.id === itemId
? { ...item, quantity }
: item
),
}
: null,
}));
try {
await cartApi.updateItem(itemId, { quantity });
} catch (error) {
// Rollback on error
set({ cart: previousCart, error: error.message });
}
},
// Remove item
removeItem: async (itemId) => {
const previousCart = get().cart;
// Optimistic update
set((state) => ({
cart: state.cart
? {
...state.cart,
items: state.cart.items.filter(
(item) => item.id !== itemId
),
}
: null,
}));
try {
await cartApi.removeItem(itemId);
} catch (error) {
// Rollback on error
set({ cart: previousCart, error: error.message });
}
},
// Clear cart
clearCart: async () => {
const previousCart = get().cart;
// Optimistic update
set((state) => ({
cart: state.cart ? { ...state.cart, items: [] } : null,
}));
try {
await cartApi.clearCart();
} catch (error) {
// Rollback on error
set({ cart: previousCart, error: error.message });
}
},
// Reset state
reset: () => {
set({ cart: null, isLoading: false, error: null });
},
}),
{
name: 'cart-storage',
partialize: (state) => ({ cart: state.cart }), // Only persist cart data
}
)
)
);
═══════════════════════════════════════════════════════ 對話 6: React 元件實作 ═══════════════════════════════════════════════════════
使用者: “實作購物車 UI 元件。
參考設計: figma.com/design/cart-ui
元件列表(按計畫):
- CartButton - 購物車按鈕(顯示數量)
- CartDrawer - 購物車側邊欄
- CartItem - 購物車項目
- AddToCartButton - 加入購物車按鈕
使用:
- Tailwind CSS
- Radix UI (Drawer, Dialog)
- React Icons
先實作 CartButton”
Claude 執行: ├─ Read src/components/common/Button.tsx(學習元件模式) ├─ Read src/stores/cartStore.ts(理解狀態管理) └─ Write src/components/Cart/CartButton.tsx
產出範例:
1// src/components/Cart/CartButton.tsx
2import { ShoppingCart } from 'react-icons/ri';
3import { useCartStore } from '../../stores/cartStore';
4import { Button } from '../common/Button';
5
6interface CartButtonProps {
7 onClick: () => void;
8}
9
10export function CartButton({ onClick }: CartButtonProps) {
11 const cart = useCartStore((state) => state.cart);
12
13 // Calculate total items
14 const itemCount = cart?.items.reduce(
15 (sum, item) => sum + item.quantity,
16 0
17 ) || 0;
18
19 return (
20 <Button
21 variant="ghost"
22 size="md"
23 onClick={onClick}
24 className="relative"
25 aria-label={`購物車,${itemCount} 件商品`}
26 >
27 <ShoppingCart className="w-6 h-6" />
28
29 {/* Badge showing item count */}
30 {itemCount > 0 && (
31 <span
32 className="absolute -top-1 -right-1 bg-red-500 text-white
33 text-xs font-bold rounded-full w-5 h-5
34 flex items-center justify-center"
35 aria-label={`${itemCount} 件商品`}
36 >
37 {itemCount > 99 ? '99+' : itemCount}
38 </span>
39 )}
40 </Button>
41 );
42}
【逐步完成所有元件…】
═══════════════════════════════════════════════════════ 對話 7: 整合與測試 ═══════════════════════════════════════════════════════
使用者: “整合所有購物車元件到主應用程式,並執行測試。
步驟:
- 在 Layout 加入 CartButton
- 在商品頁加入 AddToCartButton
- 實作 CartDrawer 的開啟/關閉邏輯
- 執行所有測試
- 手動測試完整流程”
Claude 執行: ├─ Edit src/components/Layout/Header.tsx ├─ Edit src/pages/products/[id].tsx ├─ Bash: npm test ├─ 分析測試結果 └─ 提供手動測試檢查清單
【Todo 更新】 ✓ 完成: 所有後端開發 ✓ 完成: 所有前端開發 ✓ 完成: 整合測試 🔄 進行中: 手動測試和 bug 修復 ⏳ 待處理: 部署準備
## 4️⃣ 測試驗證階段
### 目標:確保功能正確且穩定
**完整測試策略:**
```typescript
使用者:
"執行完整的測試流程,確保購物車功能正常運作。
【測試層級】
1. 單元測試
- 所有 service 函式
- 所有 React hooks
- 工具函式
2. 整合測試
- API endpoints
- 資料庫操作
- 前後端整合
3. E2E 測試
- 使用者完整流程
- 不同裝置和瀏覽器
4. 效能測試
- 回應時間
- 併發處理
請逐一執行並回報結果"
Claude 執行測試流程:
【階段 1: 單元測試】
```bash
$ npm run test:unit
執行結果:
✓ cartService.test.ts (12 tests)
✓ cartStore.test.ts (8 tests)
✓ cartUtils.test.ts (5 tests)
覆蓋率:
Statements : 92.5% (148/160)
Branches : 88.3% (53/60)
Functions : 95.0% (38/40)
Lines : 93.1% (135/145)
⚠️ 低覆蓋率區域:
- cartService.ts:156-162 (錯誤處理分支)
→ 建議: 新增錯誤情境測試
【階段 2: 整合測試】
1$ npm run test:integration
2
3執行結果:
4✓ POST /api/cart/items (4 tests)
5✓ PUT /api/cart/items/:id (3 tests)
6✓ DELETE /api/cart/items/:id (2 tests)
7✓ GET /api/cart (3 tests)
8
9所有 API endpoints 測試通過
10平均回應時間: 45ms (< 200ms 目標 ✓)
【階段 3: E2E 測試】
1$ npm run test:e2e
2
3執行結果:
4✓ User can add items to cart
5✓ User can update item quantity
6✓ User can remove items
7✓ Cart persists across page reloads
8✓ Guest cart merges after login
9
10所有使用者流程測試通過
【階段 4: 效能測試】
1$ npm run test:performance
2
3結果:
4平均回應時間:
5- GET /api/cart: 38ms ✓
6- POST /api/cart/items: 52ms ✓
7- PUT /api/cart/items/:id: 41ms ✓
8
9併發測試 (100 concurrent users):
10- 成功率: 100% ✓
11- P95 延遲: 125ms ✓
12- P99 延遲: 210ms ✓
13
14全部通過效能目標!
【測試摘要】 所有測試通過 ✓
- 單元測試: 25/25
- 整合測試: 12/12
- E2E 測試: 5/5
- 效能測試: 通過
建議修復:
- 提升錯誤處理測試覆蓋率
- 新增更多邊界情況測試
## 5️⃣ 部署上線階段
### 目標:安全、順利地部署到生產環境
**部署檢查清單:**
```markdown
使用者:
"準備將購物車功能部署到生產環境。
請協助完成部署前檢查清單,並生成部署文檔。"
Claude 生成檢查清單:
# 購物車功能部署檢查清單
## 前置檢查
### 1. 程式碼品質
- [x] 所有測試通過(單元、整合、E2E)
- [x] 程式碼已經過 Code Review
- [x] ESLint/Prettier 檢查通過
- [x] 無 TypeScript 錯誤
- [x] 無安全性漏洞(npm audit)
### 2. 資料庫
- [ ] Migration 腳本已準備
- [ ] Migration 已在 staging 環境測試
- [ ] 備份計畫已就緒
- [ ] Rollback 腳本已準備
### 3. 環境變數
- [ ] 生產環境變數已設定
- DATABASE_URL
- REDIS_URL
- SESSION_SECRET
- [ ] API keys 已更新為生產版本
- [ ] 環境變數已加密儲存
### 4. 依賴套件
- [ ] package.json 版本鎖定
- [ ] node_modules 大小合理
- [ ] 無未使用的依賴
- [ ] 安全性更新已套用
### 5. 效能
- [ ] 前端打包已優化(code splitting)
- [ ] 圖片已壓縮
- [ ] API 回應時間符合目標(< 200ms)
- [ ] Redis 快取策略已設定
### 6. 監控
- [ ] 錯誤追蹤已設定(Sentry)
- [ ] 效能監控已設定(New Relic)
- [ ] 日誌系統已配置
- [ ] Alert 規則已設定
### 7. 文檔
- [ ] API 文檔已更新
- [ ] 使用者指南已準備
- [ ] 開發者文檔已更新
- [ ] Changelog 已記錄
## 部署步驟
### Step 1: 資料庫 Migration
```bash
# 在生產環境執行
npm run migrate:production
# 驗證
npm run migrate:status
Step 2: 部署後端
1# 打包
2npm run build
3
4# 部署到伺服器
5npm run deploy:api
6
7# 健康檢查
8curl https://api.example.com/health
Step 3: 部署前端
1# 打包
2npm run build:frontend
3
4# 部署到 CDN
5npm run deploy:frontend
6
7# 驗證
8curl https://example.com
Step 4: 驗證部署
- 前端頁面正常載入
- API endpoints 正常回應
- 購物車功能正常運作
- 資料庫連線正常
- Redis 快取正常
Step 5: 監控觀察
1部署後監控 (前 24 小時):
2- 每小時檢查錯誤率
3- 監控 API 回應時間
4- 檢查資料庫連線數
5- 觀察 Redis 記憶體使用
6
7正常指標:
8- 錯誤率 < 0.1%
9- API P95 延遲 < 200ms
10- 資料庫連線 < 80% pool size
11- Redis 記憶體使用 < 70%
Rollback 計畫
如果發生問題:
停止新流量
1# 切換到舊版本 2kubectl rollout undo deployment/api-serverRollback 資料庫
1# 執行 rollback migration 2npm run migrate:rollback通知團隊
- Slack #incidents 頻道
- 記錄問題詳情
- 安排事後檢討
事後檢討
- 分析失敗原因
- 更新部署流程
- 加強測試覆蓋
成功標準
部署被視為成功當:
- 所有健康檢查通過
- 24 小時內無重大錯誤
- 效能指標符合目標
- 使用者回饋正面
- 無需 Rollback
## 6️⃣ 維護優化階段
### 目標:持續改進和維護功能
**常見維護情境:**
### 情境 1: Bug 修復
```typescript
使用者:
"生產環境回報:當購物車中有 50+ 商品時,
載入速度很慢(> 5 秒)。
錯誤追蹤 (Sentry):
- URL: /api/cart
- 回應時間: 5.2s (P95: 6.8s)
- 使用者影響: 約 2% 使用者
請協助診斷並修復"
Claude 診斷流程:
【步驟 1: 重現問題】
"根據錯誤報告,讓我們先在開發環境重現問題。
我需要:
1. 建立測試用購物車(50+ 商品)
2. 測量 API 回應時間
3. 分析效能瓶頸"
【步驟 2: 分析問題】
使用 Bash tool 執行分析:
```bash
# 使用效能分析工具
npm run profile:api -- GET /api/cart
結果分析:
┌─────────────────────────┬──────────┐
│ 操作 │ 時間 │
├─────────────────────────┼──────────┤
│ Prisma 查詢 │ 4.8s │ ← 瓶頸!
│ 資料序列化 │ 0.3s │
│ 網路傳輸 │ 0.1s │
└─────────────────────────┴──────────┘
【診斷】
問題出在 Prisma 查詢,沒有使用 select 限制欄位,
抓取了所有關聯資料(包含不需要的 product descriptions,
reviews 等大量資料)
【步驟 3: 實作修復】
1// 修復前(慢)
2const cart = await prisma.cart.findFirst({
3 where: { userId },
4 include: {
5 items: {
6 include: {
7 product: true, // 抓取所有 product 欄位
8 variant: true, // 抓取所有 variant 欄位
9 },
10 },
11 },
12});
13
14// 修復後(快)
15const cart = await prisma.cart.findFirst({
16 where: { userId },
17 include: {
18 items: {
19 include: {
20 product: {
21 select: {
22 id: true,
23 name: true,
24 price: true,
25 imageUrl: true,
26 // 只選擇需要的欄位
27 },
28 },
29 variant: {
30 select: {
31 id: true,
32 name: true,
33 price: true,
34 },
35 },
36 },
37 },
38 },
39});
【步驟 4: 測試驗證】
1# 測試修復後的效能
2npm run profile:api -- GET /api/cart
3
4新的結果:
5┌─────────────────────────┬──────────┐
6│ 操作 │ 時間 │
7├─────────────────────────┼──────────┤
8│ Prisma 查詢 │ 0.15s │ ✓ 改善 97%!
9│ 資料序列化 │ 0.08s │
10│ 網路傳輸 │ 0.05s │
11│ 總計 │ 0.28s │ ✓ 符合目標!
12└─────────────────────────┴──────────┘
【步驟 5: 部署修復】
1# 建立 hotfix branch
2/commit -m "perf(cart): optimize cart query by selecting only required fields
3
4- Reduce query time from 4.8s to 0.15s (97% improvement)
5- Select only necessary product and variant fields
6- Fixes slow cart loading for users with 50+ items
7
8Closes #BUG-123"
9
10# 部署到生產環境
11npm run deploy:hotfix
情境 2: 效能優化
1使用者:
2"想優化購物車的整體效能。請分析目前的效能瓶頸,
3並提供優化建議"
4
5Claude 分析流程:
6
7【階段 1: 效能基準測試】
8執行完整的效能分析:
9```bash
10npm run test:performance -- --detailed
11
12結果報告:
13━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14購物車效能分析報告
15━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
17API 回應時間:
18├─ GET /api/cart
19│ ├─ P50: 145ms
20│ ├─ P95: 320ms ⚠️ 超過目標 (200ms)
21│ └─ P99: 580ms ⚠️
22│
23├─ POST /api/cart/items
24│ ├─ P50: 180ms
25│ ├─ P95: 380ms ⚠️
26│ └─ P99: 650ms ⚠️
27
28前端載入時間:
29├─ 初次載入: 2.8s ⚠️
30├─ React 渲染: 850ms ⚠️
31└─ API 呼叫: 320ms
32
33識別的瓶頸:
341. 資料庫查詢未使用索引
352. 無 Redis 快取
363. 前端過度渲染
374. API 回應未壓縮
【階段 2: 優化建議】 Claude 提供完整優化計畫:
1# 購物車效能優化計畫
2
3## 優化 1: 資料庫索引 (預期改善 40%)
4
5### 分析
6目前 cart_items 表沒有在 cart_id 上建立索引,
7查詢 50+ 商品時需要全表掃描
8
9### 實作
10```sql
11CREATE INDEX idx_cart_items_cart_id ON cart_items(cart_id);
12CREATE INDEX idx_carts_user_id ON carts(user_id);
13CREATE INDEX idx_carts_session_id ON carts(session_id);
預期結果
- 查詢時間: 150ms → 90ms
- P95 延遲: 320ms → 200ms ✓
優化 2: Redis 快取 (預期改善 60%)
策略
1// 快取策略
2const CART_CACHE_TTL = 3600; // 1 hour
3
4async function getCachedCart(userId: string) {
5 // 1. 嘗試從 Redis 讀取
6 const cached = await redis.get(`cart:${userId}`);
7 if (cached) {
8 return JSON.parse(cached);
9 }
10
11 // 2. 從資料庫查詢
12 const cart = await prisma.cart.findFirst({
13 where: { userId },
14 include: { items: { include: { product: true } } },
15 });
16
17 // 3. 寫入 Redis
18 await redis.setex(
19 `cart:${userId}`,
20 CART_CACHE_TTL,
21 JSON.stringify(cart)
22 );
23
24 return cart;
25}
預期結果
- 快取命中時: 90ms → 10ms
- P95 延遲: 200ms → 50ms ✓
優化 3: 前端優化 (預期改善 50%)
React.memo 和 useMemo
1// 優化前
2function CartItem({ item }) {
3 const formattedPrice = formatPrice(item.price); // 每次都重新計算
4 return <div>{formattedPrice}</div>;
5}
6
7// 優化後
8const CartItem = React.memo(({ item }) => {
9 const formattedPrice = useMemo(
10 () => formatPrice(item.price),
11 [item.price]
12 );
13 return <div>{formattedPrice}</div>;
14});
虛擬捲動(50+ 商品時)
1import { FixedSizeList } from 'react-window';
2
3function CartDrawer({ items }) {
4 if (items.length > 20) {
5 return (
6 <FixedSizeList
7 height={600}
8 itemCount={items.length}
9 itemSize={80}
10 >
11 {({ index, style }) => (
12 <CartItem style={style} item={items[index]} />
13 )}
14 </FixedSizeList>
15 );
16 }
17
18 return items.map(item => <CartItem key={item.id} item={item} />);
19}
預期結果
- 渲染時間: 850ms → 250ms
- 捲動 FPS: 30fps → 60fps ✓
優化 4: API 回應壓縮 (預期改善 70% 傳輸)
1import compression from 'compression';
2
3app.use(compression({
4 level: 6,
5 threshold: 1024, // 只壓縮 > 1KB 的回應
6}));
預期結果
- 回應大小: 150KB → 45KB
- 傳輸時間: 200ms → 60ms (on 3G)
總體預期改善
| 指標 | 優化前 | 優化後 | 改善幅度 |
|---|---|---|---|
| API P95 延遲 | 320ms | 50ms | 84% ↓ |
| 前端載入時間 | 2.8s | 1.2s | 57% ↓ |
| 資料傳輸量 | 150KB | 45KB | 70% ↓ |
實作順序
- 資料庫索引(最快,影響最大)
- Redis 快取(中等工作量,效果顯著)
- API 壓縮(簡單,立即生效)
- 前端優化(需要較多測試)
總時程估算: 2-3 天
## 📋 工作流程最佳實踐總結
### 黃金原則
```markdown
1. **先規劃,再實作**
• 使用 Plan Mode 設計架構
• 明確定義驗收標準
• 分階段執行
2. **持續測試和驗證**
• 每個階段都要測試
• 不要累積技術債
• 自動化測試流程
3. **文檔與程式碼同步更新**
• README 保持最新
• API 文檔即時更新
• 記錄重要決策
4. **監控和回饋循環**
• 部署後密切監控
• 收集使用者回饋
• 持續優化改進
5. **團隊協作**
• Code Review 機制
• 知識分享
• 統一的工作流程
檢查清單範本
1每個功能開發的標準流程:
2
3需求分析階段
4☐ 功能需求明確
5☐ 技術需求確定
6☐ 限制條件已識別
7☐ 驗收標準可測試
8
9設計規劃階段
10☐ 架構設計完成
11☐ 資料庫設計確認
12☐ API 設計審查
13☐ 任務分解清晰
14
15開發實作階段
16☐ 程式碼符合規範
17☐ 單元測試覆蓋
18☐ Code Review 通過
19☐ 文檔已更新
20
21測試驗證階段
22☐ 單元測試通過
23☐ 整合測試通過
24☐ E2E 測試通過
25☐ 效能測試達標
26
27部署上線階段
28☐ 部署檢查清單完成
29☐ Rollback 計畫就緒
30☐ 監控已設定
31☐ 團隊已通知
32
33維護優化階段
34☐ 監控指標正常
35☐ 問題及時修復
36☐ 效能持續優化
37☐ 使用者回饋收集
🚀 下一步行動
1立即行動
2☐ 為目前專案建立工作流程文檔
3☐ 設定 Claude Code 的專案模板
4☐ 建立常用的檢查清單
5☐ 與團隊分享工作流程
6
7持續改進
8☐ 定期回顧工作流程效率
9☐ 收集團隊回饋並調整
10☐ 記錄最佳實踐案例
11☐ 建立內部知識庫
延伸閱讀:
標籤: #claude-code #工作流程 #開發流程 #軟體開發 #最佳實踐 #敏捷開發
