Project

General

Profile

CR #201 » SDD-005_狀態機設計.md

內容更新:內部稱謂去識別化(2026-10-18) - Redmine Admin, 10/18/2026 05:32 AM

 

SDD-005 狀態機設計

項目 內容
文件編號 SDD-005
版本 1.9(CR-022 裁定後:新增 §3.1 授權決策狀態機——RFP FR 1.1(授權/發卡授權)第 4 項要求「支援人工授權、強制授權、人工取消授權」(廠商已回覆「滿足」);其中人工取消=沖正(§3 轉換 5)已完成,本節補 REFERRAL(轉人工)之中間狀態與其核決轉換(SM-D1~D5),為 AuthDecision.REFERRAL 之唯一產生來源)。前版 1.8(CR-020 F4:新增 §2.4「block_code 與 status 之衍生關係」——status 由 block_code 單向推導(完整 7 事件映射表),由狀態機統一維護,消除「生命週期轉換僅改 block_code、快發快綁兩欄皆改」之不一致;併載明與 SM-09 之關係及未來若需獨立時之處理方式)
狀態 已核定
撰寫者 SD
審查者 SA / BA / QA
對應需求 ISS-2.2、ISS-2.3、ISS-2.6、ISS-2.7、ISS-2.8;BRD-001 BF-05、BF-09、BF-10、BF-12

本版差異(1.3):依 CR-003 處置 1.2 版 §12.3 值域稽核所列之 4 項不一致
(A~D),使全部狀態機之值域與可持久化之 DDL CHECK 一致(14 組全數對齊):
①**§5 繳款**——UNMATCHED 改採 DDL 增列途徑(SDD-001 §3.7 +
V4__payments_unmatched_status.sql),並釐清其與 UNMATCHED_FLAG 為正交維度;
②**§7 爭議**——由單一狀態機拆分為兩個(階段/案件),liability 明列為正交屬性;
③**§9 帳單**——由單一狀態機拆分為兩個(帳單本體/批次執行),並補 DISPUTED/CLOSED;
④**§10 點數**——由單一狀態機依維度拆分為三個(桶階段/桶狀態/帳戶),
一併移除不可達轉換、封存 FROZEN 帳戶之入點決策。
連動更正 §13.2 全轉換矩陣(組數 10 → 14,合計 80/103 → 108/139)與
§13.3(改為全數對齊並載明更正歷程)。詳見 §13。

⚠️ 章節編號遞移提示(引用本文件時必看):上段之 §12.2/§12.3 為 1.3 版當時之編號
(指全轉換矩陣/值域稽核),其後歷經兩次遞移——1.4 版(新增 §12 申請案件)
→ §13.2/§13.3;1.7 版(新增 §13 通知)→ §14.2/§14.3。
同理「狀態機實作規範」:1.3 版為 §12 → 1.4 起 §13 → 1.7 起 §14;
「變更記錄」→ §15。

⚠️ 但現行 §12 是「卡片申請案件狀態機」(1.4 版新增),其 §12.1/§12.2/§12.3
分別為值域對應/轉換表/非法轉換——與上段之舊編號無關。
→ 引用時一律看「語意」而非「號碼」:引「值域稽核」= §14.3;引「申請案件轉換表」= §12.2。

已同步更正之現行文件:CSP-007(§13→§14)、SDD-006(同上)、SCS-024(§13.2/§13.3→§14.2/§14.3)。
歷史紀錄保留原編號不動:CR-003(§12.2/§12.3/§13)與 HANDOVER §一~§九——該二者本即
「寫作當時之快照」,不隨章節遞移改寫。


1. 通用規則

規則 說明
SM-01 所有狀態轉換須經狀態機檢核,不得跳轉
SM-02 非法轉換回 CC-*-3001(HTTP 409)
SM-03 重複執行同一轉換(目標狀態已達成)→ 回 200(冪等)
SM-04 並發轉換以「狀態條件更新」實作(WHERE status = :expected)
SM-05 終態(標記 ◆)不得再轉換
SM-06 每次轉換須記錄 from_status、to_status、operator、occurred_at
SM-07 狀態機定義可參數化(狀態與轉換存於參數表),新增狀態不需改碼
SM-08 狀態值域以「可持久化之 DDL CHECK 約束」為權威。本文件不得書寫 DDL 不存在之狀態——程式一旦寫入即觸發 ORA-02290。新增狀態須先改 ER/DDL 並附遷移腳本,再改本文件(1.2 版新增;與 1.1 版 §11 Saga RUNNING→STARTED 同一原則)
SM-09 一組狀態機只表達一個欄位。若值分屬不同欄位(不同實體或不同維度),即屬混用維度,須拆分為多個狀態機,不得以單一圖表達。判準:①值域與 DDL 幾乎無交集 → 不同分類軸;②值分屬不同表 → 不同實體;③同一表之不同欄位 → 不同維度。非生命週期之分類屬性(如 liability、unmatched_flag)應明列為正交屬性,不繪為狀態機(1.3 版新增;由 §7/§9/§10 之更正歸納而得)

2. 卡片狀態機(Block Code)

stateDiagram-v2
  [*] --> INACTIVE: 製卡完成待開卡
  INACTIVE --> ACTIVE: 開卡成功
  INACTIVE --> CLOSED: 未開卡註銷
  ACTIVE --> LOCKED: 風控鎖卡
  LOCKED --> ACTIVE: 解鎖
  ACTIVE --> LOST: 掛失
  LOST --> REISSUED: 補發新卡
  ACTIVE --> REISSUED: 毀損換卡
  ACTIVE --> REISSUED: 到期換卡
  REISSUED --> ACTIVE: 新卡開卡
  ACTIVE --> EXPIRED: 到期未續
  EXPIRED --> CLOSED: 逾期末使用註銷
  ACTIVE --> CLOSED: 客戶註銷
  LOCKED --> CLOSED: 強制註銷
  REISSUED --> CLOSED: 新卡註銷
  CLOSED --> [*]

2.1 轉換表

# 來源 事件 目標 前置條件 副作用 允許角色
1 INACTIVE 開卡成功 ACTIVE 三要素驗證通過 寫入開卡時間、發 card.card.status-changed.v1 系統
2 INACTIVE 未開卡註銷 CLOSED — 釋放卡號、通知 CSR_SUP
3 ACTIVE 風控鎖卡 LOCKED 具風控權限 記錄原因、授權即時拒絕 RISK
4 LOCKED 解鎖 ACTIVE 具風控權限 記錄解除人 RISK
5 ACTIVE 掛失 LOST 客戶申請或風控判定 拒絕所有新交易、觸發補發流程 CSR
6 LOST 補發 REISSUED 已產生新卡號 舊卡註銷、權益移轉 CSR_SUP
7 ACTIVE 毀損換卡 REISSUED 已產生新卡號 同上 CSR
8 ACTIVE 到期換卡 REISSUED 到期日到達 同上 系統
9 REISSUED 新卡開卡 ACTIVE 新卡三要素驗證通過 新卡啟用 系統
10 ACTIVE 到期未續 EXPIRED 到期日 + 寬限期 停止交易 系統
11 EXPIRED 逾期末使用 CLOSED 逾期限 帳戶結清 系統
12 ACTIVE 客戶註銷 CLOSED 帳戶已結清 釋放權益、通知 CSR_SUP
13 LOCKED 強制註銷 CLOSED 主管核可 帳戶結清 RISK
14 REISSUED 新卡註銷 CLOSED 帳戶已結清 — CSR_SUP

2.2 非法轉換(須被拒絕)

嘗試 結果
CLOSED → ACTIVE ❌ CC-CARD-3001(終態)
LOST → ACTIVE ❌ 須經 REISSUED 換卡
INACTIVE → LOCKED ❌ 未開卡不得鎖卡
EXPIRED → ACTIVE ❌ 須重新申請

2.3 授權即時性要求

狀態 授權行為
ACTIVE 正常檢核
LOCKED / LOST 即時拒絕(不得等快取過期)
REISSUED(舊卡) 拒絕
EXPIRED / CLOSED 拒絕
INACTIVE 拒絕

狀態變更須於 1 秒內同步至授權服務(BR-04-04)。


2.4 ★ block_code 與 status 之衍生關係(2026-09-23 新增,依 CR-020 F4 之裁定)

