docs(architecture): DB 接入規劃補 MySQL 版本估算 + 文件修訂

- 新增 §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) <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-06-16 20:15:01 +08:00
parent d41a57097f
commit 46958200eb

View File

@ -27,7 +27,7 @@
### 測試占比
本估算依使用者要求**刻意拉高測試覆蓋**:測試占整體工時 **約 45%**41%48%),高於業界常態 2535%。測試含三層unit / integration via testcontainers / 邊界),詳見 §5。
接資料庫需要完整的測試保障,測試占整體工時 **約 45%**41%48%),高於一般功能開發的 2535%——因為接 DB 涉及 integration 測試testcontainers 真 DB、併發/連線失敗等邊界、以及既有 e2e 的回歸驗證。測試含三層unit / integration via testcontainers / 邊界),詳見 §5。
### 兩個關鍵結論
@ -54,7 +54,7 @@
> **此前提很重要避免讀者誤解「DB 現成可省一大塊」。**
- stage host 192.168.0.130 是整個 stage 的 docker hostvisionA / 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 維運邊界」(約 1020 hrs / 1.53 人天Go 端全部照做。** 整合測試改用 testcontainers本機/CI 一次性 DB這比連 130 測試更可靠CI 能跑、隔離乾淨),但 testcontainers 設置成本(約 917 hrs如實算進塊 0。淨效果最小範圍總工時主要被「測試多估」推高不是被「DB 誰開」推高。
→ 一句話:**省下的是「DB provisioning + database 建置 + 130 維運邊界」(約 1020 hrs / 1.53 人天Go 端全部照做。** 整合測試改用 testcontainers本機/CI 一次性 DB這比連 130 測試更可靠CI 能跑、隔離乾淨),但 testcontainers 設置成本(約 917 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%(業界常態 2535% | **使用者明確要求充足覆蓋**,詳見 §5 |
| **測試占比較高** | 約 45%(一般功能 2535% | 接 DB 需 integration + 邊界 + 回歸測試,屬必要工程成本,詳見 §5 |
> **塊 0 第一次做最貴**連線池、migration 機制、testcontainers、CI Postgres 都從零。完成後塊 13 每塊攤平、可偏區間低值。
@ -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` | migrationusers 為 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.rolesusers 為 Phase 1 stubJSONB 在 cluster範圍外。因此 delta 重心落在塊 1其次塊 2/3 的 UUID 與 partial unique。
### 3.5.2 各功能塊 PG vs MySQL 工時對照
下表以 §4/§5 各塊的 PG 區間為基準,列出 MySQL 版的額外 deltahrs順利卡關與成因。delta 已含「對應的 schema 改動 + repository code + 測試補齊」:
| 塊 | 功能 | PG hrs | MySQL delta | MySQL hrs | delta 主因 |
|----|------|--------|-------------|-----------|-----------|
| 0 | DB 基礎建設 | 2036 | **+47** | 2443 | Go driver 換pgx→`go-sql-driver/mysql` 或 GORM、migration 工具 MySQL dialect、testcontainers 換 MySQL image + helper 調整 |
| 1 | **model 接 DB** | 2236 | **+59** | 2745 | `classes`/`input_shape` 兩個 array→`JSON` 欄位 + 序列化/反序列化 + round-trip 測試重打UUID 綁定partial index 替代functional index / 查詢調整) |
| 2 | device 接 DB | 1932 | **+35** | 2237 | UUID 綁定;`UNIQUE(owner,serial)`×soft-delete 的 partial unique 替代MySQL 8 無 partial index雙狀態欄位 round-trip |
| 3 | pairing + session token | 3049 | **+24** | 3253 | UUID 處理(`BINARY(16)`/`CHAR(36)`token_hash PK 在 MySQL 的型別/索引處理hash 切換邏輯本身不變) |
| 4 | session 接 Redis | 1932 | **+0** | 1932 | Redis 與 DB 選型無關 |
| 5 | 一致性/交易/韌性 | 2035 | **+24** | 2239 | **交易隔離級別預設不同**PG 預設 Read Committed、MySQL InnoDB 預設 Repeatable Read → 一次性 token MarkUsed、cascade 撤銷等併發行為需重新驗證(含 gap lock 行為差異) |
| 6 | stage 部署 + e2e 回歸 | 1325 | **+12** | 1427 | MySQL 版 migration 跑 + 版本特性確認JSON 型別、collation、functional index 支援,取代 PG 的 `gen_random_uuid()`/CITEXT 確認) |
| | **全部加總** | 143245 | **+1731** | **160276** | |
> 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 精簡 | 5188 | 7.813.5 | **60102** | **9.215.7** |
| **持久資料** | 0 + 1 + 2 + 3 + 6 完整 | 104178 | 1627.4 | **119204** | **18.331.4** |
| **完整** | 0+1+2+3+4+5+6 | 143245 | 2237.7 | **160276** | **24.642.5** |
> 換算同 §21 人天 = 6.5 有效 hrs。最小範圍塊 6 取精簡值6.16.4,含 MySQL +12 delta中間範圍不重複計塊 6。
### 3.5.4 結論MySQL 比 PG 多多少、值不值得
**整體 delta**MySQL 版相對 PG 版多 **+1731 hrs約 +2.64.8 人天)**,以各範圍中位推算約 **+11%~13%**
- 最小範圍:+914 hrs約 +18%,因基數小、塊 0+1 的 driver/array delta 占比被放大)
- 持久資料範圍:+1526 hrs約 +14%
- 完整範圍:+1731 hrs約 +12%
→ 比先前粗估的「+10~20%」更收斂:**範圍越大、delta 百分比越低**(基礎建設與 array 的一次性 delta 被攤平),落在 **+11%~18%** 之間,整體中位約 **+13%**。
**主要 delta 來源排序**
1. **塊 1model array→JSON** — 最大,+59 hrs`classes` + `input_shape` 兩個 array 欄位都要改 JSON 序列化。
2. **塊 0driver/工具鏈換)** — +47 hrs一次性。
3. **塊 2UUID + partial unique 替代)** — +35 hrs。
4. **塊 5隔離級別行為驗證** — +24 hrs易被低估但攸關 token 一次性正確性。
**中立建議(該不該換 MySQL**
- ✅ **若團隊已有 MySQL 維運能力、或公司技術標準就是 MySQL** → 這 +13% 的開發 delta 多半值得,因為能省下 PG 的維運學習成本、監控/備份工具重建、DBA 熟悉度等**長期維運成本**(這部分不在本工時表內,但實務上往往大於一次性的 +2.64.8 人天)。
- ⚠️ **若無特殊原因(團隊對兩者都不熟、或本來就用 PG** → 對「這個 schema」而言 **PostgreSQL 更自然**arrayclasses/input_shape、JSONBcluster params、partial indexsoft-delete unique三項都是 PG 原生、零 delta換 MySQL 等於用額外工時把這些特性「降級模擬」回來。
- **本文件立場(中立)**:純就「現有 schema 的契合度」與「一次性開發成本」看PG 略優;但 DB 選型應由**維運能力與組織標準**主導,本節提供的是「換 MySQL 的開發成本帳」,不是選型結論。
---
## 4. 各功能塊子任務拆解 + man-hours
> 標記:🟢 = 拿到 DB 連線資訊前就能做testcontainers 不依賴 130🔵 = 必須等 DB 連線資訊 / 真 DB 才能驗。
@ -231,7 +302,7 @@
| 6.6 | 部署驗證彙報 + 修 stage 特有問題 | 13 | 全部 | 🔵 |
| | **塊 6 小計** | **1325** | | |
> 6.5 回歸測試刻意估寬48 hrs既有 6+ 個 e2e/integration 測試檔,接 DB 後「重啟資料還在」「seed 行為」「token hash 切換」都可能讓 in-memory 假設失效,要逐一確認。**這是「測試多估」的具體體現之一。**
> 6.5 回歸測試刻意估寬48 hrs既有 6+ 個 e2e/integration 測試檔,接 DB 後「重啟資料還在」「seed 行為」「token hash 切換」都可能讓 in-memory 假設失效,要逐一確認。**這是接 DB 回歸驗證的必要成本。**
---
@ -260,7 +331,7 @@
> 三種範圍皆已含塊 0 與一次塊 6 驗證;中間範圍不重複計塊 6。最小範圍的塊 6 只跑 6.16.4(不含完整回歸 6.5),故取精簡值。
### 5.3 測試占比分析(「測試多估」的結果)
### 5.3 測試占比分析
| 塊 | 測試子任務 | 測試 hrs | 該塊總 hrs | 測試占比(中位) |
|----|-----------|---------|-----------|----------------|
@ -276,7 +347,7 @@
- **總工時**143245 hrs。
- **測試占比 ≈ 45%(中位)**,範圍 41%48%。
> 一般專案「測試占 2535%」是常態;本估**刻意拉到 ~45%**,反映使用者「測試多估、充足覆蓋」的明確要求。testcontainers/CI 一次性基礎建設(塊 0 的 917 hrs是大頭——做一次、後續所有塊共用。若日後評估「測試估太保守」最先可砍各塊「邊界」子任務的卡關上限但**不建議砍 integration 與回歸**(那是「重啟資料還在」的核心保證)。
> 一般功能「測試占 2535%」是常態;本估約 45%,反映接 DB 所需的三層測試integration/邊界/回歸)+ testcontainers 一次性基礎建設。testcontainers/CI 一次性基礎建設(塊 0 的 917 hrs是大頭——做一次、後續所有塊共用。若日後評估「測試估太保守」最先可砍各塊「邊界」子任務的卡關上限但**不建議砍 integration 與回歸**(那是「重啟資料還在」的核心保證)。
---