# SCS-024　進件處理（受理／徵信／核決／製卡）程式設計規格

| 項目 | 內容 |
|---|---|
| 文件編號 | SCS-024 |
| 版本 | **1.3** |
| 狀態 | **已實作（v1.1，2026-09-20 實測通過）** |
| 撰寫者 | WorkBuddy AI |
| 審查者 | BEAM PMO |
| 服務 | `card-service` |
| 對應需求 | `BRD-001 BF-01`（申請與發卡）、`BF-10`（卡片生命週期）、`BR-01-01`～`BR-01-04`；`BRD-001 D-01`（徵審系統） |
| 對應設計 | `SDD-005 §12`（申請案件狀態機）、`SDD-005 §2`（卡片狀態機）、`SDD-006 §3.4`（錯誤碼）、`SDD-001 §3`（資料模型）、`SAD-003 §9`（遷移規範） |
| 關聯規格 | `SCS-003`（卡片服務）、`SCS-023`（商品組合） |
| 建立日期 | 2026-09-20 |

> **本文件依 BEAM PMO 2026-09-20「進件系統有缺口」之指示建立，採 SPEC 先行——
> 未核定前不得撰寫程式。**

---

## 1. 目的與範圍

補上「申請案件受理之後」整段流程：徵信、補件、核決、核准序號、製卡銜接。

**範圍內**

- 申請案件狀態機之程式實作（`SDD-005 §12`）
- 徵信介接（port／adapter，含 fail-closed）
- 核准序號產生
- 核准後與製卡／快發之銜接
- 查詢與狀態推進之 REST 端點

**範圍外**

- 徵審系統本身（`BRD-001 D-01`，外部系統，由客戶既有的負責）
- 製卡檔產生與送件（本期僅定義事件契約，見 §7.2）
- 額度核定（屬 `limit-service`；本規格僅於核准後呼叫其介面）
- 票證卡加值／電子票證帳務（另案）

---

## 2. 名詞

| 名詞 | 說明 |
|---|---|
| 進件 | 自受理至核決之作業流程 |
| 徵信 | 向外部徵審系統查詢信用評等與風險（結果：`APPROVE`／`DECLINE`／`REFER`／`SUPPLEMENT`） |
| 補件 | 資料不齊，通知客戶補充（`SUPPLEMENT`） |
| 核決 | 徵審人員作成核准或婉拒之決定 |
| 核准序號 | `approval_no`，快發「部分開卡」三要素之一（`BR-01-04`） |
| 製卡 | 實體卡壓印與送件；完成後卡片進入 `INACTIVE`（`SDD-005 §2`） |

---

## 3. 現況缺口（誠實盤點）

| # | 缺口 | 證據 |
|---:|---|---|
| 1 | **契約只有 `POST /api/v1/card-applications`**——無查詢、無狀態推進 | `contracts/openapi/card-service.yaml` 僅一路徑 |
| 2 | **領域模型無轉態方法**——`CardApplication` 只有 `received()` 工廠與 `approved()` 查詢 | `CardApplication.java` |
| 3 | **無徵信介接**——`SCS-003 §10 #9` 明載「核准屬徵信流程，無對應端點」 | `SCS-003 §10 #9` |
| 4 | **`approval_no` 永為 `NULL`**——無產生邏輯 | `CardApplicationService.create()` 未填 |
| 5 | **無製卡**——核准後直接斷鏈，卡片無從產生 | 無對應程式 |
| 6 | **本地測試以直接更新資料準備 `APPROVED` 案件**——快發快綁之前置條件靠人工改 DB | `CardApplicationService` 類別說明 |

> **#6 之風險**：以人工改 DB 準備前置條件，意味著「核准」這條路徑**從未被程式驗證過**——
> 快發快綁之實測只證明了後半段。本規格即為消除此風險。

---

## 4. 狀態機

### 4.1 權威來源

值域、轉換表、非法轉換**一律以 `SDD-005 §12` 為準，本文件不重複定義**。
本節僅規範**程式如何實作**。

