← 回看板
spec

002-voucher-ui-enhancement

功能規格:卡券系統 UI/UX 優化

功能分支: 002-voucher-ui-enhancement 建立日期: 2025-11-30 狀態: 草稿 輸入: 使用者描述:「根據 2025-11-30 會議記錄,針對卡券匯入與帳號綁定系統進行 UI/UX 優化,包含:全名搜尋調整、顧客搜尋顯示生日、卡券表格字體調整、頁籤佈局調整、綁定記錄顯示優化、開卡功能整合、卡券作廢功能、卡券來源欄位、綁定/解綁歷程獨立頁籤等。」

依賴: 此規格為 001-voucher-account-binding 的延續與增強

澄清

Session 2025-11-30

  • Q: 「全名」欄位的資料來源? → A: 系統自動從「姓」+「名」組合產生
  • Q: 「開卡」功能是什麼? → A: 開卡是既有功能(已有 API 實作),用於設計師手動新增單張卡券
  • Q: 卡券拿掉/開錯卡的處理方式? → A: 軟刪除,將卡券標記為「已作廢」
  • Q: 卡券 source 欄位的值? → A: manual(手動開卡)vs imported(批次匯入)
  • Q: 已移除顧客卡卷(視覺化)的呈現方式? → A: 使用不同 Icon 區分操作類型:🔗(綁定)vs 🔓(解綁)

Grooming Session 2025-11-30

設計決策確認

  1. 全名欄位實作

    • 決策:新增 User.full_name 實際欄位(String(100), nullable, indexed)
    • 值:由 last_name + first_name 組合產生
    • 當姓名都為空時:full_name 允許為 null
  2. 卡券綁定架構(雙軌系統)

    • 匯入卡券imported_vouchers):
      • 匯入後可綁定客戶,使用 bound_customer_id 欄位記錄
      • 綁定時同步新增 voucher_binding 記錄(用於歷程追蹤)
      • 支援解綁操作(bound_customer_id 設為 NULL)
    • 手動開卡vouchers):
      • 開卡時直接指定 customer_id,不可變更
      • 不透過 voucher_binding 記錄綁定關係
      • 使用 source 欄位區分來源(manual | imported
    • 綁定歷程voucher_binding):
      • 只記錄 imported_vouchers 的綁定/撤銷歷程
      • 欄位:imported_voucher_id, customer_id, bound_at, revoked_at
  3. 三種卡券操作定義

    • 解綁(Unbind)
      • 對象:imported_vouchers 已綁定的卡券
      • 操作:bound_customer_id = NULL, status = 'UNBOUND'
      • 權限:EMPLOYEE 以上
      • UI:✅ 有介面
    • 撤銷(Revoke)
      • 對象:已綁定的匯入卡券(透過 voucher_binding 綁定的)
      • 操作:voucher_binding.revoked_at = NOW() + 軟刪除 vouchersvoucher_items
      • 權限:僅 ADMIN
      • UI:❌ 僅 API
    • 剪卡(Void)
      • 對象:手動開卡的 vouchers(未綁定客戶)
      • 操作:軟刪除 vouchersvoucher_itemsis_deleted = TRUE
      • 權限:僅 ADMIN
      • UI:❌ 僅 API
  4. 客戶搜尋功能

    • 搜尋範圍:全名 + 電話 + 生日(複合搜尋)
    • 效能要求:500ms 內回應,需建立 full_name 索引
    • 無結果處理:顯示「查無符合的客戶」提示文字

使用者場景與測試 (必填)

使用者故事 1 - 客戶搜尋與顯示優化 (優先級: P1)

設計師在進行卡券綁定時,需要快速且準確地搜尋客戶。系統需新增「全名」欄位(由姓+名自動組合),並使用此全名欄位進行模糊搜尋,取代原本的姓名分開搜尋方式。此外,搜尋結果必須顯示客戶生日資訊,方便設計師確認客戶身份。

