跳至主要内容

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 才發送請求

驗證重點

  • 搜尋功能正確運作(姓名匹配)
  • 僅返回符合條件的客戶
  • 分頁資訊正確
  • 多租戶隔離正確

相關場景