### 4.2 轉態守門（三道）

| 道 | 位置 | 檢核 |
|---|---|---|
| ① | `CardApplication` 領域方法 | 非法轉換拋 `CC-CARD-3001`；終態拋 `CC-CARD-3002` |
| ② | `CARD_APPLICATIONS.status` 之 `CHECK` 約束 | 資料庫層最後防線（實測 5 值，見 `SDD-005 §14.3`） |
| ③ | **樂觀鎖** `version` | `UPDATE ... WHERE id=? AND version=?`，影響 0 列即併發衝突 |

> **為何①與②都做**：②只能擋「值不合法」，擋不了「合法值之間的非法路徑」
> （例如 `RECEIVED → APPROVED`）。兩者職責不同，不可互相取代。

### 4.3 樂觀鎖之紀律

`CardApplication` 採 `with*` 方法回傳新實例；**每次更新只能套用一次 `with*`**
（版本恰 +1）——鏈式呼叫會使版本 +2 而誤判衝突（此為 `common-saga` 既有教訓，
見 `MEMORY.md`「Saga 設計」）。

---

## 5. 徵信介接

### 5.1 Port（領域層）

```java
public interface CreditReviewPort {
    /** 結果：APPROVE／DECLINE／REFER／SUPPLEMENT。 */
    CreditReviewResult review(CreditReviewRequest request);
}
```

### 5.2 處置表（**fail-closed**）

| 徵信回應 | 處置 | 狀態變化 |
|---|---|---|
| `APPROVE` | 自動核准 | `REVIEWING → APPROVED` |
| `DECLINE` | 自動婉拒 | `REVIEWING → REJECTED` |
| `REFER` | 轉人工核決 | 維持 `REVIEWING` |
| `SUPPLEMENT` | 要求補件 | `REVIEWING → SUPPLEMENT` |
| **呼叫失敗／逾時／無 adapter** | ⚠️ 轉 `REFER`、**維持 `REVIEWING`**、記 **WARN** | 不變 |

> **為何是 fail-closed**：徵信不可用時若靜默放行（自動核准），
> 即為「**靜默不做**」型缺陷——與 Flyway 未顯式引入 starter、
> loki exporter 不存在、認證預設 fail-open 同類（見 `SCS-020 §9.2`、`SCS-022 §7.4`）。
> **不得自動核准，亦不得自動婉拒**——一律轉人工。

### 5.3 Adapter 之選用

| Adapter | 用途 | 狀態 |
|---|---|---|
| `ExternalCreditReviewAdapter` | HTTP 介接 `BRD-001 D-01` 徵審系統 | **待介面契約**；本期不實作（見 §12 #1） |
| `NoopCreditReviewAdapter` | 本地／測試：**一律回 `REFER`** | 本期實作 |

> ⚠️ **為何本地 adapter 回 `REFER` 而非 `APPROVE`**：回 `APPROVE` 會讓「核准」
> 在沒有徵信的情況下自動發生，正是 fail-closed 要防的。**回 `REFER` 才是誠實的**
> ——它代表「我不知道，交給人」。

---

## 6. 核決與核准序號

| 項目 | 規格 |
|---|---|
| 格式 | `APR` + `yyyyMMdd`（8） + 亂數 8 碼 = 19 碼（欄位 `VARCHAR2(24 CHAR)`） |
| 產生時機 | 於 `REVIEWING → APPROVED` **轉換當下**產生並寫入 |
| 唯一性 | 建議加 `UNIQUE`；本期先以「撞號重試 3 次」處理（同 `apply_no` 之作法） |
| 用途 | 快發部分開卡之三要素驗證（`BR-01-04`），失敗為 `CC-CARD-1002` |

> **為何在轉換當下產生**：核准序號是「核准」這件事的產物，
> 若延後產生會出現「狀態已 `APPROVED` 但無序號」之中間態——該態下快發無法開卡，
> 屬不一致狀態。故與狀態轉換**同交易**寫入。

---

## 7. 核准後之銜接

### 7.1 快發（`fast_issue_flag = 1`）

