CR #201 » CSP-006_技術棧與開發環境基線.md
CSP-006 技術棧與開發環境基線
| 項目 | 內容 |
|---|---|
| 文件編號 | CSP-006 |
| 版本 | 1.0 |
| 狀態 | 已核定 |
| 撰寫者 | SA / Tech Lead |
| 審查者 | PMO / Security Architect / SRE |
| 對應需求 | NFR-SYS 群組、NFR-QUAL 群組;SAD-001 §1.2 架構原則、SAD-006 §1 雲原生原則 |
1. 目的與適用範圍
本文件為 cardcore 全案的技術棧單一真實來源(Single Source of Truth),回答三個問題:
- 用什麼技術——語言、框架、資料庫、訊息、觀測、測試工具,逐項鎖定版本。
- 在哪裡跑——本地、SIT、UAT、PERF、PROD 各環境的組態基線與切換方式。
- 與既有文件的落差——本文件生效後,哪些已核定文件須回改(見 §6)。
適用範圍:後端 17 個微服務、平台元件(API 閘道、BFF、共用程式庫)、React 前端、
建置與部署腳本、CI 品質關卡。
與 CSP-001 的關係:CSP-001 §1 載明「正式開發環境由客戶於程式撰寫階段拍板,本文件以
Java 21 + Spring Boot 3.2 為建議基線」。客戶已拍板,故本文件取代 CSP-001 §1 之建議基線敘述;
CSP-001 之架構、命名、禁止事項、品質門檻全部繼續適用(該文 §1 後段已明文授權此種分工)。
2. 技術棧基線
版本鎖定原則:下表版本為凍結值。任何升級須走 §7 變更控制,不得由 Coder 自行調整。
所有版本皆以 2026-09-18 之 Maven Central / Docker Hub 實際可用版本為準,非推測值。
2.1 語言與執行環境
| 項目 | 鎖定版本 | 選定理由 |
|---|---|---|
| JDK | Temurin 21.0.12.1+1 LTS | LTS,支援至 2031+;與 CSP-001 基線一致;銀行案生態最穩 |
| 語言 | Java 21 | CSP-001 §5 指定之靜態分析工具鏈(Checkstyle/SpotBugs/PMD)為 Java 原生;金融業人才池與外包團隊上手成本最低 |
| 語言特性使用界線 | 可用:record、sealed、pattern matching、text block 限用:虛擬執行緒需經 TL 同意後啟用 |
虛擬執行緒與 Oracle JDBC/Hibernate 之 pinning 行為需實測,不得預設可用 |
決議紀錄(Java vs Kotlin):CSP-002 §3 之服務骨架路徑原寫
src/main/kotlin/,與 CSP-001 §5
之 Java 工具鏈矛盾。經決議採 Java 21,CSP-002 §3 須回改(見 §6 第 2 項)。
2.2 應用框架
| 項目 | 鎖定版本 | 備註 |
|---|---|---|
| Spring Boot | 4.1.1 | 2026-06 起最新穩定線;最低 Java 17、最高相容 Java 26 |
| Spring Framework | 7.0.9 | Boot 4.1.1 之內含版本 |
| Spring Cloud | 2025.1.3 | ⚠️ 見下方風險說明 |
| Spring Security | 7.0.x | OAuth2 Resource Server、方法級授權 |
| Spring Data JPA / Hibernate | 7.x | 寫側聚合持久化 |
| jOOQ | 3.20.x | 讀側複雜查詢(Oracle 方言、報表);要求 Java 21,已滿足 |
| Jackson | 3.1.x(tools.jackson) |
Boot 4 已由 com.fasterxml.jackson 遷移至 tools.jackson,Coder 勿混用兩套 |
⚠️ Spring Cloud 版本風險(必須在 Sprint 0 驗證)
Maven Central 事實:spring-cloud-dependencies最新為 2025.1.3,其 POM 內宣告
spring-boot.version = 4.0.8——即官方尚未有對齊 Spring Boot 4.1 的 release train
(下一班為 2026.0,尚未發布)。已執行實測(2026-09-18):
- 以 Boot 4.1.1 + Cloud 2025.1.3 解析依賴並編譯 → 通過(Framework 7.0.9、spring-cloud-commons 5.0.3)
- 執行期啟動驗證結果見 §2.2.1
決策:採 Boot 4.1.1 + Cloud 2025.1.3,並於 Sprint 0 設版本相容性關卡(§5.2)。
若關卡未過,降級組合為 Boot 4.0.8 + Cloud 2025.1.3(官方對齊,但 Boot 4.0 OSS 支援至 2026-12-31)。
2.2.1 版本相容性驗證紀錄(2026-09-18 實測)
| 驗證項 | 方法 | 結果 |
|---|---|---|
| 依賴解析一致性 | Gradle runtimeClasspath 解析 |
✅ 通過,無版本衝突 |
| 編譯 |
gradle compileJava(Java 21 toolchain) |
✅ 通過 |
| 執行期上下文啟動 |
gradle bootRun,載入 web + actuator + OpenFeign + Resilience4j + Stream-Kafka + Vault 六項 starter |
✅ 通過——Tomcat 啟動、Started SpikeApp in 3.975 seconds,無 BeanCreationException/NoSuchMethodError/NoClassDefFoundError
|
| 實際解析版本 | — | Boot 4.1.1/Framework 7.0.9/spring-cloud-commons 5.0.3/spring-cloud-context 5.0.3/Jackson 3.1.5 |
實測結論:Spring Boot 4.1.1 與 Spring Cloud 2025.1.3 之組合,在編譯期與執行期均可正常運作,
未出現 Spring Cloud 因對齊 Boot 4.0.8 而導致之 Bean 建立失敗。驗證範圍限制(誠實揭露):本次啟動驗證已停用
spring.cloud.vault與spring.cloud.config
(本地無對應服務)。此二者之執行期行為、以及 Spring Cloud Gateway 之實際路由,
仍須於 Sprint 0 關卡 G-1 以完整組態複驗。
2.3 建置與工具鏈
| 項目 | 鎖定版本 | 備註 |
|---|---|---|
| Gradle | 9.7.1 | 主建置工具(CSP-002 §3 之 build.gradle.kts、CSP-001 §5 之 ./gradlew check)。Boot 4.1 要求 Gradle 8.14+ 或 9.x |
| Gradle Wrapper | 每個服務必附 | CI 一律用 wrapper,不依賴機器上的 Gradle |
| Maven | 3.9.9 | 備援;本專案不作為主建置工具 |
| Node.js | 22.22.2 LTS | 前端建置 |
| pnpm | 12.4.2 | 前端套件管理(經 corepack,不污染全域) |
| Docker | 29.8.0 + Compose v5.5.1 | 本地容器環境 |
| kubectl | 1.36.1 | 叢集操作 |
| Helm | 4.3.0 | K8s manifest 封裝 |
2.4 資料層:Oracle 主 + PostgreSQL 讀側
依客戶指定「Oracle 為主,PostgreSQL 於必要時採 Hybrid DB 架構」,分工如下:
| 用途 | 資料庫 | 版本 | 理由 |
|---|---|---|---|
| 權威 OLTP:授權、帳務、額度、卡片、產品參數 | Oracle | 本地 26ai Free(23.26.0)/生產 26ai Enterprise | 客戶指定;交易強一致、金額運算須精確 |
| 平台權威資料:Saga 協調狀態 |
Oracle(CC_PLT) |
同上 | 跨服務元件,非任何單一服務所有(SDD-004 §5.3) |
| 平台共通表:Outbox、冪等紀錄、稽核軌跡 | Oracle(各服務自己的 schema) | 同上 | 依 SDD-001 §9「每服務各一份」。Outbox 必須與該服務的權威寫入同 schema 同交易(SDD-004 §4.3);集中至共用 schema 會違反 DP-01 |
| CQRS 讀模型(投影) | PostgreSQL | 18.6 | 讀多寫少、與寫庫物理隔離(SAD-003 §3.1) |
| 事件流存檔(重播/稽核) | PostgreSQL | 18.6 | 只增不改、資料量大,避免佔用 Oracle 授權 |
| 報表與分析 | PostgreSQL | 18.6 | 允許延遲,避免以 Oracle 授權承擔分析負載 |
| 快取、冪等鍵 | Redis | 8.8.2 | 高頻讀寫、TTL 語意 |
Schema 歸屬(對應 SAD-003 DP-01「一服務一 schema」):
Oracle
├── CC_AUTHORIZATION CC_CARD CC_LIMIT CC_PARTY
├── CC_PRODUCT CC_PRICING CC_POSTING CC_PAYMENT
├── CC_INSTALLMENT CC_REWARDS CC_STATEMENT CC_DISPUTE
├── CC_CLEARING CC_MERCHANT CC_MIGRATION CC_NOTIFICATION
├── CC_REPORT
│ └── 上述每個服務 schema 內各含三張平台共通表(SDD-001 §9):
│ outbox / idempotency_records / audit_trail
└── CC_PLT Saga 協調狀態(saga_instances / saga_steps,跨服務共用)
PostgreSQL
├── proj CQRS 讀模型(投影器寫、查詢側只讀)
├── evt 事件流存檔
└── rpt 報表分析
| 項目 | 選型 |
|---|---|
| 資料庫遷移 | Flyway(Oracle 與 PostgreSQL 各用對應模組;腳本須冪等,CSP-002 §5) |
| 連線池 | HikariCP(Boot 內建) |
| Oracle 驅動 | com.oracle.database.jdbc:ojdbc11 |
| 交易邊界 | 僅在 application/ 層開交易(CSP-003 §6);domain/ 層無交易概念 |
注意:本案採 Oracle 為主,SAD-003 §3 之資料庫部署圖(僅 PostgreSQL 讀寫叢集)與
SDD-001 之 ER 圖語法須回改為 Oracle 方言對照(見 §6 第 3、5 項)。
2.5 訊息與事件
| 項目 | 鎖定版本 | 用途 |
|---|---|---|
| Apache Kafka | 4.3.1(KRaft 模式,無 ZooKeeper) | 領域事件、跨服務狀態傳播(SAD-001 AP-05) |
| Spring for Apache Kafka | 隨 Boot 4.1.1 BOM | 生產者/消費者 |
| Spring Cloud Stream + Kafka Binder | 隨 Cloud 2025.1.3 | 事件綁定抽象 |
| Outbox 發送器 |
自建(Spring @Scheduled + SELECT ... FOR UPDATE SKIP LOCKED) |
Transactional Outbox(SDD-004 §4.3) |
| Schema 演進 |
schema_version 欄位向後相容(CSP-002 §5) |
契約只增不減(SAD-001 AP-08) |
| 消費者冪等 | Redis SETNX + 事件 eventId
|
至少一次投遞之去重(SDD-004 §4.1) |
為何不用 Debezium CDC:Outbox 已與權威寫入同交易,以輪詢發送即可滿足
「事件不早於資料提交」;引入 CDC 會多一層 Oracle LogMiner 相依與維運負擔,
本地開發亦無法驗證。若未來吞吐成為瓶頸,再以 ADR 評估。
2.6 Saga 與跨服務一致性
SDD-004 §5 已定義兩種 Saga 型態,本節鎖定其實作方式:
| 型態 | 適用場景(SDD-004 §5.1) | 實作方式 |
|---|---|---|
| 編排式(Orchestration) | 分期建立(佔用→入帳)、點數兌換(扣點→授權→帳務) | 自建 Saga 協調者:狀態機持久化於 Oracle CC_PLT.SAGA_INSTANCES / SAGA_STEPS,逐步推進並記錄正/補償動作 |
| 協同式(Choreography) | 請款入帳(授權→帳務→額度) | 各服務監聽 Kafka 事件自行反應;補償由反向事件觸發 |
設計要點
-
狀態機落在領域層:Saga 之狀態轉換屬業務規則,置於
domain/;不引入 Spring Statemachine
等框架相依——理由:①domain/層不得依賴框架(CSP-001 §2、SAD-001 AP-03);
② Spring Statemachine 對 Boot 4.x 之支援狀態尚未確認,不作為基線。 - 每個補償動作必須冪等(SDD-004 §5.2 對照表);發送通知類動作不補償。
-
補償失敗處理:拋
CC-PLT-5002(Saga 補償失敗),進入人工處置佇列並告警(CSP-003 §6)。 -
逾時:同步呼叫下游預設 800ms 逾時,超過即
CC-PLT-5001並觸發補償(CSP-003 §5)。
ADR:為何不自建以外之方案
| 候選 | 不採用之理由 |
|---|---|
| Axon Framework | 引入獨立 event store 與其自有持久化模型,與「Oracle 為權威來源」及 SAD-003 之 CQRS 投影設計衝突,形成兩套事件真相 |
| Temporal | 需額外部署 Temporal Server/Worker 叢集,維運成本與本案 17 服務規模不成比例 |
| Camunda / Zeebe | BPMN 引擎導向人工流程;本案 Saga 為系統間自動補償,且會新增一個狀態權威來源 |
2.7 API 與契約
| 項目 | 選型 | 備註 |
|---|---|---|
| 契約規格 | OpenAPI 3.1 |
cardcore/contracts/openapi/*.yaml(17 份)為唯一介面定義(SAD-001 AP-01) |
| 契約與實作一致性 | openapi-diff |
CI 強制,不允許實作漂移(CSP-002 §5) |
| Mock 服務 | Prism | 前端與跨組開發期使用 |
| 契約模糊測試 | Schemathesis | 依 OpenAPI 自動生成測試案例 |
| API 閘道 | Spring Cloud Gateway | 路由、限流、鑑權入口 |
| 服務間呼叫 | OpenFeign(宣告式)+ Resilience4j(斷路器、重試、艙壁) | 逾時與退避須符合 CSP-003 §5 |
2.8 前端
| 項目 | 鎖定版本 | 備註 |
|---|---|---|
| React | 18.x | 依已核定之 SDD-007 §7 與 CSP-002 §7;不用 React 19 |
| Vite | 8.x(實際 8.3.2) | 建置與開發伺服器。★ 2026-10-05 由 5.4.21 升至 8.3.2(CR-040) |
| TypeScript | 5.x(strict: true) |
禁止 any 逃逸(ESLint 規則強制) |
| 套件管理 | pnpm 12.4.2 | — |
| 伺服器狀態管理 | TanStack Query | 對接 BFF;不快取業務敏感資料於 localStorage |
| 路由 | React Router 7.x(實際 7.18.4) | ★ 2026-10-05 由 6.30.6 升至 7.18.4(CR-040) |
| 程式碼風格 | ESLint(Airbnb 子集)+ Prettier | 0 error(CSP-001 §5) |
React 版本說明:React 19 已發布,但 SDD-007 已核定為 React 18。升版屬破壞性變更,
須走 §7 變更控制並同步更新 SDD-007,本階段不變更。
★★ 2026-10-05 併發現之「規格 vs 實物落差」(
CR-040 §2):
本表原載「Vite 6.x」「React Router 7.x」,惟實際安裝者為 Vite 5.4.21/React Router 6.30.6
——規格宣告的版本從未落實。CR-040之升版實質上把實物對齊了規格(Vite 更進一步至 8.x)。
⚠️ 教訓:版本鎖定表必須與package.json/node_modules定期核對——
否則會出現「文件說 7、實物是 6」之漂移,而編譯與建置都不會報錯。
建議:納入TRP-002之 N2 批次(以工具核對規格表 vs 實際相依版本)。
2.9 測試
| 層級 | 工具 | 要求 |
|---|---|---|
| 單元測試 | JUnit 5 + AssertJ + Mockito | 不得啟動 Spring 容器(CSP-002 §6.2);覆蓋率依 CSP-005 |
| 架構測試 | ArchUnit | 強制 interfaces → application → domain ← infrastructure 依賴方向(CSP-002 §6.3),違反即建置失敗 |
| 整合測試 | Testcontainers(Oracle、PostgreSQL、Kafka) | 以真實資料庫驗證,禁止以 H2 模擬 Oracle |
| 契約測試 | Spring Cloud Contract / Pact | 消費者驅動契約 |
| API 模糊測試 | Schemathesis | 依 OpenAPI 生成 |
| 效能測試 | Gatling | 驗證 SAD-001 §1.1 之 G6(授權 P99 ≤ 200ms、≥ 1,000 TPS) |
| 覆蓋率 | JaCoCo | 門檻依 CSP-005 |
| 假測試防範 | tools/scan_faketest.py |
CI 強制(CSP-005 §6) |
⚠️ Testcontainers 與 Oracle:需拉取 Oracle 映像,首次執行較慢;本機記憶體吃緊時
可改用--profile oracle之常駐容器並以SPRING_DATASOURCE_URL指向它。
2.10 靜態分析與品質門檻
| 對象 | 工具 | 門檻 | 依據 |
|---|---|---|---|
| Java | Checkstyle + SpotBugs + PMD | 0 error、0 critical warning | CSP-001 §5 |
| TypeScript | ESLint + Prettier | 0 error | CSP-001 §5 |
| YAML | yamllint | 0 error | CSP-001 §5 |
| SQL | tools/validate_sql.py |
0 error | CSP-001 §5(⚠️ 見 §6 第 6 項) |
| 禁止模式 |
scan_scaffold.py/scan_mockdata.py/scan_faketest.py
|
0 命中 | CSP-001 §8、CSP-005 §6 |
| Mermaid 語法 | tools/validate_mermaid.py |
0 錯誤 | 客戶硬性要求 |
| 提交訊息 |
<type>(<scope>): <subject> + Refs: FR-XX-NN
|
供 GOV-004 追溯 | CSP-001 §6 |
2.11 可觀測性
| 支柱 | 本地開發 | 生產 | 備註 |
|---|---|---|---|
| 軌跡 | OTel Collector → Jaeger 1.76.0 | OTel → Tempo / Grafana | OpenTelemetry 語意約定 |
| 指標 | Prometheus 3.14.0 + Grafana 12.4.11 | 同上(HA) | 每服務暴露 /actuator/prometheus(CSP-002 §3) |
| 日誌 | OTel Collector → Loki 3.7.8 | 同上 | 結構化日誌、必含 trace_id(CSP-004) |
| 追蹤識別碼 | W3C Trace Context + correlation-id 過濾器 | 同 | 貫穿服務與事件(SAD-001 AP-09) |
| 個資保護 | Collector transform processor 遮蔽卡號/身分證 |
同 | 遙測資料不得含明文個資(SAD-005 §5) |
2.12 安全
| 項目 | 選型 | 備註 |
|---|---|---|
| 身分驗證 | OAuth2 / OIDC;本地 Keycloak 26.4,生產接行內 IdP | JWT(RS256) |
| 授權 | Spring Security 7 + 方法級 @PreAuthorize
|
最小權限(SAD-001 AP-10) |
| 密鑰管理 | 本地:.env(僅開發);生產:HashiCorp Vault 或行內密鑰管理 |
禁止密鑰進版控(SAD-006 §2.1) |
| 欄位級加密 | AES-GCM(common-security 模組) |
卡號、身分證字號(SAD-005 §5) |
| 硬體加密 | HSM 經 PKCS#11 | PIN、CVV、金鑰 |
| 相依漏洞掃描 | OWASP Dependency-Check + Trivy(映像掃描) | CI 強制 |
| 靜態安全分析 | SpotBugs(含 FindSecBugs 規則) | — |
2.13 容器與編排
| 項目 | 選型 |
|---|---|
| 映像建置 | Docker 多階段建置;執行期用 JRE(非 JDK)映像 |
| 映像基底 |
eclipse-temurin:21-jre(生產);版本以 digest 鎖定 |
| 映像不可變 | 組態一律由環境變數或組態中心注入,不打包進映像(SAD-006 §1) |
| 編排 | Kubernetes(Active-Active 雙叢集,SAD-006 §3) |
| 本地叢集 | kind 或 k3d(Docker 內)——僅供部署冒煙測試,非日常開發 |
| 封裝 | Helm 4.3.0 |
| 健康端點 |
GET /actuator/health(liveness/readiness)、/actuator/info、/actuator/prometheus
|
2.14 依賴版本覆寫(Override)——2026-10-05 新增(CR-037)
原則:BOM(spring-boot-dependencies)所管理之版本為預設;當 BOM 落後於
安全修補時,只覆寫落後的那一個版本,不連帶動其餘相依。
| 被覆寫 | BOM 之版本 | 覆寫為 | 理由 | 依據 |
|---|---|---|---|---|
org.apache.tomcat.embed:tomcat-embed-{core,el,websocket} |
11.0.24 | 11.0.26 | BOM pin 之 11.0.24 含 3 個 CRITICAL(GHSA-9xv2-5v5q-p794/GHSA-gcx9-497g-6cp6/GHSA-h3x4-894j-xpx5) |
CR-037 |
com.fasterxml.jackson:jackson-bom(2.x 線) |
2.21.5 | 2.21.7 | 含 5 個 HIGH + 2 個 MODERATE(jackson-core/jackson-databind;含 ReDoS) |
CR-038 |
tools.jackson:jackson-bom(3.x 線) |
3.1.5 | 3.1.7 | 含 5 個 HIGH + 2 個 MODERATE(同上,不同分支、修復版本不同) | CR-038 |
at.yawk.lz4:lz4-java |
(BOM 未管理) | 1.11.4 | 含 1 個 MODERATE(原生 XXHash 可致 JVM 崩潰)。★ 不在 Spring Boot BOM 內——係 kafka-clients:4.2.1 之傳遞相依 → 機制 A
|
CR-039 |
2.14.1 ★ 兩種覆寫機制(選錯會漏)
| 機制 | 做法 | 適用 | 實例 |
|---|---|---|---|
| A 逐個 artifact constraint | constraints { add("implementation", "<g>:<a>:<v>") } |
相依不屬任何 BOM 家族,或家族極小且穩定 |
CR-037(Tomcat——classpath 上恰 3 件,逐一列出不會漏) |
| B 覆寫整個 BOM ★ 優先 | 以 platform("<bom 座標>") 匯入較新之 BOM
|
相依由 BOM 管理之大家族 |
CR-038(Jackson——兩個 BOM 各管 20+ artifact;逐個列必然有一天漏) |
★★ 判準:先問「這個相依是不是某個 BOM 管的家族成員?」
是 → 機制 B(BOM 一次涵蓋全家族,語意即「這條線整體升級」);
否 → 機制 A。
★ 機制 A 的風險:classpath 上今天有 3 件、明天可能變 4 件(任何 starter 加進來就可能帶新的)。
★ 兩個 BOM 必須一起升(
CR-038 §3.2):同一生態系若有多條線(如 Jackson 2.x/3.x),
Spring Boot BOM 同時管理兩者(jackson-2-bom.version與jackson-bom.version)——
只升一條 → 另一條的漏洞仍在,且兩條之修復版本不可混用。
機制:於 backend/build.gradle.kts 之 subprojects {} 以 Gradle 專案層 constraints 宣告
(非 resolutionStrategy.force——後者為最後手段)。
版本值取自 backend/gradle/libs.versions.toml 之 tomcat(版本單一真實來源)。
★ 本項為「BOM 落後」之標準處置,非特例——
CR-037 §2已證
Spring Boot 4.1.x 僅到 4.1.1(無含修復之 patch),故「升 BOM」無路可走。
★ 新增任何覆寫前,須先依§5.2之 Version Compatibility Gate 查證,
並於本表逐列載明理由與依據——不得無紀錄地改版號。
2.15 版本鎖定之機器可讀來源與核對(2026-10-05 新增,WBS 5.10)
問題:§2.1~§2.8 之版本表為散文式 markdown(含粗體、7.0.x 之類範圍、附註文字)
——機器解析易碎,且**「文件說幾版」與「實際幾版」之間沒有任何自動化核對**。
★★ 實證(
CR-040 §2):本表原載「Vite 6.x」「React Router 7.x」,
而實際安裝為 Vite 5.4.21/React Router 6.30.6——落後兩個大版,
而tsc/建置/測試/掃描器全都不會報。這種漂移是無聲的。
| 項目 | 內容 |
|---|---|
| 規格側之單一真實來源 |
spec/versions.yaml(機器可讀;逐項載 expect/match/actual 來源/csp 節) |
| 核對工具 | python3 tools/verify_versions.py |
| 核對兩件事 | ① 規格 ↔ 實際(Gradle version catalog/node_modules/java -version)② 規格 ↔ 內文( CSP-006 對應節是否仍載有該版本字串——防散文漂移) |
| 退出碼 |
0 = 全部相符;1 = 有落差或無法解析;2 = 執行錯誤(fail-closed) |
| 自測 |
python3 tools/verify_versions.py --selftest(人工樣本回測判定力,同 scan_scaffold.py 之慣例) |
★★ 變更版本時之強制流程:
- 改實際(
libs.versions.toml/package.json/覆寫區塊) -
同步
spec/versions.yaml之expect -
同步本節(
§2.1~§2.8/§2.14)之內文版本字串 - 執行
verify_versions.py,須為0
⚠️ 本節之第 3 步與第 4 步不可省略——
verify_versions.py之首次執行即抓到
一處真實遺漏(CR-039之lz4已改實際、惟未回寫本節內文),
證明**「改了程式沒改文件」是常態,必須靠工具攔**。
3. 開發環境切換(與 Legacy ECS 並存)
本機同時存在 Legacy ECS(Java 8 + Tomcat 9)與 cardcore(Java 21)兩套環境。
| 環境 | Java | 設定來源 |
|---|---|---|
| Legacy ECS | 8(Temurin 1.8.0_504) |
~/.zshrc(全域預設) |
| cardcore | 21(Temurin 21.0.12.1 LTS) |
ops/local/env.sh(當前 shell) |
source cardcore/ops/local/env.sh # 切換至 Java 21(僅當前 shell)
強制規則:
-
禁止將 Java 21 寫入
~/.zshrc或任何全域設定——會導致 Legacy ECS 之 Maven/Tomcat 編譯失敗。 - CI 與建置一律使用 Gradle Wrapper 與 Java Toolchain(
languageVersion = 21),
不依賴機器預設JAVA_HOME。 - 工具鏈安裝位置沿用既有慣例
~/dev-tools/opt/(install-toolchain.sh為冪等)。
4. 本地開發環境
詳見 ops/local/README.md。要點:
| 分層 | 服務 | 啟動方式 |
|---|---|---|
| 輕量核心(約 4GB) | PostgreSQL、Redis、Kafka | docker compose up -d |
| Oracle(約 4GB) | Oracle 26ai Free | --profile oracle |
| 可觀測性(約 3GB) | OTel Collector、Jaeger、Prometheus、Grafana、Loki | --profile obs |
| 工具 | Kafka UI | --profile tools |
| 身分驗證 | Keycloak | --profile iam |
資源約束:本機為 4 核 / 32GB,禁止一次啟動全部 profile。日常開發建議
「輕量核心 + 正在開發的 2–3 個服務」,需要時再加 Oracle。
埠號衝突避免:Legacy ECS 之 Tomcat 佔用 8080,故 cardcore 本地服務建議由 8081 起編。
5. 版本治理
5.1 凍結與升級
- §2 各表版本為凍結值;Coder 不得自行調整版本。
- 補丁版(patch)升級由 Tech Lead 決定,於 Sprint 內進行。
- 次版(minor)以上升級須走 §7 變更控制,並更新本文件與 §6 之回改清單。
5.2 Sprint 0 必過關卡(Version Compatibility Gate)
| # | 關卡 | 通過條件 |
|---|---|---|
| G-1 | Boot 4.1.1 + Cloud 2025.1.3 執行期相容 | 一個具備 web + actuator + OpenFeign + Resilience4j + Stream-Kafka + Vault 之服務可正常啟動並回應 /actuator/health
|
| G-2 | Oracle + Flyway 遷移 | 17 個 schema 之基線遷移腳本可重跑(冪等)且 0 錯誤 |
| G-3 | Testcontainers 整合測試 | Oracle/PostgreSQL/Kafka 容器可拉起並完成一個 E2E 案例 |
| G-4 | ArchUnit 分層規則 | 可攔阻故意違反依賴方向之程式碼 |
| G-5 | Saga 骨架 | 編排式 Saga 之正向與補償路徑可跑通(含補償失敗落 CC-PLT-5002) |
G-1 未過之降級方案:改用 Spring Boot 4.0.8 + Spring Cloud 2025.1.3(官方對齊組合),
並於 2027 Q1 再評估升級至 Boot 4.2 + Cloud 2026.0。
6. 與已核定文件之衝突與回改清單
本文件生效後,下列已核定文件須回改。回改前,本文件之敘述優先。
| # | 文件 | 現況 | 應改為 | 依據 |
|---|---|---|---|---|
| 1 | CSP-001 §1 | 建議基線「Java 21 + Spring Boot 3.2」 | Spring Boot 4.1.1 | Spring Boot 3.x 全線已 EOL;最後之 3.5 於 2026-06-30 終止 OSS 支援。3.2 更早於 2024-12-31 EOL |
| 2 | CSP-002 §3 | 服務骨架路徑 src/main/**kotlin**/com/beam/cardcore/...
|
src/main/**java**/com/beam/cardcore/... |
§2.1 決議採 Java 21;與 CSP-001 §5 之 Java 工具鏈一致 |
| 3 | SAD-003 §1 DP-01、§3 | 「每個服務擁有自己的 PostgreSQL schema」、資料庫部署圖僅 PostgreSQL 讀寫叢集 | Oracle 為權威 OLTP;PostgreSQL 承擔 CQRS 讀模型/事件流存檔/報表 | 客戶指定 Oracle 為主(§2.4) |
| 4 | SAD-006 §3 | 資料層僅列 PostgreSQL Primary/Replica、Redis、Kafka | 增列 Oracle 為權威 OLTP 層 | 同上 |
| 5 | SDD-001、SDD-003 | ER 圖與 SQL 範例為 PostgreSQL 語法(如 now()、timestamptz、serial) |
補 Oracle 方言對照(SYSTIMESTAMP、TIMESTAMP WITH TIME ZONE、sequence/identity) |
同上 |
| 6 | CSP-001 §5 | 提及自製 validate_sql.py
|
tools/ 下無此檔案。須補實作,或自本表移除該列 |
實地盤點結果 |
| 7 | proposal_v2/outline.md L48 | 「NFR 878 項符合度統計」 | 「NFR 874 項」 | BRD-003 載明 874 項且為單一真實來源;README 亦寫 874 |
| 8 | GOV-001 §3.2 | 文件類型代碼表未含 CSP-006 之增列說明 |
無需新增 TYPE;CSP 序號 006 為 001–005 之連續延伸,符合 §3.1「同一 TYPE 內連續、不跳號」 |
GOV-001 §3.1 |
第 1–5 項為架構層級變更,須依 GOV-003 之品質關卡重新審查並於文件「版本」欄位升版
(1.0 → 1.1),並在修訂記錄載明變更原因。
7. 變更控制
- 本文件之變更須經 SA + Tech Lead + PMO 三方同意。
- 版本升級或技術棧替換,須以 ADR(Architecture Decision Record) 記錄:
背景、候選方案、決策、後果、替代時機。 - 變更後須同步更新 §6 之回改清單,並確認下游文件已回改。
- 每次變更須於下方修訂記錄登載。
修訂記錄
| 版本 | 日期 | 修訂者 | 說明 |
|---|---|---|---|
| 1.0 | 2026-09-18 | SA / Tech Lead | 初版。依客戶拍板之技術棧(Spring Boot 4.1、Java 21、Oracle 為主、SAGA)建立基線,並提出 §6 之 8 項文件回改清單 |
附錄 A 本地環境快速上手
# 1. 安裝工具鏈(首次)
bash cardcore/ops/local/install-toolchain.sh
# 2. 切換至 Java 21
source cardcore/ops/local/env.sh
# 3. 啟動輕量核心
cd cardcore/ops/local && cp -n .env.example .env && docker compose up -d
# 4. 需要 Oracle 時
docker login container-registry.oracle.com
docker compose --profile oracle --profile tools up -d
# 5. 需要可觀測性時(Grafana: http://localhost:3000)
docker compose --profile obs up -d
| 端點 | 位址 |
|---|---|
| Grafana | http://localhost:3000 (admin / admin) |
| Jaeger | http://localhost:16686 |
| Prometheus | http://localhost:9090 |
| Kafka UI | http://localhost:8090 |
| Keycloak | http://localhost:8180 (admin / admin) |
| Oracle |
localhost:1521/FREEPDB1(Free 映像之 PDB 固定為 FREEPDB1,見 SDD-001 §1.3 P-1) |
| PostgreSQL |
localhost:5432 / db cardcore
|
| Kafka(主機端) | localhost:9094 |