Project

General

Profile

CR #201 » SDD-006_API-Contract.md

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

 

SDD-006 API Contract

項目 內容
文件編號 SDD-006
版本 1.24(CR-049:① posting.transaction.reversed.v1 之 payload 由 4 欄擴為「4 契約欄 + 可選 postingDate」——沖正交易之入帳日=業務日錨點,下游回沖分錄不得以 occurredAt 反推(SCS-026 §7.5①);② campaign.reward.commanded.v1 之 recognition 補列 applicableRate/rateReason,並載明回沖指令同走此信封(originalPostingId/txType=REFUND/postingDate/refund:true),消費端以 txType=REFUND 為權威且欄位「recognition 優先、payload 次之」。前版 1.23(SCS-026 §7.14/§7.15:CreateCampaignRequest/CampaignView 加 priority(D9 優先序);campaign.reward.commanded.v1 之回沖指令(refund/originalPostingId)——campaign 內部契約)。前版 1.22(SCS-026 §7.13 R-3b:PointsAccountView 加 tierRank(層級序;權威在 rewards))。前版 1.21(CR-048:支付路徑結構化欄位跨服務透傳——AuthorizeRequest/PostingRequest 加可選 payPath;posting.transaction.posted.v1 payload 加可選 payPath(不升版);PointsAccountView 加 tier(R-3))。前版 1.20(SCS-026 §7.11:AccrualRequest 契約加可選 applicableRate(活動回饋率;BRD 例 1 算式))。前版 1.19(CR-047:rewards.points.accrued.v1 payload 加 4 可選欄位(campaignCode/valueMinor/instrumentId/postingDate;不升版);AccrualRequest 契約加 3 可選欄位)。前版 1.18(CR-046 AC 7:campaign 新增 GET /api/v1/campaigns/{campaignCode}/enrollments/{householdId}(查詢錄取狀態,含 accruedAmountMinor 門檻累計);EnrollmentView 加 accruedAmountMinor)。前版 1.17(CR-046 AC 7:campaign 新增 POST /api/v1/campaigns/{campaignCode}/enrollments)。前版 1.16(CR-046 B2-6:card.card.status-changed.v1 payload 新增可選 instrumentId,舊事件可為 null;不升事件版本)。前版 1.11(CR-028 hold 事件群四項矛盾之化解(2026-10-01):§4.2 刪 authorization.hold.created.v1/authorization.hold.released.v1 兩列、補登 limit.hold.created.v1;併更正 card.card.status-changed.v1 之 payload(原載差量 fromBlockCode/toBlockCode/reason,實作為變更後完整狀態——依 SCS-003 §7.10 更正,列 CR-027 §5 #13 待覆核);併標記 authorization.authorization.approved.v1 與 limit.hold.created.v1 之可選欄位。前版 1.10(GOV-007 §4:§3.4 補登 CC-PLT-3003(409 資源尚未就緒)——供報表下載之「作業未就緒(QUEUED/RUNNING/FAILED)」情境,與「狀態機非法轉換」語意區隔 → 錯誤碼 123 → 124。前版 1.9(CR-021:§3.4 補登 CC-AUTH-4040(查無授權)→ 錯誤碼 123;並修訂 check-results 契約之陣列性(單一物件 → AuthCheckResult[])。前版 1.8(C-9:補登 NOT 三碼 → 122)
狀態 已核定
撰寫者 SD
審查者 SA / TL / SEC
對應需求 SYS-4(API 完備度)、API 設計與管理、SYS-7

1. 說明

本文件定義全系統之 API 契約規範。契約本體(OpenAPI 3.1)以檔案交付:

cardcore/contracts/openapi/<service>.yaml      # 17 個服務,共 65 個端點

契約由 cardcore/tools/gen_openapi.py 產生並驗證;禁止手改 YAML,
變更須修改產生器後重新產生(確保端點清單、$ref、錯誤碼一致)。

1.1 驗證結果

服務 端點數 驗證
authorization-service 5 ✅
limit-service 6 ✅
posting-service 6 ✅
payment-service 4 ✅
card-service 7 ✅
party-service 4 ✅
product-service 5 ✅
statement-service 3 ✅
pricing-service 3 ✅
installment-service 3 ✅
rewards-service 4 ✅
clearing-service 3 ✅
dispute-service 3 ✅
merchant-service 3 ✅
notification-service 2 ✅
report-service 2 ✅
migration-service 2 ✅
合計 65 0 錯誤

驗證項目:OpenAPI 版本、info 必填、servers 存在、路徑符合 /api/v1/、
operationId 唯一、2xx 與 409 回應存在、寫入操作具 requestBody 與冪等標頭、
所有 $ref 可解析且無孤立元件。


2. 通用規範

2.1 請求標頭

標頭 必填 說明
Authorization ✅ Bearer <JWT> 或 ApiKey <key>
X-Channel ✅ WEB / MOBILE / PARTNER / BATCH / SYSTEM
X-Idempotency-Key ✅(寫入) 冪等鍵,8–120 字元
X-Trace-Id ○ 未帶則由閘道產生
Accept-Language ○ zh-TW(預設)/ en-US
Content-Type ✅ application/json

2.2 回應信封

所有回應一律採統一信封:

{
  "traceId": "01HZX8K2M4N5P6Q7R8S9T0V1W2",
  "data": { },
  "error": null
}

失敗時:

{
  "traceId": "01HZX8K2M4N5P6Q7R8S9T0V1W2",
  "data": null,
  "error": {
    "code": "CC-LIM-1001",
    "message": "可用額度不足",
    "details": [{ "field": "amount", "reason": "exceeds available limit" }]
  }
}

2.3 HTTP 狀態碼

狀態碼 語意 觸發情境
200 成功 查詢、更新成功
201 已建立 資源建立成功
202 已接受 非同步作業受理(批次、報表、清算)
400 請求錯誤 ValidationError
401 未認證 權杖無效或過期
403 無權限 角色不足
404 不存在 ResourceNotFoundError
409 衝突 冪等鍵衝突、樂觀鎖衝突、狀態衝突
422 業務規則不允許 BusinessRuleError
429 超過速率 限流
500 系統錯誤 InfrastructureError
503 服務不可用 斷路器開啟、維護中、ExternalSystemError

2.4 分頁

參數 型別 預設 上限
page integer 1 —
size integer 50 200

分頁回應於 data.meta 帶 page、size、total。

2.5 金額與日期

型別 規範
金額 整數,最小單位(分);{"amount": 12345, "currency": "TWD"} = 123.45 元
日期 date:YYYY-MM-DD
時間 date-time:ISO 8601 含時區,一律 UTC
比率 number,小數表示(0.185 = 18.5%)

禁止:金額使用浮點數(BRD-001 C-01)。

★ 通則(CR-030 §2 #10 裁定):凡事件 payload 涉及金額者,一律帶 currency(可選)。
理由:金額無幣別即無語意——多幣別帳戶下不可解讀。
業界依據:ISO 20022 之 Amount 一律為「Currency + Amount」複合型別;金融訊息中裸金額屬建模錯誤。
相容性:新增可選欄位依 SAD-004 §5.3 不升版;消費者須容忍缺欄(缺則不臆造幣別,
依各消費者之規格處理——例如 SCS-016 §7.11/§7.12:不建立通知並記 WARN)。

2.6 識別碼

型別 格式
資源主鍵 UUID v7(字串)
業務編號 前綴 + 序號(如 AUTH20260917000001)
追蹤識別碼 ULID(26 字元)
冪等鍵 客戶端產生,8–120 字元

3. 錯誤碼規範

3.1 編碼規則

CC-<SVC>-<NNNN>
段 說明
CC 固定前綴(Credit Card)
SVC 4 碼服務代碼
NNNN 4 碼;首位表類別,後三位為序號

3.2 服務代碼

代碼 服務 代碼 服務
AUTH authorization-service RWD rewards-service
LIM limit-service CLR clearing-service
CARD card-service DSP dispute-service
PTY party-service MRC merchant-service
PRD product-service NOT notification-service
POST posting-service RPT report-service
PAY payment-service MIG migration-service
STM statement-service PLT platform/common
PRC pricing-service GW platform/gateway
INS installment-service

3.3 類別位

首位 類別 HTTP 可否重試
1 業務規則拒絕 422 ❌
2 併發/冪等衝突 409 部分可
3 狀態機衝突 409 ❌
4 請求與資源 400 / 404 / 405 / 409 ❌
5 外部與基礎設施 503 / 500 ✅(冪等者)

3.3.1 類別位 4 之語意擴充(CR-004,2026-09-19)

類別位 4 =「請求本身或其所指資源無法被受理」,涵蓋四個子語意——
皆屬請求層,尚未進入業務邏輯:

子語意 HTTP 何時使用 代表碼
請求不合法 400 必填標頭/查詢參數缺失、主體格式錯誤、參數型別或 Bean Validation 失敗 CC-PLT-4001/CC-PLT-4002/CC-PLT-4003
資源或路徑不存在 404 無對應路由、聚合根查無 CC-PLT-4040、CC-PTY-4040、CC-POST-4040
方法不支援 405 HTTP 動詞與端點不符 CC-PLT-4050
資源重複 409 業務冪等鍵已存在 CC-POST-4001、CC-POST-4002

擴充理由(實測):CR-004 於 8089 實測發現,Spring MVC 之請求層例外
(缺標頭 MissingRequestHeaderException、壞 JSON HttpMessageNotReadableException、
方法不支援 HttpRequestMethodNotSupportedException、路徑不存在 NoResourceFoundException)
皆非 DomainException 子類,因而全數落 GlobalExceptionHandler 之兜底回 500——
既違反契約(應為 400/404/405),且每個客戶端錯誤都觸發 ERROR 告警(告警疲勞)。

原類別位 4 僅涵蓋「資源與重複」(404/409),無處安放 400 與 405;
若強行借用類別位 1(業務規則拒絕 422)或 5(基礎設施 5xx)皆為語意錯置。
故擴充本類別位之語意,使其成為請求層錯誤之歸屬。

設計原則:類別位 4 之碼一律不得重試(客戶端須修正請求後重送);
與類別位 1(業務規則拒絕)之區別在於——類別位 4 尚未進入業務邏輯。

3.4 錯誤碼清單

錯誤碼 HTTP 訊息 說明 處理建議
CC-AUTH-1001 422 授權拒絕 檢核未通過 依回應碼判斷
CC-AUTH-1002 422 卡片狀態不允許交易 卡片為 LOCKED/LOST/CLOSED 提示客戶聯繫客服
CC-AUTH-1003 422 超過單筆限額 交易金額超過單筆限額 拆單或調額
CC-AUTH-1004 422 超過日限額或日限次 當日累計超限 隔日再試
CC-AUTH-1005 422 MCC 控管拒絕 風險參數拒絕 聯繫客服
CC-AUTH-1006 422 EMV 驗證失敗 ARQC 驗證不通過 重新插卡
CC-AUTH-1901 422 授權併發衝突(已重試) 重試 3 次仍衝突 稍後重試
CC-AUTH-4040 404 資源不存在(授權/檢核明細) 查無指定授權編號(CR-021 補實作之沖正/檢核明細端點所需;沿用 per-service 4040 慣例) 確認授權編號
CC-AUTH-5001 503 發卡主機無回應 主機逾時 依 Stand-in 規則處理
CC-LIM-1001 422 可用額度不足 available < amount 調額或降低金額
CC-LIM-1002 422 超過可設定上限 超出角色/客層上限 送主管複核
CC-LIM-1003 422 專用額度不可用 未設定或已過期 先設定專用額度
CC-LIM-2001 409 額度併發衝突 樂觀鎖失敗 重試
CC-LIM-5001 503 商品參數服務無法連線 取參失敗(product-service 不可達/逾時/查無參數);依 CR-045 D4 之 fail-closed 降級至預設覆核門檻 檢查參數服務可用性
CC-CARD-1001 422 快發條款未勾選 fastIssueAgreed=false 先勾選條款
CC-CARD-1002 422 三要素驗證失敗 身分證字號/生日/核准序號不符 確認後重試
CC-CARD-1003 422 卡號區段已用盡 號碼池不足 聯繫系統管理
CC-CARD-3001 409 狀態轉換不允許 非法狀態轉換 依狀態機重新操作
CC-CARD-3002 409 終態不可再轉換 已 CLOSED 不可操作
CC-CARD-1004 422 Token 重複綁定 同卡同平台已有 ACTIVE 之 Token 先解綁或改用其他平台
CC-CARD-4001 400 請求欄位驗證失敗 欄位格式或列舉值不符 檢視欄位
CC-CARD-4040 404 資源不存在(卡片/Token/申請案件) 查無指定識別碼 確認識別碼
CC-CARD-2001 409 冪等鍵衝突 同鍵異指紋 更換冪等鍵

CC-CARD-1004/CC-CARD-2001/CC-CARD-4001/CC-CARD-4040 之來源(HANDOVER #C-10,2026-09-20):
card-service 補發卡/快發快綁/Token/申請案件四項(契約原已宣告 8 端點、實作僅 3 端點)。
既有 5 碼僅涵蓋業務規則(1001~1003)與狀態機(3001/3002),
無 400(欄位驗證)與 404(查無資源)——新增端點需此二碼以維持「所有錯誤一律套用封套」(CSP-003 §3);
1004 則為 Token 重複綁定之業務規則;2001 沿用既有冪等衝突碼之慣例(CC-PTY-2001/CC-POST-2001/CC-PLT-2001)。三者編碼對齊既有 1000=業務規則、4001/4040=協定層之慣例。
| CC-PTY-1001 | 422 | 管制碼不允許操作 | 帳戶管制中 | 先解除管制 |
| CC-PTY-2001 | 409 | 冪等鍵衝突 | 同鍵異指紋 | 更換冪等鍵 |
| CC-PTY-4001 | 400 | 請求欄位驗證失敗 | 欄位格式或必填不符 | 檢視欄位 |
| CC-PTY-4040 | 404 | 資源不存在(歸戶/持卡人) | 查無指定識別碼 | 確認識別碼 |
| CC-PRD-1001 | 422 | 產品代碼重複 | 已存在 | 更換代碼 |
| CC-PRD-1002 | 422 | 參數生效日重疊 | 同期間已有參數 | 調整生效日 |
| CC-POST-1001 | 422 | 授權請款比對不符 | 金額或幣別不符 | 人工確認 |
| CC-POST-1002 | 422 | 授權失效或不存在 | 無對應授權 | 人工確認 |
| CC-POST-2001 | 409 | 冪等鍵衝突 | 同鍵異指紋 | 更換冪等鍵 |
| CC-POST-2002 | 409 | 樂觀鎖衝突 | 併發更新 | 重試 |
| CC-POST-3001 | 409 | 交易狀態不允許沖正 | 已 REVERSED | 不可再沖正 |
| CC-POST-4001 | 409 | 重複入帳(業務冪等鍵已存在) | 同一筆帳務 | 檢視前次結果 |
| CC-POST-4002 | 409 | 整批重複請款(疑似) | 檔案指紋相同 | 人工判定 |
| CC-POST-4000 | 400 | 請求驗證錯誤 | 欄位格式或必填不符 | 修正請求 |
| CC-POST-4040 | 404 | 資源不存在(入帳交易/分戶餘額) | 查無指定識別碼 | 確認識別碼 |
| CC-PAY-1001 | 422 | 繳款金額不符 | 與應繳金額不符 | 確認金額 |
| CC-PAY-2001 | 409 | 繳款冪等衝突 | 重複送件 | 檢視前次結果 |
| CC-PAY-4000 | 400 | 請求驗證錯誤(含分配不平衡) | 欄位格式、金額或分配加總不符 | 修正請求 |
| CC-PAY-4040 | 404 | 資源不存在(繳款/自扣約定) | 查無指定識別碼 | 確認識別碼 |
| CC-PAY-3001 | 409 | 繳款狀態不允許沖正 | 已 REVERSED | — |
| CC-STM-1001 | 422 | 帳單週期不存在 | 週期代碼錯誤 | 確認週期 |
| CC-STM-5001 | 503 | 批次執行中 | 同一週期已有執行中批次 | 等待完成 |
| CC-STM-2001 | 409 | 週期重複執行(同帳戶同月份已產生) | UQ_STMT_MONTH 衝突 | 檢視既有帳單 |
| CC-STM-4000 | 400 | 請求驗證錯誤 | 欄位格式或必填不符 | 修正請求 |
| CC-STM-4040 | 404 | 資源不存在(帳單/批次執行) | 查無指定識別碼 | 確認識別碼 |
| CC-PRC-1001 | 422 | 無適用利率 | RBP 未評核且無產品利率 | 先完成 RBP 評核 |
| CC-PRC-1002 | 422 | 計息期間重疊 | 期間已有計息 | 調整期間 |
| CC-INS-1001 | 422 | 分期期數不支援 | 非 3/6/12/24 | 使用支援期數 |
| CC-INS-1002 | 422 | 總約未簽署 | agreementSigned=false | 先完成簽署 |
| CC-INS-4000 | 400 | 請求驗證錯誤 | 欄位格式或期數不符 | 修正請求 |
| CC-INS-4040 | 404 | 資源不存在(分期計畫) | 查無指定識別碼 | 確認識別碼 |
| CC-INS-3001 | 409 | 分期狀態不允許操作 | 非 ACTIVE | 依狀態機操作 |
| CC-RWD-1001 | 422 | 點數不足 | 餘額不足且政策為拒絕 | 部分折抵或改設定 |
| CC-RWD-1002 | 422 | 未達最低折抵金額 | 低於門檻 | 提高消費金額 |
| CC-RWD-1003 | 422 | 點數帳戶已凍結 | AV2 到期 | 不可兌換 |
| CC-RWD-1005 | 422 | 回饋規則代碼重複 | 規則代碼已存在 | 更換規則代碼 |
| CC-RWD-2001 | 409 | 扣點併發衝突 | 樂觀鎖失敗 | 重試 |
| CC-RWD-4000 | 400 | 請求驗證錯誤 | 欄位格式或必填不符 | 修正請求 |
| CC-RWD-4040 | 404 | 資源不存在(點數帳戶) | 查無指定歸戶 | 確認識別碼 |
| CC-CLR-1001 | 422 | 清算差異未歸零 | 存在差異 | 差異處理後重新比對 |
| CC-CLR-5001 | 503 | 卡組織清算檔未到 | 檔案未取得 | 稍後重試 |
| CC-DSP-1001 | 422 | 爭議類型不支援 | — | 確認類型 |
| CC-DSP-1002 | 422 | 超過卡組織時限 | 已逾時限 | 不可提爭議 |
| CC-MRC-1001 | 422 | 特店代碼重複 | 已存在 | 更換代碼 |
| CC-NOT-1001 | 422 | 通知樣板不存在 | 樣板代碼錯誤 | 確認樣板 |
| CC-NOT-1002 | 422 | 無可用發送通道 | 樣板未啟用任何請求之通道(偏好與樣板可用通道無交集) | 確認通道或樣板設定 |
| CC-NOT-1003 | 422 | 樣板變數不足 | variables 缺少樣板內文所引用之變數 | 補齊變數 |
| CC-NOT-4040 | 404 | 資源不存在(通知) | 查無指定通知識別碼 | 確認識別碼 |
| CC-RPT-1001 | 422 | 報表定義不存在 | 報表代碼錯誤 | 確認代碼 |
| CC-MIG-1001 | 422 | 遷移類型不支援 | — | 確認類型 |

CC-NOT-1002/CC-NOT-1003/CC-NOT-4040 之來源(CR-017 §9.4,2026-09-22):
notification-service 實作(C-9)時發現既有 CC-NOT-* 僅 3 碼(1001 樣板不存在、
3001/3002 狀態機),缺「無可用通道」(業務規則)與「查無通知」(協定層)——
二者皆為契約端點所必需(POST /api/v1/notifications 之 422、GET /api/v1/notifications/{id}
之 404),故依 CSP-003 §2「不得自創錯誤碼」程序補登。
編碼對齊既有慣例:1000=業務規則、4040=協定層「查無資源」(同 CC-CARD-4040/CC-PTY-4040)。

| CC-PLT-2001 | 409 | 冪等鍵衝突 | 同鍵異指紋 | 更換冪等鍵 |
| CC-PLT-2002 | 409 | 狀態版本衝突 | 樂觀鎖/狀態條件更新失敗(SDD-005 SM-04),如 Saga 並行協調 | 重讀最新狀態後重試 |
| CC-PLT-3001 | 409 | 非法狀態轉換 | 來源狀態未定義此事件之轉換(SDD-005 SM-01/SM-02) | 查詢當前狀態後重送合法事件 |
| CC-PLT-3002 | 409 | 終態不可轉換 | 來源狀態為終態(SDD-005 SM-05),例如 CLOSED → ACTIVE | 不得重送,須另立新單 |
| CC-PLT-3003 | 409 | 資源尚未就緒 | 目標資源尚未產生完成——如非同步作業仍在 QUEUED/RUNNING,或已 FAILED(與「狀態機非法轉換」語意不同,見 GOV-007 §4) | 待作業完成後重試;FAILED 者查作業狀態 |
| CC-PLT-4001 | 400 | 缺少必要請求標頭或參數 | 必填標頭(如 X-Channel)或查詢參數未提供 | 補上後重送 |
| CC-PLT-4002 | 400 | 請求主體格式錯誤 | 主體非合法 JSON,或欄位型別無法解析 | 修正請求主體 |
| CC-PLT-4003 | 400 | 請求參數驗證失敗 | 參數型別不符,或 Bean Validation 未通過 | 依 details 修正欄位 |
| CC-PLT-4010 | 401 | 未認證 | 無 Authorization 標頭、格式非 Bearer、權杖過期或簽章驗證失敗 | 重新取得權杖後重送 |
| CC-PLT-4030 | 403 | 無權限 | 已認證但角色/權限不足(SAD-005 §4) | 確認帳號之角色授權 |
| CC-PLT-4040 | 404 | 資源或路徑不存在 | 無對應路由,或聚合根查無 | 確認路徑與識別碼 |
| CC-PLT-4050 | 405 | HTTP 方法不支援 | 動詞與端點不符 | 改用正確方法 |

CC-PLT-4001~CC-PLT-4050 之來源(CR-004,2026-09-19):
本 5 碼為請求層錯誤(類別位 4,見 §3.3.1),由 common-spring 之
GlobalExceptionHandler 統一拋出,服務不需自行實作。
服務僅在需要更精確語意時才使用自有 4xxx 碼(如 CC-PTY-4040「歸戶查無」)。
對應之 Spring 例外:
MissingRequestHeaderException/MissingServletRequestParameterException → 4001;
HttpMessageNotReadableException → 4002;
MethodArgumentNotValidException/HandlerMethodValidationException/
ConstraintViolationException/MethodArgumentTypeMismatchException → 4003;
NoResourceFoundException → 4040;HttpRequestMethodNotSupportedException → 4050。

CC-PLT-4010/CC-PLT-4030 之來源(SCS-022,2026-09-19):
CR-004 之 5 碼僅涵蓋 400/404/405,無 401(未認證)與 403(無權限)——
因當時 GlobalExceptionHandler 尚未處理認證/授權(Spring Security 攔截發生在
進入控制器之前,不在 @ControllerAdvice 之攔截範圍)。
W-3 SSO 接線(SCS-022)後,common-spring 之 SecurityAutoConfiguration
需此二碼以維持「所有回應一律套用 ApiResponse 封套」(CSP-003 §3)。
依 CSP-003 §2「不得自創錯誤碼」程序補登;
後兩碼對齊 HTTP 狀態碼(401/403),與既有 4040/4050 之慣例一致。

各服務之狀態機錯誤碼(SDD-005 SM-01/SM-02/SM-05;由共用狀態機引擎依服務代碼拋出)

代碼 HTTP 名稱 觸發條件 客戶端處置
CC-AUTH-3001 409 非法狀態轉換 授權相關狀態機(來源狀態未定義此事件) 查詢當前狀態後重送合法事件
CC-AUTH-3002 409 終態不可轉換 授權相關狀態機(來源狀態為終態) 不得重送,須另立新單
CC-CARD-3001 409 非法狀態轉換 卡片狀態機(SDD-005 §2) 同上
CC-CARD-3002 409 終態不可轉換 卡片狀態機,例如 CLOSED → ACTIVE 同上
CC-LIM-3001 409 非法狀態轉換 額度佔用/額度調整狀態機(SDD-005 §3/§8) 同上
CC-LIM-3002 409 終態不可轉換 額度調整已 REJECTED/EXPIRED/REVOKED 仍嘗試覆核 同上
CC-POST-3001 409 非法狀態轉換 帳務交易狀態機(SDD-005 §4) 同上
CC-POST-3002 409 終態不可轉換 帳務交易已 REVERSED 仍嘗試入帳 同上
CC-PAY-3001 409 非法狀態轉換 繳款狀態機(SDD-005 §5) 同上
CC-PAY-3002 409 終態不可轉換 繳款已沖正仍嘗試分配 同上
CC-INS-3001 409 非法狀態轉換 分期計畫狀態機(SDD-005 §6) 同上
CC-INS-3002 409 終態不可轉換 分期已結清仍嘗試攤還 同上
CC-DSP-3001 409 非法狀態轉換 爭議案件狀態機(SDD-005 §7) 同上
CC-DSP-3002 409 終態不可轉換 爭議已 CLOSED 仍嘗試調整 同上
CC-STM-3001 409 非法狀態轉換 帳單狀態機(SDD-005 §9) 同上
CC-STM-3002 409 終態不可轉換 帳單已結清仍嘗試產製 同上
CC-RWD-3001 409 非法狀態轉換 點數帳戶狀態機(SDD-005 §10) 同上
CC-RWD-3002 409 終態不可轉換 點數帳戶已 CLOSED 仍嘗試入帳 同上
CC-PTY-3001 409 非法狀態轉換 當事人/帳戶狀態機 同上
CC-PTY-3002 409 終態不可轉換 當事人/帳戶已終止 同上
CC-PRD-3001 409 非法狀態轉換 產品/參數狀態機 同上
CC-PRD-3002 409 終態不可轉換 產品已下架 同上
CC-PRC-3001 409 非法狀態轉換 定價/利率狀態機 同上
CC-PRC-3002 409 終態不可轉換 定價已失效 同上
CC-CLR-3001 409 非法狀態轉換 清算批次狀態機 同上
CC-CLR-3002 409 終態不可轉換 清算批次已結案 同上
CC-MRC-3001 409 非法狀態轉換 特店狀態機 同上
CC-MRC-3002 409 終態不可轉換 特店已終止 同上
CC-MIG-3001 409 非法狀態轉換 遷移作業狀態機 同上
CC-MIG-3002 409 終態不可轉換 遷移作業已完成 同上
CC-NOT-3001 409 非法狀態轉換 通知狀態機 同上
CC-NOT-3002 409 終態不可轉換 通知已結案 同上
CC-RPT-3001 409 非法狀態轉換 報表作業狀態機 同上
CC-RPT-3002 409 終態不可轉換 報表已歸檔 同上
CC-PLT-5000 500 未預期系統錯誤 未分類之伺服器例外(GlobalExceptionHandler 之兜底) 已告警,聯繫系統管理
CC-PLT-5001 503 外部系統逾時 逾時 重試(冪等者)
CC-PLT-5002 500 Saga 補償失敗 補償步驟失敗 告警並人工介入
CC-PLT-5003 503 事件發布失敗 Kafka 不可用 自動重試
CC-PLT-5004 500 欄位加解密失敗 金鑰不存在、密文損毀或格式不符 告警,人工介入(不得回退為明文)
CC-PLT-5005 503 定價服務呼叫失敗 pricing-service 不可用、逾時或回應無法解析(CR-006 計息串接) 不入帳,重試(計息請求帶冪等鍵,可安全重送)
CC-GW-1001 422 缺少冪等鍵 寫入操作未帶標頭 補上標頭
CC-GW-1002 401 權杖無效或過期 簽章不符/已過期/被竄改 重新登入
CC-GW-1003 403 權限不足 角色或範圍(scope)不足 申請權限
CC-GW-4290 429 超過速率限制 限流 退避重試
CC-GW-5001 503 服務不可用 斷路器開啟 稍後重試

3.4.19 campaign-service(行銷活動引擎;CR-046/BRD-005)

★ 本組為 campaign-service 專用。編碼對齊既有慣例:1000=業務規則、2001=冪等衝突、
3001=狀態機、4001/4040=協定層。
⚠️ CC-CAM-1002/CC-CAM-1003 之語意直接來自客戶 BRD(BRD-005 D9 疊加必填、
例 9 利率型回沖必填)——非我方推測,故採獨立錯誤碼而非通用 400,以便業務端追溯。
| CC-CAM-1001 | 422 | 活動期間不合法 | 迄日早於起日 | 調整期間 |
| CC-CAM-1002 | 422 | 疊加模式未宣告 | 未提供 stackingMode(BRD-005 D9 明訂為必要參數、無預設值) | 補上疊加模式 |
| CC-CAM-1003 | 422 | 利率型活動須宣告回沖規則 | rewardForm=RATE_CUT 但未提供 clawbackRule(BRD-005 例 9) | 補上回沖規則 |
| CC-CAM-1004 | 422 | 錄取名額已額滿 | 波次名額用罄(BRD-005 BR-06) | 改選其他波次/活動 |
| CC-CAM-2001 | 409 | 冪等鍵衝突 | 同鍵異指紋 | 更換冪等鍵 |
| CC-CAM-3001 | 422 | 活動狀態不允許此操作 | 狀態機不允許(如非 DRAFT 欲核准) | 檢視活動狀態 |
| CC-CAM-4001 | 400 | 請求欄位驗證失敗 | 欄位格式或必填不符 | 檢視欄位 |
| CC-CAM-4040 | 404 | 資源不存在(活動/方案/任務) | 查無指定識別碼 | 確認識別碼 |


4. 事件契約

事件信封與命名規範見 SAD-004 §5。事件之 JSON Schema 位於
cardcore/contracts/events/<context>.<aggregate>.<verb>.v<major>.json。

4.1 事件信封(固定)

{
  "eventId": "01HZX8K2M4N5P6Q7R8S9T0V1W2",
  "eventType": "posting.transaction.posted.v1",
  "eventVersion": 1,
  "occurredAt": "2026-09-17T02:15:30.123Z",
  "aggregateId": "018f2a3b-...",
  "sequenceNo": 42,
  "traceId": "01HZX8K2M4N5P6Q7R8S9T0V1W2",
  "causationId": "01HZX8K2M4N5P6Q7R8S9T0V1W1",
  "correlationId": "AUTH20260917000001",
  "schemaRef": "posting.transaction.posted.v1",
  "payload": { }
}

4.2 主要事件

★ 事件之唯一權威清單為 SAD-004 §5.2(CR-030 §2 #5)。本表僅列 payload 欄位。

事件 payload 主要欄位
authorization.authorization.approved.v1 authorizationId, authNo, cardId, accountId, amount, currency, holdId, holdAmount, standinFlag, cardNoMasked*, merchantId*, decision*
authorization.authorization.declined.v1 authorizationId, respCode, failedChecks[] ⛔ 刻意未發射(見下)
limit.limit.adjusted.v1 accountId, adjustType, beforeAmount, afterAmount, effectiveFrom
limit.hold.created.v1 holdId, accountId, holdAmount, holdType, instrumentId*, authorizationId*, currency*
limit.hold.released.v1 holdId, accountId, releasedAmount, instrumentId*
card.card.issued.v1 cardId, cardNoMasked, productCode, instantIssued
card.card.status-changed.v1 instrumentId*, cardNoHash, cardId, accountId, cardNoMasked, status, blockCode, expiryDate
card.token.bound.v1 tokenId, cardId, platform
product.parameter.changed.v1 namespace, paramKey, effectiveFrom
posting.transaction.posted.v1 postingId, txNo, accountId, instrumentId*, merchantId*, mcc*, payPath*(CR-048;支付路徑,未提供=未判定), txType, amount, currency, postingDate, subAccountEntries[]
campaign.reward.commanded.v1 commandId, campaignCode, recognition{campaignCode, postingId, txNo, accountId, instrumentId*, merchantId*, mcc*, txType, amount, currency, postingDate, applicableRate*, rateReason*} (★ CR-046 B4 首次定義:REWARD_CMDS(PENDING) 經 relay 派發;rewards 以 campcmd:<commandId> 冪等入點。★ CR-049:回沖指令同走此信封,recognition{…, originalPostingId, txType=REFUND, amount, postingDate, refund:true}——消費端以 txType=REFUND 為權威,欄位一律「recognition 優先、payload 次之」)
posting.transaction.reversed.v1 postingId, reversalOf, amount, reason, postingDate*(★ CR-049:沖正交易之入帳日=業務日錨點;下游回沖分錄以此為 posting_date,不得以 occurredAt 反推——SCS-026 §7.5①。可選欄位,不升版)
posting.exception.raised.v1 postingId, exceptionType, detail
payment.payment.posted.v1 paymentId, accountId, amount, allocations[], availableLimitAfter, currency*
payment.payment.unmatched.v1 paymentId, accountId, amount, daysUnmatched, currency*
payment.payment.reversed.v1 paymentId, accountId, amount, reason, currency* (★ CR-030 §2 #9 首次定義)
statement.statement.issued.v1 statementId, accountId, statementMonth, totalAmount, minimumDue, paymentDueDate, currency*
installment.plan.created.v1 planId, accountId, originalAmount, periodCount, perPeriodAmount
rewards.points.accrued.v1 accountId, pointsType, bucket, points, afterBalance
rewards.points.redeemed.v1 redemptionId, accountId, pointsUsed, amountPaid, merchantShare
clearing.batch.matched.v1 runId, businessDate, txCount, totalAmount, differenceCount
dispute.case.opened.v1 disputeId, accountId, transactionId, disputeType, amount
dispute.case.closed.v1 disputeId, resolution, adjustAmount
merchant.settlement.submitted.v1 settlementId, merchantId, grossAmount, feeAmount, netAmount
notification.sent.v1 notificationId, channels[], sentAt

* 可選欄位(SAD-004 §5.3:新增可選欄位不升版;通則見 §2.5)。

  • cardNoMasked/merchantId(approved.v1)——2026-10-01(#A-125),供通知樣板 AUTH_APPROVED;
    ★ cardNoMasked 為遮罩值(不含 PAN),符合 PCI DSS。
  • authorizationId(limit.hold.created.v1)——CR-028,供 authorization-service 之本地投影對應。
  • currency(limit.hold.created.v1/payment.posted.v1/statement.issued.v1/
    payment.unmatched.v1/payment.reversed.v1)——依 §2.5 通則(CR-030 §2 #10)。
  • decision(approved.v1)——CR-030 §2 #8 新增:值域 APPROVED/STANDIN/REFERRAL。
    ★ 本事件之語意為「授權已佔用額度」(三者皆佔用);下游據 decision 分辨「核准」與「轉人工待覆核」。
  • instrumentId(card.card.status-changed.v1)——CR-046 B2-6:交易載體最小識別;由 CC_CARD.INSTRUMENTS 依 cardId 解析。既有尚未回填載體之卡片可為 null,不臆造值。
  • instrumentId(posting.transaction.posted.v1)——CR-046 B4 前置增量:直接取既有入帳交易之 INSTRUMENT_ID;非載體交易(例如利息)可為 null,舊事件亦可缺欄;消費端不得將 cardId 猜回載體。
  • merchantId(posting.transaction.posted.v1)——CR-046 AC 11 前置增量:取既有 PostingRequest.merchantId/Transaction.merchantId;歷史或未提供者為 null。mcc 與支付路徑不在本次補入,避免臆造來源。
  • mcc(posting.transaction.posted.v1)——CR-046 AC 11 資料鏈補強:呼叫端自授權紀錄(CC_AUTH.AUTHORIZATIONS.mcc,權威)如實帶入;posting 不做 MCC 對映、不從 merchantId 推導;非授權來源交易與舊事件為 null,消費端必須容忍缺欄。
  • instrumentId(limit.hold.created.v1/limit.hold.released.v1)——CR-054 P1(2026-10-17):
    交易載體最小識別,供 authorization-service 之投影把佔用歸到正確的卡。
    ★ 補此欄之根因:權威表 CC_LIM.LIMIT_HOLDS.INSTRUMENT_ID 早於 V10 即有值,
    但事件原本不帶 → 投影永遠拿不到(CR-054 §3.1「權威表有、事件沒有」)。
    created 取 hold() 之入參;released 因入參不含載體,由同交易 findHoldInstrumentId 回查。
    ⚠️ V10 前之歷史佔用無載體 → 可為 null(不得回填、不得以 cardId 猜);消費端須容忍缺欄。

⛔ authorization.authorization.declined.v1 為「刻意未發射」(CR-030 §2 #7 裁定):
拒絕不改變任何下游狀態(不佔額度、不產生待請款),依「事件=已發生的狀態變更」原則不應灌入事件流;
拒絕率/原因分佈改以 metrics(cardcore_authorization_declined_total{reason})涵蓋。
payload 保留於本表,供日後「拒絕率即時看板」需求時啟用(無契約破壞)。

🔧 本表之歷史修訂:
(i) CR-028:刪除 authorization.hold.created.v1/.released.v1 兩列(「同一事實兩個生產者」之矛盾)、
補登 limit.hold.created.v1;(ii) CR-028:更正 card.card.status-changed.v1 之 payload——
原載 fromBlockCode/toBlockCode/reason(差量),惟實作(SCS-003 §7.10,#A-118 真機驗證)
發射者為變更後之完整狀態——本表原為該事件之唯一錯誤記載,已依實作更正
(CR-030 §2 #13 追認以實作為準,結案)。
(iii) ★ 結構修復:本表原被上述 CR-028 說明從中間截斷(後半表格失去表頭)——已一併修復。

4.3 事件相容性規則

變更 相容性 處置
新增可選欄位 相容 不升版
新增必填欄位 不相容 升版並雙軌 ≥ 1 release
移除欄位 不相容 升版並雙軌
改型別 不相容 升版並雙軌
改語意 不相容 升版並雙軌
消費者 須同時容忍 vN 與 vN+1 至少一個 release

5. 契約測試

測試類型 說明 工具
Provider 契約測試 服務實作是否符合契約 自動化(依 OpenAPI 驗證回應)
Consumer 契約測試 消費端對契約之期待 自動化
破壞性變更檢測 新版契約是否破壞舊版 CI 契約 diff
Schema 驗證 回應是否符合宣告之 schema 自動化
錯誤碼驗證 錯誤情境是否回傳宣告之錯誤碼 自動化

通過標準

項目 標準
Provider 契約測試 100% 通過
破壞性變更 0 筆(或已升版雙軌)
錯誤碼一致性 實作與本文件 100% 一致
$ref 可解析 100%

6. 端點清單(依服務)

服務 方法與路徑 說明
authorization POST /api/v1/authorizations 取授權
authorization GET /api/v1/authorizations/{authId} 查詢授權
authorization POST /api/v1/authorizations/{authId}/reversals 取消/沖正
authorization POST /api/v1/authorizations/{authId}/advices 人工/強制授權
authorization GET /api/v1/authorizations/{authId}/check-results 檢核明細
limit GET /api/v1/accounts/{accountId}/limits 歸戶額度
limit GET /api/v1/accounts/{accountId}/limits 歸戶額度(★ CR-043 §3.1 #7:原載卡級路徑,更正為歸戶級)
limit POST /api/v1/limit-adjustments 額度調整
limit GET /api/v1/limit-adjustments/{adjustmentId} 查詢調整
limit POST /api/v1/limit-holds 建立佔用
limit POST /api/v1/limit-holds/{holdId}/releases 釋放佔用
posting POST /api/v1/postings 入帳
posting GET /api/v1/postings/{postingId} 查詢入帳
posting POST /api/v1/postings/{postingId}/reversals 錯帳沖正
posting GET /api/v1/accounts/{accountId}/balances 帳務餘額
posting GET /api/v1/accounts/{accountId}/transactions 交易明細
posting POST /api/v1/posting-duplicate-checks 重複請款偵測
payment POST /api/v1/payments 繳款受理
payment GET /api/v1/payments/{paymentId} 查詢繳款
payment POST /api/v1/auto-debit-enrollments 自扣設定
payment POST /api/v1/payments/{paymentId}/reversals 繳款沖正
card POST /api/v1/cards 發卡
card GET /api/v1/cards/{cardId} 查詢卡片
card POST /api/v1/cards/{cardId}/lifecycle-transitions 狀態轉換
card POST /api/v1/cards/{cardId}/instant-issuance 快發快綁
card POST /api/v1/cards/{cardId}/tokens Token 綁定
card GET /api/v1/cards/{cardId}/tokens 查詢 Token
card POST /api/v1/card-applications 申請案件
party GET /api/v1/accounts/{accountId} 查詢歸戶
party GET /api/v1/parties/{partyId} 查詢持卡人
party POST /api/v1/parties/{partyId}/flags 貼標
party POST /api/v1/accounts/{accountId}/block-codes 管制碼
product POST /api/v1/products 建立產品
product GET /api/v1/products/{productCode} 查詢產品
product PUT /api/v1/products/{productCode} 更新產品
product GET /api/v1/parameters/{namespace}/{paramKey} 查詢參數
product PUT /api/v1/parameters/{namespace}/{paramKey} 設定參數
statement POST /api/v1/statement-cycles/{cycleCode}/runs 帳單批次
statement GET /api/v1/statement-runs/{runId} 批次狀態
statement GET /api/v1/accounts/{accountId}/statements 查詢帳單
pricing POST /api/v1/pricing/interest-calculations 利息計算
pricing GET /api/v1/pricing/interest-inquiries 利息查詢
pricing GET /api/v1/pricing/fees 費用設定
installment POST /api/v1/installments 建立分期
installment GET /api/v1/installments/{planId} 查詢分期
installment POST /api/v1/installments/{planId}/settlements 結清/違約
rewards POST /api/v1/rewards/accruals 點數回饋
rewards POST /api/v1/rewards/redemptions 點數兌換
rewards GET /api/v1/rewards/accounts/{accountId} 點數帳戶
rewards POST /api/v1/reward-rules 回饋規則
clearing POST /api/v1/clearing/runs 清分比對
clearing GET /api/v1/clearing/reconciliations/{runId} 差異明細
clearing POST /api/v1/clearing/settlements 撥款與分錄
dispute POST /api/v1/disputes 爭議受理
dispute GET /api/v1/disputes/{disputeId} 查詢爭議
dispute POST /api/v1/disputes/{disputeId}/chargebacks 扣款與仲裁
merchant POST /api/v1/merchants 建立特店
merchant GET /api/v1/merchants/{merchantId} 查詢特店
merchant POST /api/v1/merchant-settlements 商店請款
notification POST /api/v1/notifications 發送通知
notification GET /api/v1/notifications/{notificationId} 查詢通知
report POST /api/v1/report-jobs 產生報表
report GET /api/v1/report-jobs/{jobId} 查詢報表
migration POST /api/v1/migration-jobs 資料轉換
migration GET /api/v1/legacy-accounts/{legacyId} 查詢舊資料
合計 65 端點

7. 代表端點範例(請求/回應)

本節列出關鍵端點的具體 JSON 範例,使 Coder 無須反推欄位形狀。
全部 65 個端點的請求/回應 example 已內嵌於
cardcore/contracts/openapi/<service>.yaml,並可經契約測試直接驗證。
所有回應皆套用 §2.2 之統一信封(成功 error=null;失敗 data=null)。

7.1 取授權 POST /api/v1/authorizations

請求

{
  "stan": "20260917000001",
  "cardNo": "4111111234567890",
  "txType": "PURCHASE",
  "amount": 12345,
  "currency": "TWD",
  "mcc": "5411",
  "merchantId": "MERCH001",
  "merchantName": "便利商店",
  "entryMode": "CHIP",
  "txTime": "2026-09-17T02:15:30Z",
  "emvData": { "arqc": "A1B2C3D4" }
}

成功回應(201)— data 主體

{
  "authorizationId": "018f2a3b-0000-0000-0000-000000000001",
  "authNo": "AUTH000123",
  "decision": "APPROVED",
  "respCode": "00",
  "holdId": "018f2a3b-0000-0000-0000-000000000002",
  "holdAmount": 12345,
  "availableLimit": 876550,
  "checkResults": [
    { "checkCode": "LIMIT", "checkOrder": 1, "result": "PASS", "reasonCode": null }
  ],
  "txTime": "2026-09-17T02:15:30Z"
}

7.2 入帳 POST /api/v1/postings

請求

{
  "accountId": "018f2a3b-0000-0000-0000-000000000010",
  "cardId": "018f2a3b-0000-0000-0000-000000000020",
  "authorizationId": "018f2a3b-0000-0000-0000-000000000001",
  "txCode": "PUR",
  "txType": "PURCHASE",
  "amount": 12345,
  "currency": "TWD",
  "postingDate": "2026-09-17",
  "merchantId": "MERCH001",
  "businessIdempotencyKey": "4111111234567890|AUTH000123|2026-09-17|12345|TWD"
}

成功回應(201)— data 主體(含分欄位與更新後餘額)

{
  "postingId": "018f2a3b-0000-0000-0000-000000000030",
  "txNo": "TXN20260917000001",
  "status": "POSTED",
  "amount": 12345,
  "currency": "TWD",
  "postingDate": "2026-09-17",
  "subAccountEntries": [
    { "subAccount": "PRINCIPAL", "amount": 12345, "beforeAmount": 0, "afterAmount": 12345 }
  ],
  "releasedHoldAmount": 12345,
  "balanceAfter": {
    "accountId": "018f2a3b-0000-0000-0000-000000000010",
    "principalAmount": 12345, "interestAmount": 0, "feeAmount": 0, "taxAmount": 0,
    "totalAmount": 12345, "minimumDue": 0, "paymentDueDate": null,
    "agingBucket": 0, "currency": "TWD", "asOf": "2026-09-17T02:20:00Z"
  }
}

7.3 繳款受理 POST /api/v1/payments

請求

{
  "accountId": "018f2a3b-0000-0000-0000-000000000010",
  "amount": 50000,
  "currency": "TWD",
  "paymentMethod": "AUTO_DEBIT",
  "channel": "BATCH",
  "paymentDate": "2026-09-17",
  "externalRef": "AD20260917001"
}

成功回應(201)— data 主體(即時恢復額度)

{
  "paymentId": "018f2a3b-0000-0000-0000-000000000040",
  "paymentNo": "PAY20260917000001",
  "status": "POSTED",
  "amount": 50000,
  "currency": "TWD",
  "allocations": [
    { "subAccount": "PRINCIPAL", "amount": 50000, "allocationOrder": 1 }
  ],
  "availableLimitAfter": 926550,
  "limitRestored": true,
  "postedAt": "2026-09-17T03:00:00Z"
}

7.4 建立額度佔用 POST /api/v1/limit-holds

請求

{
  "accountId": "018f2a3b-0000-0000-0000-000000000010",
  "authorizationId": "018f2a3b-0000-0000-0000-000000000001",
  "holdAmount": 12345,
  "holdType": "GENERAL"
}

成功回應(201)— data 主體

{
  "holdId": "018f2a3b-0000-0000-0000-000000000002",
  "accountId": "018f2a3b-0000-0000-0000-000000000010",
  "holdAmount": 12345,
  "releasedAmount": 0,
  "status": "HELD",
  "availableAmount": 864105
}

8. 變更記錄

版本 說明
1.0 初版:端點清單、通用規範、錯誤碼清單、事件契約
1.1 契約強化:65 端點全部補齊欄位級 example 與每端點業務規則/不變式(OP_RULES);reward-rules 端點改用 RewardRuleRequest;詳見 cardcore/tools/gen_openapi.py
1.2 ①修正表頭版本:本文件表頭原停留於 1.0,但變更記錄已有 1.1 條目,兩者不一致;現更正為 1.2 並同步本記錄。②新增錯誤碼 CC-PLT-5000(500 未預期系統錯誤)——CSP-003 §3 明訂「內部錯誤一律轉為 CC-PLT-5xxx + 通用訊息」,但本表原無通用之未預期錯誤碼,致 GlobalExceptionHandler 之兜底分支無碼可用。依 CSP-003 §2「不得自創錯誤碼,新增碼須先擴充本節」之程序補登。③新增錯誤碼 CC-PLT-5004(500 欄位加解密失敗)——SAD-005 §5 要求卡號等個資欄位加密儲存;金鑰不存在或密文損毀屬須告警之基礎設施失敗,與「未分類之系統錯誤」處置不同,故獨立登錄。新碼均符合既有 pattern ^CC-[A-Z]{2,4}-[0-9]{4}$,無須調整 OpenAPI 之 Error.code.pattern
1.3 補登 401/403 授權類錯誤碼:CC-GW-1002(401 權杖無效或過期)、CC-GW-1003(403 權限不足)。CSP-003 §2 規範「所有可用錯誤碼以本節為唯一登錄表」,但原表僅有 422 之 CC-GW-1001(缺少冪等鍵),無任何 401/403 碼;而 CSP-007 §5.3.4 之 JWT 驗證流程需要 401。依程序補登,並同步 tools/gen_error_codes.py 重新產生 ErrorCodes.java。新增碼符合既有 pattern,無須調整 OpenAPI Error.code.pattern
1.4 補登狀態機與樂觀鎖類錯誤碼(Sprint 3 之 common-saga 需要,依 CSP-003 §2 程序補登):CC-PLT-3001(409 非法狀態轉換)、CC-PLT-3002(409 終態不可轉換)——SDD-005 §14(1.7 起;1.4 起為 §13;原 §12)明訂此二情境之錯誤碼為 CC-<SVC>-3001/3002,但平台層(Saga 狀態機)原無對應登錄;CC-PLT-2002(409 狀態版本衝突/樂觀鎖)——SDD-005 SM-04 要求「以狀態條件更新實作並發轉換」,衝突時需有明確錯誤碼。三碼皆符合既有 pattern ^CC-[A-Z]{2,4}-[0-9]{4}$,無須調整 OpenAPI Error.code.pattern;已同步重新產生 ErrorCodes.java(63 個錯誤碼)
1.5 ①移除重複登錄之 CC-RW-*(4 碼):§3.2 服務代碼 明訂 rewards-service 之代碼為 RWD(§3.1 亦規範 SVC 即服務代碼),但 §3.4 另存在 CC-RW-1001/2001/4000/4040 一組——同一服務兩個代碼前綴,違反「一服務一服務代碼」。經查此 4 碼係 2026-09-19 為 SCS-010 補登時未察覺 CC-RWD-* 已存在所致,屬登錄重複,故予移除(非功能變更;移除前已確認全庫 Java 無任何引用)。②補登 CC-RWD-4000(400 請求驗證錯誤)、CC-RWD-4040(404 資源不存在):CC-RWD-* 原有 1001/1002/1003/2001/3001/3002,缺類別位 4 之通用驗證碼與查無資源碼,而 rewards-service 之 4 支端點(SCS-010 §6)需要此二碼。③補登 CC-RWD-1005(422 回饋規則代碼重複):POST /api/v1/reward-rules 之 rule_code 於主檔為 UNIQUE,重複設定須有明確拒絕碼,不得以「靜默覆蓋」處理(覆蓋會使已生效之回饋條件無聲改變)。新碼均符合既有 pattern,無須調整 OpenAPI Error.code.pattern;已同步重新產生 ErrorCodes.java(107 個錯誤碼)
1.6 擴充類別位 4 語意 + 補登 5 個請求層錯誤碼(CR-004,2026-09-19 BEAM PMO 核定):
①**§3.3 類別位 4 由「資源與重複」擴充為「請求與資源」(HTTP 400/404/405/409),並新增 §3.3.1 明訂四個子語意。理由:實測發現 Spring MVC 之請求層例外(缺標頭、壞 JSON、方法不支援、路徑不存在)皆非 DomainException 子類,全數落兜底回 500——既違反契約(應為 400/404/405),且每個客戶端錯誤都觸發 ERROR 告警(告警疲勞)。原類別位 4 僅有 404/409,無處安放 400 與 405。
②
補登 CC-PLT-4001(400 缺少必要請求標頭或參數)、CC-PLT-4002(400 請求主體格式錯誤)、CC-PLT-4003(400 請求參數驗證失敗)、CC-PLT-4040(404 資源或路徑不存在)、CC-PLT-4050(405 HTTP 方法不支援)**——由 common-spring 之 GlobalExceptionHandler 統一拋出,服務不需自行實作。
③實測影響:17/17 服務受影響,自行補 @ExceptionHandler 者 0 個(6 項情境中 4 項錯誤)。
新碼均符合既有 pattern ^CC-[A-Z]{2,4}-[0-9]{4}$,無須調整 OpenAPI Error.code.pattern;已同步重新產生 ErrorCodes.java(112 個錯誤碼)
1.7 補登 CC-PLT-4010(401 未認證)、CC-PLT-4030(403 無權限)(SCS-022,2026-09-19;W-3 SSO 接線):
①缺口:CR-004(本文件 1.6)之 5 碼僅涵蓋 400/404/405,無 401 與 403。當時看似無需——相關例外由 GlobalExceptionHandler 處理;但 Spring Security 之認證攔截發生在進入控制器之前,不在 @ControllerAdvice 之攔截範圍,故無碼可用。
②若不補登將被迫二選一:要麼回傳空主體(違反 CSP-003 §3「所有回應一律套用 ApiResponse 封套」),要麼濫用 CC-PLT-4001(400 缺參數)回 401(碼與狀態不一致)。
③依 CSP-003 §2「不得自創錯誤碼」程序補登;後兩碼對齊 HTTP 狀態碼(401/403),與既有 4040/4050 慣例一致。
④實測:Keycloak 核發之真實權杖可通過、過期/偽造權杖皆回 401 且主體含封套(見 SCS-022 §9.1)。
新碼符合既有 pattern,無須調整 OpenAPI Error.code.pattern;已同步重新產生 ErrorCodes.java(114 個錯誤碼)
1.8 補登 CC-NOT-1002/CC-NOT-1003/CC-NOT-4040(C-9/CR-017 §9.4,2026-09-22)——notification-service 實作時發現既有 CC-NOT-* 僅 3 碼(1001 樣板不存在、3001/3002 狀態機),缺「無可用通道」(業務規則 422)與「查無通知」(協定層 404)→ 依 CSP-003 §2 程序補登 → 錯誤碼 114 → 122
1.9 補登 CC-AUTH-4040(404 查無授權)(CR-021,2026-09-22)——authorization-service 之授權明細/檢核明細端點需要;併修訂 check-results 契約之陣列性(原誤宣告單一物件 → AuthCheckResult[])→ 錯誤碼 122 → 123
1.10 補登 CC-PLT-3003(409 資源尚未就緒)(GOV-007 §4,2026-10-01)——供報表下載之「作業未就緒(QUEUED/RUNNING/FAILED)」情境;原暫用 CC-PLT-3001(非法狀態轉換)語意不符,故另立。與「狀態機非法轉換」語意區隔 → 錯誤碼 123 → 124;已重新產生 ErrorCodes.java(--force)
(9-9/67)