核准後**即時給號**：呼叫既有 `CardIssueService.issue(...)`，卡片建立為 `INACTIVE`，
再由 `POST /api/v1/cards/{cardId}/instant-issuance` 完成部分開卡（三要素驗證）。

### 7.2 一般（非快發）

核准後寫入 **Transactional Outbox** 事件 `card.application.approved`
（與權威寫入同庫同交易，見 `CSP-006`），payload：

```json
{ "applicationId": "...", "applyNo": "...", "approvalNo": "...",
  "accountId": "...", "productCode": "...", "approvedAt": "..." }
```

由批次作業撈取送製卡檔。**本期不實作製卡檔產生器**（見 §12 #2）。

### 7.3 與商品組合之關係（`SCS-023`）

申請案件僅帶 `productCode`；該商品之**能力集合**由 `product-service` 之 `parameters` 表
以 `namespace = product_code` 讀取（`SCS-023 §4`）。進件流程中之下列決策**一律由參數決定，
不得硬編**：

| 決策 | 參數鍵 |
|---|---|
| 是否需徵信 | `intake.credit_review_required` |
| 補件期限（天） | `intake.supplement_days` |
| 是否允許快發 | `issuance.form` 且 `intake.fast_issue_allowed` |
| 是否需票證帳號 | `ticket.enabled` |

> 此即 BEAM PMO 2026-09-20「**不應局限維度與取值**」之指示於進件段之落法——
> 新增商品不需改程式。

---

## 8. API 契約（新增端點）

> ⚠️ **`contracts/openapi/*.yaml` 由 `gen_openapi.py` 產生，禁止手改**
> （見 `MEMORY.md`「產生器紀律」）。本節為**需求**，實作時須改產生器後 `--write`。

| # | 端點 | 方法 | 說明 |
|---:|---|---|---|
| 1 | `/api/v1/card-applications/{applicationId}` | `GET` | 查詢案件（補現況缺口 #1） |
| 2 | `/api/v1/card-applications/{applicationId}/transitions` | `POST` | 狀態推進 |

### 8.1 `POST .../transitions` 請求

```json
{ "event": "SUBMIT_REVIEW", "reason": null, "operatorId": "credit.user01" }
```

| `event` | 起始 → 結果 | 對應 `SDD-005 §12.2` |
|---|---|---|
| `SUBMIT_REVIEW` | `RECEIVED → REVIEWING` | #2 |
| `REQUEST_SUPPLEMENT` | `REVIEWING → SUPPLEMENT` | #3 |
| `COMPLETE_SUPPLEMENT` | `SUPPLEMENT → REVIEWING` | #4 |
| `APPROVE` | `REVIEWING → APPROVED` | #5 |
| `REJECT` | `REVIEWING`/`RECEIVED`/`SUPPLEMENT` → `REJECTED` | #6／#8／#7 |
| `SUPPLEMENT_EXPIRED` | `SUPPLEMENT → REJECTED` | #7（批次） |

### 8.2 回應

`CardApplicationView`，新增欄位：`updatedAt`、`version`。
成功 **200**；非法轉換 **409 `CC-CARD-3001`**；終態 **409 `CC-CARD-3002`**；
查無案件 **404 `CC-CARD-4040`**；`event` 不在列舉內 **400 `CC-CARD-4001`**。

### 8.3 ⚠️ 一項刻意之設計決策：建立後**不自動**送徵信

受理（建立）後案件維持 `RECEIVED`，須顯式呼叫 `SUBMIT_REVIEW`。理由：

1. 分行收件與送徵信在實務上**可分離**（收件後批次送件）；
2. 若建立時自動呼叫外部徵信，則「建立申請」這支 API 會承擔外部系統失敗之風險，
   違反「建立應為本地交易」；
3. 快發雖需即時，但仍是「受理 → 送徵信 → 核准」三段，可於同一 workflow 內串接。

---

## 9. 錯誤碼（**不新增**）

全部沿用 `SDD-006 §3.4` 既有登錄：

