依
docs/features/FR-052-2607-cloud-tab-gate/design.md。 跨 repo:FE 為主(compliance-manager-fe);BE 視 Step 0 選項(零或極小)。 只規劃不實作——user approve 後才進 Phase 5。
先讓 user 二選一(design §2.2 表):
| 選項 | BE 改動 | 說明 |
|---|---|---|
| A(建議) | 零 | FE 直接打既有 GET /integrations/google-drive,判 status==='CONNECTED' |
| B(user Phase 0 原選) | 新一支 /connected route |
語意最窄但與既有 GET 重疊 |
user Phase 0 選 B,但當時未知既有 GET 已非 admin gated。開工前一句話確認——若改選 A,跳過所有 BE 任務。
FE 前置 grep:CloudIntegrationService(src/service/)是否已有取 tenant drive status 的方法?有 → 直接用,FE 也不重造。
輸出:Step 0 結論寫本檔末,再開工。
app/cloud_integration/service/google_drive_integration_service.py:加
@transaction
def is_connected(self, tenant_id: int) -> bool:
return self.get_status(tenant_id).status == "CONNECTED"api/cloud_integration/routes/google_drive_integration_route.py:新 GoogleDriveConnectedRoute(MethodResource),GET,jwt_required(),回 return_response(True, {"connected": service.is_connected(user.tenant_id)})。api/cloud_integration/__init__.py:add_resource(GoogleDriveConnectedRoute, "/integrations/google-drive/connected")。CloudIntegrationService.getGoogleDriveStatus() 已存在(src/service/CloudIntegrationService.js:14-17,打 GET /integrations/google-drive,已含 BaseService 返回值歸一化)→ F1 零改動,直接用。getDriveConnected() → GET /integrations/google-drive/connected + src/config/api/api.js 補常數。src/views/project/ProjectPlanningView.vue:
const driveConnected = ref(false);onMounted 內 loadDriveStatus()(A: s.status==='CONNECTED';B: s.connected===true;catch → false,fail-closed)。<TabPanel>(:2110)加 v-if="driveConnected"。ProjectPlanningView.vue:289-296 TAB_INDEX_BY_QUERY 含 cloud:5,activeTabIndex 在 setup 同步初始化、早於 loadDriveStatus() resolve。未連接 tenant 帶 ?tab=cloud 進來 → activeIndex=5 指向不存在的 tab。F2 必做 clamp:loadDriveStatus resolve 後 if (!connected && activeTabIndex.value >= 5) activeTabIndex.value = 0。
tab=cloud 來源,但 query 是 user 可自由帶的 → clamp 不可省。v-if 移除末 tab 不影響前 5 index。連 / 未連 / ?tab=cloud 深連結三情境驗。tab_cloud_integrations 譯名不動。Step 0(A/B 拍板 + FE grep 既有 service)
↓
[若 B] B1 → B2(BE pytest 綠)
↓
F1(service)→ F2(tab v-if)→ 驗 TabView index
↓
manual smoke(連 / 未連兩 tenant)→ Phase 4 test-plan → E2E
v-if 即恢復恆顯);B1/B2 各一 commit。2026-07-21 首腦 review 已做完 FE grep + BE route 複核。A/B 最終仍等 user 一句話拍板(勿自行定案),但證據強烈指向 A。
✅ FE grep(已做完):
CloudIntegrationService.getGoogleDriveStatus() 已存在(src/service/CloudIntegrationService.js:14-17,打 GET /integrations/google-drive,已含 BaseService 返回值歸一化)→ 選 A 連 F1 都零改動,FE 只剩 F2 一個 task。✅ BE route 複核(已做完):
GET /integrations/google-drive 只有 jwt_required(),DELETE 才 viewer_is_super_admin(google_drive_integration_route.py:22-50)→ 選 A 的 reuse 端點對全登入者開放,可行。判定:選 B 的唯一理由「不外洩 email/folder」不成立——既有 GET 本來就對全 JWT 開放,B 收不回任何暴露。選 A 則整個 FR-052 = ProjectPlanningView.vue 單檔改動(F1 零改、只做 F2)。首腦強烈建議 A。
✅ 決策:走 A(reuse 既有 GET,零 BE 改動)(2026-07-21 首腦「往下做」授權下定案;B 唯一理由已證不成立)。→ BE 任務全跳過,FR-052 = ProjectPlanningView.vue 單檔 F2(F1 用既有 getGoogleDriveStatus())。
✅ 深連結風險已證實(見 F2):?tab=cloud 殘留 index=5 為真(ProjectPlanningView.vue:289-296),F2 clamp 已從「保險」升為「必做」。