FR-062 License 控管機制 — 全案 SUMMARY(含 STG/POC 雙環境部署)

產出日期:2026-08-10 · 由 fr062-LOG.md 四個 block 濃縮,非憑記憶重建 living 現況見同資料夾 fr062-STATE.md;決策軌跡與教訓全文見 fr062-LOG.md

§1

一句話成果

Guidant AI 上線銷售所需的 License 控管機制全案完成:公司自建簽發端(License Center,獨立 repo 獨立 DB,私鑰不出機)+產品端只驗不簽的信任模型落地,涵蓋簽章引擎、按模組授權、到期狀態機與通知、執法與唯讀降級、序號開通與機器指紋綁定、簽發 Web 後台,並於 2026-08-10 完成 STG 與 POC 雙環境部署與請照實測。


§2

全案階段回顧

階段 內容 狀態
.1 簽發端地基 Ed25519 簽章引擎+CLI+plans/license_issuance DB;照檔格式歷經三次演進(v2 信封 zlib+base64 打包·非加密 → v3 .license PEM 風格 armor → v2.1 三段 send_email 旗標) 完成
.2 產品端驗照 config.tenant_licenses 資料模型、root 後台授權管理、FE 授權狀態頁;照綁頂層租戶、整條讀照鏈過租戶樹 resolve 完成
.3 狀態機+橫幅 每日排程 cron 推進 notify→grace→readonly,conditional UPDATE 冪等;FE 全域到期橫幅;root tenant 特判豁免 完成
.4 執法進場 common/authz 第六軸+全域唯讀 gate+選單/任務型態動態過濾;兩支環境開關可整體關閉;/license/ 前綴整段豁免防死鎖 完成
.5 開通 離線(機器碼→簽照→上傳)與線上(序號+指紋一鍵換照)兩路;線上路徑 LC 開放公開 API,BE 代打並完整驗章 完成
.6 簽發 Web 後台 Tabler UI(pin 版入 static/vendor,不依賴 CDN):客戶總覽、簽發/換發表單、詳情頁、照檔下載、客戶授權時間線 完成
.7 通知+migration notify/grace/readonly 三段到期信(收件人=三旗標聯集+root fallback);既有租戶發照 SOP 與護欄腳本(DEV 演練) 完成
.8 角色矩陣 license 維度(驗收回饋追加) ui-routesis_licensed、FE 未授權能力點反灰空框、roles 寫入端守門、provisioning 第三道扣除、選單結構調整 完成
.9 手動停權獨立欄位(追加) 停權升為獨立欄位,cron 不再覆寫人為決策;API 回傳旗標;FE 文案與狀態快取失效 完成
.10 產品後台向 LC 請照(追加) LC API token 白名單+管理頁+三支內部簽發 API;產品 BE lc-issue/lc-extend/lc/plans;FE 請照 dialog——SaaS 續約從此免人工搬檔 完成

§3

今日(2026-08-10)重點

三輪追加開發

  • FR-062.8:執法上線後發現角色權限矩陣完全沒有 license 維度——只買基礎包的租戶,管理員仍勾得下未購買模組的能力點且真的入庫。採業界 show-and-disable(反灰+原因),存量資料走 evaluate-time 抑制不做破壞性移除。初版把存量項渲染成「打勾+標籤」,驗收後推翻為反灰空框。
  • FR-062.9:手動停權與到期狀態混用,導致橫幅顯示錯誤且人為停權會被 cron 自動撤銷。停權改為獨立欄位,cron 只管到期軸。migration 回填時刻意不寫 suspend_reason——該欄會直接顯示給客戶。
  • FR-062.10:SaaS 續約原本要 admin 在 LC 簽發下載、再切回產品上傳,兩趟手動搬檔。改為產品後台帶 API token 直打 LC 內部簽發 API,回照仍走本地完整驗章與既有落地漏斗。驗收當下另追加三卡(LC 總覽開通狀態三態化、同客戶分組+排序、搜尋+篩選)。

STG / POC 雙環境部署

每環境依序走:套 migration → keygen → 公鑰進 BE code → BE 重部署 → LC 起服務 → 建 API token → 請照實測。

  • 三環境簽發鑰各自獨立(決策者要求):DEV 2ce3bb59a6f5a2ce / STG 04b1e65f100c6c8f / POC f3b562a6d9755527,三把公鑰共存於 common/license/public_keys.py,私鑰各留該機。STG 首把因 passphrase 對不上作廢重產。
  • POC 首發簽出 deployment_mode 記載錯誤的照(BE 未傳、LC 套預設 saas),修為請照時帶本站台 config;兩側 license 資料依決策者指示清空重發。