| 碼 | HTTP | 用於 |
|---|---|---|
| `CC-CARD-3001` | 409 | 非法狀態轉換（如 `RECEIVED → APPROVED`） |
| `CC-CARD-3002` | 409 | 終態不可再轉換（`APPROVED`／`REJECTED`） |
| `CC-CARD-4001` | 400 | `event` 不在列舉內、欄位檢核失敗 |
| `CC-CARD-4040` | 404 | 查無申請案件 |
| `CC-CARD-1002` | 422 | 三要素驗證失敗（快發部分開卡） |
| `CC-CARD-1001` | 422 | 快發條款未勾選（`BR-01-01`） |
| `CC-CARD-2001` | 409 | 冪等鍵衝突（同鍵異指紋） |

> 若日後需「徵信系統連線失敗」之專屬碼，須依 `CSP-003 §2` 程序**補登 `SDD-006 §3.4`**
> 後重跑 `gen_error_codes.py --write`，**不得於程式內自創**。

---

## 10. 交易與一致性

| 項目 | 規格 |
|---|---|
| 狀態推進 | `@Transactional`；狀態與 `updated_at`／`version` 同交易寫入 |
| 併發 | 樂觀鎖；影響 0 列視為衝突（回 `CC-CARD-3001` 並記 WARN） |
| 冪等 | `POST .../transitions` 帶 `X-Idempotency-Key`；指紋含 `applicationId + event + reason` |
| 核准序號 | 與狀態轉換**同交易**寫入（§6） |
| Outbox | 一般（非快發）核准時，事件寫入與狀態轉換同交易 |

---

## 11. 測試要求

| # | 案例 | 預期 |
|---:|---|---|
| 1 | **全轉換矩陣**：8 條合法轉換逐一實測 | 皆成功，`SDD-005 §14.2` 要求 |
| 2 | **4 條非法轉換**（`RECEIVED→APPROVED`、`APPROVED→*`、`REJECTED→*`、`REVIEWING→RECEIVED`） | `CC-CARD-3001`／`3002` |
| 3 | 徵信回 `APPROVE` | 自動 `APPROVED` 且 `approval_no` 非 `NULL` |
| 4 | 徵信回 `DECLINE` | 自動 `REJECTED` |
| 5 | **徵信拋例外**（模擬外部系統故障） | 維持 `REVIEWING`、記 WARN、**不核准** |
| 6 | **無 adapter**（`NoopCreditReviewAdapter`） | 回 `REFER`，維持 `REVIEWING` |
| 7 | 樂觀鎖衝突（同案件並發轉態） | 一方失敗 |
| 8 | 冪等重放 | 回前次結果，狀態不重複推進 |
| 9 | `event` 不在列舉內 | `CC-CARD-4001` |
| 10 | 查無案件 | `CC-CARD-4040` |
| 11 | 核准序號格式 | `APR`+`yyyyMMdd`+8 碼亂數，全案唯一、非 `NULL` |
| 12 | 徵信回 `SUPPLEMENT` | → `SUPPLEMENT`（補件） |
| 13 | 版本號遞增 | 每次合法轉態 `version` 恰 +1（樂觀鎖基礎） |
| 14 | 快發路徑 | `fastIssueFlag=true` 時**不**寫 Outbox（即時給號由快發端點負責） |
| 15 | 一般路徑 | `fastIssueFlag=false` 時寫 `card_application_outbox`（事件 `card.application.approved`） |
| 16 | 建立冪等重放 | 同 `X-Idempotency-Key` 回前次結果，不重複建案件 |

> **#5 為本規格之核心測試**——它證明「徵信掛掉時不會自動核准」。
> 若以「回 `APPROVE`」之假 adapter 測試，此案例**永遠是綠的**，屬假驗證，**禁止**。

### 11.1 實測證據（2026-09-20，card-service 單元測試）

以 `Fakes`（記憶體假實作）＋ 可控 `CreditReview` 假 adapter 執行，含 **#5 徵信拋例外** 與 **#7 樂觀鎖** 之真實驗證：

