# A.1 盤點：platform 平台層端點 × 三段式能力點

> 卡片 CM-2515（FR-132 T-1.5）。唯讀盤點，不改程式、不改 DB。

## 範圍與數量

- **範圍**：AI 儀表板（ai-dashboard）、AI 呼叫紀錄（ai-call-log）、AI 額度（ai-quota）、公告（bulletin、bulletin-list）、意見回饋（feedback、feedback-view）、操作紀錄（log）、支援頁（診斷包、最近錯誤）。另把卡片「怎麼做」列到的 AI 小幫手（jedi-ai-bot）一併盤。
- **主專案 route 檔 4 支、15 個 method**：`api/ai_quota/` 1 支（7）、`api/ai_call_log/` 1 支（5）、`api/support/` 2 支（2）。
- **外部套件 route 檔 6 支、20 個 method**：jedi-ai-dashboard 1 支（2）、jedi-ai-bot 1 支（2）、jedi-bulletin 1 支（5）、jedi-issue 2 支（8，含標籤下拉）、jedi-log `api_log` 1 支（2）。讀的是 `.venv/lib/python3.11/site-packages/` 內實際執行的版本（ai-dashboard 1.6.1、ai-bot 1.5.0、bulletin 1.2.1、issue 1.3.2、log 1.3.2）。jedi-log 的 `forwarding`（log 轉發設定）屬 T-1.4 系統設定，不列。
- **合計 10 支檔、35 個 method**。
- **DEV 查詢時間**：2026-10-06 17:28（本機 `localhost:5432/guidant_ai_dev`）。範圍內舊能力點 16 個；全庫能力點 123 個，其中 `is_platform = true` 16 個。

## 先看這幾點

1. **「16 個平台層能力點」跟本卡的資源幾乎沒有交集。** DEV 的 16 個 `is_platform` 能力點只有 `log.read` 在本卡範圍；其餘 15 個是合規框架（3）、外部議題整合設定（4）、授權（1）、通用系統設定（3）、系統選單（4），分屬 T-1.2 與 T-1.4。本卡範圍的 16 個舊能力點裡，15 個是 `is_platform = false`。16 這個數字對（123 − 16 − 4 ＝ 103 成立），但「平台層能力點集中在 platform 模組」這個前提不成立。逐一對照見文末「附錄：16 個 is_platform 能力點」。
2. **所以「platform（原廠）」這個模組名放錯了大半內容。** AI 儀表板、AI 額度、AI 呼叫紀錄是租戶自己用、自己管的；公告是租戶對自己部門發的；意見回饋是租戶成員自己送、租戶管理員看全部。真正只有原廠（root 租戶）能碰的，只有操作紀錄、支援頁、AI 額度的「各租戶上限」三塊。建議見「待首腦裁清單」第 1～3 條。
3. **原廠層的後端守門走的是「平台管理員」判定，不是能力點。** 操作紀錄（`platform_admin_required`）、支援頁（service 層 `require_platform_admin()`）、AI 額度上限（同上）三塊，沒有一支 route 檢查能力點；`log.read` 只決定選單看不看得到。平台層要不要也改成能力點守門，見待裁第 4 條。
4. **公告列表有一個疑似缺口**：`POST /bulletins` 只驗登入，「看哪些公告」由請求帶不帶 `auth: true` 決定。不帶、且使用者沒有所屬部門時，service 不下任何條件，等於看到本租戶全部公告（不受發送範圍限制）。見「確認要補的守門缺口」第 1 條。
5. **`feedback.export` 不是孤兒**：匯出端點 `POST /feedback/export/<type>` 由它守（`jedi_issue/api/routes/feedback_route.py:140`），DEV 有 5 個角色持有。它只是沒綁任何頁面選單；FE 匯出鈕不判權限、一律顯示，沒權限的人按了才 403。

## 新名總覽（定案）

模組歸屬依決策者 2026-10-06 的八條定案填（見文末「定案結論」）。

