FR-110 收口 SUMMARY — Google Drive 應用程式憑證從主機設定檔搬進畫面

整案四階段全部驗收通過,決策者手測完畢。BE 20 支 commit + FE 7 支,兩 repo 均已 push。

2026-09-18 決策者二度手測後追加三張卡(CM-1912/CM-1913/CM-1940),全數 Done,本檔已含其內容(§2 commit 清單、§4 行為差異、§9 追加卡明細、§10 已知事項)。

1. 做完的事(一句話)

把「Guidant AI 這套系統在 Google 登記的那組應用程式帳號」從主機的 .env 搬到畫面上:平台管理員登入 → 側邊選單「系統設定 → Google Drive 應用程式設定」→ 填編號與密鑰 → 按「驗證憑證」當場知道填對沒有 → 複製畫面上算好的回呼網址貼進 Google 後台 → 存檔。密鑰加密落庫,改完不必重啟服務。

2. Commits

BE(compliance-manager-be,branch feature/review,20 支)

Hash 卡 內容
2e41513e CM-1895 T-1.1 GOOGLE_DRIVE_APP_CONFIG 群組落地——密鑰遮罩、寫入合併、平台管理員守門
bb4aba21 CM-1896 T-1.2 憑證解析器——整組切換、繞 RLS 讀 ROOT、網址推導
784917f7 CM-1897 T-1.3 GoogleOAuthClient 改成每次呼叫才解析憑證 + DI 接線改造
f00cab28 CM-1910 T-1.3b OAuth 用戶端測試 fixture 跟上新簽章(補卡)
5f51315a CM-1911 T-1.5 通知頻道對外網址改成向解析器要(補卡,設計遺漏補接)
5e4396b6 CM-1899 T-2.1 讀/存回應帶上推導後的兩個網址
f3840d1f CM-1900 T-2.2 驗證憑證端點——三態判定
292700ab CM-1900 清掉測試檔未使用 import
0c1b1c00 CM-1902 T-3.2 選單登記 migration
3c04dfc3 CM-1903 T-3.3 平台憑證未設定時擋下租戶連接,回 GRC_412053
6e580e8f CM-1903 凍結碼表補登 GRC_412053(驗收補正)
7bca3b32 CM-1904 T-4.1 設定檔範本與部署文件退場
60be8007 CM-1905 T-4.2 離線 Drive 分類腳本停用而非炸 TypeError
f5cf8bfb — 收尾文件(2026-09-17):spec 兩頁、SUMMARY、STATE、analysis、FR 登記、memory 同步
1fda5f46 CM-1912 T-3.4 資料夾初始化子執行緒補回身分——修「授權成功但 0 個子資料夾」的靜默失敗
844e9d87 CM-1913 T-3.5 通知登記失敗不再帶掉授權 + 兩個覆寫欄位後端擋格式 + 手冊補「在 Google 取憑證」六步
a0ae4f37 CM-1940 T-3.6 專案總覽可一鍵開啟該輪 Drive 資料夾(新增唯讀端點)
a8b906cf CM-1940 spec:專案總覽 14b 入口改名「證據雲端資料夾」(決策者回饋,供應商中性)
dbee2d9b CM-1940 spec:專案雲端整合頁補「證據雲端資料夾」入口一段
8cc99148 CM-1902 出貨基線重產——選單 migration 進 02-schema.sql(與 FR-071 一支同批,共用 commit)
(本次) — 收尾補正:本檔、STATE、FR 站 README、FR 登記表,重 build 兩站

另有一支 design commit(設計定案,早於實作)。8cc99148 是與 FR-071 共用的基線重產 commit,兩案各一支 migration。

FE(compliance-manager-fe,7 支)

Hash 卡 內容
4bcb361 CM-1901 T-3.1 設定頁——五欄位、複製鈕、驗證鈕、換帳號確認框、路由守衛、選單過濾、i18n
7380674 CM-1903 平台憑證未設定時租戶頁停用連接鈕並留住提示
0f48c0d CM-1901 密鑰欄標籤列撐高導致與 ID 欄輸入框不對齊(手測回饋)
4ccbc25 CM-1913 對外網址非 HTTPS 當場警告 + 兩個覆寫欄位格式檢查 + 整合卡顯示降級提示
93b1dc7 CM-1940 專案總覽動作列新增開啟 Drive 資料夾按鈕
9d8c140 CM-1940 按鈕改名「證據雲端資料夾」並換供應商中性圖示(決策者回饋)
5f42099 CM-1940 專案規劃頁雲端整合 Tab 也加同一個入口

