CR #201 » SCS-017_報表服務程式設計規格.md
SCS-017 報表服務(report-service)程式設計規格
| 項目 | 內容 |
|---|---|
| 文件編號 | SCS-017 |
| 版本 |
1.6(GOV-007 §4:§6.2 之下載「作業未就緒」錯誤碼定案——由暫用之 CC-PLT-3001(非法狀態轉換)改為另立之 CC-PLT-3003(409 資源尚未就緒),語意區隔;錯誤碼 123 → 124。前版 1.5(HANDOVER #A-109:新增 §6.2 報表檔案下載端點(代理端點)——BEAM PMO 裁定採方案 B;§8.1.4 定案) |
| 狀態 | 已核定(規格先行) |
| 對應需求 |
SYS-1(Report Generation Tool)、ACQ-4.5(商店報送與報表)、ISS-2.11(信用卡報送與報表)、DEB-3.4(DEBIT 卡報送與報表) |
| 服務埠號 | 待骨架產生時依 CSP-006 §4 分配(自 8081 起編) |
| 套件根 | com.beam.cardcore.rpt |
| 權威 schema |
CC_RPT(尚未建表;報表以 rpt Postgres 讀模型為主) |
| 關聯文件 |
SDD-006 §7、BRD-002、GOV-005
|
1. 對應需求
| FR 編號 | 需求名稱 | 來源 |
|---|---|---|
SYS-1 |
Report Generation Tool 能力 | BRD-002 |
ACQ-4.5 |
商店報送與報表(收單) | BRD-002 |
ISS-2.11 |
信用卡報送與報表 | BRD-002 |
DEB-3.4 |
DEBIT 卡報送與報表 | BRD-002 |
1.1 上層設計依據(本規格不重複這些圖,僅引用)
| 圖種 | 文件 | 數量(實測) | 本服務相關 |
|---|---|---|---|
| ER-Diagram | SDD-001_領域模型與ER-Diagram |
16 個 erDiagram
|
⚠️ 本服務 schema 尚未建表(SDD-001 §3 僅涵蓋 14 個 bounded context;報表主體位於 rpt Postgres 讀模型) |
| DFD | SDD-002_DFD與流程分解 |
10 個 flowchart | 報表產生流 |
| Sequence | SDD-003_Sequence-Diagrams |
15 個 sequenceDiagram
|
報表作業時序 |
| 狀態機 | SDD-005_狀態機設計 |
10 個 stateDiagram
|
⚠️ 報表作業狀態待確認 |
| API Contract |
SDD-006 + contracts/openapi/report-service.yaml
|
17 份 | 本服務 2 支端點 |
2. 服務職責與邊界
承作:
- 報表定義(
ReportDefinition:欄位、篩選、排程、格式) - 報表作業(
ReportJob:非同步產生、狀態、輸出) - 報送(監管/商店報送,含
ACQ-4.5/ISS-2.11/DEB-3.4)
不做(屬他服務):
- 交易處理 → 各領域服務
- 即時查詢 → 各領域服務 API
3. 領域模型
- 聚合(依
services.yaml):ReportDefinition(報表定義)、ReportJob(報表作業) - 值物件:
ReportCode、ReportStatus、OutputFormat(PDF/CSV/EXCEL) - 狀態(設計意圖):
ReportJob.status ∈ {QUEUED, RUNNING, COMPLETED, FAILED}(待SDD-005正式化)
4. 程式結構
| 套件/類別 | 職責 | 對應需求 |
|---|---|---|
domain/model/ReportDefinition ReportJob
|
聚合與值物件 |
SYS-1/ACQ-4.5/ISS-2.11/DEB-3.4
|
domain/port/ReportRepository |
持久化埠(待建表) | — |
application/ReportService |
定義/作業/報送 | SYS-1 |
infrastructure/jdbc/*RepositoryImpl |
JDBC 實作(待建表) | — |
interfaces/rest/ReportController |
REST 端點 | SYS-1 |
5. 資料模型
CR-017裁定 D(BEAM PMO 2026-09-22):C-7 範圍含 Postgres 讀模型。本節為設計權威,
實體交付見 §5.4(V2遷移 +db/migration-postgres/V1)。
5.1 架構:作業指標(Oracle)+ 讀模型(Postgres)
| 存放 | 內容 | 理由 |
|---|---|---|
Oracle CC_RPT |
REPORT_DEFINITIONS(報表定義)/REPORT_JOBS(作業指標:狀態、筆數、輸出參照) |
作業狀態為權威事務資料(契約直接對應);與 CSP-006 §2.4「Oracle 為權威 OLTP」一致 |
Postgres rpt |
讀模型表(報表主體) | CQRS 讀側(SCS-017 §7):報表查詢不佔用權威 OLTP |
5.2 讀模型(Postgres rpt,實測 schema 已存在、0 表)
| 表 | 欄位 | 說明 |
|---|---|---|
rpt.daily_auth_summary |
business_date DATE/channel/tx_type/decision/tx_count BIGINT/total_amount NUMERIC(19,0)/currency CHAR(3)/refreshed_at TIMESTAMPTZ |
每日授權彙總(DAILY_AUTH_SUMMARY);主鍵=(日 × 通路 × 交易型別 × 決策),冪等 upsert
|
⚠️ CQRS 讀側首例:實測
evt/proj/rpt三 schema 由ops/local/init/postgres/01-init.sql
建立,惟迄今無任何服務使用(grep jdbc:postgresql全庫 0 命中)——本服務為首個接線者,
其 DataSource/Flyway 配置方式即為後續讀側之慣例(見 §5.4)。
5.3 投影(Oracle → Postgres)
SCS-017 §7 原載「讀模型與寫側最終一致」,惟同步機制未實作(GOV-006 4.8 W-2 Kafka 消費端 ⬜)。
本期採 批次投影(排程自 Oracle 權威彙總後 upsert 讀模型)為 stand-in——
不阻塞、可實測、可重跑,且與 #A-79 之排程慣例一致;待 Kafka 消費端落地後可改為事件驅動。
5.4 交付
| 項 | 位置 |
|---|---|
| Oracle 作業指標 |
V2__report_definitions_and_jobs.sql(+report_job_no_seq+內建定義 DAILY_AUTH_SUMMARY) |
| Postgres 讀模型 |
db/migration-postgres/V1__rpt_read_model.sql(獨立 Flyway 實例,schemas("rpt")) |
| 輸出 |
${cardcore.report.output-dir}(預設 ops/local/logs/reports);downloadUrl 為 file://
|
| ⚠️ 誠實揭露 |
物件儲存「基礎設施已就緒、程式尚未接線」(2026-10-01 更新,HANDOVER #A-106):本地物件儲存已建置並實測(Garage v2.4.1,S3 API 埠 3900、bucket cardcore-artifacts,見 SAD-006 §3.2)——惟本服務尚未接線,downloadUrl 仍為 file://。⚠️ 併更正:原載「實測 compose 無 MinIO」仍成立,但結論已變——不是「無替代方案」,而是 MinIO 開源版已封存(官方回 410)、改用 Garage。XLSX/PDF 需額外函式庫,未支援(請求即回 FAILED 並載明原因,非靜默) |
6. API 設計(來自 contracts/openapi/report-service.yaml)
| 端點 | 方法 | 說明 | 對應 FR |
|---|---|---|---|
/api/v1/report-jobs |
POST | 報表作業提交 |
SYS-1/ACQ-4.5/ISS-2.11/DEB-3.4
|
/api/v1/report-jobs/{jobId} |
GET | 報表作業查詢 | SYS-1 |
/api/v1/report-jobs |
GET | 報表作業清單(最近 N 筆;2026-09-30 補建,見 §6.1) |
SYS-1/ACQ-4.5/ISS-2.11/DEB-3.4
|
/api/v1/report-jobs/{jobId}/download |
GET | 報表檔案下載(代理端點;2026-10-01 補建,見 §6.2) |
SYS-1/ISS-2.11
|
錯誤碼:
404找不到作業/定義、400參數錯誤、409重複作業。
6.2 報表檔案下載端點(代理端點;2026-10-01 補建,HANDOVER #A-109)
緣由:
W-5階段二接線後,DOWNLOAD_URL存的是物件鍵(§8.1.4),
但如何下載尚未實作。BEAM PMO 2026-10-01 裁定採方案 B(代理端點)——
理由:本案為銀行核心系統,報表可能含敏感資料;presigned URL 會把授權交給物件儲存
(URL 一旦外流,有效期內人人可載),與全案「一律經服務認證」之架構(SAD-005 §3)不一致。
GET /api/v1/report-jobs/{jobId}/download(回應檔案位元組,200)
| 項目 | 規格 |
|---|---|
| 回應 |
非 ApiResponse 封套——直接回檔案內容(application/octet-stream) |
Content-Disposition |
attachment; filename="<jobNo>.<ext>"(供瀏覽器另存) |
Content-Type |
依格式(CSV → text/csv; charset=utf-8;JSON → application/json; charset=utf-8) |
| 認證 | 受本服務認證與授權保護(與其他端點一致)——此即方案 B 之核心價值 |
行為要求:
- 唯讀——僅取回,不觸發產生。
- ⚠️ 作業須為
COMPLETED:QUEUED/RUNNING無檔案可下載 →409CC-PLT-3003(資源尚未就緒)(不得回空檔假裝成功)。 - ⚠️
FAILED亦無檔案 → 同樣409CC-PLT-3003(並於訊息載明作業失敗原因)。 -
作業不存在 →
404CC-PLT-4040。 - ⚠️ 物件不存在(鍵在但物件儲存查無) →
404——如實回報,不回空檔:
這是「DB 說有、儲存說沒有」的不一致,須讓人看見(比照CSP-001 §8 B2不靜默)。 - 不快取。
✅
409錯誤碼已定案(BEAM PMO 2026-10-01 裁定;GOV-007 §4):
原暫用CC-PLT-3001(非法狀態轉換)——因SDD-006 §3.4之既有 4 個409平台碼
(CC-PLT-2001/2002/3001/3002)皆為「狀態機轉換」語意。
惟本情境「資源尚未就緒」(QUEUED/RUNNING/FAILED)與「狀態機非法轉換」語意不同 →
已於SDD-006 §3.4另立CC-PLT-3003(409 資源尚未就緒) 並回填登錄表
(錯誤碼 123 → 124);本端點改用之。
⚠️
DOWNLOAD_URL仍存物件鍵(不變)——下載由此端點動態取回,
故資料庫欄位不必隨 URL 效期變動,且換物件儲存後端不影響下載路徑。
⚠️ 未竟:(i) 無範圍請求(Range)支援——大檔續傳俟需求確認;
(ii) 無下載稽核留痕(誰下載了什麼)——報表可能含敏感資料,建議另立 CR 補稽核。
6.1 報表作業清單端點(2026-09-30 補建,HANDOVER #A-104)
緣由:
SDD-007 §5.4.26之桶 C「批次作業監控」(/system/batch)——
bff-web依SCS-020 §9.9聚合四服務之批次執行紀錄,需各服務提供「列出批次」端點。
⚠️ 實測揭露:/api/v1/report-jobs原僅有POST(送交)——GET實測回 404。
GET /api/v1/report-jobs?limit=N(回應 ReportJobSummary[],200)
| 參數 | 型別 | 說明 |
|---|---|---|
limit |
integer(可選) | 回傳筆數上限。預設 20,上限 100 |
回應欄位(ReportJobSummary):
| 欄位 | 說明 |
|---|---|
jobId |
作業識別碼(UUID) |
jobNo |
作業編號(RPTJ + 年月 + 連號,可稽核) |
reportCode |
報表代碼 |
format |
輸出格式(CSV/JSON/…) |
status |
QUEUED/RUNNING/COMPLETED/FAILED
|
rowCount |
產出列數(未完成時為 0) |
downloadUrl |
輸出參照(本期為 file://<絕對路徑>,見 §10) |
errorDetail |
失敗原因(非 FAILED 時為 null) |
startedAt/finishedAt
|
開始/完成時刻(未開始/未完成者為 null) |
⚠️ 為何不沿用既有
ReportJobView:該 DTO 為受理/單筆查詢回應之形狀,
未含jobNo/reportCode/format——清單需可辨識「這是哪一支報表」與時間錨點
(SCS-020 §9.9.4 #3)。故另立清單專用 DTO,不動既有已驗證之契約。
行為要求:
-
唯讀——僅查詢,不觸發產生(觸發為
POST /report-jobs)。 -
依
startedAt遞減(最近送交者在前;startedAt為null之QUEUED置後)。 -
無資料回
200+ 空陣列——非404。 -
不快取(
SCS-020 §9.9.4 #4)。 - ⚠️ 與
POST /report-jobs同路徑、不同方法——須明確@GetMapping/@PostMapping。
錯誤碼:
400參數錯誤(limit超出1..100)。無404情境。
未竟:
-
不支援分頁游標(僅取最近 N 筆);不含
parameters原文(清單僅需辨識與狀態;
參數原文仍由單筆查詢取得)。
7. 關鍵邏輯
-
非同步產生:
ReportJob入隊,common-batch批次產出,避免阻塞。 -
讀模型:報表資料源自
rptPostgres(CQRS 讀側),與寫側(CC_*)最終一致。 - 報送:監管/商店報送依定義排程,輸出於物件儲存。
CR-017(BEAM PMO 2026-09-22 裁定 D)後定案之實作要點
-
非同步(實作方式):受理僅入隊(
QUEUED)即回 202;實際產生由排程取件
(ReportJobScheduler)→RUNNING→COMPLETED/FAILED——狀態由流程推進。 -
讀模型投影(stand-in):
ReportProjectionScheduler以追趕視窗「N 日前 ~ 昨日」
自 Oracle 權威彙總後 upsert 至rpt.daily_auth_summary(冪等、可回補)。
⚠️ 正規機制為事件驅動(W-2Kafka 消費端 ⬜);本地以跨 schema 授權暫代(見 §10)。 -
產生器:
DAILY_AUTH_SUMMARY→ 讀讀模型 → 輸出 CSV/JSON(金額為分);
XLSX/PDF未支援 → 作業FAILED並載明原因(不產空檔、不假裝成功)。 -
冪等:受理以冪等鍵派生主鍵(
UUID v3,前綴rpt:job:)——同鍵重送回同一作業。 -
失敗可稽核:
FAILED必載errorDetail(領域層強制,未載即拒)。
8. 外部依賴與降級
| 依賴 | 失敗處理(Stand-in) |
|---|---|
rpt Postgres 讀模型、common-batch
|
報表為非同步;來源延遲僅影響報表即時性,不影響交易 |
8.1 物件儲存(輸出媒體)——2026-10-01 補建(HANDOVER #A-107)
緣由:
W-5之本地替代方案已建置並實測(Garagev2.4.1,SAD-006 §3.2),
本節為程式接線之規格——規格先行,先立本節再動程式。
8.1.1 契約:S3 API(不綁特定實作)
本服務只依賴 S3 API(endpoint + region + 靜態憑證),不依賴任何 Garage 專屬特性。
故本地後端(Garage)與正式環境(客戶之企業物件儲存)可互換,程式不動。
| 組態 | 值(本地) |
|---|---|
| endpoint | http://localhost:3900 |
| region |
cardcore(由 config/garage.toml 之 s3_region 決定,非 AWS 固定值) |
| bucket | cardcore-artifacts |
| 憑證 |
GARAGE_ACCESS_KEY/GARAGE_SECRET_KEY(環境變數,不寫入組態檔) |
| 物件鍵前綴 |
reports/<jobNo>.<ext>(以 jobNo 為鍵——可稽核、可追溯至作業) |
8.1.2 分層:埠(application)+ 實作(infrastructure)
| 角色 | 類別 | 說明 |
|---|---|---|
| 埠 | application/ObjectStoragePort |
本輪只有 put(key, bytes, contentType) |
| 實作 |
infrastructure/storage/S3ObjectStorageAdapter(+S3StorageConfig) |
AWS SDK v2 for Java;沿用 AccountOverviewPort 之慣例
|
⚠️
get/delete本輪「不」納入埠(規格與實作一致):本輪範圍為「上傳 + 存鍵」,
取回/刪除俟「下載呈現方式」(§8.1.4)定案後再補——
依「不預先加未使用之介面方法」之原則,避免死碼。
⚠️
S3StorageConfig之 fail-closed:憑證刻意不給預設值——缺任一項即啟動期失敗
(IllegalStateException),不靜默略過、不退回本地檔案(§8.1.5)。
endpoint/region/bucket則給本地預設值(比照POSTGRES_URL之慣例)。
⚠️path-style預設true——本地localhost必須用路徑式尋址
(虛擬主機式會把 bucket 名當前綴,cardcore-artifacts.localhost:3900無法解析);
正式環境若需虛擬主機式,改組態即可,程式不動。
⚠️ 為何要埠:與
KeyProvider/ServiceClientHttpClient同一思路——
換後端(Garage → 客戶企業儲存)、換 SDK、或改為測試替身時,應用層不動;
且應用層得以手寫 fake 測試(無須起 S3)。
8.1.3 輸出流程(RUNNING → COMPLETED)
① 產生內容(CSV/JSON,記憶體)
② put(key, bytes, contentType) → 上傳物件儲存
③ complete(rowCount, key, now) → 將「物件鍵」寫入 REPORT_JOBS.DOWNLOAD_URL
⚠️ 順序不可顛倒:先上傳成功、才標
COMPLETED。
若先標完成再上傳,上傳失敗將留下「已完成但沒有檔案」的作業——
那是假成功,比失敗更難查(比照#C-42「零產出必須可區分」之教訓)。
8.1.4 ⚠️ downloadUrl 之語意(關鍵決策——本節之核心)
REPORT_JOBS.DOWNLOAD_URL 是寫入資料庫的欄位,故:
⚠️ 不得存入 presigned URL——presigned URL 有時效,
存進 DB 後一旦過期即失效,而作業紀錄不會再更新(COMPLETED為終態)。
這會產生「資料庫裡有一條永遠打不開的連結」的缺陷。
故:DOWNLOAD_URL 存「物件鍵」(如 reports/RPTJ20261001000001.csv),
不存 URL——物件鍵永久有效,且下載呈現方式(見下)可日後更換而不動資料。
下載之呈現方式(✅ 2026-10-01 BEAM PMO 裁定採 B):
| 方案 | 做法 | 優點 | 缺點 |
|---|---|---|---|
| A. 動態 presigned URL | 查詢時由 ObjectStoragePort 產生短效 URL |
改動最小 | URL 會過期(前端顯示的字串有時效);授權交給物件儲存——URL 一旦外流,有效期內人人可下載 |
| B. 代理下載端點(✅ 採用) | 新增 GET /api/v1/report-jobs/{jobId}/download,由服務向物件儲存取回後回傳 |
受本服務認證與授權保護(與其他端點一致);URL 永久有效;不洩漏物件儲存憑證 | 需新增端點(契約+前端+測試);檔案流量經服務 |
裁定理由:本案為銀行核心系統,報表可能含敏感資料;把授權交給物件儲存的 presigned URL,
與全案「一律經 gateway 認證」之架構不一致(SAD-005 §3)→ 採 B。
端點規格見§6.2。
8.1.5 降級政策
| 情境 | 行為 |
|---|---|
| 物件儲存不可用(連線失敗/逾時) | 該作業標 FAILED 並載明原因——不得退回寫本地檔案(否則「已上傳」與「寫本機」兩種狀態混雜,日後無法辨識) |
未組態 cardcore.storage.*(endpoint 空白) |
啟動期即失敗(fail-closed),不靜默略過——比照 CR-010 之出站憑證政策 |
⚠️ 不再有
file://fallback:接線後移除本地檔案路徑,避免「兩種輸出媒體並存」。
此為刻意的破壞性變更——SCS-017 §10.1之 stand-in 記載同時廢止。
8.1.6 依賴(已查證 + 已 spike 驗證)
| 項目 | 值 |
|---|---|
| SDK |
software.amazon.awssdk:s3:2.55.9(Maven Central 實查 :s3 與 :bom 皆存在;版本鎖於 gradle/libs.versions.toml) |
| 傳遞相依 |
:s3 之 sync 客戶端預設即 url-connection-client(JDK 內建)→ 不需 Apache HttpClient/Netty,與 Spring 之 HTTP 疊層無衝突
|
| 驗證 | ✅ 編譯 + 執行期皆通過(version-compat-verification skill 步驟 4/5)——見下 |
8.1.7 ⚠️ ★ S3 相容性之兩個地雷(實測踩到並修除,必讀)
這兩項編譯期不會報錯、對 AWS S3 也無感,但在 S3 相容實作(Garage/MinIO 等)
一律失敗——是典型的「靜默相容性地雷」。
地雷 ①:SDK 2.30 起預設「盡量加校驗」+ aws-chunked 串流簽章
| 項目 | 內容 |
|---|---|
| 症狀 | 上傳回 400:Bad request: Invalid payload signature (Service: S3, Status Code: 400)
|
| 根因 | SDK 2.30 起 requestChecksumCalculation 預設為 WHEN_SUPPORTED,會附加 x-amz-checksum-* trailer;搭配 aws-chunked 串流簽章,S3 相容實作不支援
|
| 修法 |
S3Configuration.chunkedEncodingEnabled(false) + client 層 requestChecksumCalculation(WHEN_REQUIRED)/responseChecksumValidation(WHEN_REQUIRED)——即 SDK 2.30 之前的預設值,對 AWS S3 亦完全有效
|
地雷 ②:校驗設定「只能在一處」
| 項目 | 內容 |
|---|---|
| 症狀 |
啟動期失敗:IllegalStateException: Checksum behavior has been configured on both S3Configuration and the client/global level. Please limit checksum behavior configuration to one location.
|
| 根因 | 於 S3Configuration 亦設 checksumValidationEnabled,與 client 層之校驗設定衝突(SDK 明文禁止) |
| 修法 | 校驗只在 client 層設;S3Configuration 只留尋址方式(pathStyleAccessEnabled)與 chunkedEncodingEnabled
|
8.1.8 ★ 真機驗證(2026-10-01,HANDOVER #A-107)
| 驗證項 | 結果 |
|---|---|
| 服務啟動 | ✅ S3StorageConfig 記錄「物件儲存(S3 API)已建立:endpoint=http://localhost:3900 region=cardcore pathStyle=true」 |
送出作業(POST /report-jobs,CSV) |
✅ 202、QUEUED
|
| 排程取件 | ✅ COMPLETED、rowCount=7
|
DOWNLOAD_URL 之值 |
✅ reports/RPTJ202610000006.csv(物件鍵,非 file://) |
| 物件確實進 Garage | ✅ 以 S3 客戶端取回:ContentType=text/csv; charset=utf-8、385 bytes、內容為真實讀模型資料(表頭 + 7 列) |
| 負樣本:本機不留檔 | ✅ 近 10 分鐘內無新增本地報表檔——證實未退回 file://(§8.1.5) |
| 失敗路徑(修正前) | ✅ 亦已驗證:上傳失敗時作業標 FAILED 並載明原因(Invalid payload signature),無假成功、無本地 fallback
|
9. 測試案例(對應 TRP-001)
- 報表定義/作業/查詢(
SYS-1) - 商店/信用卡/DEBIT 報送(
ACQ-4.5/ISS-2.11/DEB-3.4)、格式與排程
10. 已知限制(誠實揭露)
-
→ 已建(CC_RPT尚未建表V2__report_definitions_and_jobs.sql;SDD-001 §3.16已補 DDL 章節)。 - 報表作業狀態機待
SDD-005正式化(本期狀態轉換由領域層守衛,未建模為正式狀態機)。 -
→ 已產生,埠號 8098,已啟動實測。report-service骨架與埠號尚未產生(規格先行)
CR-017 執行後新增之限制(2026-09-22)
-
物件儲存已接線,惟「下載呈現」尚未提供(2026-10-01,
HANDOVER #A-107):
輸出已改走物件儲存(S3 API)(本地 Garagev2.4.1,見SAD-006 §3.2),
DOWNLOAD_URL存物件鍵(非 URL,理由見§8.1.4);
⚠️ 已移除本地檔案(file://)fallback(§8.1.5)。
仍待:下載呈現方式(方案 A 動態 presigned/方案 B 代理端點,§8.1.4)待 BEAM PMO 裁定——
故目前前端只顯示物件鍵文字,尚無法直接下載。
正式環境為客戶之企業物件儲存(契約為 S3 API,換後端只需改組態、程式不動)。 -
投影之來源以跨 schema 讀取暫代(
GRANT SELECT ON CC_AUTH.AUTHORIZATIONS TO CC_RPT,
ops/local/init/oracle/12-dev-report-projection-grant.sql)——本地 stand-in:
正規為事件驅動(W-2⬜);經 API 亦不可行(authorization-service之allowed-callers
依SAD-002 §5為空集合)。正式環境不得如此(破壞服務邊界)。 -
僅一支報表:
DAILY_AUTH_SUMMARY;其餘報表(監管/商店報送)未實作。 -
僅兩種格式:
CSV/JSON;XLSX/PDF未支援(需額外函式庫)。 -
無排程報送:
REPORT_DEFINITIONS之排程欄位(Cron)未納入本期(契約無排程端點)。 - 無預設區間策略:參數未提供時取讀模型全部資料(避免產出看似正確卻空無一列之報表)。
-
REPORT_DEFINITIONS無管理端點:定義由遷移內建;契約未定義 CRUD。 -
common-batch未使用:SCS-017 §7原載「common-batch批次產出」,
本期以服務內排程實作(common-batch尚未落地)。
11. 修訂記錄
| 版本 | 日期 | 修訂者 | 說明 |
|---|---|---|---|
| 1.6 | 2026-10-01 | WorkBuddy AI |
§6.2 之下載「作業未就緒」錯誤碼定案(GOV-007 §4;BEAM PMO 裁定)——由暫用之 CC-PLT-3001(非法狀態轉換)改為另立之 CC-PLT-3003(409 資源尚未就緒)。緣由:「資源尚未就緒」(QUEUED/RUNNING/FAILED)與「狀態機非法轉換」語意不同;已於 SDD-006 §3.4 補登 CC-PLT-3003(錯誤碼 123 → 124)並重生 ErrorCodes.java(--force);ReportJobService.download 與 ReportJobServiceTest 同步。★ 解除 v1.5 所載之「語意落差」
|
| 1.5 | 2026-10-01 | WorkBuddy AI |
新增 §6.2「報表檔案下載端點(代理端點)」(HANDOVER #A-109)——BEAM PMO 裁定採方案 B(代理端點),§8.1.4 由「待裁定」改為定案。規格先行:立 §6.2 → 改 gen_openapi.py(新增 BINARY_RESP 哨兵以產生非封套之二進位回應)→ 契約 86 端點、0 錯誤 → 實作(ObjectStoragePort.get + S3ObjectStorageAdapter.get + ReportJobService.download + controller)→ 前端 downloadReportFile + 下載鈕 → 真機驗證。★ 設計要點:(i) 回應為檔案位元組(application/octet-stream + Content-Disposition),全案唯一非封套回應;(ii) 追蹤碼改以 X-Trace-Id 回應標頭回傳(回應體已非封套,否則此路徑追蹤斷掉);(iii) 三種「沒有檔案」分開講:作業不存在→404、作業未完成/失敗→409、物件查無→404 如實回報不一致(不回空檔)。★ 併載錯誤碼語意落差之誠實揭露:409 之既有平台碼皆為「狀態機轉換」語意,本情境以最接近之 CC-PLT-3001 表達,不為單一端點擴充登錄表;若此類情境增多建議另立 CC-PLT-3003。真機驗證:QUEUED→409 CC-PLT-3001;完成後→200、Content-Disposition 正確、下載內容與物件儲存內之原始檔逐位元組一致(SHA-256 相同);作業不存在→404、非 UUID→400 |
| 1.4 | 2026-10-01 | WorkBuddy AI |
新增 §8.1「物件儲存(輸出媒體)」——程式接線(HANDOVER #A-107)。規格先行:立 §8.1 → 加依賴(awssdk:s3:2.55.9,Maven Central 實查)→ 實作埠與 S3 實作 → 真機驗證。設計要點:埠(application/ObjectStoragePort)+ 實作(infrastructure/.../S3ObjectStorageAdapter)——應用層只認物件鍵,換後端程式不動;只依賴 S3 API。★ downloadUrl 語意定案:DOWNLOAD_URL 存物件鍵(非 URL)——presigned URL 會過期,存進 DB 即成死連結(§8.1.4)。⚠️ 移除 file:// fallback(避免兩種輸出媒體並存,§8.1.5);憑證 fail-closed(缺則啟動期失敗)。★ 併載 S3 相容性兩個地雷(實測踩到並修除):① SDK 2.30 起預設校驗+aws-chunked → S3 相容實作回 400 Invalid payload signature(修:關閉 chunked + 校驗改 WHEN_REQUIRED);② 校驗只能在一處設,兩處並設會啟動期失敗。真機驗證:作業 COMPLETED、DOWNLOAD_URL=reports/RPTJ202610000006.csv、物件確實可自 Garage 取回(385 bytes)、本機未留檔
|
| 1.3 | 2026-10-01 | WorkBuddy AI |
物件儲存狀態更正(HANDOVER #A-106):§5.4/§10.1 原載「物件儲存未部署」→ 更正為「基礎設施已就緒、程式尚未接線」。本地物件儲存已建置並實測(Garage v2.4.1,S3 API 埠 3900、region cardcore、bucket cardcore-artifacts,見 SAD-006 §3.2);惟本服務尚未接線,downloadUrl 仍為 file://。★ 併載選型更正:原「無 MinIO」之觀察仍成立,但結論已變——MinIO 開源版已封存不再維護(官方下載站 410 Gone),故改採 Garage。接線所需 Java SDK 已查證 awssdk:s3:2.55.9(未做 spike,不得視為已驗證) |
| 1.2 | 2026-09-30 | WorkBuddy AI |
新增 §6.1「報表作業清單端點」(GET /api/v1/report-jobs?limit=N)——解鎖 SDD-007 §5.4.26 桶 C「批次作業監控」(SCS-020 §9.9)。⚠️ 併載實測揭露:該路徑原僅有 POST、GET 回 404。新增 ReportJobSummary(含 jobNo/reportCode/format/時間錨點)——不沿用既有 ReportJobView(受理/單筆查詢形狀),不動既有已驗證之契約。limit 預設 20/上限 100;無資料回空陣列非 404 |
| 1.0 | — | 開發團隊 | 初版(規格先行) |
| 1.1 | 2026-09-22 | WorkBuddy AI |
CR-017 裁定 D 執行完成(含 Postgres 讀模型)——①**§5 改寫為設計權威(Oracle 作業指標/Postgres 讀模型之分工、rpt.daily_auth_summary 定義、批次投影 stand-in、交付清單);②§7** 新增實作要點(非同步語意、投影追趕視窗、產生器支援矩陣、冪等、失敗可稽核);③**§10** 移除兩項已解除限制、新增 8 項(物件儲存未部署/跨 schema stand-in/僅一支報表/僅兩種格式/無排程報送/無預設區間/無定義管理端點/common-batch 未使用);④補建本修訂記錄區(原文件欠缺)。單測 16 例 0 失敗;真機 e2e 六項 |