| 項目 | 結果 |
|---|---|
| 測試數 | **16 支全過**（5 建立＋11 轉態） |
| card-service 整模組 | **42 支 0 失敗**（無回歸） |
| #5 徵信拋例外 | ✅ 維持 `REVIEWING`、記 WARN、**不核准**（fail-closed 成立） |
| #7 樂觀鎖 | ✅ 並發轉態一方失敗（`CC-CARD-3001`）；`Fakes.update` 已模擬 `version+1` 與衝突 |
| #13 版本號 | ✅ 每次轉態 `version` 恰 +1 |
| #14/#15 Outbox | ✅ 快發不寫、一般寫（由 `appendOutbox` 落 `V4__card_application_outbox.sql`） |

> ⚠️ **實測前抓到兩個會讓編譯碎的錯**：①`CreditReviewPort` import 錯套件（`domain.model`→`domain.port`）②既有 `CardIssueServiceTest.newApplication` 用 8 引數構造 `CardApplication`，重寫後變 12 引數——已補 `approvedAt`/`updatedAt`/`version` 三引數。> 均修復後編譯通過。


---

### 11.2 端到端實測（2026-09-20，Vite 5173 → card-service 8082 → 真實 Oracle）

經 `/card-api` 代理實測**完整進件流程**（非單元測試、非假物件）：

| # | 情境 | 實測結果 |
|---:|---|---|
| 1 | 受理進件 | **201**；`applyNo=APP2026092062814284`、狀態 `RECEIVED`、`version=0` |
| 2 | 送徵信 `SUBMIT_REVIEW` | **`REVIEWING`**（`version=1`）——徵審未接上，維持徵審中轉**人工核決**，**未核准**（fail-closed ✅） |
| 3 | 要求補件 `REQUEST_SUPPLEMENT` | **`SUPPLEMENT`**（`version=2`） |
| 4 | 補件完成 `COMPLETE_SUPPLEMENT` | **`REVIEWING`**（`version=3`） |
| 5 | 核准 `APPROVE` | **`APPROVED`**（`version=4`）；`approvalNo=APR2026092036624916`（**19 碼**＝`APR`+8 日期+8 序號） |
| 6 | 終態再轉換 | **`CC-CARD-3002`**（409）✅ |
| 7 | 查詢案件 `GET` | 狀態 `APPROVED`、`version=4`，與轉態結果一致 |
| 8 | 查無案件 | **`CC-CARD-4040`**（404）✅ |
| 9 | 冪等重放（同鍵同內容） | **`replayed=true`、`version` 仍為 4**——證明**未重複轉態** ✅ |

> ⚠️ **本輪實測抓到兩個真缺陷（單元測試完全測不出）**，皆已修復：

| 缺陷 | 現象 | 根因 | 修復 |
|---|---|---|---|
| **A. 查詢拋 `ORA-17006`** | 轉態與查詢皆回 `CC-PLT-5000` | `FIND_SQL` 之 SELECT **漏選 `approved_at`**，但 RowMapper 會讀它 → **讀取階段**才報錯 | 補入 `approved_at`；新增 `JdbcCardApplicationRepositorySqlTest`（3 支）以「SELECT 清單須涵蓋 DDL 全部欄位」固樁 |
| **B. 冪等寫入拋 `ORA-12899`** | 值太大（實際 27，最大 20） | `card_idempotency.entity_type` 為 `VARCHAR2(20 CHAR)`，但 `CardApplicationService` 寫入 `CARD_APPLICATION_TRANSITION`（**27 字元**） | 新增 `V6__widen_idempotency_entity_type_fix.sql` 放大為 `VARCHAR2(64 CHAR)` |