| 新資源 | read | create | update | delete | 獨立動詞 | 取代的舊名 | 模組歸屬狀態 |
|---|---|---|---|---|---|---|---|
| `ai.dashboard` | ✓ | ✓ | ✓ | ✓ | — | `ai-dashboard.read` | `ai` 模組 |
| `ai.call-log` | ✓ | ✓ | ✓ | ✓ | `export` | `ai-call-log.read` | `ai` 模組 |
| `ai.quota` | ✓ | ✓ | ✓ | ✓ | — | `ai-quota.read`、`ai-quota.update` | `ai` 模組 |
| `ai.assistant` | ✓ | ✓ | ✓ | ✓ | — | 無（小幫手今天只驗登入） | `ai` 模組 |
| `workspace.bulletin` | ✓ | ✓ | ✓ | ✓ | — | `bulletin.*`、`bulletin-list.read` | `workspace` 模組 |
| `workspace.feedback` | ✓ | ✓ | ✓ | ✓ | `export` | `feedback.*`（5 個） | `workspace` 模組 |
| `workspace.feedback-review` | ✓ | —（破例只開 read） | —（破例只開 read） | —（破例只開 read） | — | `feedback-view.read` | `workspace` 模組 |
| `platform.api-log` | ✓ | ✓ | ✓ | ✓ | `export` | `log.read` | `platform`，`is_platform = true` |
| `platform.support` | ✓ | ✓ | ✓ | ✓ | `export` | 無（今天沿用 `storage-config.*` 綁選單） | `platform`，`is_platform = true` |
| `platform.ai-quota-ceiling` | ✓ | ✓ | ✓ | ✓ | — | 無（今天只驗平台管理員） | `platform`，`is_platform = true` |

- 「每個資源固定四個」照規則全開（`feedback-review` 例外，見定案第 8 條）；今天沒有對應端點的動詞（例如 `ai.call-log.create`）仍要建出來。
- `is_platform` 欄位：只有 `platform.*` 三組為 true，其餘 false。

## 主表

欄位：route 路徑 ｜ HTTP ｜ 程式位置 ｜ 現有守門 ｜ 新三段名 ｜ 現有能力點 ｜ is_platform（新名）｜ 對應 UI ｜ 可指派範圍層 ｜ 備註。

守門縮寫：**J**＝`jwt_required`；**L(x)**＝`require_license("x")`；**C(x)**＝`require_capability("x")` 或套件的 `capability_required`；**PA**＝平台管理員（`require_platform_admin`／`platform_admin_required`）；**S:** 後面是 service 層的檢查。路徑前綴一律 `/api/1.0`。套件路徑省略 `.venv/lib/python3.11/site-packages/`。

### AI 儀表板（ai.dashboard）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/ai-dashboard/health` | GET | 套件 `jedi_ai_dashboard/api/routes/ai_dashboard_route.py:71` | **無**（刻意免登入） | 不開能力點 | 無 | — | `DynamicDashboard.vue`（`useDashboardGenerator.js`） | — | 頁面載入時還沒 token 也要能回「小幫手上線了沒」；套件 `api/routing.py:17-27` 與套件測試焊死這個分工，不要補守門 |
| `/ai-dashboard/auto-generate` | POST | `ai_dashboard_route.py:110` | J（掛載期 `_guarded`）＋L(ai-dashboard)＋C(ai-dashboard.read) | `ai.dashboard.read` | `ai-dashboard.read` | false | `DynamicDashboard.vue`（選單 `/dashboard/ai-dashboard`） | tenant | 每次實打兩次外部 AI；能力點名由套件 `jedi_ai_dashboard/plugin/contract.py:25` 的 `GENERATE_CAPABILITY` 決定。生成是「看儀表板」的動作，維持 read |

套件守門 `jedi_ai_dashboard/api/guards.py`：license 與能力點都委派宿主注入（`core/plugins/ai_dashboard.py:89-91`），宿主沒接線一律拒絕，不放行。