3. 改動範圍

BE 新增:app/system_config/service/google_drive_app_config_resolver.py(憑證解析器,224 行)、app/cloud_integration/service/drive_app_credential_verify_service.py、api/cloud_integration/routes/drive_app_credential_verify_route.py、common/constant/drive_app_config.py、scripts/sql/2026-09-17-fr110-google-drive-app-config-menu.sql,以及五支測試檔。

BE 修改:app/system_config/service/guarded_system_config_service.py(加 Drive 群組分支)、infra/cloud_integration/google_drive/google_oauth_client.py(改每次呼叫解析 + probe_credentials)、app/cloud_integration/service/google_drive_integration_service.py(未設定時擋)、app/notification/service/webhook_channel_manager.py(對外網址改向解析器要)、di_containers/cloud_integration/、common/code/flow_control_error_code.py、common/middleware/app_mw.py、config/config.py、.env.sample。

FE 新增:src/views/google-drive-app-config/GoogleDriveAppConfigForm.vue(404 行)、src/config/driveAppConfig.js、兩份 i18n。FE 修改:router、AppMenu、CloudIntegrationService、axios interceptor、GoogleDriveIntegrationCard.vue、error-code i18n。

無新表、無新 repository、無新 domain service——設定進共用的 system_configs,只多一個 group。

4. 使用者看得到的行為差異

  1. 新頁面:側邊選單「系統設定」底下多一項「Google Drive 應用程式設定」(/system/drive-app-config)。只有平台管理員看得到,一般租戶管理員完全看不到(有能力點也擋)。
  2. 四項憑證改在畫面填:應用程式編號、密鑰、系統對外網址(新欄位),另兩串網址自動算出、唯讀顯示附複製鈕。改完不必重啟服務。
  3. 驗證憑證按鈕:當場回「憑證正確 / 憑證錯誤 / 無法連線至 Google」三態。憑證正確時多一句提醒:回呼網址仍要自己貼進 Google 後台(換票不比對它)。
  4. 密鑰不再有明文出現在畫面:已設定只顯示「已設定」;留空存檔=沿用舊值;要清除得按「清除密鑰」再存檔。
  5. 換應用程式編號會跳確認框:說明「所有已連接的客戶都需要重新授權一次」。只警告,不自動清任何租戶的連線狀態。
  6. 租戶端有前提提示:平台端還沒設定時,「雲端空間整合」頁的「連接 Google Drive」按鈕停用並顯示「系統尚未完成 Google Drive 應用程式設定,請聯繫平台管理員」,不再讓人按下去撞 Google 的英文錯誤頁。
  7. 安裝手冊動線變了:原本要 ssh 進主機改 guidant.env 再 guidant start,現在改成登入畫面填。手冊另補一節「怎麼去 Google 拿到這組資訊」六步(建專案 → 啟用 Drive API → OAuth 同意畫面 → 建用戶端 → 貼回呼網址 → 複製編號與密鑰),含三個踩過的坑:同意畫面停在「測試中」要把帳號加進測試使用者、回呼網址兩邊必須逐字一樣、密鑰只顯示一次。
  8. 即時通知登記失敗不再帶掉整個授權:Google 規定通知網址必須是 https,內網/開發環境常常不是。原本這個失敗會把已拿到的權杖一起 rollback,畫面丟英文「WebHook callback must be HTTPS」;現在授權照常完成、狀態維持已連接,只在該租戶那列記一句白話降級說明(「即時通知未啟用……改由定時輪詢同步」),並顯示在「雲端空間整合」卡片上(警告色,不是錯誤色)。設定頁在對外網址不是 https 時當場警告,但不擋存檔——內網部署是合法的降級用法。
  9. 兩個進階覆寫欄位填錯當場擋下:回呼網址覆寫必須以 /api/1.0/integrations/google-drive/callback 結尾、通知用對外網址覆寫不可帶路徑,前後端各擋一層(SYSTEM_CONFIG_400002 / 400003)。原本填錯存得進去,症狀要等別人按授權時撞 Google 的英文 redirect_uri_mismatch 才浮現。
  10. 專案頁可一鍵開該輪的 Drive 資料夾:專案總覽動作列與專案規劃頁的雲端整合 Tab 各多一顆「證據雲端資料夾」,按下去新分頁開這個專案、這一輪在雲端硬碟的資料夾;切換稽核輪次後開的是另一個資料夾。沒接 Drive、或資料夾還沒建好時按鈕不顯示(不是反灰)。新增唯讀端點 GET /integrations/google-drive/projects/<uid>/folders?round_uid=。
  11. 資料夾初始化不再靜默 0 個:重新授權後系統會自動建六層資料夾骨架,原本最上兩層建得出來、底下全是 0 個,而那支背景工作還標成「成功」,使用者要等到真的要放檔案才發現無處可放。現已修正(子執行緒補回身分),且整批全滅時工作會標失敗而不是假裝成功。

