Scenario 1: 搜尋客戶(姓名模糊匹配)
User Story: US-302: 客戶列表與搜尋
Given: 系統初始狀態
已登入用戶
{
"userId": "staff-001",
"email": "staff@florist.com",
"role": "SALES_STAFF",
"tenantId": "ROLE_FLORIST-abc"
}
現有客戶資料
[
{
"id": "cust-001",
"customerNumber": "ABC-CUST-000001",
"type": "individual",
"name": "王小明",
"phone": "0912345678",
"tier": "vip",
"totalSpent": 5000,
"lastOrderDate": "2025-10-31"
},
{
"id": "cust-002",
"customerNumber": "ABC-CUST-000002",
"type": "individual",
"name": "王大明",
"phone": "0912111222",
"tier": "regular",
"totalSpent": 1200,
"lastOrderDate": "2025-10-15"
},
{
"id": "cust-003",
"customerNumber": "ABC-CUST-000003",
"type": "corporate",
"companyName": "XX 科技公司",
"phone": "0212345678",
"tier": "vvip",
"totalSpent": 25000,
"lastOrderDate": "2025-11-01"
}
]
When: 執行操作
API 請求
GET /api/v1/customers?search=王小明&page=1&limit=20
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Then: 預期結果
1. HTTP 響應狀態碼
200 OK
2. 響應 Payload
{
"customers": [
{
"id": "cust-001",
"customerNumber": "ABC-CUST-000001",
"type": "individual",
"name": "王小明",
"companyName": null,
"phone": "0912345678",
"email": "wang@example.com",
"status": "active",
"tier": "vip",
"tags": ["常客"],
"totalSpent": 5000,
"totalOrders": 8,
"lastOrderDate": "2025-10-31T10:00:00Z",
"createdAt": "2025-01-15T10:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalPages": 1,
"totalItems": 1
}
}
3. 業務規則驗證
✅ 模糊搜尋邏輯
- 搜尋關鍵字:
王小明 - 匹配方式: 精確匹配姓名
- 結果: 僅返回「王小明」,不包含「王大明」
✅ 多租戶隔離
- 僅返回當前租戶
ROLE_FLORIST-abc的客戶
✅ 防抖延遲
- 前端輸入後防抖 500ms 才發送請求
驗證重點
- 搜尋功能正確運作(姓名匹配)
- 僅返回符合條件的客戶
- 分頁資訊正確
- 多租戶隔離正確