### AI 小幫手（ai.assistant）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/ai-chatbot` | POST | 套件 `jedi_ai_bot/api/routes/ai_bot_route.py:39` | J（`jedi_ai_bot/plugin/assembly.py:70`，宿主 `core/plugins/ai_bot.py:87`） | `ai.assistant.read` | 無 | false | `ChatBox.vue`（`AppLayout` 右下角，全站） | tenant | 待裁第 6 條。只受 AI 額度限制；套件 `CAPABILITIES` 是空的（`jedi_ai_bot/plugin/contract.py:35`），也沒有 license 軸 |
| `/ai-chatbot` | DELETE | `ai_bot_route.py:71` | J | `ai.assistant.read` | 無 | false | 同上（清對話紀錄） | tenant | 只清自己的 session，跟使用歸同一個 |

### AI 呼叫紀錄（ai.call-log）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/system/ai-call-logs` | POST | `api/ai_call_log/routes/ai_call_log_route.py:46` | J＋C(ai-call-log.read) | `ai.call-log.read` | `ai-call-log.read` | false | `AiCallLogList.vue`（選單 `/system/ai-call-log`） | tenant | 列表；租戶隔離靠 RLS |
| `/system/ai-call-logs/<uid>` | GET | `ai_call_log_route.py:58` | J＋C(ai-call-log.read) | `ai.call-log.read` | `ai-call-log.read` | false | `AiCallLogList.vue`（明細） | tenant | |
| `/system/ai-call-logs/export` | POST | `ai_call_log_route.py:68` | J＋C(ai-call-log.read) | `ai.call-log.export` | `ai-call-log.read` | false | `AiCallLogList.vue` | tenant | 今天跟 read 同一顆；建議拆出 export（對外送出類），客戶可做到「看得到但不能整批帶走」 |
| `/system/ai-call-logs/usage` | POST | `ai_call_log_route.py:91` | J＋C(ai-call-log.read)；S: `tenant_id` 篩選限平台管理員 | `ai.call-log.read` | `ai-call-log.read` | false | `AiUsageSummary.vue` | tenant | 用量彙總 |
| `/system/ai-call-logs/usage/export` | POST | `ai_call_log_route.py:102` | J＋C(ai-call-log.read) | `ai.call-log.export` | `ai-call-log.read` | false | `AiUsageSummary.vue` | tenant | 同上 export |

基礎設施豁免：`common/authz/license.py:116` 把 `ai-call-log` 列在不受授權照管制的清單，改名時這個字串要跟著改。

### AI 額度（ai.quota／platform.ai-quota-ceiling）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/system/ai-quota` | GET | `api/ai_quota/routes/ai_quota_route.py:28` | J；S: C(ai-quota.read)（`app/ai_quota/service/ai_quota_setting_service.py:88`） | `ai.quota.read` | `ai-quota.read` | false | `AiQuotaPage.vue`（選單 `/system/ai-quota`） | tenant | route 層只驗登入（卡上說的「J 組」），守門在 service；本身不是缺口 |
| `/system/ai-quota` | PUT | `ai_quota_route.py:34` | J；S: C(ai-quota.update)（`:93`） | `ai.quota.update` | `ai-quota.update` | false | 同上 | tenant | |
| `/system/ai-quota` | DELETE | `ai_quota_route.py:40` | J；S: C(ai-quota.update)（`:107`） | `ai.quota.update` | `ai-quota.update` | false | 同上（「還原預設」鈕） | tenant | HTTP 是 DELETE，語意是把設定改回繼承，歸 update |
| `/system/ai-quota/me` | GET | `ai_quota_route.py:70` | J；S: 無（只回自己的） | 不掛守門 | 無 | — | `AiQuotaBanner.vue`、`ChatBox.vue`、`AutoClassifyBatch.vue`、`AiQuotaUsageCards.vue`（`useAiQuota.js`） | tenant | 個人視角：額度 80% 黃條。掛 `ai.quota.read` 的話一般成員會 403，見待裁第 2 條 |
| `/system/ai-quota/tenants` | GET | `ai_quota_route.py:48` | J；S: PA（`ai_quota_setting_service.py:118`） | `platform.ai-quota-ceiling.read` | 無 | true | `AiQuotaCeilingTable.vue`（`AiQuotaPage` 內，平台管理員才顯示） | tenant（root 限定） | 跨租戶總覽 |
| `/system/ai-quota/tenants/<id>/ceiling` | GET | `ai_quota_route.py:56` | J；S: PA（`:151`，`_assert_ceiling_target`） | `platform.ai-quota-ceiling.read` | 無 | true | 同上 | tenant（root 限定） | |
| 同上 | PUT | `ai_quota_route.py:62` | J；S: PA（同上） | `platform.ai-quota-ceiling.update` | 無 | true | 同上 | tenant（root 限定） | |