5. 規範文件

文件 狀態
docs/spec-site/current/system-admin/google-drive-app-config.md 本次新增(13 節完整頁面 spec)
docs/spec-site/current/evidence/cloud-integrations.md 本次更新(連接前提、UC-CI-01 前置條件、錯誤碼、變更紀錄各一處)
docs/spec-site/mkdocs.yml 本次更新(nav「系統設定」群組新增一列)
docs/user-manual/onprem/10-optional-features.md T-4.1 已改(7bca3b32)——操作步驟由「改設定檔+重啟」改為「登入畫面填」
.env.sample T-4.1 已改——四項標註「改由畫面設定,此處僅開發機後備」,並補上一直漏掉的 DRIVE_WEBHOOK_PUBLIC_BASE_URL
docs/features/FR-063-2608-nuitka-packaging/deployment-env.md T-4.1 已改(同一支 commit)
docs/spec-site/current/project-management/project-overview.md CM-1940 已改(a0ae4f37 / a8b906cf)——§1.1 功能總覽表新增「證據雲端資料夾」入口一列
docs/spec-site/current/evidence/project-cloud-integration.md CM-1940 已改(dbee2d9b)——雲端整合 Tab 補「證據雲端資料夾」入口一段
docs/user-manual/onprem/10-optional-features.md(第二次) CM-1913 已改(844e9d87)——補一節「前置:在 Google 取得這組應用程式憑證」六步
docs/analysis/2026-09-17-drive-app-credential-db-first-env-fallback.md 本次新增(設計取捨與兩個遺漏的教訓)

6. 已知 follow-up

  1. error code 鏡像測試 test_error_code_mirror_parity 紅:主專案的 flow_control_error_code 碼表比 jedi_compliance_audit 多三碼(含本案新增的 GRC_400122 / GRC_412053)。決策者裁下次發套件時一併補,本案不動。memory:followup_error_code_mirror_parity_jedi_compliance_audit_lagging。
  2. 離線 Drive 分類腳本待刪:classify_evidence_drive.py 現為停用狀態(60be8007),屬 FR-107 舊 Drive 分類線的一部分,待下一版隨該線一併移除。memory:followup_fr107_remove_legacy_drive_classification_line。
  3. AI 服務設定頁尚無對應 spec 頁:本案照抄的機制先例(FR-107 T-5.5 的 AI 金鑰 DB 化)自己沒有頁面 spec。Drive 這半邊本案已補齊,AI 那半邊仍缺,待該線收口時補。

7. 部署 handover

項目 內容
Migration scripts/sql/2026-09-17-fr110-google-drive-app-config-menu.sql(一支,選單登記)。已套 DEV。STG / POC 走 init image 的 migrate 模式(GUIDANT_INIT_MODE=migrate),不手動 psql 逐支套
出貨基線 已重產(8cc99148)——選單 migration 已進 scripts/init/02-schema.sql 與 99-stamp.sql,新裝機器側邊選單看得到這一項
環境變數 GOOGLE_DRIVE_OAUTH_CLIENT_ID / ..._SECRET / ..._REDIRECT_URI / DRIVE_WEBHOOK_PUBLIC_BASE_URL 四項可留作後備(資料庫沒設定時整組退回讀它們),開發機仍靠它們;DRIVE_TOKEN_ENCRYPTION_KEY 必留——密文與鑰匙必須分開放,鑰匙進資料庫等於沒加密。這把是空的時候,本頁存檔會直接拋錯(沒有存明文這條路)
裝機不 seed 刻意不把設定檔的值寫進資料庫:「資料庫裡有=有人設過」是個乾淨的判準,日後做「未開通」提示要靠它
升級既有機器 既有客戶的 .env 不動照樣運作(後備層讀得到);要改用畫面設定就在畫面上填一次,填完資料庫那組即接管

8. 驗收時發現與修正的事

