FR-062 派工 Prompt 全集(七棒)

首腦棒 2026-08-08 產出。每份可獨立複製給實作 session。發令順序見 fr062-STATE.md「執行順序」。 通用規則(每份 prompt 已內含,此處備忘):開工先 fetch Notion 卡讀完整內容;完成回寫子卡「修正待驗證」+白話補充+commit hash+執行紀錄;顯式 git add 禁 -am 不 push 不切 branch;停下等驗收不自動往下。


§1

第 1 棒:FR-062.1 簽發端地基

接手 FR-062.1「簽發端地基」(License Center 專案起手式)。

【Notion 卡】
子需求:FR-062.1 = CM-1113 https://app.notion.com/p/FR-062-1-1-3b6346da4cd081e89315e8334cb00518
子任務:T-1.1 = CM-1114、T-1.2 = CM-1115(開工前務必先用 scripts/notion_case.py get 讀完整內容)
母案:CM-1112 https://app.notion.com/p/FR-062-License-3b6346da4cd081fca6b0ca8cf87cee26

【必讀】
1. compliance-manager-be repo:docs/features/FR-062-2608-license-management/design.md
   - §2 決策定案表 D1(自建理由)、D4(Ed25519/kid 機制)、D7(簽發集中)
   - §4.1(license 檔格式全欄位表)、§4.2(簽章與驗證引擎)、§4.3(簽發站 DB schema:license_issuance + plans)
2. 同資料夾 discussion.md「金鑰生命週期管理」節(私鑰備份規範、kid+公鑰列表輪替劇本)

【工作目錄】
新 repo:~/Projects/Billows/Audit-Manager/license_center/(已有基底 commit,remote gitlab.com/auditmanager/license_center.git)
DB:license_center_dev(開發期只建/只套這個環境;host 192.168.50.188:25432、帳號 cmmgr 密碼查主產品 .env DB_SECRET)

【關鍵約束】
- 私鑰絕不可進 compliance-manager-be repo,也不可進主產品 DB
- 私鑰檔以 passphrase 加密存放,路徑寫進 README 但本體加 .gitignore 不入版控
- 簽章引擎用 Python cryptography 或 PyNaCl 做 Ed25519,欄位格式照 design.md §4.1,不自創
- CLI 與未來 Web 後台(FR-062.6)共用同一簽章引擎模組;本階段只做引擎+CLI,不做 Web
- 對 compliance-manager-be 主產品「零侵入」——不改主產品任何程式碼
- 遵守 BE CLAUDE.md 共用政策:可自行 commit 不切 branch、push 等明示、顯式 git add 禁 -am、憑證禁入版控

【人工驗收】
CLI 產一張測試照 → CLI verify 指令驗簽章通過 → license_issuance 表有紀錄。完全不碰主產品,隨時可中斷。

【完成時回寫】
CM-1114、CM-1115 狀態改「修正待驗證」+ 白話「已完成修正」補充(做了什麼/怎麼測/commit hash);CM-1113 同步;記錄執行紀錄(開始/結束/耗時)。

完成後停下等驗收,不自動往 FR-062.2 或收尾跑。

§2

第 2 棒:FR-062.2 產品端驗照與狀態顯示

接手 FR-062.2「產品端驗照與狀態顯示(只讀不執法)」。前置:FR-062.1 已完成並驗收。

【Notion 卡】
子需求:FR-062.2 = CM-1116(用 scripts/notion_case.py get CM-1116 取得 URL 與完整內容)
子任務:T-2.1 = CM-1117、T-2.2 = CM-1118、T-2.3 = CM-1119(開工前先 fetch 三張卡)
母案:CM-1112

【必讀】
compliance-manager-be repo:docs/features/FR-062-2608-license-management/design.md
- §4.4(產品端 tenant_licenses 表結構)
- §4.2(驗證引擎:公鑰列表 kid 查表、時鐘回撥防護——在主產品實作驗證端)
- §3 現況接入點盤點表(root tenant 後台既有頁面掛點)