> **為何單元測試測不出**：
> ① `ORA-17006` 屬**讀取階段**錯誤——SQL 解析不會錯（缺欄不是語法錯誤），
> 而單測以假 Repository（`Fakes`）執行**根本不走 JDBC**，讀不到就報不出來。
> ② `ORA-12899` 屬**欄位寬度**錯誤——H2／假物件無此約束。
> 兩者皆印證「**編譯過不等於能跑，單測過不等於能在真實 Oracle 跑**」。
>
> ⚠️ **附記（遷移檔之自我修正）**：原 `V5__widen_idempotency_entity_type.sql` 之守衛
> 以 `data_length` 判斷，但該欄回傳的是**位元組**長度（`VARCHAR2(20 CHAR)` 於 AL32UTF8 下為 80），
> 而判斷式寫 `v_len < 64` → **80 < 64 為偽，V5 實為 no-op**。
> V5 已寫入 Flyway schema history，**不可改其內容**（會 checksum 失配），
> 故另立 **V6** 修正：改用 `CASE WHEN char_used='C' THEN char_length ELSE data_length END`。
> **教訓：判斷長欄位長度須看 `char_length`（配合 `char_used`），不可看 `data_length`（位元組）。**

---

## 12. 已知限制（誠實揭露）

1. ~~**無外部徵信契約（本期不實作）**~~ → **已於 v1.2 全部實作完成**：
   `CreditReviewPort`＋`CreditReviewResult`＋`NoopCreditReviewAdapter`（v1.1）
   ＋**`ExternalCreditReviewAdapter`**（v1.2）皆已落地並測試通過。

   後者依 **`SCS-025`（我方自行設計之徵審介面契約）** 實作——RFP 與
   `BRD-001 D-01` 皆未提供介面規格，為使 POC 完整、避免客戶質疑「徵審在哪」，
   由我方設計契約並實作 adapter（`SCS-025 §1.1`）。

   ⚠️ 該契約**為建議版，待客戶確認**（`SCS-025 §10 #1`）；客戶提供其自身規格時
   **僅換 adapter**，領域層與狀態機不受影響（`SAD-002` bounded context）。
   `base-url` 未設定時一律轉人工核決（fail-closed，**不自動核准**）。

2. **製卡僅定義事件契約**：`card.application.approved` 事件已定義，
   但**製卡檔產生器與送件作業本期不實作**。
3. **補件逾期批次未實作**：`SUPPLEMENT_EXPIRED` 事件已定義，觸發之批次作業本期不實作。
4. **`approval_no` 未加 `UNIQUE`**：本期以撞號重試處理；建議後續加約束
   （須走 V4 遷移，不改 V1 基線）。
5. ~~**WebUI 未納入**~~ → **已於 v1.3 實作完成**（`SDD-007 §5.4.9`）：
   進件作業台（`/card-applications`）前端已建置並接線（Vite `/card-api` → 8082），
   依規格逐鈕定義實作受理／查詢／送徵信／補件／補件完成／核准／婉拒／清除；
   並已通過 **9 情境端到端實測**（§11.2）。
   ⚠️ 「送徵信」結果維持 `REVIEWING` 時畫面明示「**轉人工核決**」，不顯示為核准。
   **截圖存證**（`docs/08-evidence/`，與既有 8 頁一致）：
   `webui-applications-01-作業台初始畫面.png`／`02-受理後案件明細.png`／
   `03-送徵信後轉人工核決.png`（**fail-closed 之畫面證明**）／
   `04-核准後顯示核准序號.png`。

6. **額度核定未串接**：核准後呼叫 `limit-service` 之介面本期不實作。

---

## 13. 修訂記錄