基礎設施豁免：`common/authz/license.py:118`（`ai-quota`）。

### 公告（workspace.bulletin）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/bulletins` | POST | 套件 `jedi_bulletin/api/routes/bulletin_route.py:37` | J；S: 依請求的 `auth` 旗標分兩種模式（`jedi_bulletin/app/service/bulletin_service.py:234-251`） | `workspace.bulletin.read` | 無（選單綁 `bulletin-list.read`／`bulletin.read`） | false | `BulletinList.vue`（`view=true`，帶 `auth:true`，選單 `/bulletin/bulletin-list`）；`BulletinManage.vue`（管理模式，選單 `/bulletin/bulletin-manage`） | org_unit | 讀者模式只看發給自己部門的；管理模式只看自己建的。**模式由前端決定**，見缺口第 1 條 |
| `/bulletin/<uid>` | GET | `bulletin_route.py:58` | J；S: 檢查發送範圍（帶 `current_user_context()`） | `workspace.bulletin.read` | 無 | false | `BulletinView.vue` | org_unit | |
| `/bulletin` | POST | `bulletin_route.py:103` | J＋C(bulletin.create) | `workspace.bulletin.create` | `bulletin.create` | false | `BulletinForm.vue` | org_unit | 能力點名由套件 `jedi_bulletin/plugin/contract.py:41-43` 預設值決定 |
| `/bulletin/<uid>` | PUT | `bulletin_route.py:70` | J＋C(bulletin.update) | `workspace.bulletin.update` | `bulletin.update` | false | `BulletinForm.vue` | org_unit | |
| `/bulletin/<uid>` | DELETE | `bulletin_route.py:81` | J＋C(bulletin.delete) | `workspace.bulletin.delete` | `bulletin.delete` | false | `BulletinManage.vue` | org_unit | |

套件沒有 license 軸。`bulletin.read` 與 `bulletin-list.read` 兩顆舊名，**後端沒有任何 route 守**，只綁選單。