優先級理由: 這是設計師日常操作最頻繁的功能,搜尋效率直接影響工作流程。全名搜尋能更準確地匹配客戶,生日顯示能協助確認同名客戶。

獨立測試: 可透過輸入客戶姓名搜尋,驗證系統使用全名欄位進行模糊搜尋,並確認搜尋結果中顯示客戶生日。

驗收場景:

  1. Given 系統中有客戶資料(姓:王、名:小明、生日:03/15),When 系統計算全名欄位,Then 全名欄位值為「王小明」
  2. Given 設計師在客戶搜尋輸入「王小」,When 執行搜尋,Then 系統使用全名、電話、生日欄位進行複合模糊搜尋,返回所有符合條件的客戶,回應時間應在 500ms 內
  3. Given 搜尋結果 Modal 顯示客戶清單,When 設計師檢視清單內容,Then 每位客戶的資訊必須包含:全名、電話、生日(MMDD格式)
  4. Given 系統中有兩位客戶全名都是「王小明」但生日不同(0315 和 0720),When 搜尋結果顯示,Then 設計師可透過生日欄位區分兩位客戶
  5. Given 設計師搜尋「不存在的客戶」,When 搜尋完成,Then 系統顯示「查無符合的客戶」提示文字

使用者故事 2 - 綁定/解綁歷程獨立頁籤 (優先級: P1)

設計師需要查看匯入卡券的綁定與撤銷歷程記錄(透過 voucher_binding 記錄的操作),以追蹤操作歷史和責任歸屬。系統需提供獨立的「綁定/解綁歷程」頁籤,顯示完整的操作記錄,並使用視覺化 Icon 區分不同操作類型。歷程支援依操作類型和時間區間篩選,預設顯示最近一週的記錄。

優先級理由: 操作歷程是追蹤和稽核的重要依據,獨立頁籤能讓設計師快速找到所需資訊,Icon 區分能提升可讀性。篩選功能能快速定位特定時間段的操作。

獨立測試: 可透過切換至歷程頁籤,驗證系統顯示所有綁定/撤銷記錄,並確認 Icon 正確區分操作類型,篩選功能正常運作。

驗收場景:

  1. Given 設計師進入卡券管理介面,When 檢視頁籤列表,Then 系統顯示獨立的「綁定/解綁歷程」頁籤
  2. Given 設計師點擊「綁定/解綁歷程」頁籤,When 頁面載入完成,Then 系統顯示歷程記錄表格,包含欄位:操作設計師、卡券 ID、操作類型、顧客名稱(全名)、操作時間,預設顯示最近一週的記錄
  3. Given 歷程記錄中有一筆綁定操作(revoked_at IS NULL),When 顯示該筆記錄,Then 操作類型欄位顯示 🔗 Icon 並標示「綁定」
  4. Given 歷程記錄中有一筆撤銷操作(revoked_at IS NOT NULL),When 顯示該筆記錄,Then 操作類型欄位顯示 🔓 Icon 並標示「已撤銷」,並顯示撤銷時間
  5. Given 歷程記錄表格有多筆資料,When 檢視排序,Then 記錄依操作時間倒序排列(最新在最上方)
  6. Given 設計師使用篩選功能,When 選擇「僅綁定」,Then 系統只顯示 revoked_at IS NULL 的記錄
  7. Given 設計師使用篩選功能,When 選擇「已撤銷」,Then 系統只顯示 revoked_at IS NOT NULL 的記錄
  8. Given 設計師使用時間區間篩選,When 選擇「最近一個月」,Then 系統顯示最近 30 天內的記錄
  9. Given 歷程記錄超過 20 筆,When 檢視表格,Then 系統提供分頁功能,每頁顯示 20 筆記錄

使用者故事 3 - 開卡功能與紀錄整合 (優先級: P2)