【工作目錄】
compliance-manager-be(BE)+ compliance-manager-fe(FE 頁面;先讀 FE CLAUDE.md 與 docs/claude/frontend-overview.md)

【關鍵約束】
- DDD 分層:repo 實作放 infra/、app service @transaction、route 不碰 session
- 公鑰列表編譯進 BE 程式碼(不放 DB/config)
- 只做「顯示」不擋操作——照過期也不擋寫入(那是 FR-062.4 的事)
- FE 頁面放 root tenant 系統管理選單下
- migration 只套 DEV(sql-migration skill 規範:日期註解、GRANT cm_app、schema_migrations 收尾)

【人工驗收】
root 帳號查全租戶授權狀態;上傳第 1 棒簽的照 → 解析欄位與狀態正確入庫;竄改照上傳被拒且留證;FE 頁面完整呈現照內容。不影響既有功能。

【完成時回寫】CM-1117/1118/1119 改「修正待驗證」+白話補充;CM-1116 同步;記錄執行紀錄。

完成後停下等驗收。

§3

第 3 棒:FR-062.3 狀態機排程與橫幅

接手 FR-062.3「狀態機排程與橫幅(仍不擋操作)」。前置:FR-062.1、.2 已完成並驗收。

【Notion 卡】
子需求:FR-062.3 = CM-1120 https://app.notion.com/p/FR-062-3-3-3b6346da4cd08175b2b6fc19c70a1781
子任務:T-3.1 = CM-1121、T-3.2 = CM-1122(先 fetch)
母案:CM-1112

【必讀】
compliance-manager-be repo:docs/features/FR-062-2608-license-management/design.md
- §4.5(狀態機與排程設計)
- discussion.md「到期狀態機(可組態管線)」節(各段開關語意、出廠預設 notify30/grace14/readonly 終態/lockout 關)
- core/scheduler.py 既有 APScheduler cron 樣板(照抄 framework_parse_job_cleanup 寫法)

【關鍵約束】
- 排程必 with app.app_context();DI 取 app.extensions.get("di_container")+None check;with session_scope()(無 user context → RLS 全開跨租戶掃描);整段 try/except + logger.exception
- 狀態轉換只更新 tenant_licenses.status + 顯示橫幅,仍不擋任何寫入
- 多副本部署時 scheduler 每 pod 各跑一份(無分散式鎖)→ 狀態更新要冪等

【人工驗收】
發一張短效照(2 天後到期)觀察按 expiry_policy 走完 notify→grace→readonly 狀態轉換,橫幅文案正確。

【完成時回寫】CM-1121/1122 改「修正待驗證」+白話補充;CM-1120 同步;記錄執行紀錄。

完成後停下等驗收。

§4

第 4 棒:FR-062.4 執法進場(風險最高)

接手 FR-062.4「執法進場(帶環境開關可整體關閉)」——真正「擋」的階段。前置:FR-062.1~.3 已完成並驗收。

【Notion 卡】
子需求:FR-062.4 = CM-1123 https://app.notion.com/p/FR-062-4-4-3b6346da4cd081bf89c0f530e659a6a8
子任務:T-4.1=CM-1124、T-4.2=CM-1125、T-4.3=CM-1126、T-4.4=CM-1127(務必先 fetch,任務間有依賴順序)
母案:CM-1112

【必讀】
compliance-manager-be repo:docs/features/FR-062-2608-license-management/design.md
- §4.6(執法設計:authz 第六軸、唯讀 gate、任務型態過濾、選單過濾)
- §3 現況接入點盤點表全部,特別是:
  - common/authz/ 新增第六軸 require_license(照抄 capability.py 的 CapabilityGuard:DI 解析、flask.g memoize、decorator)
  - api/grc、api/project 零 capability 守門技術債(本階段必補,否則「沒買 project」擋不住)
  - GrcJobType enum 寫死(common/enum/grc_job_type_enum.py + api/grc/serializers/job.py:173-177,209-213)改按租戶授權動態過濾
  - job_import_service.py:31 VALID_JOB_TYPES 與 enum 同步修(現缺 detection_tool)
  - TENANT_ADMIN_EXCLUDED_RESOURCE_TYPES(app/auth/service/tenant_provisioning_service.py)退役
  - ui_route 選單過濾(api/auth/routes/ui_route_route.py 既有樣板)