§4

Commits(僅 FR-062 相關)

BE(compliance-manager-be,main,已 push)

今日 16 支:

8ca60a81 docs 授權管理使用指南(平台管理員 + 租戶使用者兩視角)
8c82e8e6 fix .10 請照未指定 deployment_mode 時帶本站台 DEPLOYMENT_MODE
358cb601 feat POC 簽發鑰 f3b562a6d9755527 進 PUBLIC_KEYS
d7cc0394 fix STG 簽發鑰換為二次 keygen 的 04b1e65f100c6c8f
de96ed92 feat group-license 選單群組沉底 sort 45→90
214b72f6 feat STG 簽發鑰進 PUBLIC_KEYS(首把,後作廢)
a14f2070 feat .10 CM-1177 產品 BE 向 LC 請照 app service + route
543ff6dd docs .10 CM-1179 design.md §4.7 圖 4 修正+設計摘要
bde8fc1b fix .9 CM-1173 migration 回填不寫 suspend_reason
d725ade1 feat .9 CM-1173 手動停權升獨立欄位+API 旗標
e63649c8 docs .8 T-8.5 補登 design.md §5+統計校正 27→28
d0de3baf feat .8 CM-1171 選單結構調整(is_platform 正解)
6802da99 feat CM-1169 POST/PUT /roles 寫入端 license 守門
50652ec1 feat .8 CM-1170 建租戶 seed 第三道扣除未授權模組
9c5a1d71 feat .8 CM-1167 GET /ui-routes 附 is_licensed
37cc661b docs .8 子需求補登 design.md §5+features README

先前階段(.1~.7 與驗收回饋期)另有約 35 支,見 git log --oneline | grep FR-062

FE(compliance-manager-fe,main,已 push)

今日 9 支 FR-062 相關:

d00ba1b feat .10 請照 dialog 補照型態選項(admin 可發 Trial)
48041e2 fix .9 CM-1183 追加:登出前先等 chatbot session 清完
0f734d0 fix .9 CM-1183 登出後不再誤打 license status
2a1d3c5 fix .10 CM-1178 授權歷程補 lc_issue/lc_extend 翻譯
21677cd feat .10 CM-1178 授權管理頁「向 LC 請照」dialog
7462cab feat .9 CM-1174 停權文案與狀態快取失效
5b76fae fix .8 CM-1168 未授權能力點一律不打勾
3263045 feat .8 CM-1171 角色矩陣平台頁判定改吃 is_platform
c8dab0c feat .8 CM-1168 角色矩陣未授權反灰+顯示原因

另有 SaaS 版文案/入口三支(7b767ca/1c2a46d/4ed56cd)與 4d24a1a error-code 補譯。

LC(license_center,main,已 push)

今日 8 支:

d001b76 docs LC repo CLAUDE.md(架構守則、安全鐵律、與主產品介面)
3671e38 docs License Center 部署手冊——以 STG 實戰部署為藍本
72d61ba feat 綁定位址環境變數化 LICENSE_CENTER_BIND_HOST
4122456 feat .10 CM-1182 客戶總覽搜尋框+下拉篩選
4b45d81 fix  .10 CM-1181 客戶名稱欄補表頭排序(原實作漏掛 sort)
cb9a73d feat .10 CM-1181 客戶總覽同客戶視覺分組+List.js 排序
1464d91 fix  .10 CM-1180 開通狀態三態化
e622350 feat .10 CM-1176 API token 白名單+管理頁+內部簽發 API

§5

行為差異(使用者看得到的變化)

對象 變化
平台管理員(root) 授權管理頁可直接向 License Center 請照(新簽/展延/Trial),不必再去 LC 下載檔案再回來上傳;每租戶列有授權歷程時間線
平台管理員 手動停權成為獨立軸——停權不會被每日 cron 依到期日自動撤銷,狀態顯示與到期狀態不再互相干擾
所有使用者 側邊選單新增獨立的**「授權管理」群組**(沉底 sort=90);未完成的「自定義儀表板」入口關閉
租戶管理員 角色權限矩陣中,未購買模組的能力點反灰並顯示原因,不再看得到也勾得下去;繞過 UI 直打 API 亦回 403
LC 操作者 客戶總覽:開通狀態改三態(無序號照不再誤標未開通)、同客戶視覺分組、表頭可排序、有搜尋框與下拉篩選
LC 操作者 新增 API token 管理頁(新增/列表/停用),發照紀錄可看出由哪個環境請發