設計師除了批次匯入卡券外,也需要能夠手動開立單張卡券。系統需整合既有的開卡 API,並在卡券資料中新增 source 欄位區分來源(manual 手動開卡 vs imported 批次匯入)。開卡紀錄需與綁定紀錄分開顯示,便於追蹤。

優先級理由: 開卡是既有功能,需確保與新系統整合順暢。來源欄位能幫助追蹤卡券的建立方式,對於資料分析和問題排查很重要。

獨立測試: 可透過手動開卡操作,驗證系統正確記錄卡券來源為 manual,並在紀錄中與匯入卡券區分顯示。

驗收場景:

  1. Given 設計師透過手動開卡功能建立新卡券,When 卡券建立成功,Then 該卡券的 source 欄位值為 manual
  2. Given 設計師透過批次匯入建立卡券,When 匯入成功,Then 這些卡券的 source 欄位值為 imported
  3. Given 卡券列表中有手動開卡和匯入的卡券,When 顯示列表,Then 系統能透過來源欄位區分並標示卡券來源
  4. Given 設計師手動開卡失敗(例如卡號重複),When 錯誤發生,Then 系統顯示明確錯誤訊息,並將錯誤記錄到系統日誌

使用者故事 4 - 卡券操作功能(解綁/撤銷/剪卡) (優先級: P2)

系統需要提供三種卡券操作功能,分別對應不同的業務場景:

  1. 解綁(Unbind):設計師需要解除匯入卡券與客戶的綁定關係,使卡券可重新綁定給其他客戶。此操作透過 UI 執行,權限為 EMPLOYEE 以上。

  2. 撤銷(Revoke):管理員需要撤銷錯誤的綁定操作並移除相關卡券記錄。此操作僅透過 API 執行,權限僅限 ADMIN,操作具永久性(軟刪除)。

  3. 剪卡(Void):管理員需要作廢手動開錯的卡券。此操作僅透過 API 執行,權限僅限 ADMIN,操作具永久性(軟刪除)。

優先級理由: 這些操作是資料維護的基本需求,能處理人為錯誤。解綁是日常操作,撤銷和剪卡是管理功能,軟刪除確保資料可追溯性,符合稽核需求。

獨立測試: 可分別測試三種操作,驗證權限控制、資料變更正確性,以及軟刪除的卡券不再出現於可用清單中。

驗收場景:

解綁操作

  1. Given 設計師(EMPLOYEE 角色)檢視一張已綁定客戶的匯入卡券(imported_vouchers.bound_customer_id 不為 NULL),When 點擊「解綁」按鈕,Then 系統彈出確認視窗,顯示卡券資訊和綁定客戶姓名
  2. Given 解綁確認視窗已開啟,When 設計師點擊「確認解綁」,Then 系統更新 imported_vouchers.bound_customer_id = NULLstatus = 'UNBOUND',顯示「解綁成功」訊息
  3. Given 卡券已解綁,When 設計師再次搜尋該卡券,Then 該卡券顯示為未綁定狀態,可重新綁定給任何客戶(包含原客戶)