緣由(CR-020 F4,真機實測):原生命週期轉換(POST /cards/{cardId}/lifecycle-transitions)
僅更新 block_code,而快發快綁(POST …/instant-issuance)兩欄皆更新
→ 同一業務事件(開卡)因路徑不同而結果不同,實測產生 block_code=ACTIVE、
status=UNACTIVATED 之組合(測試前 0 列、測試後 2 列)。

裁定(BEAM PMO 2026-09-23):採完整映射——status 由 block_code 單向推導,
由狀態機統一維護,消除「兩條寫入路徑不一致」。

block_code(生命週期) status(啟用/帳務) 說明
INACTIVE UNACTIVATED 製卡完成、待開卡
ACTIVE ACTIVE 已開卡可用
LOCKED SUSPENDED 風控鎖卡 → 停用
LOST SUSPENDED 掛失 → 停用
REISSUED UNACTIVATED 新卡(補發/換卡)待開卡
EXPIRED SUSPENDED 到期未續 → 停用
CLOSED CLOSED 終態

⚠️ 三條鐵律(不可違反,違者即為漂移):

  1. status 為衍生欄位,非獨立維度——任何寫入路徑皆須由 block_code 推導,
    不得由呼叫端指定、不得單獨更新。(此即 CR-020 F4 之根因。)
    實作上映射表內建於 CardBlockCode 狀態列舉,以 switch 運算式之窮盡性檢查
    保證:新增區塊碼而未定義對應 status 時編譯即失敗。
  2. 與 SM-09 之關係:SM-09 要求「一組狀態機只表達一個欄位」。本節之 status 既為
    block_code 之衍生,不另繪狀態機圖——其轉換全由 §2 之圖決定,故未違反 SM-09。
    ⚠️ 若日後 status 需獨立於 block_code 變化(例:「卡片 ACTIVE 但帳務 SUSPENDED」
    ——欠款停用而卡片仍可交易),則兩欄即為真正之兩個維度,屆時須新增獨立狀態機
    並廢除本映射表。不可同時維持映射與獨立更新——那必然漂移。
  3. 保留兩欄(而非廢除 status)之理由:status 已出現於對外契約
    (CardStatusView.status)與既有 DDL(V1__baseline.sql),廢除屬破壞性變更。
    故本期保留欄位、消除其獨立性,使其不可能與 block_code 不一致——
    此為「既相容又一致」之取捨,不是承認兩欄各有語意。

3. 授權佔用狀態機(Limit Hold)

⚠️ 本節已於 CR-044 ③(BEAM PMO 2026-10-15 裁定)修訂:裁定「以 limit-service 為權威、
讀模型鏡射
」。★ 原狀態機將 PARTIALLY_RELEASED 列為部分請款後之可達中繼態,
惟權威端之釋放 SQL 為「僅全額才轉 RELEASED」——部分請款不改變狀態。
→ ★ 本節依權威行為重寫:PARTIALLY_RELEASED 改為「DDL 值域內、本期權威不可達」之值。

stateDiagram-v2
  [*] --> HELD: 授權核准並佔用
  HELD --> RELEASED: 全額請款(含先前已部分釋放之差額)
  HELD --> RELEASED: 授權取消或沖正
  HELD --> EXPIRED: 超過有效期限未請款
  RELEASED --> [*]
  EXPIRED --> [*]
