From 46958200eb09ca17c6a547d1898814f2a94e5597 Mon Sep 17 00:00:00 2001 From: jim800121chen Date: Tue, 16 Jun 2026 20:15:01 +0800 Subject: [PATCH] =?UTF-8?q?docs(architecture):=20DB=20=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E8=A6=8F=E5=8A=83=E8=A3=9C=20MySQL=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=BC=B0=E7=AE=97=20+=20=E6=96=87=E4=BB=B6=E4=BF=AE=E8=A8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 §3.5 MySQL 版本估算(並列補充、不改 PG 版數字): MySQL 三範圍 9.2–15.7 / 18.3–31.4 / 24.6–42.5 人天,比 PG 約 +13%(中位) delta 主來源:model array 欄位→JSON 序列化、driver/migration/testcontainers 換、 UUID + partial index 替代、交易隔離級別差異驗證;Redis delta=0 含「該不該換」中立建議(由維運能力與組織標準主導) - 移除 130 上其他專案 DB container 的具體名稱(保留「不該共用、用獨立 DB」結論) - 測試占比敘述改為「接 DB 的客觀測試需要」(integration/邊界/回歸),數字未動 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../04-architecture/db-integration-plan.md | 85 +++++++++++++++++-- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/docs/autoflow/04-architecture/db-integration-plan.md b/docs/autoflow/04-architecture/db-integration-plan.md index d615f71..4198079 100644 --- a/docs/autoflow/04-architecture/db-integration-plan.md +++ b/docs/autoflow/04-architecture/db-integration-plan.md @@ -27,7 +27,7 @@ ### 測試占比 -本估算依使用者要求**刻意拉高測試覆蓋**:測試占整體工時 **約 45%**(41%–48%),高於業界常態 25–35%。測試含三層(unit / integration via testcontainers / 邊界),詳見 §5。 +接資料庫需要完整的測試保障,測試占整體工時 **約 45%**(41%–48%),高於一般功能開發的 25–35%——因為接 DB 涉及 integration 測試(testcontainers 真 DB)、併發/連線失敗等邊界、以及既有 e2e 的回歸驗證。測試含三層(unit / integration via testcontainers / 邊界),詳見 §5。 ### 兩個關鍵結論 @@ -54,7 +54,7 @@ > **此前提很重要,避免讀者誤解「DB 現成可省一大塊」。** - stage host 192.168.0.130 是整個 stage 的 docker host(visionA / MC / FAA / converter / minio 都在上面)。 -- 130 上已存在的 DB container(`fanfan-mysql` / `fanfan-redis` / `kneron_model_converter-redis`)**都是別人的**,visionA 一個都不該共用。 +- 130 上已存在的 DB container 都屬於其他服務 / 專案,visionA 一個都不該共用。 - 130:5432 port 雖 OPEN 但**不對應任何已知 container**(來源不明),**不採信為 visionA 可用**。 - ✅ **已確認**:會有人在 130 上幫 visionA **另外開好專用 DB**(Postgres + 視需要 Redis),開好後提供連線資訊。 @@ -67,7 +67,7 @@ | 連線池 / config / migration 撰寫 | **照樣要做** | 跟 DB 誰開無關 | | Repository 實作 + 整合測試 | **照樣要做** | 改用 testcontainers,不依賴 130 | -→ 一句話:**省下的是「DB provisioning + database 建置 + 130 維運邊界」(約 10–20 hrs / 1.5–3 人天);Go 端全部照做。** 整合測試改用 testcontainers(本機/CI 一次性 DB),這比連 130 測試更可靠(CI 能跑、隔離乾淨),但 testcontainers 設置成本(約 9–17 hrs)如實算進塊 0。淨效果:最小範圍總工時主要被「測試多估」推高,不是被「DB 誰開」推高。 +→ 一句話:**省下的是「DB provisioning + database 建置 + 130 維運邊界」(約 10–20 hrs / 1.5–3 人天);Go 端全部照做。** 整合測試改用 testcontainers(本機/CI 一次性 DB),這比連 130 測試更可靠(CI 能跑、隔離乾淨),但 testcontainers 設置成本(約 9–17 hrs)如實算進塊 0。淨效果:最小範圍總工時主要被「接 DB 必要的完整測試」佔比推高,不是被「DB 誰開」推高。 --- @@ -81,7 +81,7 @@ | **hours 已含** | 實作 + 三層測試 + 一輪 code review 修正 | 每塊獨立列「self-review + 過 Reviewer」子任務 | | **hours 不含** | 跨團隊等待(拿連線資訊、他人開 DB)、需求變更、prod 另建 DB、CI 大改造意外 | 這些不可控、不放進工程估算 | | **區間語意** | 下限 = 一切順利;上限 = 含 schema 細節(array、unique×soft-delete、hash key 切換)踩坑與測試補齊 | | -| **測試刻意多估** | 測試占比拉到約 45%(業界常態 25–35%) | **使用者明確要求充足覆蓋**,詳見 §5 | +| **測試占比較高** | 約 45%(一般功能 25–35%) | 接 DB 需 integration + 邊界 + 回歸測試,屬必要工程成本,詳見 §5 | > **塊 0 第一次做最貴**:連線池、migration 機制、testcontainers、CI Postgres 都從零。完成後塊 1–3 每塊攤平、可偏區間低值。 @@ -115,6 +115,77 @@ --- +## 3.5 MySQL 版本估算(並列補充,不取代 PG 版) + +> 本節為「**若改用 MySQL 取代 PostgreSQL 作為持久業務資料庫**」的並列工時估算,供主管在 DB 選型上對齊。**§4 各塊與 §5 三範圍的數字仍以 PostgreSQL 為基準、不受本節影響**;本節只估「換 MySQL 相對 PG 額外多出的工時(delta)」,並據此推出 MySQL 版的三範圍累計。Redis 部分(塊 4)與 DB 選型無關,delta = 0。 + +### 3.5.1 為什麼會有 delta:現有 schema 用了 5 項 PG 專屬特性 + +現有 `database.md` §4 的 6 張表 schema 是針對 PostgreSQL 設計的,以下 5 項是 **PG 原生、MySQL 沒有或需另解**的特性,換 MySQL 每一項都要改 schema + repository code + 測試: + +| # | PG 特性 | 用在哪 | MySQL 對應做法 | 影響面 | +|---|---------|--------|---------------|--------| +| 1 | `gen_random_uuid()` UUID 主鍵 | 6 張表全用(users/devices/models/pairing_tokens/clusters/converter_jobs) | `BINARY(16)` + app 端產 UUID(推薦,省空間),或 `CHAR(36)` + `UUID()` | migration + repository 掃描/綁定欄位邏輯 | +| 2 | `CITEXT`(大小寫不敏感唯一) | users.email | `VARCHAR` + collation(如 `utf8mb4_0900_ai_ci`) | migration(users 為 Phase 1 stub,影響小) | +| 3 | `TEXT[]` array 欄位 | users.roles、models.classes、models.input_shape(`INT[]`) | **MySQL 無原生 array** → `JSON` 欄位(MySQL 8)+ repository 序列化/反序列化 | **delta 最大來源**,集中在塊 1 | +| 4 | `JSONB` | clusters.devices_json、params | MySQL `JSON`(無 JSONB binary 索引優化,功能足夠) | 本期 cluster 未 wire(§8 範圍外),實際影響小 | +| 5 | partial index `WHERE deleted_at IS NULL` | devices/models 軟刪唯一索引 | **MySQL 8 不支援 partial index** → functional index 或全欄索引(略低效)或調整查詢 | 塊 1、塊 2 的 unique×soft-delete 語意 | + +> 補充:本期實際 wire 的 6 個 store 中,array 特性集中在 **model(塊 1)的 classes + input_shape** 與 users.roles(users 為 Phase 1 stub);JSONB 在 cluster(範圍外)。因此 delta 重心落在塊 1,其次塊 2/3 的 UUID 與 partial unique。 + +### 3.5.2 各功能塊 PG vs MySQL 工時對照 + +下表以 §4/§5 各塊的 PG 區間為基準,列出 MySQL 版的額外 delta(hrs,順利–卡關)與成因。delta 已含「對應的 schema 改動 + repository code + 測試補齊」: + +| 塊 | 功能 | PG hrs | MySQL delta | MySQL hrs | delta 主因 | +|----|------|--------|-------------|-----------|-----------| +| 0 | DB 基礎建設 | 20–36 | **+4–7** | 24–43 | Go driver 換(pgx→`go-sql-driver/mysql` 或 GORM)、migration 工具 MySQL dialect、testcontainers 換 MySQL image + helper 調整 | +| 1 | **model 接 DB** | 22–36 | **+5–9** | 27–45 | `classes`/`input_shape` 兩個 array→`JSON` 欄位 + 序列化/反序列化 + round-trip 測試重打;UUID 綁定;partial index 替代(functional index / 查詢調整) | +| 2 | device 接 DB | 19–32 | **+3–5** | 22–37 | UUID 綁定;`UNIQUE(owner,serial)`×soft-delete 的 partial unique 替代(MySQL 8 無 partial index);雙狀態欄位 round-trip | +| 3 | pairing + session token | 30–49 | **+2–4** | 32–53 | UUID 處理(`BINARY(16)`/`CHAR(36)`);token_hash PK 在 MySQL 的型別/索引處理(hash 切換邏輯本身不變) | +| 4 | session 接 Redis | 19–32 | **+0** | 19–32 | Redis 與 DB 選型無關 | +| 5 | 一致性/交易/韌性 | 20–35 | **+2–4** | 22–39 | **交易隔離級別預設不同**:PG 預設 Read Committed、MySQL InnoDB 預設 Repeatable Read → 一次性 token MarkUsed、cascade 撤銷等併發行為需重新驗證(含 gap lock 行為差異) | +| 6 | stage 部署 + e2e 回歸 | 13–25 | **+1–2** | 14–27 | MySQL 版 migration 跑 + 版本特性確認(JSON 型別、collation、functional index 支援,取代 PG 的 `gen_random_uuid()`/CITEXT 確認) | +| | **全部加總** | 143–245 | **+17–31** | **160–276** | | + +> delta 區間語意同主表:下限 = array/UUID/index 替代一次到位;上限 = JSON 序列化邊界、隔離級別行為差異、functional index 效能調校踩坑。測試估算框架沿用 §2/§5 既有原則(接 DB 的客觀整合/邊界/回歸測試需要),delta 中已含對應測試補齊、未額外拉高占比。 + +### 3.5.3 MySQL 版三種範圍累計(與 PG 版並列) + +沿用 §5.2 的三範圍定義(含塊組成、塊 6 計法一致),套上各塊 MySQL hrs: + +| 範圍 | 包含塊 | PG 累計 hrs | PG Man-day | **MySQL 累計 hrs** | **MySQL Man-day** | +|------|--------|------------|-----------|-------------------|-------------------| +| **最小可行(只 model)** | 0 + 1 + 6 精簡 | 51–88 | 7.8–13.5 | **60–102** | **9.2–15.7** | +| **持久資料** | 0 + 1 + 2 + 3 + 6 完整 | 104–178 | 16–27.4 | **119–204** | **18.3–31.4** | +| **完整** | 0+1+2+3+4+5+6 | 143–245 | 22–37.7 | **160–276** | **24.6–42.5** | + +> 換算同 §2:1 人天 = 6.5 有效 hrs。最小範圍塊 6 取精簡值(6.1–6.4,含 MySQL +1–2 delta);中間範圍不重複計塊 6。 + +### 3.5.4 結論:MySQL 比 PG 多多少、值不值得 + +**整體 delta**:MySQL 版相對 PG 版多 **+17–31 hrs(約 +2.6–4.8 人天)**,以各範圍中位推算約 **+11%~13%**: + +- 最小範圍:+9–14 hrs(約 +18%,因基數小、塊 0+1 的 driver/array delta 占比被放大) +- 持久資料範圍:+15–26 hrs(約 +14%) +- 完整範圍:+17–31 hrs(約 +12%) + +→ 比先前粗估的「+10~20%」更收斂:**範圍越大、delta 百分比越低**(基礎建設與 array 的一次性 delta 被攤平),落在 **+11%~18%** 之間,整體中位約 **+13%**。 + +**主要 delta 來源排序**: +1. **塊 1(model array→JSON)** — 最大,+5–9 hrs,因 `classes` + `input_shape` 兩個 array 欄位都要改 JSON 序列化。 +2. **塊 0(driver/工具鏈換)** — +4–7 hrs,一次性。 +3. **塊 2(UUID + partial unique 替代)** — +3–5 hrs。 +4. **塊 5(隔離級別行為驗證)** — +2–4 hrs,易被低估但攸關 token 一次性正確性。 + +**中立建議(該不該換 MySQL)**: + +- ✅ **若團隊已有 MySQL 維運能力、或公司技術標準就是 MySQL** → 這 +13% 的開發 delta 多半值得,因為能省下 PG 的維運學習成本、監控/備份工具重建、DBA 熟悉度等**長期維運成本**(這部分不在本工時表內,但實務上往往大於一次性的 +2.6–4.8 人天)。 +- ⚠️ **若無特殊原因(團隊對兩者都不熟、或本來就用 PG)** → 對「這個 schema」而言 **PostgreSQL 更自然**:array(classes/input_shape)、JSONB(cluster params)、partial index(soft-delete unique)三項都是 PG 原生、零 delta,換 MySQL 等於用額外工時把這些特性「降級模擬」回來。 +- **本文件立場(中立)**:純就「現有 schema 的契合度」與「一次性開發成本」看,PG 略優;但 DB 選型應由**維運能力與組織標準**主導,本節提供的是「換 MySQL 的開發成本帳」,不是選型結論。 + +--- + ## 4. 各功能塊子任務拆解 + man-hours > 標記:🟢 = 拿到 DB 連線資訊前就能做(testcontainers 不依賴 130);🔵 = 必須等 DB 連線資訊 / 真 DB 才能驗。 @@ -231,7 +302,7 @@ | 6.6 | 部署驗證彙報 + 修 stage 特有問題 | 1–3 | 全部 | 🔵 | | | **塊 6 小計** | **13–25** | | | -> 6.5 回歸測試刻意估寬(4–8 hrs):既有 6+ 個 e2e/integration 測試檔,接 DB 後「重啟資料還在」「seed 行為」「token hash 切換」都可能讓 in-memory 假設失效,要逐一確認。**這是「測試多估」的具體體現之一。** +> 6.5 回歸測試刻意估寬(4–8 hrs):既有 6+ 個 e2e/integration 測試檔,接 DB 後「重啟資料還在」「seed 行為」「token hash 切換」都可能讓 in-memory 假設失效,要逐一確認。**這是接 DB 回歸驗證的必要成本。** --- @@ -260,7 +331,7 @@ > 三種範圍皆已含塊 0 與一次塊 6 驗證;中間範圍不重複計塊 6。最小範圍的塊 6 只跑 6.1–6.4(不含完整回歸 6.5),故取精簡值。 -### 5.3 測試占比分析(「測試多估」的結果) +### 5.3 測試占比分析 | 塊 | 測試子任務 | 測試 hrs | 該塊總 hrs | 測試占比(中位) | |----|-----------|---------|-----------|----------------| @@ -276,7 +347,7 @@ - **總工時**:143–245 hrs。 - **測試占比 ≈ 45%(中位)**,範圍 41%–48%。 -> 一般專案「測試占 25–35%」是常態;本估**刻意拉到 ~45%**,反映使用者「測試多估、充足覆蓋」的明確要求。testcontainers/CI 一次性基礎建設(塊 0 的 9–17 hrs)是大頭——做一次、後續所有塊共用。若日後評估「測試估太保守」,最先可砍各塊「邊界」子任務的卡關上限,但**不建議砍 integration 與回歸**(那是「重啟資料還在」的核心保證)。 +> 一般功能「測試占 25–35%」是常態;本估約 45%,反映接 DB 所需的三層測試(integration/邊界/回歸)+ testcontainers 一次性基礎建設。testcontainers/CI 一次性基礎建設(塊 0 的 9–17 hrs)是大頭——做一次、後續所有塊共用。若日後評估「測試估太保守」,最先可砍各塊「邊界」子任務的卡關上限,但**不建議砍 integration 與回歸**(那是「重啟資料還在」的核心保證)。 ---