### 意見回饋（workspace.feedback／workspace.feedback-review）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/feedbacks` | POST | 套件 `jedi_issue/api/routes/feedback_route.py:50` | J＋C(feedback.read 或 feedback-view.read 任一)；S: 有 `feedback-view.read` 看全部，否則只看自己送的（`jedi_issue/app/feedback/service/feedback_service.py:160-173`） | `workspace.feedback.read`；看全部要 `workspace.feedback-review.read` | `feedback.read`、`feedback-view.read` | false | `SystemFeedbackManage.vue`（`FeedbackManageTabView`，選單 `/feedback/system-feedback-manage` 與 `/feedback/system-feedback-view`） | tenant | 「看自己的」與「看全部人的」在同一支端點，由能力點切範圍 |
| `/feedback/<uid>` | GET | `feedback_route.py:73` | J＋C(同上任一) | `workspace.feedback.read` | 同上 | false | `SystemFeedbackView.vue`、`SystemFeedbackForm.vue` | tenant | 單筆讀取有沒有檢查「是不是自己的」未逐行核 |
| `/feedback` | POST | `feedback_route.py:81` | J＋C(feedback.create) | `workspace.feedback.create` | `feedback.create` | false | `SystemFeedbackForm.vue` | tenant | |
| `/feedback/<uid>` | PUT | `feedback_route.py:97` | J＋C(feedback.update)；S: 只能改自己送的（`_assert_owner`） | `workspace.feedback.update` | `feedback.update` | false | `SystemFeedbackForm.vue` | tenant | |
| `/feedback/<uid>` | DELETE | `feedback_route.py:115` | J＋C(feedback.delete)；S: 只能刪自己的 | `workspace.feedback.delete` | `feedback.delete` | false | `SystemFeedbackManage.vue` | tenant | |
| `/feedback/file/<uid>/<file_uid>` | DELETE | `feedback_route.py:127` | J＋C(feedback.update) | `workspace.feedback.update` | `feedback.update` | false | `SystemFeedbackForm.vue` | tenant | 刪附件＝改回饋內容 |
| `/feedback/export/<type>` | POST | `feedback_route.py:141` | J＋C(feedback.export) | `workspace.feedback.export` | `feedback.export` | false | `SystemFeedbackManage.vue`（匯出鈕不判權限、一律顯示） | tenant | 不是孤兒，見「先看這幾點」第 5 條 |
| `/labels/menu/<scope>` | GET | 套件 `jedi_issue/api/routes/label_route.py:14` | J | `workspace.feedback.read` | 無 | false | `SystemFeedbackManage.vue`、`SystemFeedbackForm.vue`（類別下拉） | tenant | 輔助端點 |

能力點名由套件 `jedi_issue/plugin/contract.py:59-65` 預設值決定（`feedback-view.read` 對應 `feedback_read_all_capability`）。套件沒有 license 軸。

### 操作紀錄（platform.api-log）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/log/api-logs` | POST | 套件 `jedi_api_log/api_log/api/routes/api_log_route.py:27` | J＋PA | `platform.api-log.read` | `log.read`（只綁選單） | true | `UserLogs.vue`（選單 `/log/user-log`） | tenant（root 限定） | 後端不看能力點 |
| `/log/api-logs/export` | GET | `api_log_route.py:54` | J＋PA | `platform.api-log.export` | `log.read`（只綁選單） | true | `UserLogs.vue` | tenant（root 限定） | |

資源名建議 `api-log` 不沿用 `log`：同模組還有 log 轉發設定（T-1.4 的 `log-forwarding`），單一個 `log` 會讓人分不出是哪個。`log.read` 宣告在套件 `jedi_api_log/plugin/contract.py:22`。

### 支援頁（platform.support）

| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | is_platform | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|---|
| `/support/recent-errors` | GET | `api/support/routes/recent_error_route.py:35` | J；S: PA（`app/support/service/recent_error_app_service.py:46`） | `platform.support.read` | 無 | true | `SupportPage.vue`（FE 路由 `requiresPlatformAdmin`） | tenant（root 限定） | 整台機器的錯誤紀錄，跨租戶 |
| `/support/diagnostic-bundle` | POST | `api/support/routes/diagnostic_bundle_route.py:37` | J；S: PA＋稽核事件（`app/support/service/diag_bundle_export_service.py:75-81`） | `platform.support.export` | 無 | true | `SupportPage.vue` | tenant（root 限定） | 「J 組」只是 route 層看起來沒守，service 層有平台管理員判定與稽核，不是缺口。下載的是系統完整現場（跨租戶），必須留在原廠層 |

DEV `ui_routes` 把 `/system/support` 綁在 `storage-config.read`／`storage-config.update`，FE 路由註解也寫明「能力點擋不住（每個租戶管理員都有 storage-config），改靠 `requiresPlatformAdmin`」。改成 `platform.support.read` 後這個借用就可以拆掉，見待裁第 5 條。

## 現有能力點反查（DEV 本卡範圍 16 個）

