S-KYC QA Report(第 1 輪|Pass ✅)
QA Validator Agent 針對 S-KYC 客戶 KYC 資料 Feature 的第 1 輪驗收報告(Round 1)。日期 2026-04-20,Pass ✅(28/28 AC + 2 項 Minor Finding)。1
驗收摘要
| 欄位 | 值 |
|---|---|
| Date | 2026-04-20 |
| Validator | QA Agent |
| Round | 第 1 輪 |
| Result | Pass ✅(2 項 Minor Finding,不構成退回條件) |
1. Acceptance Criteria 結果(28 / 28 Pass)
列表頁 AC-01 ~ 07
| AC | 重點 | 結果 |
|---|---|---|
| AC-01 | GET /api/customer-kycs?page=1&pageSize=20 渲染 DataTable | Pass |
| AC-02 | keyword F1 / 查詢按鈕 | Pass |
| AC-03 | RiskToleranceLevel「全部」不帶參數 | Pass |
| AC-04 | 8 欄 DataTable + RiskToleranceLevelBadge + ROC → 西元 | Pass |
| AC-05 | Status Bar「第 {page}/{totalPages} 頁,共 {totalCount} 筆」 | Pass |
| AC-06 | 無資料 empty state | Pass |
| AC-07 | 雙擊 / Enter 導向明細 | Pass |
明細頁 AC-08 ~ 16
| AC | 重點 | 結果 |
|---|---|---|
| AC-08 | 實際呼叫 useCustomerKycQuery | Pass |
| AC-09 | ViewMode 唯讀、TopBar 顯示 F3/F2 | Pass |
| AC-10 | F3 進 EditMode 且主鍵 readonly | Pass |
| AC-11 | Ctrl+S → PUT → Toast | Pass |
| AC-12 | dirty Esc 彈 Modal | Pass |
| AC-13 | 無 dirty Esc 直接切 ViewMode | Pass |
| AC-14 | F2 → 確認 Modal → DELETE | Pass |
| AC-15 | Audit Bar 顯示「建檔 / 最後更新」 | Pass |
| AC-16 | UpdatedDate/UpdatedTime 純文字、TellerNo 可輸入(maxLength=6) | Pass |
新增頁 AC-17 ~ 20
AC-17 綠色 Banner ✅|AC-18 必填 BrokerNo/AccountNo 未填顯示 inline 錯誤 ✅|AC-19 Ctrl+Enter → POST ✅|AC-20 Esc 回列表 ✅
欄位格式 AC-21 ~ 25
| AC | 欄位 | 規則 | 結果 |
|---|---|---|---|
| AC-21 | RiskProfileDate / TradingLimitCreateDate | 8 位數字 | Pass |
| AC-22 | TradingLimit | 正整數 ≤ 999999 | Pass |
| AC-23 | BankVirtualTaxId | ≤ 11 碼 | Pass |
| AC-24 | OfficePhone / MobilePhone | ≤ 24 / 14 碼 | Pass |
| AC-25 | EnglishAddress | ≤ 60 碼 | Pass |
鍵盤快速鍵 AC-26 ~ 28
6 列表(F1/F7/F11/Esc/↑↓/Enter/PgUp-PgDn)、View(F3/F2/Esc/PgUp-PgDn)、Edit(Ctrl+S/Esc/Tab/↑↓)全部實作。
2. Edge Cases
| 類型 | 場景 | 結果 |
|---|---|---|
| null input | keyword 空字串 | Pass(apiClient 忽略) |
| 非法格式 | BrokerNo 含中文 / AccountNo 負數 | Pass |
| 日期格式 | RiskProfileDate 非 8 位 | Pass(前後端雙檢) |
| 範圍 | TradingLimit 負 / >999999 | Pass |
| 列舉 | RiskToleranceLevel 非 ‘1’~‘5’ | Pass |
| 列舉 | Gender 非 M/F、AccountPurpose 非 1/2 | Pass |
| 超長輸入 | EnglishAddress / Phone / TaxId | Pass |
| 資料不存在 | URL 直連不存在資料 | Pass(404) |
| 並發 | 同時編輯,後儲存者 409/422 | Partial(後端未實作樂觀鎖;Spec Out of Scope) |
| 並發 | 明細開著被他人刪除 → 404 | Pass |
| XSS | <script>alert(1)</script> | Pass(EF parameterized + React escape) |
| 日期轉換 | UpdatedDate 民國→西元 | Pass(formatRocDateToDisplay) |
3. 欄位完整性
8 業務欄位 16/16 完整呈現 ✅:BrokerNo / AccountNo(主鍵,Create editable、Edit readonly)、RiskToleranceLevel、RiskProfileDate、CountryCode、BankVirtualTaxId、TradingLimit、TradingLimitCreateDate、OfficePhone、MobilePhone、EnglishAddress、Gender、AccountPurpose、OccupationCategory、NewOccupationCategory、TellerNo(使用者可輸入,maxLength=6)。
系統欄位:UpdatedDate(ROC + 西元)、UpdatedTime、Created_at、Update_at(有值才顯示);CreatedUserId / UpdatedUserId 未顯示(見 Finding-01)。
4. 關鍵重點驗證
| 重點 | 結果 | 證據 |
|---|---|---|
| AC-08 明細頁真正呼叫 API(非假造 tempDetail) | Pass | page.tsx L80-84 useCustomerKycQuery;L112-116 useEffect 以 detailData 覆寫 detailItem |
AC-11 Ctrl+S 透過 handleExitEdit(true) → PUT | Pass | Keyboard hook L252-256;handleSaveEdit 呼叫 updateMutation.mutateAsync |
| UpdateCustomerKycCommand Patch 語意 — null 欄位不覆寫原值 | Pass | if (request.X != null) entity.X = request.X;Unit Test Handle_ShouldNotOverwriteExistingValues_WhenCommandFieldIsNull 覆蓋 |
DB Table 設定 CustomerKycConfiguration.ToTable("CustomerKYC") | Pass | CustomerKycConfiguration.cs L12 |
5. Regression 檢查
10 CustomerBaseInfos(S-CUST)、CustomerAccounts(S-ACCT)、Forward Proxy、Sidebar/Routing、Auth/JWT 皆 Pass 無波及。
6. 文件同步檢查
| 文件 | 狀態 |
|---|---|
docs/features/customerKyc/spec.md | ✅ 已建立 |
docs/domain/scenarios.md | ✅ 已更新(S-KYC 前綴共 24 處) |
docs/domain/feature-map.md | ⚠️ 未查到 S-KYC 條目 → Finding-02 |
docs/domain/domain.md | N/A(未新增 BR 條目,Spec Out of Scope) |
7. Issues Found(4 項)
Finding-01(Minor)— 系統欄位 Card 未顯示 CreatedUserId / UpdatedUserId
- 現況:DetailPage 系統欄位 Card 僅顯示 UpdatedDate / UpdatedTime;後端
CustomerKycDetailDto未輸出CreatedUserId/UpdatedUserId - Spec 比對:Feature Spec
UI Design ReferenceL244-249 明列「系統欄位(唯讀)」應包含 CreatedUserId / UpdatedUserId - AC 比對:AC-15 / AC-16 未明列 → 不構成 AC Fail
- 建議:下一輪補齊前後端 DTO + UI
Finding-02(Minor)— feature-map.md 未新增 S-KYC 條目
- 現況:
docs/domain/feature-map.md搜尋不到 S-KYC 條目 - Spec T-12 任務:明確要求新增 customerKyc / S-KYC 條目
- 建議補上:
| 客戶 KYC 資料 | S-KYC | customerKyc | /customer-kycs | CustomerKycsController |
Finding-03(Informational,非 Fail)— Patch 語意下「清空欄位」的 tradeoff
- 現況:
handleSaveEditL211-225 使用(updates.X ?? detailItem.X) || undefined,將空字串轉為undefined,後端 Patch Handler 不覆寫原值 - 影響:使用者無法把欄位清空為 null;屬 Patch 語意的刻意 tradeoff
- 判定:不列為 Fail,記錄供 PM 評估
Finding-04(Informational,非 Fail)— tempDetail 預設 createdAt 為當下時間
- 現況:
handleOpenDetailL143-154 建立 tempDetail 時createdAt設為new Date().toISOString(),在 API 回傳前會短暫顯示當前日期 - 判定:UX 閃爍(毫秒級),不列為 Fail
8. Required Fixes
本輪無 Required Fix(全部 AC Pass)。 下一輪建議補:
- Finding-01:CreatedUserId / UpdatedUserId 顯示
- Finding-02:feature-map.md 加入 S-KYC 條目
- Finding-04(可選):改善 tempDetail createdAt 初始值
9. QA Decision
- Pass ✅
- Fail
判定理由摘錄
- 28 條 AC 全部通過靜態驗收,核心流程行為完全符合 Spec
- 使用者指定的核心驗證重點全部通過(AC-08、AC-11、Patch 語意、DB Table)
- 欄位完整性 16/16;TellerNo 為 user-editable input(maxLength=6)
- Patch 語意後端實作正確(
if (request.X != null)+ Unit Test 覆蓋) - Edge Cases 處理完整,XSS / 超長輸入 / 非法格式均有防禦
- Regression 無影響
相關頁面
- Feature Spec:S-KYC 客戶 KYC 資料 Feature Spec
- QA 總覽:FSTS QA 報告總覽
- BA 情境:BA 情境規格
- 姊妹模組:S-CUST 客戶基本資料、S-ACCT 客戶開戶資料
補充資訊
(未來 ingest 新來源或後續輪次報告會在此追加段落)