跳至主要内容

US-101: 商品基本資料管理

User Story

作為 花店管理者 我想要 能夠新增、編輯、查看和上/下架商品 以便 維護完整的商品目錄供訂單創建時選用


驗收標準 (Acceptance Criteria)

Scenario 1: 新增標準化商品(必填欄位)

  • Given 我是已登入的管理者
  • And 我在「商品管理」頁面
  • When 我點擊「新增商品」按鈕
  • And 我選擇商品類型為「花束」
  • And 我填寫商品名稱「玫瑰花束(12 朵)」
  • And 我填寫基礎價格「1200」
  • And 我上傳主圖
  • And 我點擊「儲存」按鈕
  • Then 系統應創建商品並自動分配 SKU 編號(格式:{租戶代碼}-BQT-{流水號}
  • And 我應看到商品創建成功的通知
  • And 商品狀態應預設為「已上架」
  • And 庫存數量應預設為 0

Scenario 2: 新增商品(完整欄位)

  • Given 我是已登入的管理者
  • And 我在「新增商品」頁面
  • When 我選擇商品類型為「盆花」
  • And 我填寫商品名稱「蝴蝶蘭(3 株)」
  • And 我填寫商品描述「優雅大方,適合開幕送禮」
  • And 我填寫基礎價格「2500」
  • And 我填寫成本價格「1500」
  • And 我填寫庫存數量「20」
  • And 我填寫低庫存警戒值「5」
  • And 我勾選「熱門商品」
  • And 我上傳主圖和 3 張副圖
  • And 我點擊「儲存」按鈕
  • Then 系統應創建商品並儲存所有填寫的資訊
  • And SKU 編號應為「{租戶代碼}-POT-{流水號}」

Scenario 3: 編輯商品基本資訊

  • Given 我是已登入的管理者
  • And 我在商品「玫瑰花束(12 朵)」的詳情頁
  • When 我點擊「編輯」按鈕
  • And 我修改商品名稱為「紅玫瑰花束(12 朵)」
  • And 我修改基礎價格為「1350」
  • And 我修改商品描述為「經典浪漫,情人節首選」
  • And 我點擊「儲存」按鈕
  • Then 系統應更新商品資訊
  • And 我應看到「儲存成功」的通知
  • And 更新應立即反映在詳情頁
  • And 價格變更應記錄在審計日誌

Scenario 4: 下架商品

  • Given 我是已登入的管理者
  • And 商品「玫瑰花束(12 朵)」目前狀態為「已上架」
  • When 我點擊「下架」按鈕
  • And 系統要求我確認
  • And 我點擊「確認下架」
  • Then 系統應將商品狀態改為「已下架」
  • And 此商品不應再出現在創建訂單時的商品選擇列表
  • And 但商品仍可在後台商品列表中查看(標記為已下架)
  • And 歷史訂單中已使用此商品的記錄不受影響

Scenario 5: 重新上架商品

  • Given 我是已登入的管理者
  • And 商品「玫瑰花束(12 朵)」目前狀態為「已下架」
  • When 我點擊「上架」按鈕
  • And 我點擊「確認」按鈕
  • Then 系統應將商品狀態改為「已上架」
  • And 此商品應重新出現在商品選擇列表

Scenario 6: 刪除商品

  • Given 我是已登入的店主(ROLE_OWNER)
  • And 我在商品「測試商品」的詳情頁
  • And 此商品從未被任何訂單使用過
  • When 我點擊「刪除」按鈕
  • And 系統要求我輸入商品名稱確認刪除
  • And 我輸入「測試商品」
  • And 我點擊「確認刪除」
  • Then 系統應永久刪除此商品
  • And 商品照片也應一併刪除
  • And 我應被導航回商品列表頁

Scenario 7: 無法刪除已被訂單使用的商品

  • Given 我是已登入的店主
  • And 商品「玫瑰花束(12 朵)」已被歷史訂單使用過
  • When 我嘗試刪除此商品
  • Then 系統應顯示錯誤訊息「此商品已被訂單使用,無法刪除。請改為下架此商品。」
  • And 商品不應被刪除

Scenario 8: 新增商品時缺少必填欄位(錯誤場景)

  • Given 我是已登入的管理者
  • And 我在「新增商品」頁面
  • When 我僅填寫商品名稱「測試商品」(未填寫價格、未上傳主圖)
  • And 我點擊「儲存」按鈕
  • Then 系統應顯示錯誤訊息:
    • 「請填寫基礎價格」
    • 「請上傳商品主圖」
  • And 錯誤欄位應以紅色邊框標示
  • And 商品不應被創建
  • And 表單應保留我已填寫的資料

Scenario 9: 價格驗證(錯誤場景)

  • Given 我是已登入的管理者
  • And 我在「新增商品」頁面
  • When 我填寫基礎價格為「-100」
  • Then 系統應顯示錯誤訊息「價格必須大於 0」
  • When 我填寫基礎價格為「abc」
  • Then 系統應顯示錯誤訊息「請輸入有效的數字」

業務規則 (Business Rules)

  1. SKU 編號規則

    • 格式: {租戶代碼}-{類型代碼}-{流水號}
    • 類型代碼對應表:
      • BQT = 花束 (bouquet)
      • POT = 盆花 (pot)
      • STD = 高架 (stand)
      • BSK = 花籃 (basket)
      • BOX = 盒花 (box)
      • GFT = 禮品 (gift)
      • CST = 客製化 (custom)
    • 範例: ABC-BQT-000001
    • 流水號從 000001 開始,每次創建同類型商品遞增
    • SKU 編號創建後不可修改
  2. 必填欄位

    • 商品名稱
    • 商品類型
    • 基礎價格(> 0)
    • 主圖
  3. 選填欄位

    • 商品描述
    • 成本價格
    • 庫存數量(預設 0)
    • 低庫存警戒值(預設 5)
    • 副圖(最多 5 張)
  4. 價格規則

    • 基礎價格必須 > 0
    • 成本價格必須 >= 0(若填寫)
    • 價格支援小數點後兩位(如 NT$ 99.50)
    • 價格變更需記錄審計日誌
  5. 庫存規則

    • 庫存數量必須 >= 0
    • 當庫存 <= 低庫存警戒值時,列表顯示「低庫存」警示
    • 當庫存 = 0 時,列表顯示「缺貨」警示
  6. 上架/下架權限

    • ROLE_MANAGER 或更高權限可上架/下架商品
    • 下架商品不出現在訂單創建的商品選擇列表
    • 下架商品仍可在後台查看與編輯
  7. 刪除權限與限制

    • ROLE_OWNER 可刪除商品
    • 已被訂單使用的商品無法刪除(需改為下架)
    • 刪除前需輸入商品名稱確認(防止誤刪)
    • 刪除後商品照片一併刪除
  8. 多租戶隔離

    • 商品自動關聯到當前用戶的 tenantId
    • 商品列表僅顯示當前租戶的商品
    • 跨租戶訪問返回 404
  9. 成本價格可見性

    • 成本價格僅 ROLE_MANAGER 或更高權限可見
    • ROLE_STAFF 看不到成本價格欄位

UI/UX 需求 (UI/UX Requirements)

新增/編輯商品表單佈局

左側 - 照片區

  • 主圖上傳:
    • 拖曳區域或點擊上傳
    • 預覽已上傳的主圖
    • 「更換」按鈕
  • 副圖上傳:
    • 最多 5 張副圖
    • 網格式顯示
    • 支援拖曳排序
    • 每張圖有刪除按鈕

右側 - 表單區

  • 基本資訊區:

    • 商品類型(必填,下拉選單)
    • 商品名稱(必填)
    • 商品描述(選填,多行文字)
  • 價格與庫存區:

    • 基礎價格(必填)
    • 成本價格(選填,僅管理者可見)
    • 庫存數量(預設 0)
    • 低庫存警戒值(預設 5)
    • 庫存單位(預設「個」)
  • 狀態設定區:

    • 上架狀態(開關)
    • 熱門商品(勾選框)
    • 新品標記(勾選框)

商品詳情頁佈局

頂部區域

  • 商品主圖(大圖)
  • 副圖縮圖列表
  • 商品名稱
  • SKU 編號
  • 商品類型標籤
  • 上架狀態標籤

操作按鈕

  • 編輯(管理者以上)
  • 上架/下架(管理者以上)
  • 刪除(僅店主,已使用的商品不可刪除)

資訊區塊

  • 價格資訊:

    • 基礎價格
    • 成本價格(僅管理者可見)
    • 毛利率(自動計算,僅管理者可見)
  • 庫存資訊:

    • 當前庫存
    • 低庫存警戒值
    • 庫存狀態(正常/低庫存/缺貨)
  • 統計資訊:

    • 創建日期
    • 最後更新日期
    • 銷售數量(來自訂單統計)

互動行為

  • 照片上傳:

    • 支援拖曳上傳
    • 上傳前預覽
    • 上傳進度顯示
    • 上傳失敗時顯示錯誤訊息
  • 表單驗證:

    • 即時驗證(輸入後驗證)
    • 錯誤欄位紅色邊框
    • 錯誤訊息顯示在欄位下方
  • 刪除確認:

    • Modal 彈窗
    • 需輸入商品名稱確認
    • 輸入正確後才啟用「確認刪除」按鈕

錯誤訊息

  • 缺少必填欄位: 紅色邊框 + 欄位下方顯示錯誤訊息
  • 價格格式錯誤: 「請輸入有效的價格」
  • 價格為負數: 「價格必須大於 0」
  • 主圖未上傳: 「請上傳商品主圖」
  • 照片上傳失敗: 「照片上傳失敗,請重試」
  • 照片過大: 「照片大小不能超過 10MB」
  • 照片格式錯誤: 「僅支援 JPEG、PNG、WebP 格式」

成功反饋

  • 商品創建成功: Toast 通知「商品 {SKU} 創建成功」
  • 商品更新成功: Toast 通知「儲存成功」
  • 商品下架成功: Toast 通知「商品已下架」
  • 商品上架成功: Toast 通知「商品已上架」
  • 商品刪除成功: Toast 通知「商品已刪除」

響應式設計

  • 桌面: 雙欄佈局(左側照片,右側表單)
  • 平板: 雙欄佈局(縮小間距)
  • 手機: 單欄佈局(照片在上,表單在下)

技術規格 (Technical Specifications)

API 端點

1. 創建商品

  • 端點: POST /api/v1/products
  • 權限要求: ROLE_MANAGER 或更高
  • 多租戶隔離: 自動附加 tenantId

請求 Payload:

{
"category": "bouquet", // 商品類型
"name": "玫瑰花束(12 朵)",
"description": "經典浪漫,情人節首選", // 選填
"basePrice": 1200,
"costPrice": 800, // 選填
"stock": 50, // 選填,預設 0
"lowStockThreshold": 5, // 選填,預設 5
"stockUnit": "個", // 選填,預設「個」
"status": "active", // 選填,預設 "active"
"isFeatured": true, // 選填,預設 false
"isNew": true, // 選填,預設 false
"mainImageUrl": "https://...", // 先上傳照片獲得 URL
"galleryImageUrls": ["https://...", "https://..."] // 選填
}

響應 Payload:

{
"id": "prod-abc123",
"tenantId": "tenant-001",
"sku": "ABC-BQT-000001",
"category": "bouquet",
"categoryLabel": "花束",
"name": "玫瑰花束(12 朵)",
"description": "經典浪漫,情人節首選",
"basePrice": 1200,
"costPrice": 800, // 僅管理者可見
"stock": 50,
"lowStockThreshold": 5,
"stockUnit": "個",
"status": "active",
"isFeatured": true,
"isNew": true,
"mainImageUrl": "https://...",
"galleryImageUrls": ["https://...", "https://..."],
"createdAt": "2025-12-03T10:00:00Z",
"updatedAt": "2025-12-03T10:00:00Z",
"createdBy": "user-001"
}

2. 獲取單一商品

  • 端點: GET /api/v1/products/{id}
  • 權限要求: ROLE_STAFF 或更高

3. 更新商品

  • 端點: PUT /api/v1/products/{id}
  • 權限要求: ROLE_MANAGER 或更高

請求 Payload: 同創建商品(部分欄位更新)

4. 上架/下架商品

  • 端點: PATCH /api/v1/products/{id}/status
  • 權限要求: ROLE_MANAGER 或更高

請求 Payload:

{
"status": "inactive" // "active" | "inactive"
}

5. 刪除商品

  • 端點: DELETE /api/v1/products/{id}
  • 權限要求: ROLE_OWNER

響應: 204 No Content(成功)或 409 Conflict(已被訂單使用)

6. 上傳商品照片

  • 端點: POST /api/v1/products/upload-image
  • 權限要求: ROLE_MANAGER 或更高
  • Content-Type: multipart/form-data

請求: FormData with file field

響應 Payload:

{
"url": "https://cdn.example.com/tenant-001/products/abc123.webp",
"thumbnailUrl": "https://cdn.example.com/tenant-001/products/abc123_thumb.webp"
}

前端驗證規則

// Zod Schema
const ProductSchema = z.object({
category: z.enum(['bouquet', 'pot', 'stand', 'basket', 'box', 'gift', 'custom'], {
required_error: '請選擇商品類型',
}),
name: z.string()
.min(1, '請填寫商品名稱')
.max(100, '商品名稱過長'),
description: z.string().max(500, '商品描述過長').optional(),
basePrice: z.number({
required_error: '請填寫基礎價格',
invalid_type_error: '請輸入有效的數字',
}).positive('價格必須大於 0'),
costPrice: z.number()
.nonnegative('成本價格必須 >= 0')
.optional(),
stock: z.number()
.int('庫存數量必須為整數')
.nonnegative('庫存數量必須 >= 0')
.default(0),
lowStockThreshold: z.number()
.int('警戒值必須為整數')
.nonnegative('警戒值必須 >= 0')
.default(5),
stockUnit: z.string().default('個'),
status: z.enum(['active', 'inactive']).default('active'),
isFeatured: z.boolean().default(false),
isNew: z.boolean().default(false),
mainImageUrl: z.string().url('請上傳商品主圖'),
galleryImageUrls: z.array(z.string().url()).max(5, '副圖最多 5 張').optional(),
});

元件架構

src/applets/product-applet/
├── ProductApplet.tsx # 容器組件
├── ProductForm.tsx # 商品表單(新增/編輯)
├── ProductDetailPage.tsx # 商品詳情頁
├── ProductListPage.tsx # 商品列表頁(參見 US-102)
├── components/
│ ├── ProductImageUploader.tsx # 照片上傳組件
│ ├── ProductGallery.tsx # 照片畫廊組件
│ ├── ProductStatusBadge.tsx # 狀態標籤組件
│ ├── ProductCategorySelect.tsx # 類型選擇組件
│ └── StockStatusBadge.tsx # 庫存狀態標籤
├── hooks/
│ ├── useProductForm.ts # 商品表單邏輯
│ ├── useImageUpload.ts # 照片上傳邏輯
│ └── useProductMutation.ts # 商品 CRUD 邏輯
└── types.ts # TypeScript 類型定義

測試需求 (Test Requirements)

單元測試

  • 表單驗證邏輯(必填欄位、格式驗證、價格驗證)
  • SKU 編號生成邏輯
  • 庫存狀態計算邏輯
  • 毛利率計算邏輯

整合測試

  • 創建商品 API 整合
  • 更新商品 API 整合
  • 上架/下架 API 整合
  • 刪除商品 API 整合
  • 照片上傳 API 整合

E2E 測試

  • Scenario 1: 新增標準化商品(必填欄位)
  • Scenario 2: 新增商品(完整欄位)
  • Scenario 3: 編輯商品基本資訊
  • Scenario 4: 下架商品
  • Scenario 5: 重新上架商品
  • Scenario 6: 刪除商品
  • Scenario 7: 無法刪除已被訂單使用的商品
  • Scenario 8: 表單驗證錯誤

驗收檢查清單 (Acceptance Checklist)

  • 可創建商品(必填欄位)
  • 可創建商品(完整欄位)
  • SKU 編號自動生成且格式正確
  • 可編輯商品資訊
  • 價格變更記錄審計日誌
  • 管理者可上架/下架商品
  • 下架商品不出現在訂單商品選擇列表
  • 店主可刪除未使用的商品
  • 已被訂單使用的商品無法刪除
  • 表單驗證錯誤訊息正確顯示
  • 照片上傳功能正常
  • 成本價格僅管理者可見
  • 響應式設計正常(桌面/平板/手機)
  • 審計日誌記錄正確
  • 多租戶隔離正常

Story Points

估算: 8 points

理由:

  • 需要處理商品 CRUD 四種操作
  • 包含複雜的表單驗證(必填、格式、價格)
  • 照片上傳功能較複雜(主圖/副圖、拖曳、預覽)
  • 上架/下架與刪除需要權限檢查
  • SKU 編號生成邏輯
  • 成本價格的權限控制

相關文檔


最後更新: 2025-12-03 撰寫者: AI Assistant