§6

規範文件清單

文件 狀態
docs/features/FR-062-2608-license-management/design.md 已回寫至最新(§4.7 圖 4 修正+.10 設計摘要、§5 拆分表 28 子任務、.8 三段裁示 callout);.9 手動停權尚未在 design.md 留段落,屬已知缺口
docs/features/FR-062-2608-license-management/discussion.md 已含實作後記
license_center/docs/deployment-guide.html 新增,以 STG 實戰部署為藍本(systemd unit、環境變數、keygen 與公鑰接線)
license_center/CLAUDE.md 新增(架構守則、安全鐵律、與主產品介面)
BE docs/.../授權管理使用指南 由平行 runner 於 8ca60a81 補入(平台管理員+租戶使用者兩視角)
docs/specs/current/ 頁面 spec 由平行 runner 處理中
existing-tenant-license-migration-sop.md 保留,轉為 DEV 演練與離線備援用途(STG/POC 實際改走「向 LC 請照」)

§7

已知 follow-up

  1. 三 repo push:本次已完成(HEAD == origin/main);未來新 commit 仍等決策者明示
  2. v1.14.0 發版未完成release/v1.14.0 branch 存在但落後 main 2 commit,release note 未寫、pyproject.toml 仍為 1.13.0 — 要發版走 version-bump skill
  3. STG 兩租戶正式發照:BE/LC 已就緒,發照動作由決策者手動執行(現有 2 張為部署驗證照)
  4. 雲端 LC 公網補驗:TLS/網域/防火牆,清單在 CM-1130 卡內;目前 LC 皆內網 :5062
  5. 正式環境簽發鑰:產出後必須先進 common/license/public_keys.py 才 build 出貨 image
  6. design.md 缺 FR-062.9 段落:手動停權獨立欄位的設計未落 design.md
  7. CM-1143 遺留模組整鏈退役(cruise-project/resource/report+jedi-resource-store):Not started,全案後另議
  8. 未套的三支 migration(決策者裁示這次不動):2026-07-20-ssp-shared-metadata-DEV-cleanup2026-08-01-fr058-22-openscap-content-path-advanced2026-08-03-fr060-1-detection-profile-split

§8

部署 handover

三環境座標

DEV(本機/188) STG(192.168.50.188) POC(192.168.50.189)
產品 DB guidant_ai_dev guidant_ai_stg guidant_ai_poc
LC DB license_center_dev license_center_stg license_center_poc
產品 BE 本機 :8000 /opt/compliance-manager-be :8000 /opt/compliance-manager-be :8000
LC 本機 :5062 /opt/license_center,systemd license-center.service(enabled,BIND_HOST=0.0.0.0):5062 /opt/license_center :5062
FE dev :5180 nginx /var/www/html/audit-manager :80 nginx /var/www/html/audit-manager :80
簽發鑰 kid 2ce3bb59a6f5a2ce 04b1e65f100c6c8f f3b562a6d9755527
LC API token BE-dev-T2-test(dev) Staging(stg) GuidantAI-POC(production)
FR-062 migration 7 支 7 支 7 支

DB 連線一律 -p 25432 -U cmmgr,密碼請查 .envDB_SECRET。LC 管理密碼與 passphrase 在各機 LC .env

上正式環境的檢查項

  1. 簽發鑰先於 image:正式環境 keygen 後,公鑰 kid 必須先進 common/license/public_keys.py 並 commit,才 build 出貨 image。順序顛倒=產品收不到正式照,報「未知的 kid」
  2. 私鑰保管:正式私鑰須進密碼管理器+兩處站外備份。私鑰遺失=無法簽續約,且 passphrase 是 keygen 當下設定的檔案解鎖密碼,事後改設定檔無效
  3. 請照必帶 deployment_mode:不讓 LC 用預設值猜(POC 曾因此簽出錯誤照)
  4. 三環境公鑰共存不取代:新增 kid 不刪舊 kid,否則既有環境的照全部驗不過
  5. 執法總開關LICENSE_ENFORCEMENT_ENABLED / LICENSE_READONLY_GATE_ENABLED 預設 true,上線前確認符合預期
  6. root tenant 永不持照:root 無條件豁免執法,正式環境不應為 root 發照