撤銷操作(API only)

  1. Given 管理員(ADMIN 角色)透過 API 呼叫撤銷端點,對象為已綁定的匯入卡券,When API 執行成功,Then 系統更新 voucher_binding.revoked_at = NOW(),並軟刪除相關的 vouchers.is_deleted = TRUEvoucher_items.is_deleted = TRUE
  2. Given 卡券綁定已撤銷,When 查詢有效綁定記錄,Then 該記錄不出現(因 revoked_at IS NOT NULL
  3. Given 非 ADMIN 角色嘗試呼叫撤銷 API,When API 執行,Then 系統返回 403 Forbidden 錯誤

剪卡操作(API only)

  1. Given 管理員(ADMIN 角色)透過 API 呼叫剪卡端點,對象為未綁定客戶的手動開卡卡券,When API 執行成功,Then 系統軟刪除 vouchers.is_deleted = TRUEvoucher_items.is_deleted = TRUE
  2. Given 卡券已剪卡,When 設計師搜尋卡券,Then 該卡券不出現在可用卡券列表中(因 is_deleted = TRUE
  3. Given 管理員嘗試剪卡一張已綁定客戶的卡券,When API 執行,Then 系統返回錯誤「此卡券已綁定客戶,無法剪卡」
  4. Given 非 ADMIN 角色嘗試呼叫剪卡 API,When API 執行,Then 系統返回 403 Forbidden 錯誤

使用者故事 5 - 介面佈局與視覺優化 (優先級: P3)

為提升使用者體驗,系統需調整頁籤順序(共 4 個頁籤:卡券綁定 → 卡券管理 → 綁定/解綁歷程 → 卡券匯入)、將綁定按鈕放置於 footer 區域、以及將卡券表格字體從 14px 增大到 16px 以提升可讀性。

優先級理由: 這是視覺優化,不影響核心功能但能提升使用體驗。相對於功能性需求,優先級較低。

獨立測試: 可透過檢視介面佈局,驗證頁籤順序、按鈕位置和字體大小符合設計要求。

驗收場景:

  1. Given 設計師進入卡券管理介面,When 檢視頁籤順序,Then 頁籤依序為:1) 卡券綁定、2) 卡券管理、3) 綁定/解綁歷程、4) 卡券匯入(最右邊)
  2. Given 設計師在卡券綁定頁面,When 檢視頁面佈局,Then「確認綁定」按鈕位於頁面 footer 區域(固定於底部)
  3. Given 設計師搜尋卡券後,When 檢視卡券表格,Then 表格字體大小為 16px(原為 14px),提升可讀性
  4. Given 綁定記錄列表顯示,When 檢視記錄內容,Then 顯示完整的顧客全名(非 ID)、綁定時間、操作設計師

邊界案例

  • 全名為空: 當客戶只有姓或只有名時,全名欄位應正確處理(僅顯示有值的部分);當姓名都為空時,full_name 為 null
  • 同名同生日: 若存在全名和生日都相同的客戶,搜尋結果應顯示其他可區分資訊(如電話末四碼)
  • 解綁後重新綁定: 匯入卡券解綁後,可重新綁定給任何客戶(包含原客戶),無限制
  • 軟刪除後的卡券: 已執行撤銷或剪卡的卡券(is_deleted = TRUE),在所有查詢中應被過濾,不出現在任何可用清單中
  • 歷程記錄分頁: 歷程記錄每頁固定顯示 20 筆,超過時自動分頁
  • Icon 顯示異常: 當作業系統不支援 emoji 時,應有文字替代方案(「綁定」/「已撤銷」)
  • 撤銷永久性: 已撤銷的綁定記錄和已剪卡的卡券無法恢復,操作具永久性

需求 (必填)

功能需求

客戶全名欄位與搜尋

  • FR-001: 系統必須在 User 資料表新增 full_name 欄位(String(100), nullable, indexed),值由 last_name + first_name 組合產生。新增使用者或更新姓名時,系統應自動同步更新 full_name 欄位。當姓名都為空時,full_name 允許為 null。
  • FR-002: 客戶搜尋功能必須支援複合搜尋,同時對 full_namephonebirthday 欄位進行模糊查詢,回應時間應在 500ms 內
  • FR-003: 客戶搜尋結果 Modal 必須顯示客戶生日資訊(MMDD 格式)
  • FR-004: 客戶搜尋無結果時,系統必須顯示「查無符合的客戶」提示文字

卡券表格與佈局

  • FR-005: 卡券搜尋結果表格字體大小必須為 16px(原為 14px)
  • FR-006: 頁籤順序必須為:1) 卡券綁定、2) 卡券管理、3) 綁定/解綁歷程、4) 卡券匯入(最右邊)
  • FR-007: 綁定卡券的「確認綁定」按鈕必須放置於頁面 footer 區域

