本卡為 FR-089 母案。承接 FR-069 D8「第三階段:既有套件升級插件模式」,起於 FR-080 第 1 棒產出的 jedi-asset。決策者 2026-09-12 拍板三段:① jedi-asset 定形(已完成)→ ② 主專案側殘留收斂(FR-090,進行中)→ ③ 18 支套件套用(待開)。子卡清單在末段。
這系列在做什麼(白話)
後端已經把功能一支支搬進 jedi-* 套件(FR-069/FR-080),但每支套件是不同時期、不同人抽出來的,同一件事有好幾種寫法:有的把「掛載到主程式」的程式全塞在一個 plugin.py 檔裡、有的拆開;有的資料物件用 dataclass、有的用普通 class;取「執行期組件」的函式有的叫 ctx() 有的叫別的;主專案這邊留了空目錄、放錯層的檔案、一層又一層的轉發殼。這樣下去每個人接手一支套件都要重新學一次它的長相。
本案先拿 jedi-asset(資產管理:設備與資訊系統盤點)當範例,把它整理成「標準形狀」並寫進 SOP;再把主專案這邊的殘留收乾淨;最後把其餘 18 支套件照同一個形狀整理一遍。整理過程零對外行為變更(API、DB 資料不變),順手修掉發現的小 bug。
為什麼要做
- FR-069 design.md D8(2026-08-30)早已定下「第三階段:既有套件升級插件模式」,FR-080 把四組套件合併、五支空殼補實、清掉套件間直接依賴(第一、二階段),但沒有統一每支套件內部的形狀——這是 D8 留下的最後一段。
- 決策者 2026-09-12 看到 app/auth/ 下九個檔問「不是已經拆成 iam 了嗎,怎麼還在」,首腦掃主專案 app/ 28 個目錄,發現四種並存做法(空殼/port 放錯層/轉發殼與 wrapper/補暱稱各自手寫);套件側同樣是 19 支各長各的。決策者裁「全部做法統一」。
- 整理 jedi-asset 時順手抓到真 bug:資訊系統狀態 enum 的 DB 值域與程式寫入值大小寫不一致,五個系統狀態只有兩個存得進去(CM-1678 修);三環境與出貨基線都有。沒有統一形狀這種病會在 18 支各自長一遍。
首腦讀完後的重點
- D1 定案的統一形狀(jedi-asset 版,已寫進 SOP §4.3):plugin/ 五檔(init/contract/runtime/assembly/migrations);api/ 拆 guards.py(runtime()+三個 lazy decorator)與 routing.py;取用執行期組件的函式一律叫
runtime() 不叫 ctx();logger 掛 common.jedi_<pkg>;entity 一律 dataclass 並用 inspect.signature 對照 ORM 欄位。
- D2 主專案側的統一形狀:port 實作放
infra/<pkg>/、接線放 core/<pkg>_wiring.py、套件上移後 app/<pkg>/ 整個刪、補暱稱由套件走 identity port(D8)主專案不寫 wrapper、主專案 DI 不重複建套件 service 只給 port。
- D3 順序:主專案側(FR-090)先於 18 支——18 支每支都要確認主專案有沒有重複給工廠/port,主專案先清乾淨,18 支的卡才寫得準。
- D4 enum 值域走 A 案「統一小寫」(CM-1678):DB CHECK 與程式端寫入值對齊小寫,migration 只加不破。
- 🔴 D5 runner 查出的出貨缺口(需另開卡):出貨 image 只複製主專案
scripts/init/ 與 scripts/sql/,完全不碰套件自帶的 migrations 目錄,所以套件隨包的 migration 客戶端永遠套不到。需另開卡評估「宿主自動撿套件 migration」機制;且 CM-1678 的 002 migration 內容要在主專案 scripts/sql/ 另放一支,否則 RLS 四條 policy 與 enum 修正出不了貨。三環境與出貨基線目前都帶著這個 enum bug。
- D6 與 FR-080 的關係:FR-080(母卡 CM-1619,八棒 Done、收口中)的「發版推 Nexus、pin 還原、SPEC 頁更新、release note」四項已於 2026-09-12 移出 FR-080 歸本案,等 18 支整理完一次做(已寫進 CM-1619 末段)。FR-080 只收 code review、e2e 假綠、母卡與 design.md 收 Done。
怎麼拆
- 第一段 jedi-asset 定形(三張,已 Done)— CM-1676 結構整理(A 清施工日誌註解/B plugin.py 拆五檔、api 拆 guards+routing/C 統一 device 與 information_system 兩型別內部寫法/D entity dataclass/E 刪零呼叫者 oscal 模組、error_code 搬目錄/F 寫回 SOP §4.3);CM-1677 收尾修正(刪 upsert_by_name、引用計數改明確分派、補 18 支 testcontainers 整合測試、README 落差表、ctx() 改名 runtime());CM-1678 資訊系統表補 RLS 四條 policy+FORCE、devices.tenant_id NOT NULL、enum 值域統一小寫。
- 第二段 主專案側殘留收斂(FR-090,母卡 CM-1682,四棒)— 第 1 棒空殼清理(Done)、第 2 棒 port 實作歸位 infra/<pkg>/(Done)、第 3 棒 iam 宿主側收斂含 jedi-iam 開 identity port(待派)、第 4 棒補審計暱稱統一走 D8(待派)。獨立成 FR-090 是因為它動的是主專案不是套件,且必須先於第三段。
- 第三段 18 支套件套用(待開卡)— 把 jedi-asset 定的形狀套到其餘 18 支有 plugin.py 的套件。三批各 5 支(輕→中)+ iam/detection/task-platform 三張大卡(各自獨立一張,量大且有宿主接線)。oscal-v2 與 common 無 plugin.py,只做 A 組(清施工日誌註解)與 logger 統一,範圍待決策者裁。
建議順序:第一段已完 → 第二段第 3、4 棒依序派(第 3 棒含套件異動,第 4 棒依賴第 3 棒開出的 identity port)→ 第二段收口後才開第三段卡。第三段三批可依序派,同批 5 支若不動共用檔可平行。