| 舊名 | is_platform | 主表有 route 守它？ | 新名 | 其他引用處 |
|---|---|---|---|---|
| `ai-dashboard.read` | false | 有：`/ai-dashboard/auto-generate` | `ai.dashboard.read` | 套件 `jedi_ai_dashboard/plugin/contract.py:25`；選單 `/dashboard/ai-dashboard`；角色範本 `core/role_templates.py:21`（一般成員） |
| `ai-call-log.read` | false | 有：五支全部 | `ai.call-log.read`（匯出兩支改 `ai.call-log.export`） | `core/host_capabilities.py:68`；選單 `/system/ai-call-log`；`common/authz/license.py:116` |
| `ai-quota.read` | false | 有（service 層）：GET `/system/ai-quota` | `ai.quota.read` | `core/host_capabilities.py:73`；選單 `/system/ai-quota`；`common/authz/license.py:118` |
| `ai-quota.update` | false | 有（service 層）：PUT、DELETE `/system/ai-quota`；`/me` 回傳 `can_adjust` 也看它 | `ai.quota.update` | `core/host_capabilities.py:74`；選單 `/system/ai-quota` |
| `bulletin.create` | false | 有 | `workspace.bulletin.create` | 套件 contract；選單 `/bulletin/bulletin-manage` |
| `bulletin.read` | false | **無** | 併入 `workspace.bulletin.read`（見待裁第 7 條） | 只綁選單 `/bulletin/bulletin-manage` |
| `bulletin.update` | false | 有 | `workspace.bulletin.update` | 選單同上 |
| `bulletin.delete` | false | 有 | `workspace.bulletin.delete` | 選單同上 |
| `bulletin-list.read` | false | **無** | `workspace.bulletin.read` | 只綁選單 `/bulletin/bulletin-list`；角色範本 `core/role_templates.py:19`（一般成員） |
| `feedback.create` | false | 有 | `workspace.feedback.create` | 選單 `/feedback/system-feedback-manage`；角色範本 :26 |
| `feedback.read` | false | 有：列表、單筆 | `workspace.feedback.read` | 同上；角色範本 :27 |
| `feedback.update` | false | 有：改回饋、刪附件 | `workspace.feedback.update` | 同上；角色範本 :28 |
| `feedback.delete` | false | 有 | `workspace.feedback.delete` | 同上；角色範本 :29 |
| `feedback.export` | false | 有：`/feedback/export/<type>` | `workspace.feedback.export` | **不綁選單**；DEV 持有角色 5 個（Administrator、System Manager 等） |
| `feedback-view.read` | false | 有：列表、單筆（切成「看全部」） | `workspace.feedback-review.read` | 選單 `/feedback/system-feedback-view`；角色範本 :20（一般成員） |
| `log.read` | **true** | **無**（route 用平台管理員判定） | `platform.api-log.read` | 套件 `jedi_api_log/plugin/contract.py:22`；選單 `/log/user-log` |

### 沒有任何 route 用到的能力點（孤兒）

`bulletin.read`、`bulletin-list.read`、`log.read`，共 3 個。三個都有綁選單，**孤兒不等於沒用**：它們目前決定選單看不看得到。卡上懷疑的 `feedback.export` 不是孤兒。

### 角色範本要注意的

決策者已裁：`feedback-view.read`（新名 `workspace.feedback-review.read`）從一般成員範本**拿掉**，改由系統人員或管理員角色持有。以下為盤點原始觀察。

`core/role_templates.py` 給一般成員 `bulletin-list.read`、`feedback-view.read`、`ai-dashboard.read`、`feedback.*`（create／read／update／delete）。其中 **`feedback-view.read` 給一般成員，意思是每個成員都看得到全公司的意見回饋**——如果這不是本意，改名時順便從範本拿掉；如果是本意，第 8 條「拆兩個資源」就沒有實質意義，可以直接合併。請首腦一併確認。

## 確認要補的守門缺口

本卡只讀，修正另開卡。第 1 條（公告列表）已併入 T-4.6（CM-2542）；第 2、3 條屬改名時順手修，由 A.2／A.5 帶走。