綁定記錄顯示

  • FR-008: 綁定記錄必須顯示顧客全名(非 ID 或部分姓名)
  • FR-009: 綁定記錄必須顯示綁定時間(完整日期時間格式)
  • FR-010: 綁定記錄必須顯示操作設計師姓名

開卡功能整合

  • FR-011: 系統必須整合既有開卡 API,支援設計師手動新增單張卡券
  • FR-012: vouchers 表必須新增 source 欄位(ENUM: manual | imported),區分卡券來源
  • FR-013: 手動開卡的卡券 sourcemanual;從 imported_vouchers 轉入的卡券 sourceimported
  • FR-014: 開卡紀錄失敗時,系統必須將錯誤記錄到系統日誌

卡券操作功能

解綁(Unbind)
  • FR-015: 系統必須提供解綁功能(有 UI),允許 EMPLOYEE 以上角色解除 imported_vouchers 與客戶的綁定
  • FR-016: 解綁操作必須彈出確認視窗,顯示卡券資訊和綁定客戶姓名
  • FR-017: 解綁執行時,系統必須更新 imported_vouchers.bound_customer_id = NULLstatus = 'UNBOUND'
  • FR-018: 解綁後的卡券可重新綁定給任何客戶(包含原客戶),無限制
撤銷(Revoke)
  • FR-019: 系統必須提供撤銷 API(無 UI),僅 ADMIN 角色可執行
  • FR-020: 撤銷操作對象為已透過 voucher_binding 綁定的匯入卡券
  • FR-021: 撤銷執行時,系統必須:1) 更新 voucher_binding.revoked_at = NOW(),2) 軟刪除 vouchers.is_deleted = TRUE,3) 軟刪除所有相關 voucher_items.is_deleted = TRUE
  • FR-022: 撤銷操作具永久性,無法恢復
  • FR-023: 非 ADMIN 角色呼叫撤銷 API 時,系統必須返回 403 Forbidden 錯誤
剪卡(Void)
  • FR-024: 系統必須提供剪卡 API(無 UI),僅 ADMIN 角色可執行
  • FR-025: 剪卡操作對象為手動開卡的 vouchers(未綁定客戶)
  • FR-026: 剪卡執行時,系統必須:1) 軟刪除 vouchers.is_deleted = TRUE,2) 軟刪除所有相關 voucher_items.is_deleted = TRUE
  • FR-027: 剪卡操作具永久性,無法恢復
  • FR-028: 嘗試剪卡已綁定客戶的卡券時,系統必須返回錯誤「此卡券已綁定客戶,無法剪卡」
  • FR-029: 非 ADMIN 角色呼叫剪卡 API 時,系統必須返回 403 Forbidden 錯誤

綁定/解綁歷程頁籤

  • FR-030: 系統必須提供獨立的「綁定/解綁歷程」頁籤,只顯示 voucher_binding 表的記錄(匯入卡券的綁定/撤銷歷程)
  • FR-031: 歷程記錄必須包含欄位:操作設計師(Employee.name)、卡券 ID、操作類型、顧客名稱(全名)、操作時間
  • FR-032: 操作類型必須使用 Icon 視覺化區分:🔗(綁定,revoked_at IS NULL)、🔓(已撤銷,revoked_at IS NOT NULL
  • FR-033: 歷程記錄必須依操作時間倒序排列(最新在最上方)
  • FR-034: 已撤銷的綁定記錄必須顯示撤銷時間(revoked_at
  • FR-035: 歷程頁籤必須支援篩選功能:1) 操作類型(全部/僅綁定/已撤銷),2) 時間區間(最近一週/最近一個月/最近三個月/自訂區間),預設顯示最近一週
  • FR-036: 歷程記錄必須提供分頁功能,每頁固定顯示 20 筆