【關鍵約束(務必全守)】
- root tenant 經 viewer_is_platform_admin() 無條件豁免所有 license 執法
- License 上傳端點與登入端點豁免唯讀 gate(防死鎖:過期後要能裝新照)
- 唯讀 gate 全域攔 POST/PUT/PATCH/DELETE 回 403,做成環境開關可整體關閉(上線保險絲)
- decorator 順序:@jwt_required() → @require_xxx → @inject(common/authz/decorators.py 定死)
- 新 error code 照 GRC_<HTTP><序號> 命名,BE 新增必同步 FE error-code.json

【人工驗收】
測試租戶未授權模組 API 403、授權模組通;開關關閉全放行;root 完全不受限;readonly 租戶所有寫入 403 但可登入可下載匯出可上傳新照;沒買問卷包的租戶任務型態下拉無問卷;未授權模組選單消失;「沒買 project」在 API 層被擋。

【完成時回寫】CM-1124~1127 逐一改「修正待驗證」+白話補充;CM-1123 同步;記錄執行紀錄。

完成後停下——本階段風險最高,必等 user 實測過才進下一階段。

§5

第 5 棒:FR-062.5 開通流程(兩張 case 分開派)

接手 FR-062.5「開通流程」。前置:FR-062.1、.2 已完成並驗收(不依賴 .3/.4 可並行;與 .4 同 repo 建議錯開避免衝突)。

本棒拆兩張獨立 case:

== Case A:T-5.1 離線開通(CM-1129,先做)==
【必讀】design.md §4.7 離線路徑 + discussion.md「開通流程」節;Notion 卡 CM-1129 完整內容
【內容】客戶系統首次登入偵測無照 → 導向開通頁 → 顯示本機機器碼 → 客戶把序號+機器碼交公司(人工)→ 公司簽出綁定該機的照回寄 → 客戶上傳 → 開通成功回寫(機器指紋+時間)
【repo】compliance-manager-be(開通頁 FE+BE)+ license_center(序號生成/機器碼受理,若卡內有列)
【驗收】新環境模擬全流程:離線開通走通、機器指紋正確綁定、發照紀錄表回寫成功

== Case B:T-5.2 線上開通(CM-1130,後做,等雲端環境就緒)==
【必讀】design.md §4.7 線上路徑 + SaaS 直寫路徑;Notion 卡 CM-1130
【內容】客戶輸入序號 → 打公司開通伺服器(掛自營雲端環境、主產品的一個模組、獨立公開端點)→ 自動下載照+回傳機器指紋。SaaS「後台指派即生效」一併補上(不走序號,內部產照直接寫入)
【驗收】離線案例流程改線上一鍵完成;SaaS 後台指派立即生效

【完成時回寫】各自對應卡改「修正待驗證」+白話補充;CM-1128 子需求卡同步;記錄執行紀錄。

各 case 完成後停下等驗收。

§6

第 6 棒:FR-062.6 簽發 Web 後台

接手 FR-062.6「簽發 Web 後台」。前置:FR-062.1 已完成並驗收(CLI+簽章引擎就緒)。可與 .2/.3 並行(不同 repo 零衝突)。

【Notion 卡】
子需求:FR-062.6 = CM-1131 https://app.notion.com/p/FR-062-6-Web-6-3b6346da4cd0810db707d5c6d7efd51e
子任務:T-6.1 = CM-1132、T-6.2 = CM-1133(先 fetch 完整內容)
母案:CM-1112