1. **公告列表的「管理模式」對沒有所屬部門的人不設範圍**：`POST /bulletins` 只驗登入；請求不帶 `auth: true` 就走管理模式，而管理模式只有在使用者有所屬部門時才限定「自己建的」（`jedi_bulletin/app/service/bulletin_service.py:246-251`）。沒有部門的登入者直接打 API 不帶旗標，看得到本租戶全部公告，不受發送範圍限制（RLS 仍限在本租戶內）。可能是刻意給沒有部門的管理員看全部，但沒有能力點檢查，任何人都能用。建議：管理模式要求 `workspace.bulletin.update`（或 create），讀者模式要求 `workspace.bulletin.read`，由後端依能力點決定模式，不吃前端旗標。
2. **意見回饋匯出鈕不判權限**：`SystemFeedbackManage.vue:265` 的匯出鈕一律顯示，沒有 `feedback.export` 的人按了才 403。不是安全缺口（後端有守），是「按鈕按了沒反應」型的體驗問題，改名時 FE 補一個 `hasCap`。
3. **支援頁選單借用 `storage-config.*`**：見待裁第 5 條。不是安全缺口（FE 路由與後端都另驗平台管理員），但選單綁定是錯的。

## 改名時要一起動的地方（給下一棒）

- `core/host_capabilities.py:66-75`（`AI_CALL_LOG`、`AI_QUOTA`）
- `app/ai_quota/service/ai_quota_setting_service.py` 的 `_READ_CAPABILITY`／`_UPDATE_CAPABILITY`；`api/ai_call_log/routes/ai_call_log_route.py:34`
- `common/authz/license.py:116-118`（基礎設施豁免清單的 `ai-call-log`、`ai-quota`）——這是 resource_type 字串，模組改名後 license 軸怎麼對要一起定
- 套件 contract：`jedi_ai_dashboard/plugin/contract.py:25-30`（另 `api/guards.py` 的 `LICENSE_RESOURCE_TYPE = "ai-dashboard"` 是授權照的模組名，不是能力點，FR-062 的加值包名要不要跟著改另議）、`jedi_bulletin/plugin/contract.py:30-43`、`jedi_issue/plugin/contract.py:48-65`、`jedi_api_log/plugin/contract.py:22`
- `core/role_templates.py:19-21`、`:26-29`
- DEV `route_capabilities`：`/dashboard/ai-dashboard`、`/system/ai-call-log`、`/system/ai-quota`、`/bulletin/bulletin-manage`、`/bulletin/bulletin-list`、`/feedback/system-feedback-manage`、`/feedback/system-feedback-view`、`/log/user-log`、`/system/support` 九頁的綁定
- FE：`SystemFeedbackManage.vue` 匯出鈕補判斷；`AiQuotaPage.vue` 依 `can_adjust` 顯示（後端回的，不用改）

## 定案結論

決策者 2026-10-06 逐條裁決，第 1～7 條照盤點建議，第 8 條決策者補了理由。