關鍵實體

  • User(使用者/客戶):

    • 新增 full_name 欄位(String(100), nullable, indexed),由 last_name + first_name 自動組合
  • ImportedVoucher(匯入卡券):

    • 匯入的待綁定卡券清單
    • 關鍵欄位:bound_customer_id (nullable, 綁定的客戶)、status (UNBOUND | BOUND)
    • 支援解綁操作:設定 bound_customer_id = NULL
  • Voucher(正式卡券):

    • 手動開卡的卡券記錄(開卡時直接指定客戶)
    • 新增欄位:source (ENUM: manual | imported)、customer_idis_deleted (軟刪除)
    • 不透過 voucher_binding 記錄綁定關係
  • VoucherItem(卡券項目):

    • 卡券的詳細項目(次數、金額等)
    • 新增欄位:is_deleted (軟刪除,跟隨 voucher 一起作廢)
  • VoucherBinding(綁定歷程):

    • 只記錄 imported_vouchers 的綁定/撤銷歷程
    • 關鍵欄位:imported_voucher_id (foreign key)、customer_idbound_atrevoked_at (nullable, 撤銷時間)、operator_idoperator_role

成功標準 (必填)

可衡量成果

  • SC-001: 設計師使用全名搜尋客戶的成功率達到 95% 以上(首次搜尋即找到目標客戶)
  • SC-002: 客戶搜尋結果顯示生日後,同名客戶的選擇錯誤率降低 80%
  • SC-003: 設計師能在 5 秒內透過歷程頁籤找到特定卡券的綁定記錄
  • SC-004: 卡券作廢操作在 3 步驟內完成(點擊作廢 → 確認 → 完成)
  • SC-005: 新頁籤佈局(匯入置右、綁定按鈕在 footer)在使用者測試中獲得 80% 正面評價
  • SC-006: 卡券表格字體調整後,設計師閱讀卡券資訊的時間縮短 20%

假設

  • 既有開卡 API 已正常運作,本規格僅需整合而非重新開發
  • 客戶資料已有 first_namelast_name 欄位,系統可據此計算 full_name
  • 系統日誌機制已存在,可直接寫入開卡失敗記錄
  • 使用者裝置支援 emoji 顯示(作為 Icon 主要方案)
  • 此規格變更與 001-voucher-account-binding 的既有功能相容
  • VoucherBinding 表已存在 operator_idoperator_role 欄位,可複用記錄操作者
  • 資料庫支援為 User.full_name 欄位建立索引,以達成 500ms 搜尋效能要求
  • 綁定/解綁歷程記錄永久保留,無保留期限限制
  • 手動開卡功能(vouchers 表)在開卡時就指定客戶,不需要額外的綁定操作
  • 系統已有角色權限控制機制(EMPLOYEE, ADMIN, OWNER),可用於操作權限管理

範圍界定

包含在此功能內

  • 客戶全名欄位新增與複合搜尋邏輯(全名+電話+生日)
  • 客戶搜尋結果顯示生日與無結果提示
  • 客戶搜尋效能優化(500ms 內,建立索引)
  • 卡券表格字體調整(14px → 16px)
  • 頁籤順序調整(4 個頁籤:綁定 → 管理 → 歷程 → 匯入)
  • 綁定按鈕位置調整(移至 footer)
  • 綁定記錄顯示欄位擴充
  • 開卡功能整合與來源欄位(source: manual | imported)
  • 三種卡券操作功能:
    • 解綁(有 UI,EMPLOYEE 以上)
    • 撤銷(API only,ADMIN)
    • 剪卡(API only,ADMIN)
  • 綁定/解綁歷程獨立頁籤(只顯示 voucher_binding 記錄)
  • 歷程篩選功能(操作類型 + 時間區間)
  • 歷程分頁功能(每頁 20 筆)
  • 操作類型 Icon 視覺化