| 版本 | 日期 | 修訂者 | 說明 |
|---|---|---|---|
| 1.1 | 2026-09-20 | WorkBuddy AI | **BEAM PMO 核定後實作完成並測試通過**：
| 1.2 | 2026-09-20 | WorkBuddy AI | **徵審介接補完（BEAM PMO 2026-09-20 指示「RFP 無徵審規格，POC 會被質疑，須自行設計提供」）**：新增 **`SCS-025` 徵審介面契約規格**（我方建議版）與 **`ExternalCreditReviewAdapter`**（OpenFeign，照 `CardServiceClient` 慣例）；`CreditReviewClient` 自有 DTO、不共用領域類；`Noop` 與 `External` 以 `@ConditionalOnProperty` 互斥（避免兩 bean 注入歧義）；領域 `CreditReviewRequest` 補 `applyNo`／`channel`；`application.yml` 為 `creditReviewClient` 專屬覆寫 resilience4j（7s／retry 1 次，因全域 800ms／3 次對徵審不適用）。測試 `ExternalCreditReviewAdapterTest` **14 支全過**。§12 #1 由「待契約」改列「已依 `SCS-025` 實作完成（契約待客戶確認）」 |
| 1.3 | 2026-09-20 | WorkBuddy AI | **進件作業台 WebUI 實作完成（`SDD-007 §5.4.9`）＋ 端到端實測**：新增 `frontend/src/api/cardApplications.ts` 與 `pages/CardApplicationConsole.tsx`（照既有 8 頁慣例：自有 DTO、標籤對照集中於 api 檔、卡片式佈局、不自創 className）；`vite.config.ts` 加 `/card-api` → 8082；`App.tsx` 四處接線。⚠️ **端到端實測抓到兩個真缺陷（單元測試完全測不出）**：①`FIND_SQL` 漏選 `approved_at` → 真實 Oracle 讀取時拋 `ORA-17006`（已補欄，並新增 `JdbcCardApplicationRepositorySqlTest` 3 支以「SELECT 須涵蓋 DDL 全部欄位」固樁）；②`card_idempotency.entity_type` 僅 `VARCHAR2(20)`、裝不下 27 字元之 `CARD_APPLICATION_TRANSITION` → `ORA-12899`（新增 `V6` 放大為 64 CHAR；原 `V5` 因守衛誤用 `data_length`（位元組）而 no-op，已於 §11.2 誠實記述）。9 情境端到端全數符合預期（§11.2），含 fail-closed 轉人工核決、核准序號 19 碼、終態 `CC-CARD-3002`、冪等重放不重複轉態。§12 #5「WebUI 未納入」解除。已**截圖存證** 4 張（`docs/08-evidence/webui-applications-01～04`），其中 03 為 fail-closed 之畫面證明 |
   新增 `CardApplication` 轉態方法（6 合法／4 非法，領域層拋 `CC-CARD-3001/3002`）、
   `CardApplicationRepository.update`（樂觀鎖 `version+1 WHERE version=?`，0 列拋 `CC-CARD-3001`）／`appendOutbox`；
   `JdbcCardApplicationRepository` 讀寫 `updated_at`/`version`/`approved_at`、樂觀鎖、Outbox 寫入（`V4__card_application_outbox.sql`）；
   `CardApplicationService` 接徵信 fail-closed（`safeReview` 捕例外轉 `REFER`）、核准序號（`APR+yyyyMMdd+8碼`）、Outbox；
   `CardController` 加 `GET /{id}` 與 `POST /{id}/transitions`；`gen_openapi.py` 加兩端點後 `--write`；
   `Fakes` 補 `update`/`appendOutbox`/`CreditReview` 可控假 adapter；`CardApplicationServiceTest` 16 支全過。
   §11 補 #11~#16、§11.1 實測證據；§12 #1 改列「已實作（核心），僅外部 adapter 待契約」。
   品質關卡全過（空殼／mock／假測試 0 命中、OpenAPI 0 錯誤）。狀態「待核定」→「已實作」。 |
| 1.0 | 2026-09-20 | WorkBuddy AI | 初版。依 BEAM PMO 2026-09-20「進件系統有缺口」之指示建立：§3 現況缺口盤點（6 項）、§4 轉態守門三道（領域／DDL CHECK／樂觀鎖）、§5 徵信 port 與 **fail-closed**（徵信不可用轉 `REFER`、**不自動核准亦不自動婉拒**）、§6 核准序號、§7 製卡銜接與**商品參數化**、§8 新增兩端點、§9 不新增錯誤碼、§11 測試（#5「徵信拋例外不核准」為核心，禁用假 adapter）。連動 `SDD-005` 升 1.4 新增 §12 申請案件狀態機 |