1. **開 `ai` 模組**，收 `ai.dashboard`、`ai.call-log`、`ai.quota`、`ai.assistant` 四個資源，不放 platform。AI 儀表板是賣給租戶的加值包，硬規則要求整包落在單一模組；另外三個客戶會當「AI 相關」一組來授權，放同一模組最符合客戶的想法（模組可以比加值包大，混進不收費項目不違規）。
2. **AI 額度拆兩半。** 租戶自己的額度歸 `ai.quota`；原廠「各租戶上限」三支端點歸 `platform.ai-quota-ceiling`（`is_platform = true`）；`/system/ai-quota/me` 不掛能力點。理由：`ai-quota.read/update` 管的是本租戶自己的額度，每個租戶管理員都要能設，放 platform 會被 `is_platform` 擋掉；`/me` 是額度黃條，一般成員也要看。
3. **`platform` 只留 `api-log`、`support`、`ai-quota-ceiling` 三個資源**；公告與意見回饋開 `workspace` 模組（名字沿用 workspace）。理由：公告與意見回饋是租戶內部使用，`is_platform` 為 false，放原廠名下會讓人誤解。
4. **原廠層後端維持平台管理員判定，再加能力點檢查，兩道都要過。** 只看平台管理員，原廠內部分不出「客服能看錯誤、不能下載診斷包」；只看能力點，`is_platform` 能力點被誤配給客戶角色就直接開門（診斷包含跨租戶資料），第二道是安全網。
5. **新建 `platform.support.read`（最近錯誤）與 `platform.support.export`（診斷包）**，`/system/support` 改綁 `platform.support.read`，拆掉借用的 `storage-config.*`。診斷包屬對外送出類，獨立成 export 才能分給不同人。
6. **新建 `ai.assistant.*`**，聊天與清除紀錄要求 `ai.assistant.read`，出貨範本一般成員給 read（行為不變）。理由：每次聊天都花 AI 錢，客戶要做「只有某些部門能用 AI」目前沒有任何開關。
7. **公告合併成一個 `workspace.bulletin`。** `bulletin-list.read` → `workspace.bulletin.read`；`bulletin.read` 刪除，管理頁改綁 `workspace.bulletin.create`；後端依能力點決定管理／讀者模式，不吃前端旗標（對應缺口第 1 條，併入 T-4.6）。
8. **意見回饋分開，不合併。** `feedback.*` → `workspace.feedback.*`（建立並看自己送的回饋）；`feedback-view.read` → `workspace.feedback-review.read`（系統人員或管理員收集全公司意見用）。決策者理由：「兩個功能意義不同，一個是建立自己的回饋，一個是系統人員或管理員來收集意見」。連帶兩個決定：
   - `feedback-review.read` 從一般成員出貨範本拿掉（本意不是讓全員看全公司回饋）。
   - `feedback-review` 這種範圍型讀取權限破例只開 read，不補 create／update／delete 空殼；T-1.6 把此寫成通則。

## 附錄：16 個 is_platform 能力點

DEV `capabilities WHERE is_platform`，共 16 個（查詢時間同上）。除 `log.read` 外都不在本卡範圍，這裡只對到守門位置與歸屬卡，逐 method 明細由該卡負責。

| 能力點 | 後端怎麼守 | 選單綁定 | 歸屬卡 |
|---|---|---|---|
| `log.read` | 不守；`/log/api-logs*` 用平台管理員判定 | `/log/user-log` | 本卡（T-1.5） |
| `compliance-framework.create`／`.update`／`.delete`（3） | 後端零直呼（`core/host_capabilities.py:28` 註解） | `/compliance-framework/compliance-framework-manage` | T-1.2 |
| `issue-integrate-config.create`／`.read`／`.update`／`.delete`（4） | 通用系統設定端點依設定群組分流守門（`core/plugins/system_core.py:70`，`ISSUE_INTEGRATE_CONFIG` → `issue-integrate-config`） | `/system/issue-integrate-config` | T-1.4 |
| `license.read` | 不守；授權管理 route 用平台管理員判定（`core/plugins/license.py:322-327`） | `/license/manage` | T-1.4 |
| `system_config.create`／`.update`／`.delete`（3） | 通用系統設定端點，設定群組不在對照表時的備援（`core/plugins/system_core.py:87-91`） | 無 | T-1.4 |
| `system-menu.create`／`.update`／`.delete`（3） | 能力點＋平台管理員兩道（套件 `jedi_system_core/api/routes/system_menu_route.py:92`、`:112`、`:124`） | `/system/system-menu-manage` | T-1.4 |
| `system-menu.read` | 不守；列表 route 只用平台管理員判定（同檔 `:52`、`:74`） | `/system/system-menu-manage` | T-1.4 |

合計 1＋3＋4＋1＋3＋3＋1 ＝ 16。非 root 租戶 `*.*.*` 展開範圍 123 − 16 − 4（workflow）＝ 103 成立。

沿革見 `FR-132-LOG.md` 與 git log。