# 發現 處置
1 T-1.3 改了 GoogleOAuthClient 簽章,但既有 12 支測試沒跟著改,在啟動階段就錯 補卡 CM-1910,f00cab28
2 設計漏了「Google 變更通知的對外網址」這個消費端——它另有一條取值路徑,不跟著改就仍讀舊環境變數 補卡 CM-1911,5f51315a
3 T-3.3 新增 GRC_412053 但沒同步凍結碼表,守衛測試紅 首腦補正 6e580e8f
4 FE 密鑰欄因多了狀態標記把標籤列撐高,與編號欄輸入框上緣不齊 手測回饋,0f48c0d
5 common/middleware/app_mw.py 的 request body log 原本沒有遮罩 T-2.2 順手接上(client_secret 落在 mark_password 的 secret 樣式內)

9. 2026-09-18 二度手測後追加的三張卡

決策者 2026-09-18 實際拿這頁去開通 Drive,連撞多關,追加三張卡全部 Done。

卡 問題 處置
CM-1912(T-3.4) 重新授權後,資料夾骨架只建出最上兩層,底下 0 APs, 0 CGs, 0 CONTROLs, 0 AOs, 0 TASKs,而背景工作標成成功。授權畫面顯示已連結,雲端硬碟裡卻沒有可放證據的資料夾,整條路徑沒有任何錯誤訊息 根因是既有潛伏 bug 被本案手測暴露:建資料夾用 ThreadPoolExecutor 扇出,子執行緒不繼承 ContextVar 裡的身分,session_scope() 讀不到身分走 fail-closed,PostgreSQL RLS 把 tenant_drive_integrations 整張擋成 0 列。改成每個 task 各 contextvars.copy_context().run(...) 帶一份 context 進去;整批全滅時新增 DriveFolderBatchFailedError 讓工作記 FAILED(不再假裝成功);部分失敗維持不中斷、下次冪等補齊。修後同一專案從 0 個變成 1 AP/6 CG/17 控制項/59 AO/59 任務。1fda5f46
CM-1913(T-3.5) 三個缺口都是「沒有訊息或只有 Google 的英文原文」:①租戶走完授權卻整個失敗,畫面丟英文「WebHook callback must be HTTPS」;②設定頁填 http 對外網址存檔顯示成功,要等別人按授權才爆;③回呼網址覆寫少填路徑段照樣存得進去,症狀是使用者撞 Google 的 redirect_uri_mismatch ①通知登記包 try/except,失敗記 WARNING + 白話降級訊息寫進該租戶的 last_sync_error,授權本體與權杖保住(沿用既有的獨立 session 寫法,不另造);②設定頁對實際生效的通知網址判 https,不是就在該欄位下顯示黃色警告,不擋存檔;③兩個覆寫欄位前後端各擋一層。另補手冊一節。BE 844e9d87、FE 4ccbc25
CM-1940(T-3.6) Drive 都設定好了,但系統裡找不到路走到雲端硬碟,證據檔在哪只能自己翻 新增唯讀端點 GET /integrations/google-drive/projects/<uid>/folders?round_uid=(查 drive_folder_mapping,查不到或已失聯一律回 null,不拋錯);專案總覽與專案規劃頁雲端整合 Tab 各加一顆按鈕,有輪次資料夾就開它、否則退開專案資料夾、兩個都沒有就不顯示。按鈕原名「開啟 Google Drive」,決策者改名「證據雲端資料夾」並換供應商中性圖示——日後接別的雲端硬碟不必再改文案。BE a0ae4f37、FE 93b1dc7 / 9d8c140 / 5f42099

10. 已知事項(手測撞到但不是系統問題,記錄供日後排查)

  1. Google 的通知網址必須是 https:內網或開發環境沒有對外 https 時,即時通知登記一定會失敗。這是 Google 的規定不是系統缺陷——檔案同步照樣靠定時輪詢進行,只是延遲較久。設定頁會警告、整合卡片會顯示降級說明。
  2. 對外網址那條隧道一次只能一邊用:本機與 189 若指向同一條 cloudflare tunnel,Google 的回呼與通知會被導到另一邊,症狀是回呼落空或通知打到別台。要在本機測就先確認那條隧道現在指著誰。
  3. 在 Google 後台登記回呼網址後要等幾分鐘才生效:這段期間按授權會看到 redirect_uri_mismatch,那是正常的、等一下再試,不是設定填錯。手冊那一節已寫進這個提醒。
  4. 通知的「channel mismatch」可能是時序:系統把通知頻道寫進資料庫的那筆交易還沒 commit,Google 就已經打通知回來,這邊查到的還是舊頻道編號於是丟棄。下一次推送就正常。
  5. 狀態 API 不回 webhook_channel_id:那支 DTO 本來就沒有這個欄位,不是漏填。要看頻道編號直接查 tenant_drive_integrations。