不包含在此功能內

  • 開卡 API 的重新開發(使用既有 API)
  • 卡券硬刪除功能(僅支援軟刪除)
  • 已撤銷綁定的恢復功能
  • 已剪卡卡券的恢復功能
  • 客戶 first_namelast_name 欄位的新增(假設已存在)
  • 歷程記錄的匯出功能
  • 多語系支援
  • imported_vouchers 的解綁歷程記錄(只記錄透過 voucher_binding 的操作)
  • 手動開卡(vouchers)的綁定/解綁功能(開卡時就指定客戶,不可變更)

Change Log

v0.3.0 - Phase 2 Grooming 完成 (2025-12-07)

架構重大調整

  • 確認雙軌卡券綁定系統:
    • imported_vouchers 使用 bound_customer_id 直接綁定,同步記錄到 voucher_binding
    • vouchers 使用 customer_id 直接綁定,開卡時指定,不透過 voucher_binding
  • 釐清三種卡券操作:
    • 解綁(Unbind):UI 操作,EMPLOYEE 權限,針對 imported_vouchers
    • 撤銷(Revoke):API 操作,ADMIN 權限,撤銷 voucher_binding 並軟刪除 vouchers
    • 剪卡(Void):API 操作,ADMIN 權限,軟刪除手動開卡的 vouchers
  • 確認歷程頁籤只顯示 voucher_binding 的記錄(匯入卡券的綁定/撤銷歷程)

功能需求大幅擴充

  • FR-001~004: 補充搜尋效能要求(500ms)和無結果提示
  • FR-005~007: 明確字體大小(16px)和完整頁籤順序
  • FR-012~014: 新增 vouchers.source 欄位定義
  • FR-015~029: 新增三種卡券操作的完整需求(解綁/撤銷/剪卡)
  • FR-030~036: 新增歷程篩選功能(操作類型 + 時間區間)和分頁功能

User Story 重寫

  • US2: 補充篩選功能(操作類型 + 時間區間,預設一週)和分頁規格(每頁 20 筆)
  • US4: 從單一「作廢功能」重寫為三種操作(解綁/撤銷/剪卡),明確權限和 UI/API 區分
  • US5: 補充具體規格(字體 16px、4 個頁籤順序)

關鍵實體修訂

  • ImportedVoucher: 新增 bound_customer_idstatus 欄位說明
  • Voucher: 新增 source, customer_id, is_deleted 欄位
  • VoucherItem: 新增 is_deleted 欄位
  • VoucherBinding: 明確只記錄 imported_vouchers 的綁定,欄位包含 imported_voucher_id

假設新增

  • 資料庫索引支援(達成 500ms 搜尋效能)
  • 歷程記錄永久保留
  • 角色權限控制機制已存在

邊界案例更新

  • 補充解綁後重新綁定規則
  • 補充撤銷和剪卡的永久性說明
  • 更新歷程分頁規格

v0.2.0 - Grooming Session (2025-11-30)

設計決策

  • 確認 full_nameUser 表的實際欄位,非計算欄位
  • 確認撤銷狀態使用 VoucherBinding.revoked_at 欄位記錄
  • 確認客戶搜尋支援全名+電話+生日複合搜尋
  • 確認開卡功能已實作綁定客戶流程

功能需求修訂

  • FR-001: 明確 full_name 欄位規格(String(100), nullable, indexed)
  • FR-002: 擴展為複合搜尋(全名+電話+生日)
  • FR-014~018: 從「卡券作廢」調整為「綁定撤銷」概念
  • FR-020: 新增撤銷狀態欄位顯示
  • FR-023: 新增已撤銷記錄的視覺標記需求

關鍵實體修訂

  • 移除「作廢記錄 (Void Record)」實體
  • 新增 VoucherBinding.revoked_at 欄位說明
  • 更新 User.full_name 欄位說明

v0.1.0 - Initial Draft (2025-11-30)

  • 初始規格草稿建立