# 來源 事件 目標 說明
1 — 授權核准 HELD 佔用可用額度
2 HELD 部分請款 HELD(狀態不變) ★ CR-044 ③:原訂目標為 PARTIALLY_RELEASED,惟權威(limit-service)之 CASE 僅全額轉 RELEASED,部分請款只累計 released_amount、不改狀態;BEAM PMO 2026-10-15 裁定「以 limit 為權威、讀模型鏡射」→ 讀模型亦維持 HELD
3 PARTIALLY_RELEASED 請款完成 RELEASED ⬜ 本期不可達(#2 不再產生 PARTIALLY_RELEASED)——「全額釋放」由 #2 直接收斂至 #4 之語意
4 HELD 全額請款 RELEASED 全額釋放
5 HELD 取消/沖正 RELEASED 全額釋放
6 HELD 逾期未請款 EXPIRED 釋放額度(依參數之有效天數)
7 PARTIALLY_RELEASED 逾期 EXPIRED ⬜ 本期不可達(HELD 逾期由 #6 處理)

規則:RELEASED 與 EXPIRED 為終態;釋放操作具冪等性(已釋放則略過)。

3.0.1 權威來源與讀取端注意事項(CR-044 ③)

# 規則
R1 權威:佔用狀態之權威為 limit-service(CC_LIM.LIMIT_HOLDS)。authorization-service 之 CC_AUTH.LIMIT_HOLDS 為讀模型投影,其 status 必須鏡射權威(SCS-001 §7.6/§7.15)——★ 兩端對同一事實不得有兩種陳述
R2 部分請款不改變狀態:部分釋放之事實由 released_amount 累計表達;status 僅於「全額釋放」轉 RELEASED
R3 PARTIALLY_RELEASED 保留於 DDL/契約值域,但本期不可達:SDD-001 §3 之 CHECK 與契約 enum 刻意不放寬(放寬值域屬破壞性變更,且無需求支撐);惟權威不寫入之 → 為不可達值。前端仍須保留其顯示分支(防舊資料)
R4 ⚠️ 讀取端之過濾條件必須保留 PARTIALLY_RELEASED:availableLimit 之 SUM 原為 status IN ('HELD','PARTIALLY_RELEASED')(SCS-001 §7.6 曾因低估佔用而修正)。★ 即使本期不再新寫 PARTIALLY_RELEASED,歷史資料仍可能存在;省略該值將低估佔用、高估可用額度 → 超額風險。★ 故「權威不再寫入」≠「讀取時可省略」

3.1 授權決策狀態機(Authorization Decision)——2026-09-24 新增(CR-022 裁定後)

緣由:RFP 業務功能需求(授權) S/N 1.1(授權/發卡授權)第 4 項明文要求
「支援人工授權、強制授權、人工取消授權」(廠商回覆欄已填「滿足」)。
其中「人工取消授權」=沖正(§3 轉換 5)已完成;「人工授權/強制授權」須有
轉人工(REFERRAL) 之中間狀態方能成立。
⚠️ 查證:AuthDecision.REFERRAL 原存在於 enum 但全服務零產生處——
本節為其唯一產生來源(SCS-001 §7.8.1)。

stateDiagram-v2
  [*] --> APPROVED: 檢核全數通過
  [*] --> DECLINED: 硬性拒絕(卡況/黑名單)
  [*] --> REFERRAL: 命中人工複核門檻
  [*] --> STANDIN: 額度服務不可用(降級代佔)
  REFERRAL --> APPROVED: 人工授權(APPROVE)
  REFERRAL --> DECLINED: 人工婉拒(DECLINE)
  APPROVED --> [*]
  DECLINED --> [*]
  STANDIN --> [*]
# 來源 事件 目標 副作用
1 [*] 檢核全數通過 APPROVED 佔額(hold)
2 [*] 硬性拒絕 DECLINED 不佔額
3 [*] 命中人工複核門檻 REFERRAL 仍佔額(交易已發生,先保留額度)
4 [*] 額度服務不可用 STANDIN 本地代佔、standin_flag=1、待上送
5 REFERRAL APPROVE(人工授權) APPROVED 保留原佔額
6 REFERRAL DECLINE(人工婉拒) DECLINED 釋放原佔額(LimitPort.release,§3 轉換 5 同一路徑)

規則:

規則 說明
SM-D1 僅 REFERRAL 可被核決——對 APPROVED/DECLINED/STANDIN 核決回 CC-AUTH-3001(409)
SM-D2 核決為一次性——override_at 非空後再核決回 CC-AUTH-3002(409,終態)
SM-D3 不修改原檢核明細——auth_check_results 為當時事實;核決寫入 auth_overrides(新增紀錄,與 §4 轉換 4「產生反向交易、不修改原紀錄」同一原則)
SM-D4 force=true 僅限軟性拒絕——不得用於硬性拒絕(卡片 LOCKED/CLOSED、黑名單),避免繞過風控
SM-D5 門檻參數化且預設關閉——AUTH.MANUAL_REVIEW 未設時不轉人工(fail-safe:不因缺參數把正常交易卡住)

⚠️ 與 CR-022 (B) 案之區別:本狀態機不允許對已 DECLINED 之件強制核准
——那會繞過檢核(人工可強制放行任何拒絕件),業務風險過高,故 (B) 案不予採納。


4. 帳務交易狀態機

stateDiagram-v2
  [*] --> PENDING: 交易受理
  PENDING --> POSTED: 入帳成功
  PENDING --> FAILED: 入帳失敗
  POSTED --> REVERSED: 沖正
  FAILED --> PENDING: 異常處理後重新入帳
  REVERSED --> [*]
  FAILED --> [*]
# 來源 事件 目標 說明
1 — 交易受理 PENDING 寫入待處理
2 PENDING 入帳成功 POSTED 更新餘額、發事件
3 PENDING 入帳失敗 FAILED 記錄原因,可查詢
4 POSTED 沖正 REVERSED 產生反向交易(不修改原紀錄)
5 FAILED 異常處理 PENDING 調整後重新入帳

規則

規則 說明
POSTED 不得回到 PENDING 已入帳不得重複入帳
REVERSED 為終態 沖正後不得再沖正(須以新交易處理)
原紀錄不可變 REVERSED 僅標記,不刪除、不修改金額

5. 繳款狀態機

stateDiagram-v2
  [*] --> RECEIVED: 繳款受理
  RECEIVED --> ALLOCATED: 分配完成
  ALLOCATED --> POSTED: 入帳並恢復額度
  POSTED --> REVERSED: 繳款沖正
  RECEIVED --> FAILED: 檢核失敗
  POSTED --> UNMATCHED: 逾三日未收銷帳檔(重新佔額)
  UNMATCHED --> POSTED: 收到銷帳檔後入帳
  UNMATCHED --> REVERSED: 確認未入帳後沖正
  REVERSED --> [*]
  FAILED --> [*]
# 來源 事件 目標 說明
1 — 受理 RECEIVED 寫入繳款紀錄
2 RECEIVED 分配 ALLOCATED 依沖銷順序分配
3 ALLOCATED 入帳 POSTED 即時恢復額度
4 POSTED 沖正 REVERSED 反向處理並重新佔額
5 RECEIVED 檢核失敗 FAILED 記錄原因
6 POSTED 逾三日未銷帳 UNMATCHED 重新佔額(POC-11 情境三)
7 UNMATCHED 收到銷帳檔 POSTED 補入帳
8 UNMATCHED 確認未入帳 REVERSED 沖正

值域:RECEIVED/ALLOCATED/POSTED/REVERSED/FAILED/UNMATCHED
——對齊 SDD-001 §3.7 ER 與 CC_PAYMENT.PAYMENTS.status 之 CHECK 約束(CK_PAYMENTS_STATUS)。

⚠️ 1.3 版更正說明(UNMATCHED 改採 DDL 增列途徑)

1.2 版之稽核曾判定本節 UNMATCHED 不可持久化(PAYMENTS.status 之 CHECK 無此值),
並提出二途:①移除該狀態、改以旗標語意;②於 DDL 增列該值。
經核定採 ②DDL 增列——理由:本節之 UNMATCHED 為作業狀態
(已分配、逾三日未收銷帳檔),與旗標語意不同,不應為遷就 DDL 而捨棄。

項 內容
設計權威 SDD-001 §3.7——status 之 CHECK 增列 UNMATCHED
實體交付 V4__payments_unmatched_status.sql(V1 基線已凍結,不得修改)
契約 PaymentView.status 枚舉增列 UNMATCHED(改 gen_openapi.py 後重生)
實作 PaymentStatus 增列 UNMATCHED
實測 寫入 UNMATCHED 成功;非法值觸發 ORA-02290(CK_PAYMENTS_STATUS)——約束確為生效,非僅名稱存在

UNMATCHED 與 UNMATCHED_FLAG 之關係(正交,非取代):

欄位 語意 判定時機
UNMATCHED_FLAG 本次受理未取得沖抵來源(資料品質訊號) 受理時
status = 'UNMATCHED' 已分配、逾三日未收銷帳檔(作業狀態) 批次

二者可同時成立;UNMATCHED_FLAG 不移除。

保留事項(不得視為已實作):

  • 轉換 #6(ALLOCATED → UNMATCHED)之產生者尚未實作
    → ✅ 已實作(C-19,2026-09-22):PaymentUnmatchedService+PaymentUnmatchedScheduler
    (逾三日批次)、Payment#markUnmatched()(含重新佔額)。真機實測(走真實受理流程):
    POSTED(LIMIT_RESTORED=1)→ 逾期 → UNMATCHED(LIMIT_RESTORED=0)、VERSION 2→3;
    未逾時者不動(負樣本)。詳 SCS-008 §8.2。
  • 轉換 #8(UNMATCHED → REVERSED)尚未實作
    → ✅ 已放行(C-19,2026-09-22):PaymentStatus#reversible() 現回 true 於
    POSTED 與 UNMATCHED,消除「狀態機允許、程式拒絕」之缺陷;
    真機實測對 UNMATCHED 繳款呼叫沖正端點 → 200 REVERSED(SCS-008 §8.2)。

⚠️ 轉換 6 來源狀態之更正(BEAM PMO 2026-09-22 裁定採方案 B)

本節原記來源為 ALLOCATED,惟實作 C-19 時發現三方不相容:
① 現行受理流程不停留 ALLOCATED(PaymentService#accept 一次完成
RECEIVED → ALLOCATED → POSTED、僅落地 POSTED),故該狀態不可達;
② BRD-004 POC-11 情境 11-3 之「繳款當下額度恢復 → 三日後回復原值(重新佔額)」
隱含額度已先恢復,而額度於 post() 才標 LIMIT_RESTORED = true;
③ SCS-008 §10 #5 原載「受理即標」與實物不符。
故來源狀態更正為 POSTED(額度已恢復者方有可撤銷之恢復),
並同步修訂本節轉換 6 與 SCS-008。此更正使 POC-11 11-3 之語意自洽、批次對
現行常態狀態立即可達。


6. 分期計畫狀態機

stateDiagram-v2
  [*] --> ACTIVE: 建立分期(佔用額度、產生各期明細)
  ACTIVE --> COMPLETED: 按期攤還完畢
  ACTIVE --> PRE_CLOSED: 提前結清
  ACTIVE --> DEFAULTED: 違約加速到期
  ACTIVE --> CANCELLED: Saga 補償取消
  DEFAULTED --> COMPLETED: 清償完畢
  COMPLETED --> [*]
  PRE_CLOSED --> [*]
  CANCELLED --> [*]
# 來源 事件 目標 說明
1 — 建立分期 ACTIVE 佔用額度、產生各期明細(建立即生效)
2 ACTIVE 按期攤還完畢 COMPLETED 最終期入帳
3 ACTIVE 提前結清 PRE_CLOSED 剩餘本金一次清償、免收後續手續費
4 ACTIVE 違約 DEFAULTED 計收違約金、加速到期
5 ACTIVE Saga 補償 CANCELLED 首期入帳失敗時取消
6 DEFAULTED 清償 COMPLETED —

值域:ACTIVE/COMPLETED/PRE_CLOSED/DEFAULTED/CANCELLED
——對齊 SDD-001 §3.9 ER 與 CC_INST.INSTALLMENT_PLANS.status 之 CHECK 約束。

⚠️ 1.2 版更正說明(原 1.0/1.1 版之 PENDING/REJECTED 未採納)

1.0/1.1 版之本節另含 PENDING(申請,未佔用)與 REJECTED(拒絕),
以及 SETTLED/EARLY_SETTLED 二名稱。經查證後更正,依據如下:

項 原值 更正為 依據
申請狀態 PENDING 移除(建立即 ACTIVE) ① CC_INST.INSTALLMENT_PLANS.status 之 CHECK 無 PENDING,DEFAULT 'ACTIVE'——無法持久化;② BRD-001 §5.6 之流程為「申請 → 資格與額度檢核 → {拒絕-額度不足 / 總約簽署 → 首期入帳}」,其中拒絕為同步交易拒絕,流程中不存在「已申請、待核准」之持久狀態;③ 實作 InstallmentService.create 直接建立 ACTIVE
拒絕狀態 REJECTED 移除 同①(CHECK 無此值);額度不足之拒絕為同步回應(BRD-001 §5.6 C3「拒絕-額度不足」),非持久狀態
攤還完畢 SETTLED COMPLETED DDL CHECK 之值域;語意相同,以 DDL 為權威統一術語
提前結清 EARLY_SETTLED PRE_CLOSED 同上

原則:與 1.1 版更正 §11 Saga RUNNING→STARTED 同一原則——
狀態值域以可持久化之 DDL 為權威;書寫 DDL 不存在之狀態,程式一旦寫入即觸發
ORA-02290(違反 CHECK 約束)。

保留事項(不得視為已實作):

  • 本節僅定義狀態與合法轉換。COMPLETED 之產生者(每期扣款/攤還排程)尚未實作,
    故目前無程式路徑可達;詳見 SCS-009 §10.5 #7。
  • 轉換 #5(ACTIVE → CANCELLED,Saga 補償)尚未實作。
  • 若日後業務確需「申請—核准」流程(即恢復 PENDING/REJECTED),
    須另提 CR 於 SDD-001 §3.9 ER/DDL 補入該二狀態並附遷移腳本,
    不得僅修改本文件——否則將重現「狀態機有、資料庫存不下」之同一缺陷。

7. 爭議案件狀態機(兩個正交狀態機)

1.3 版更正:本節原為單一狀態機,將兩個正交分類軸繪入同一圖——
「卡組織流程階段」與「案件處理/結果」,且與 SDD-001 §3.13 之
DISPUTE_CASES.stage/status 二欄值域幾乎無交集(僅 CLOSED 一值相同)。
經核定拆分為兩個狀態機,分別對應實體之兩個欄位;
第三個欄位 liability(責任歸屬)為正交屬性,非狀態機,見 §7.3。

7.1 爭議階段機(DISPUTE_CASES.stage)——卡組織流程階段

stateDiagram-v2
  [*] --> INQUIRY: 受理並向收單行提出調單請求
  INQUIRY --> FIRST_PRESENTMENT: 收單行第一次再提示
  FIRST_PRESENTMENT --> SECOND_PRESENTMENT: 發卡行不服,第二次再提示
  SECOND_PRESENTMENT --> PRE_ARB: 進入仲裁前置協商
  PRE_ARB --> ARBITRATION: 協商不成,提交卡組織仲裁
  INQUIRY --> CLOSED: 階段終止
  FIRST_PRESENTMENT --> CLOSED: 階段終止
  SECOND_PRESENTMENT --> CLOSED: 階段終止
  PRE_ARB --> CLOSED: 階段終止
  ARBITRATION --> CLOSED: 裁決確定
  CLOSED --> [*]
# 來源 事件 目標 說明
1 — 受理並調單 INQUIRY 客服建檔後向收單行提出調單請求(BRD-001 BF-09 C1)
2 INQUIRY 第一次再提示 FIRST_PRESENTMENT 收單行提交請款證明
3 FIRST_PRESENTMENT 第二次再提示 SECOND_PRESENTMENT 發卡行不接受第一次提示
4 SECOND_PRESENTMENT 仲裁前置 PRE_ARB 依卡組織規則進入強制協商
5 PRE_ARB 提交仲裁 ARBITRATION 協商不成
6 INQUIRY 階段終止 CLOSED 撤案,或收單行不再提示
7 FIRST_PRESENTMENT 階段終止 CLOSED 同上
8 SECOND_PRESENTMENT 階段終止 CLOSED 同上
9 PRE_ARB 階段終止 CLOSED 同上
10 ARBITRATION 裁決確定 CLOSED 卡組織裁決書確定

值域:INQUIRY/FIRST_PRESENTMENT/SECOND_PRESENTMENT/PRE_ARB/ARBITRATION/CLOSED
——對齊 SDD-001 §3.13 ER 與 CC_DIS.DISPUTE_CASES.stage 之 CHECK 約束(實測值)。

7.2 爭議案件狀態機(DISPUTE_CASES.status)——案件處理與結果

stateDiagram-v2
  [*] --> OPEN: 客服案件建檔
  OPEN --> EVIDENCE_PENDING: 證據不完整,待補件
  EVIDENCE_PENDING --> REPRESENTED: 補件完成並送件
  OPEN --> REPRESENTED: 證據完整,逕行送件
  REPRESENTED --> WON: 發卡行勝
  REPRESENTED --> LOST: 商戶勝
  WON --> CLOSED: 帳務沖銷完成並結案
  LOST --> CLOSED: 爭議駁回並結案
  OPEN --> CLOSED: 撤案
  EVIDENCE_PENDING --> CLOSED: 撤案
  REPRESENTED --> CLOSED: 撤案
  CLOSED --> [*]
# 來源 事件 目標 說明
1 — 受理 OPEN 客服案件建檔、記錄卡組織時限
2 OPEN 證據不完整 EVIDENCE_PENDING BRD-001 BF-09 C2「否」→ 補充資料要件後重新送件
3 EVIDENCE_PENDING 補件完成 REPRESENTED C3 → C1 送件
4 OPEN 證據完整 REPRESENTED C2「是」→ 已向收單行提出
5 REPRESENTED 發卡行勝 WON 含「逾時未回覆逕行裁決」(C5)與仲裁「持卡人勝」(D5)
6 REPRESENTED 商戶勝 LOST 含仲裁「商戶勝」(D5)→ 爭議駁回(D7)
7 WON 帳務沖銷完成 CLOSED 沖銷、額度恢復、結案通知(E1~E3)
8 LOST 結案 CLOSED 同上
9 OPEN 撤案 CLOSED 持卡人撤回
10 EVIDENCE_PENDING 撤案 CLOSED 同上
11 REPRESENTED 撤案 CLOSED 同上

值域:OPEN/EVIDENCE_PENDING/REPRESENTED/WON/LOST/CLOSED
——對齊 SDD-001 §3.13 ER 與 CC_DIS.DISPUTE_CASES.status 之 CHECK 約束(實測值)。

規則:CLOSED 為終態;爭議期間之計息依卡組織規則暫停(BR-09-03)。

7.3 正交屬性:liability(責任歸屬,非狀態機)

DISPUTE_CASES.liability 為分類屬性而非生命週期狀態,故不繪為狀態機:

值 語意 對應 BRD-001 BF-09
PENDING 尚未定案(預設) 案件進行中
ISSUER 發卡行承擔損失 D1「發卡行責任」→ D2
ACQUIRER 收單行退款 D1「收單行責任」→ D3
MERCHANT 特約商店承擔 D1 之商戶側歸屬

liability 之寫入時機為 §7.2 轉換 5/6 定案之後;WON/LOST 與 liability
之精確對應(孰為 ACQUIRER、孰為 MERCHANT)須於實作時依卡組織規則確認,
已列入 SCS-012 §10。

保留事項(不得視為已實作):

  • dispute-service 目前僅有骨架(無領域模型),本節二狀態機之轉換全部尚未實作。
  • §7.1 之 PRE_ARB/ARBITRATION 涉及卡組織仲裁程序與時限控管,
    BRD-001 BF-09 僅至「提交卡組織仲裁」;各階段之組織時限參數尚未取得,
    實作前須補(BR-09-01 要求受卡組織時限控管)。

8. 額度調整狀態機

stateDiagram-v2
  [*] --> DRAFT: 建立申請
  DRAFT --> PENDING_APPROVAL: 送出(超過權限上限)
  DRAFT --> EFFECTIVE: 生效(未超過權限上限)
  PENDING_APPROVAL --> EFFECTIVE: 覆核通過
  PENDING_APPROVAL --> REJECTED: 覆核駁回
  EFFECTIVE --> EXPIRED: 臨時額度到期
  EFFECTIVE --> REVOKED: 撤銷
  EXPIRED --> [*]
  REVOKED --> [*]
  REJECTED --> [*]
# 來源 事件 目標 說明
1 — 建立 DRAFT 未生效
2 DRAFT 送出(超限) PENDING_APPROVAL 待覆核
3 DRAFT 送出(未超限) EFFECTIVE 直接生效
4 PENDING_APPROVAL 覆核通過 EFFECTIVE 生效並同步授權
5 PENDING_APPROVAL 覆核駁回 REJECTED —
6 EFFECTIVE 臨時額度到期 EXPIRED 自動調降
7 EFFECTIVE 撤銷 REVOKED 需主管核可

9. 帳單狀態機(兩個正交狀態機)

1.3 版更正:本節原為單一狀態機,將兩個實體繪入同一圖——
帳單本體(stmt.statements)與批次執行(stmt.statement_runs)。
其中 GENERATING/FAILED 屬批次執行,其餘屬帳單本體;
且原圖缺 DISPUTED/CLOSED 二值。經核定拆分為兩個狀態機。

9.1 帳單本體狀態機(stmt.statements.status)

stateDiagram-v2
  [*] --> GENERATED: 出帳批次產製完成
  GENERATED --> SENT: 帳款通知送達客戶
  SENT --> PAID: 全額繳款
  SENT --> PARTIALLY_PAID: 部分繳款
  SENT --> OVERDUE: 逾繳款期限未達最低應繳
  SENT --> DISPUTED: 帳款爭議成立
  PARTIALLY_PAID --> PAID: 補足繳款
  PARTIALLY_PAID --> OVERDUE: 逾繳款期限
  OVERDUE --> PAID: 逾期後清償
  DISPUTED --> PAID: 爭議處理後清償
  DISPUTED --> OVERDUE: 爭議駁回且未清償
  DISPUTED --> CLOSED: 爭議調整完成結案
  PAID --> CLOSED: 結案歸檔
  OVERDUE --> CLOSED: 轉催收後結案
  CLOSED --> [*]
# 來源 事件 目標 說明
1 — 出帳批次完成 GENERATED 歸戶合併、計算應繳、凍結明細(BRD-001 BF-05 A1~A4)
2 GENERATED 帳款通知送達 SENT 電子/行動/紙本(A5~A6)
3 SENT 全額繳款 PAID —
4 SENT 部分繳款 PARTIALLY_PAID 未達全額
5 SENT 逾繳款期限 OVERDUE 未達最低應繳(B6「否」→ C2 延滯標記)
6 SENT 帳款爭議 DISPUTED 轉 dispute-service(BF-09)
7 PARTIALLY_PAID 補足繳款 PAID —
8 PARTIALLY_PAID 逾繳款期限 OVERDUE —
9 OVERDUE 逾期後清償 PAID —
10 DISPUTED 爭議處理後清償 PAID —
11 DISPUTED 爭議駁回 OVERDUE 爭議不成立且仍未清償
12 DISPUTED 爭議調整完成 CLOSED 帳務調整後結案
13 PAID 結案歸檔 CLOSED —
14 OVERDUE 轉催收後結案 CLOSED C3 催收流程結束

值域:GENERATED/SENT/PAID/PARTIALLY_PAID/OVERDUE/DISPUTED/CLOSED
——對齊 SDD-001 §3.10 ER 與 CC_STMT.STATEMENTS.status 之 CHECK 約束(實測值)。

9.2 批次執行狀態機(stmt.statement_runs.status)

stateDiagram-v2
  [*] --> GENERATING: 出帳批次啟動
  GENERATING --> GENERATED: 產製完成
  GENERATING --> FAILED: 產製異常
  FAILED --> GENERATING: 自 Checkpoint 續跑
  GENERATED --> [*]
# 來源 事件 目標 說明
1 — 批次啟動 GENERATING 建立本次執行紀錄
2 GENERATING 產製完成 GENERATED 寫入 finished_at、statement_count
3 GENERATING 產製異常 FAILED 寫入 error_detail,保留 checkpoint
4 FAILED 續跑 GENERATING 自 checkpoint 續跑,不從頭重跑

值域:GENERATING/GENERATED/FAILED
——對齊 CC_STMT.STATEMENT_RUNS.status 之 CHECK 約束(實測值)。

與 SDD-001 §3.10 之關係:statement_runs 與 statement_cycle_accounts
係因契約要求「批次狀態與 Checkpoint」而於 V2 遷移補建
(V2__statement_runs_and_no_seq.sql),SDD-001 §3.10 之 ER/DDL 為
V1 基線快照,未含此二表——已於該節加註變更交付說明。


10. 點數狀態機(三個正交狀態機)

1.3 版更正:本節原為單一狀態機,將三個維度繪入同一圖——
① 桶階段(bucket_stage:CUR/AV1/AV2)
② 桶狀態(points_expiry_buckets.status)
③ 帳戶營運狀態(points_accounts.status)。
經核定依維度拆分為三個狀態機。
原圖之 CLOSED 實屬帳戶狀態,已移至 §10.3。

10.1 桶階段流轉(points_expiry_buckets.bucket_stage)

stateDiagram-v2
  [*] --> CUR: 首筆回饋入帳
  CUR --> AV1: CUR 到期且餘額為正
  AV1 --> AV2: AV1 到期且餘額為正
  AV1 --> [*]: AV1 到期且無餘額可搬
  AV2 --> [*]: AV2 到期並清零
# 來源 事件 目標 說明
1 — 首筆回饋 CUR 效期 = 入帳日 + 25 個月
2 CUR 到期且餘額 > 0 AV1 餘額搬至 AV1(效期 +3 個月),CUR 桶重設效期
3 AV1 到期且餘額 > 0 AV2 餘額搬至 AV2(效期 +1 個月),AV1 桶清零
4 AV1 到期且無餘額 (結束) 該階段桶已用盡,不建新桶
5 AV2 到期 (結束) 餘額清零、移除效期

值域:CUR/AV1/AV2——對齊 POINTS_EXPIRY_BUCKETS.bucket_stage 之 CHECK(實測)。
依據:BRD-001 BR-07-03(CUR 當期/AV1 年度/AV2 活動三類分別管理)、POC-02 情境 2-11。

⚠️ 1.3 版更正說明(原 1.2 版之轉換 3 已移除)

原圖含轉換 3「CUR 到期且餘額 < 0 → CUR(餘額不移轉,僅重設效期)」。
經實測,CC_RW.POINTS_ACCOUNTS.BALANCE 有 balance >= 0 之 CHECK 約束,
負餘額不可能存在,故該轉換不可達——已移除。
(此項原已由 SCS-010 §10.2 揭露為「不可達轉換」,本次一併更正。)

10.2 桶狀態機(points_expiry_buckets.status)

stateDiagram-v2
  [*] --> ACTIVE: 桶建立
  ACTIVE --> EXPIRED: 到期未用盡
  ACTIVE --> REDEEMED: 兌換扣抵用盡
  EXPIRED --> [*]
  REDEEMED --> [*]
# 來源 事件 目標 說明
1 — 桶建立 ACTIVE 隨 §10.1 之階段產生,points > 0
2 ACTIVE 到期未用盡 EXPIRED 沒收(FORFEIT)
3 ACTIVE 兌換扣抵用盡 REDEEMED 先到期先用(POC 2-12)
4 EXPIRED — (終態) —
5 REDEEMED — (終態) —

值域:ACTIVE/EXPIRED/REDEEMED
——對齊 POINTS_EXPIRY_BUCKETS.status 之 CHECK(實測)。

10.3 帳戶營運狀態機(points_accounts.status)

stateDiagram-v2
  [*] --> ACTIVE: 帳戶開立
  ACTIVE --> FROZEN: 風控凍結
  FROZEN --> ACTIVE: 解除凍結
  ACTIVE --> CLOSED: 歸戶結清
  FROZEN --> CLOSED: 凍結後結清
  CLOSED --> [*]
# 來源 事件 目標 說明
1 — 開立 ACTIVE 首筆回饋或歸戶建立時開立
2 ACTIVE 風控凍結 FROZEN 停卡/爭議等風險事由
3 FROZEN 解除凍結 ACTIVE 風險事由消滅
4 ACTIVE 歸戶結清 CLOSED 帳戶註銷
5 FROZEN 結清 CLOSED —
6 CLOSED — (終態) —

值域:ACTIVE/FROZEN/CLOSED
——對齊 POINTS_ACCOUNTS.status 之 CHECK(實測)。

各狀態之操作權限(封存現行實作,見 SCS-010 §10.6):

狀態 入點 兌換
ACTIVE ✅ ✅
FROZEN ✅ ❌ 422 CC-RWD-1003
CLOSED ❌ 409 CC-RWD-3002 ❌

凍結僅限制負債側(兌換);消費仍會發生,點數屬客戶既有權益。
此為規格空白之封存決策(原 SCS-010 §10.6 列為「待 CR 確認」)——
本次補入本節即為該待辦之第 ① 項(「於 SDD-005 新增帳戶營運狀態機」)。
若日後改為「凍結應全面停止累積」,須另提 CR,並同步改 AccrualService
與 SDD-006 §3.4 之錯誤碼。


11. Saga 狀態機

stateDiagram-v2
  [*] --> STARTED: 啟動
  STARTED --> COMPLETED: 全部步驟成功
  STARTED --> COMPENSATING: 某步驟失敗
  COMPENSATING --> COMPENSATED: 補償全部成功
  COMPENSATING --> FAILED: 補償失敗
  FAILED --> COMPENSATING: 人工介入後重試補償
  COMPLETED --> [*]
  COMPENSATED --> [*]
# 來源 事件 目標 說明
1 — 啟動 STARTED 持久化 Saga 狀態
2 STARTED 全部成功 COMPLETED —
3 STARTED 步驟失敗 COMPENSATING 逆序執行補償
4 COMPENSATING 補償成功 COMPENSATED 回覆失敗結果
5 COMPENSATING 補償失敗 FAILED 告警並可人工介入(CC-PLT-5002)
6 FAILED 重試補償 COMPENSATING 人工觸發

術語對齊(2026-09-18):本節原將初始狀態書為 RUNNING,但
ops/local/init/oracle/01-init.sh 之 ck_saga_status 約束實際枚舉為
('STARTED','COMPENSATING','COMPLETED','COMPENSATED','FAILED')——
持久化契約無 RUNNING。以 DDL 為權威,本節正式更名為 STARTED;
程式端 SagaState 列舉亦以此五值為準,避免寫入時觸發 ORA-02290。

終態:COMPLETED、COMPENSATED(FAILED 可經人工重試回 COMPENSATING,非終態)。


12. 卡片申請案件狀態機(CC_CARD.CARD_APPLICATIONS.status)

1.4 版新增(2026-09-20,BEAM PMO 核定「進件系統缺口」)。
對應 BRD-001 BF-01(受理進件 → 身分驗證與徵信 → 核決 → 製卡/即時給號 → 開卡)
與 BRD-001 BF-10(Applied → UnderReview → Approved → Manufactured → Active)。
程式設計規格見 SCS-024。

12.1 值域與 BRD 對應(以 DDL CHECK 為權威)

本機值域 BRD BF-10 說明
RECEIVED Applied 受理(通路 WEB/MOBILE/API/BRANCH/MERCHANT)
REVIEWING UnderReview 送徵信/徵審中
SUPPLEMENT —(BRD 未列) 補件;補件期限由商品參數控制
APPROVED Approved 核准,產生核准序號 approval_no
REJECTED Rejected 婉拒

終態:APPROVED、REJECTED。

⚠️ Manufactured 不在本狀態機:BRD BF-10 之 Manufactured(製卡完成)
實為卡片狀態機 §2 之 INACTIVE——§2 之入邊即為「[*] --> INACTIVE: 製卡完成待開卡」。
故本機以 APPROVED 為終態,其後由 §2 接手;兩機之交界點為「製卡完成、卡片建立」。
如此設計無需新增 DDL 值域(CARD_APPLICATIONS.status 之 CHECK 五值已足)。

12.2 轉換表

# 起始 事件 結果 觸發者 附帶效果
1 — 受理 RECEIVED 通路/分行 產生 apply_no
2 RECEIVED 送徵信 REVIEWING 系統/徵審 呼叫徵信(§12.4)
3 REVIEWING 要求補件 SUPPLEMENT 徵審 記補件原因與期限
4 SUPPLEMENT 補件完成 REVIEWING 客戶/徵審 重送徵信
5 REVIEWING 核准 APPROVED 徵審 產生 approval_no(§12.5)
6 REVIEWING 婉拒 REJECTED 徵審 記婉拒原因
7 SUPPLEMENT 補件逾期 REJECTED 批次 逾 supplement.days 未補
8 RECEIVED 逕予婉拒 REJECTED 徵審 資格明顯不符,免徵信

12.3 非法轉換(須被拒絕,CC-CARD-3001)

起始 事件 為何非法
RECEIVED 核准 未經徵信不得核准(fail-closed,見 §12.4)
APPROVED 任何 終態
REJECTED 任何 終態
REVIEWING 回 RECEIVED 不可逆向退回受理

CC-CARD-3002(終態不可再轉換) 用於 APPROVED/REJECTED;
RECEIVED → APPROVED 與 REVIEWING → RECEIVED 屬「非法轉換」,用 CC-CARD-3001。

12.4 徵信(外部系統)與 fail-closed

徵信為外部系統(BRD-001 D-01 徵審系統),以 port/adapter 介接(§14.1)。

徵信結果 處置
APPROVE 自動 → APPROVED
DECLINE 自動 → REJECTED
REFER 轉人工核決(CREDIT 角色),案件維持 REVIEWING
SUPPLEMENT → SUPPLEMENT
呼叫失敗/逾時/未設定 adapter ⚠️ 轉 REFER、維持 REVIEWING,記 WARN

為何是 fail-closed:徵信不可用時若靜默放行即為「靜默不做」型缺陷
(與 Flyway 未顯式引入 starter、認證預設 fail-open 同類,見 SCS-020 §9.2、
SCS-022 §7.4)。故不得自動核准、亦不得自動婉拒——一律轉人工。

12.5 核准後之銜接(製卡/快發)

路徑 條件 處置
快發 fast_issue_flag=1 且已勾選快發條款(BR-01-01) 核准後即時給號(POST /api/v1/cards),卡片建立為 INACTIVE
一般 其他 核准後寫入 Transactional Outbox 事件 card.application.approved,由批次送製卡檔

快發之三要素驗證(身分證字號+生日+核准序號)見 BR-01-04,失敗為 CC-CARD-1002。


13. 通知狀態機(notif.notifications.status)——1.7 版新增

來源:C-9(notification-service)實作(CR-017 裁定 F/G)。
CC_NOTIF 於 V1 基線完全無表,本輪以 V2__notification_templates_and_notifications.sql
建表;值域以契約 NotificationView.status 為權威(QUEUED/SENT/FAILED)。
設計權威見 SCS-016 §3/§7、SDD-001 §3.18。

stateDiagram-v2
  [*] --> QUEUED: 受理(建立通知)
  QUEUED --> SENT: 遞送成功
  QUEUED --> QUEUED: 遞送失敗且未達重試上限(retry_count+1)
  QUEUED --> FAILED: 遞送失敗且已達重試上限
  SENT --> [*]
  FAILED --> [*]
# 來源 事件 目標 說明
1 — 受理 QUEUED 受理期已驗證樣板存在/通道交集非空/變數齊備(fail-fast,SCS-016 §7.3)
2 QUEUED 遞送成功 SENT 寫入 sent_at;終態 ◆
3 QUEUED 遞送失敗(未達上限) QUEUED 自轉換:retry_count + 1、寫入 fail_reason,待下一輪取件重試
4 QUEUED 遞送失敗(達上限) FAILED 終態 ◆;fail_reason 必載(領域層強制,未載即拒)

值域:QUEUED/SENT/FAILED
——對齊 CC_NOTIF.NOTIFICATIONS.STATUS 之 CHECK 約束(實測值)。

⚠️ 為何「重試」不是一個狀態:SCS-016 §3 原載設計意圖含 RETRYING,惟契約未定義該值
(NotificationView.status 僅 3 值)。若於 DDL 增列 RETRYING,則契約無處回傳,
應用層必須把它映射回 QUEUED——即一個無對應語意之死狀態(假綠)。
故以轉換 3(QUEUED → QUEUED 自轉換 + retry_count 遞增)表達重試,不新增狀態。

⚠️ 轉換 3 與 SM-03(冪等)之區別:SM-03 指「目標狀態已達成 → 回 200(無狀態變更)」;
轉換 3 之來源與目標同為 QUEUED,但非冪等重複——其為有意義之重試計數
(retry_count 遞增、fail_reason 更新)。判準為有無狀態變更:SM-03 無,轉換 3 有。

⚠️ 終態不可轉換(SM-05):SENT/FAILED 再嘗試轉換 → CC-NOT-3002(409)。
逾時重送同一冪等鍵不產生新通知(SM-03:回傳前次結果)——此為受理層之冪等,
與本節之狀態轉換無關。

⚠️ 本期實作邊界(誠實揭露):轉換 2/3/4 之觸發者為本地 Log 通道 stand-in
(SCS-016 §8)——真實閘道未接(鐵則所稱真阻塞之一)。其「失敗」判定為
通道內容長度上限(真實閘道限制之近似值),目的在使轉換 3/4 可達且可測。


14. 狀態機實作規範

規範 說明
定義方式 狀態與轉換存於參數表(product.parameters,namespace state_machine.<entity>)
檢核時機 領域層於執行轉換前檢核;資料庫以狀態條件更新為第二道防線
值域權威(SM-08) 狀態值域一律以「可持久化之 DDL CHECK 約束」為權威(見 §1)。本文件不得書寫 DDL 不存在之狀態——程式一旦寫入即觸發 ORA-02290。新增狀態須先改 ER/DDL 並附遷移腳本,再改本文件
錯誤碼 非法轉換 CC-<SVC>-3001;終態轉換 CC-<SVC>-3002
冪等 目標狀態已達成 → 回 200,不重複執行副作用
稽核 每次轉換寫入 audit_trail(含前後狀態)
事件 每次轉換發布 <context>.<aggregate>.status-changed.v1
測試 每個狀態機須有「全轉換矩陣測試」:合法轉換全通過、非法轉換全拒絕

14.1 狀態機參數化範例

{
  "namespace": "state_machine.card",
  "param_key": "transitions",
  "param_value": [
    { "from": "INACTIVE", "event": "ACTIVATE", "to": "ACTIVE",
      "guard": "three_factor_verified", "roles": ["SYSTEM"] },
    { "from": "ACTIVE", "event": "LOCK", "to": "LOCKED",
      "guard": "risk_authorized", "roles": ["RISK"] },
    { "from": "LOST", "event": "REISSUE", "to": "REISSUED",
      "guard": "new_card_no_generated", "roles": ["CSR_SUP"] }
  ]
}

14.2 全轉換矩陣測試要求

狀態機 轉換數 必測案例數
卡片 14 14(合法)+ 4(非法)= 18
佔用 7 7 + 3 = 10
交易 5 5 + 2 = 7
繳款 8 8 + 2 = 10
分期 6 6 + 3 = 9
爭議階段(§7.1) 10 10 + 2 = 12
爭議案件(§7.2) 11 11 + 2 = 13
額度調整 7 7 + 2 = 9
帳單本體(§9.1) 14 14 + 2 = 16
帳單批次(§9.2) 4 4 + 2 = 6
點數桶階段(§10.1) 5 5 + 2 = 7
點數桶狀態(§10.2) 5 5 + 2 = 7
點數帳戶(§10.3) 6 6 + 2 = 8
Saga 6 6 + 1 = 7
申請案件(§12,1.4 新增) 8 8 + 4 = 12
通知(§13,1.7 新增) 4 4 + 2 = 6
合計 120 157

狀態機測試為 CSP-005 §3 之必要覆蓋項:分支覆蓋率須達 100%。

⚠️ 1.7 版:新增 §13 通知狀態機(4 轉換,含 1 條重試自轉換),組數 15 → 16,
合計 116/151 → 120/157。

⚠️ 分期之轉換數於 1.2 版由 8 修正為 6(移除 PENDING/REJECTED 相關 2 條,
見 §6 更正說明);合計由 82/105 更正為 80/103。

⚠️ 1.4 版:新增 §12 申請案件狀態機(8 轉換),組數 14 → 15,
合計 108/139 → 116/151。

⚠️ 1.3 版:§7/§9/§10 拆分為多個狀態機,故組數由 10 增為 14,
合計由 80/103 更正為 108/139:
§7 由 9 → 10 + 11 = 21;§9 由 11 → 14 + 4 = 18;
§10 由 7 → 5 + 5 + 6 = 16(原轉換 3 因不可達而移除,見 §10.1 說明)。

14.3 值域稽核(1.2 版新增;1.3 版全數對齊;1.4 版含 §12 申請案件;1.7 版含 §13 通知)

本節為對本文件全部 16 組狀態機之值域合規稽核——目的在於檢驗 SM-08
(狀態值域以可持久化之 DDL 為權威)是否被遵守。稽核方法:以 all_cons_columns +
all_constraints.search_condition_vc 實測各 schema 之 CHECK 約束,與本文件逐值比對。

§ 狀態機 對應 DDL 欄位 結果
2 卡片(Block Code) CC_CARD.CARDS.BLOCK_CODE ✅ 對齊(7 值全同)
3 授權佔用 CC_LIM.LIMIT_HOLDS.STATUS ✅ 對齊(4 值全同)
4 帳務交易 CC_POSTING.TRANSACTIONS.STATUS ✅ 對齊(4 值全同)
5 繳款 CC_PAYMENT.PAYMENTS.STATUS ✅ 對齊(6 值全同,1.3 版 DDL 增列 UNMATCHED)
6 分期計畫 CC_INST.INSTALLMENT_PLANS.STATUS ✅ 對齊(1.2 版修正)
7.1 爭議階段 CC_DIS.DISPUTE_CASES.STAGE ✅ 對齊(6 值全同,1.3 版拆分)
7.2 爭議案件 CC_DIS.DISPUTE_CASES.STATUS ✅ 對齊(6 值全同,1.3 版拆分)
7.3 爭議責任歸屬(正交屬性) CC_DIS.DISPUTE_CASES.LIABILITY ✅ 對齊(4 值全同)
8 額度調整 CC_LIM.LIMIT_ADJUSTMENTS.STATUS ✅ 對齊(6 值全同)
9.1 帳單本體 CC_STMT.STATEMENTS.STATUS ✅ 對齊(7 值全同,1.3 版拆分並補 DISPUTED/CLOSED)
9.2 帳單批次 CC_STMT.STATEMENT_RUNS.STATUS ✅ 對齊(3 值全同,1.3 版拆分)
10.1 點數桶階段 CC_RW.POINTS_EXPIRY_BUCKETS.BUCKET_STAGE ✅ 對齊(3 值全同,1.3 版拆分)
10.2 點數桶狀態 CC_RW.POINTS_EXPIRY_BUCKETS.STATUS ✅ 對齊(3 值全同,1.3 版拆分)
10.3 點數帳戶 CC_RW.POINTS_ACCOUNTS.STATUS ✅ 對齊(3 值全同,1.3 版拆分)
11 Saga CC_PLT.SAGA_INSTANCES.STATUS ✅ 對齊(5 值全同)
12 申請案件 CC_CARD.CARD_APPLICATIONS.STATUS ✅ 對齊(5 值全同,1.4 版新增;2026-09-20 以 all_constraints.search_condition_vc 實測)
13 通知 CC_NOTIF.NOTIFICATIONS.STATUS ✅ 對齊(3 值全同,1.7 版新增;2026-09-22 以 all_constraints.search_condition_vc 實測)

16 組全數對齊、0 組待處理。 1.2 版稽核所列之 4 項不一致(A~D)
已於 1.3 版全數更正,逐項對照如下。

更正歷程(1.2 版 A~D → 1.3 版處置)

# 1.2 版之發現 1.3 版處置 交付
A §5 繳款 UNMATCHED 不可持久化 採 DDL 增列途徑:SDD-001 §3.7 增列該值 V4__payments_unmatched_status.sql;契約與 PaymentStatus 同步
B §7 爭議值域幾乎完全不同(僅 CLOSED 交集) 拆分為兩個狀態機(階段/案件),liability 明列為正交屬性 本文件 §7;DDL 已有對應三欄,無須改 DDL
C §9 帳單混用兩實體、缺 DISPUTED/CLOSED 拆分為兩個狀態機(帳單本體/批次執行),並補入缺值 本文件 §9;SDD-001 §3.10 加註 V2 交付說明
D §10 點數混用三個維度 依維度拆分為三個狀態機(桶階段/桶狀態/帳戶) 本文件 §10;一併移除不可達轉換、封存 FROZEN 入點決策

1.4 版新增第 15 組(§12 申請案件):值域直接取 CARD_APPLICATIONS.STATUS 既有 CHECK 五值,
未新增值域、未改 DDL——BRD BF-10 之 Manufactured 歸屬 §2 卡片狀態機之 INACTIVE。

A~D 均涉及設計決策,業經逐案核定後執行(核定紀錄見 CR-003)。
本次更正之共同依據為 SM-08:值域以可持久化之 DDL CHECK 為權威;
值分屬不同欄位者即屬混用維度,應拆分狀態機,不得以單一圖表達。


15. 變更記錄

版本 說明
1.7 2026-09-22|WorkBuddy AI|新增 §13 通知狀態機(notif.notifications.status)——C-9(notification-service,CR-017 裁定 F/G)落地後補正式化。3 狀態/4 轉換(含 1 條重試自轉換 QUEUED → QUEUED);值域以契約 NotificationView.status 為權威(QUEUED/SENT/FAILED)。⚠️ 兩項設計決策:①**「重試」不設獨立狀態**——SCS-016 §3 原載 RETRYING 而契約未定義,若增列則無處回傳、須映射回 QUEUED,即成無對應語意之死狀態(假綠);故以自轉換+retry_count 表達,並於節內載明其與 SM-03(冪等)之區別(判準:有無狀態變更)。②本期觸發者為本地 Log 通道 stand-in(真實閘道真阻塞),其失敗判定為通道內容長度上限,目的在使轉換 3/4 可達且可測。原 §13/§14 依序遞移為 §14/§15(CR-003 所載 §13.2/§13.3 即為本版之 §14.2/§14.3,內容不變);連動更新 §14.2(組數 15 → 16,合計 116/151 → 120/157)與 §14.3(16 組全數對齊,新增第 13 列)
1.6 2026-09-22|WorkBuddy AI|BEAM PMO 裁定採方案 B:§5 轉換 6 之來源狀態由 ALLOCATED 更正為 POSTED(含 mermaid 與轉換表)——理由:現行 accept() 不停留 ALLOCATED(不可達),且「重新佔額」須以「額度已先恢復」為前提,而額度於 post() 才標;此更正使 BRD-004 POC-11 情境 11-3 之語意自洽。真機重跑(真實受理流程):POSTED(LIMIT_RESTORED=1)→ 逾期 → UNMATCHED(LIMIT_RESTORED=0)、VERSION 2→3;負樣本未逾時者不動。併揭露:SCS-008 §10 #5「受理即標」與實物不符,已於該文件更正
1.5 2026-09-22|WorkBuddy AI|C-19:§5 繳款之兩項「保留事項」解除——①轉換 6(ALLOCATED → UNMATCHED)之產生者已實作(PaymentUnmatchedService/Scheduler,逾三日批次;含 markUnmatched() 之重新佔額),真機實測逾時轉換與未逾時負樣本;②轉換 8(UNMATCHED → REVERSED)之 reversible() 已放行,實測沖正回 200。⚠️ 新增待裁定事項:轉換 6 之來源狀態可達性存疑——現行受理流程不停留 ALLOCATED(accept() 一次完成至 POSTED),且 BRD-004 POC-11 情境 11-3 之「重新佔額」隱含額度已先恢復,與本節轉換 6 之來源狀態不相容;須 BEAM PMO 裁定(裁定為 POSTED 時本節須隨之修訂)。併更正 1.4 列之懸空引用:原引 HANDOVER #C-31,該編號現屬他項(pricing TX_TYPE),實應為 #A-43
1.9 2026-09-24|開發團隊|新增 §3.1 授權決策狀態機(CR-022 裁定後)——依據 RFP FR 1.1 第 4 項「支援人工授權、強制授權、人工取消授權」(廠商回覆欄已填「滿足」,未實作即未履約)。新增 REFERRAL→APPROVED/DECLINED 兩條核決轉換,並訂 SM-D1~D5(僅 REFERRAL 可核決/核決一次性/不修改原檢核明細/force 僅限軟性拒絕/門檻參數化預設關閉)。⚠️ 併載明不採 CR-022 (B) 案(不得對 DECLINED 強制核准,以免繞過風控)。
1.0 初版:通用規則 SM-01~SM-07 與 11 組狀態機(卡片、佔用、交易、繳款、分期、爭議、額度調整、帳單、點數帳戶、Saga)
1.1 2026-09-18|SA/Tech Lead|①**§11 Saga 初始狀態更名 RUNNING → STARTED——ops/local/init/oracle/01-init.sh 之 ck_saga_status 約束實際枚舉 ('STARTED','COMPENSATING','COMPLETED','COMPENSATED','FAILED'),持久化契約無 RUNNING;原書寫會使程式寫入時觸發 ORA-02290。以 DDL 為權威統一術語,並補註終態定義(COMPLETED/COMPENSATED 為終態,FAILED 可人工重試)。②§11 轉換 #5 補註錯誤碼 CC-PLT-5002。③新增本變更記錄區**(原文件欠缺,無法追溯修訂)。④§12 之非法/終態轉換碼 CC-<SVC>-3001/3002 於平台層具體化為 CC-PLT-3001/CC-PLT-3002,已依 CSP-003 §2 程序登錄於 SDD-006 §3.4
1.3 2026-09-19|開發團隊|依 CR-003 處置 §12.3 稽核所列之 4 項不一致(A~D),全數更正——①A §5 繳款:UNMATCHED 經核定採 DDL 增列途徑(原二選一:移除該狀態/DDL 增列)。理由:本節 UNMATCHED 為作業狀態(已分配、逾三日未收銷帳檔),與旗標語意不同,不應為遷就 DDL 而捨棄。交付:SDD-001 §3.7 之 CHECK 增列該值、V4__payments_unmatched_status.sql(V1 基線已凍結)、契約 PaymentView.status 與 PaymentStatus 同步;實測寫入成功、非法值觸發 ORA-02290。並釐清 UNMATCHED 與 UNMATCHED_FLAG 為正交維度(受理時/批次判定,可同時成立)。②B §7 爭議:原單一狀態機將「卡組織階段」與「案件處理/結果」二正交軸繪於一圖,與 DISPUTE_CASES.stage/status 值域幾乎無交集(僅 CLOSED)。經核定拆分為二(§7.1 階段機/§7.2 案件機),並將 liability 明列為正交屬性(§7.3)。DDL 已有對應三欄,無須改 DDL。③C §9 帳單:原單一狀態機混用兩個實體(STATEMENTS/STATEMENT_RUNS)且缺 DISPUTED/CLOSED。經核定拆分為二(§9.1 帳單本體 7 值/§9.2 批次執行 3 值)並補入缺值。④D §10 點數:原單一狀態機混用三個維度(桶階段/桶狀態/帳戶狀態)。經核定依維度拆分為三(§10.1/§10.2/§10.3);一併移除不可達轉換(原轉換 3「CUR 到期且餘額 < 0」——受 balance >= 0 之 CHECK 所限,SCS-010 §10.2 原已揭露)並封存 FROZEN 帳戶之入點決策(原 SCS-010 §10.6 之規格空白,本次即其待辦 ①)。⑤連動更正 §12.2:組數 10 → 14,合計 80/103 → 108/139。⑥**§12.3 改為全數對齊**(14 組)並載明更正歷程。⑦SDD-001 §3.7 加註變更交付說明(V1 凍結、不得 --force 重生);§3.10 加註 STATEMENT_RUNS/STATEMENT_CYCLE_ACCOUNTS 係 V2 交付
1.4 2026-09-20
1.2 2026-09-19|開發團隊|依 CR-002 更正 §6 分期計畫狀態機——①移除 PENDING(申請)與 REJECTED(拒絕):CC_INST.INSTALLMENT_PLANS.status 之 CHECK 約束無此二值(DEFAULT 'ACTIVE',無法持久化),且 BRD-001 §5.6 之流程中「拒絕-額度不足」為同步交易拒絕,不存在「已申請、待核准」之持久狀態;實作 create 亦直接建立 ACTIVE。②**SETTLED → COMPLETED、EARLY_SETTLED → PRE_CLOSED:語意相同,以 DDL 為權威統一術語。③轉換 #4 之來源由 PENDING 更正為 ACTIVE(Saga 補償發生於首期入帳階段)。④轉換數 8 → 6。⑤新增通用規則 SM-08「狀態值域以可持久化之 DDL CHECK 為權威」——與 1.1 版同一原則,並明訂「新增狀態須先改 ER/DDL 再改本文件」。⑥連動更正 §12.2** 全轉換矩陣:分期 8/11 → 6/9,合計 82/105 → 80/103。⑦§6 新增更正說明區,載明未採納之原設計與保留事項(COMPLETED 無產生者、轉換 #5 未實作;日後若需核准流程須另提 CR 補 ER/DDL,不得僅改本文件)。⑧新增 §12.3 值域稽核——對本文件全部 10 組狀態機逐一比對實體 DDL CHECK 約束(實測):6 組對齊、4 組待處理(§5 繳款 UNMATCHED、§7 爭議值域幾乎完全不同、§9 帳單混用兩實體、§10 點數混用三維度),各項均載明待決方向;稽核發現之 4 項未自行更正,因涉及設計決策(值軸歸屬、分類軸選擇),須逐案核定
(22-22/67)