【必讀】
compliance-manager-be repo:docs/features/FR-062-2608-license-management/design.md §4.8(簽發站 Web 設計)
discussion.md「簽發端形態:極簡 Web 後台」節、「Plan 套餐範本」節、「補發與換綁流程」節

【工作目錄】
license_center repo(獨立部署、公司內部、不對外公開)

【內容】
兩頁 Flask 小應用,包在第 1 棒的簽章引擎上(Web 是殼、CLI 是引擎):
1. 客戶總覽頁:每客戶一列(客戶代碼/名稱/訂單編號/照型態/Plan/模組集/到期日/推算狀態/開通狀態),臨期排序上色。推算狀態=按到期日與 expiry_policy 推算(Host 客戶非即時實況,此限制照 design.md 標注)
2. 簽發/換發表單頁:選 Plan(讀 plans 表)帶入模組集 → 微調 → 產照+序號 → 寫 license_issuance;展延一鍵(抓原照改到期日、type: extension);補發一鍵(同內容重出)
Plan 管理:plans 表 CRUD(名稱/模組集合),改 Plan 只影響之後發的照

【關鍵約束】
- 私鑰仍只在簽發引擎層,Web 層不直接碰
- 內部系統但仍要有基本登入保護
- 遵守 license_center repo 自己的慣例(README 有基本說明)

【人工驗收】
總覽頁正確列出第 1 棒以來發的所有照與推算狀態;表單頁走完「選 Plan → 產照 → 紀錄入表」全流程;展延與補發一鍵可用;改 Plan 內容後新發照吃到新組合、舊照不變。

【完成時回寫】CM-1132/1133 改「修正待驗證」+白話補充;CM-1131 同步;記錄執行紀錄。

完成後停下等驗收。

§7

第 7 棒:FR-062.7 通知 + 既有租戶發照 migration(上版前最後動作)

接手 FR-062.7「通知與既有租戶發照 migration」。前置:FR-062.3 已完成並驗收(.7 依賴狀態機;migration 另需 .1/.2 的簽發與驗證能力就緒)。

【Notion 卡】
子需求:FR-062.7 = CM-1134 https://app.notion.com/p/FR-062-7-migration-7-migration-3b6346da4cd081e3831cd79b829bde60
子任務:T-7.1 = CM-1135(email 通知)、T-7.2 = CM-1136(既有租戶發照 migration)(先 fetch 完整內容)
母案:CM-1112

【必讀】
compliance-manager-be repo:docs/features/FR-062-2608-license-management/design.md §4.9(通知設計)+ §2 D14(最終修正:直接發正常照)
T-7.2 卡內易踩雷提醒全文

【內容】
T-7.1 email 通知:expiry_policy 各段的 send_email 旗標驅動,通知租戶管理員;沿用系統既有 SMTP/通知基礎設施
T-7.2 既有租戶發照 migration:為既有租戶(root tenant 除外)直接發正常格式照(全模組、效期約一年、type: formal);DEV/STG 內部環境發長效內部照。無過渡照、無豁免分支——執法第一天全量生效

【關鍵約束(最重要的一條)】
- 🔴 migration 只套 DEV。STG/POC 需決策者當次明確放行——即使交接文件或卡片寫了其他環境,套用前仍要停下確認
- 發照動作跨 repo:license_center 簽發、BE 側入庫,串接方式照卡內指示

【人工驗收】
T-7.1:發短效照觸發各段通知,email 正確送達租戶管理員
T-7.2:DEV 跑 migration 後全部非 root 租戶各有一張現行照、驗章通過、功能照常;新開租戶(無照)路徑行為正確

【完成時回寫】CM-1135/1136 改「修正待驗證」+白話補充;CM-1134 同步;記錄執行紀錄。

完成後停下等驗收——這是全案最後一棒,後續全案收尾(母卡收 Done、spec、手冊)由 user 另行發令。