---
title: "掃描工具資源管理 — 需求討論稿 (FR-165)"
brand: "Guidant AI · **FR-165** 掃描工具資源管理"
eyebrow: "FR-165 · 需求討論稿 · 2026-10-26（v1 待審）"
h1: "掃描工具資源管理"
subtitle: "把「掃描設定檔管理」與「弱點資料庫」收進同一個入口，之後再多工具也不再多一頁"
lede: "掃描工具跑起來要吃的東西現在散在兩個地方：**掃描設定檔管理**（合規稽核群組，給 CINC／GCB 挑基準）與**弱點資料庫**（系統設定群組，給第三方元件掃描用）。兩者都是「工具要吃的內容，都要管來源、日期、送到 Agent」，卻各長一頁、各走一套。本案把它們收進**一個入口「掃描工具資源管理」**，兩個分頁對應兩種形狀；資料層不合併。並定下一條規則：**之後任何工具的設定檔或參考資料庫進來，都只能掛在這裡，不准再開新頁。**"
chips: [
  {text: "已拍板 D1、D2、D4", kind: ok},
  {text: "待確認 D3、D5、D6", kind: warn},
  {text: "前作：FR-059／060（設定檔庫）、FR-134／156（弱點資料）", kind: accent},
  {text: "雛形：prototype/index.html", kind: accent}
]
footer: "FR-165 · 掃描工具資源管理 — 需求討論稿 · 2026-10-26 v1 待審 · 現況數字來源：DEV 本機 DB 唯讀查詢（config.detection_profiles、public.ui_routes、public.capabilities）"
---

## 需求背景 {#why nav="背景"}

> 我們現在的 Agent 組態檔好像沒有統一在一個功能內……未來應該還會有很多掃描套件的組態檔案或是 profile 或是資料庫等等要管理，是不是應該整理在一個功能裡面？不然每次多一個工具又多一個功能頁面，實在太亂也四散各處，像這次新的弱點資料庫就是這樣，當初做的時候完全忘記有掃描設定檔管理。
> [— 決策者原話（2026-10-26）]{.attr}

### 1.1 現況：兩頁各自為政

| | 掃描設定檔管理 | 弱點資料庫 |
|---|---|---|
| 出身 | FR-059／060（2026-08） | FR-134／156（2026-10） |
| 選單位置 | 合規稽核群組 `/plugin/detection-profile-manage`（排序 35，在「工具插件管理」旁） | 系統設定群組 `/system/vulndb`（排序 38） |
| 幾份 | 每個工具很多支：DEV 現況 CINC 2 支、GCB 9 支（含 1 支租戶私有） | 全機一份，不分租戶 |
| 誰挑 | 派掃描任務時使用者在下拉選要用哪支 | 沒人挑，掃描自動用現行那份 |
| 版本 | 每支有版本鏈，可回看歷史版、切現行版 | 只有「現行＋更新紀錄」，切換後舊版即刪 |
| 來源 | 使用者上傳檔案或填網址 | 自家發布站每日出包帶簽章，主系統自動抓；也可手動上傳 |
| 送到 Agent | 派工時 Agent 依任務參數去主系統拉檔 | 心跳告知有新版，Agent 自己來拉整包 |
| 權限點 | `detection.profile.{read,create,update,delete}` | `system.vulndb.{read,update}` |
| 資料表 | `config.detection_profiles`／`_versions`／`_controls`（有 RLS） | `public.vulndb_updates`（平台層、無 RLS、只增不改） |
| 前端 | `DetectionProfileManageView.vue`（947 行）＋控制項頁（723 行） | `VulndbManage.vue`（254 行）＋更新紀錄＋Agent 同步面板 |

### 1.2 它們像在哪、不像在哪

**像的部分**：都是掃描工具要吃的內容；都要管「從哪來、多新、送到 Agent 沒有」；都是管理員在維護。

**不像的部分是形狀**，而且未來進來的東西也會落在這兩種形狀之一：

::: grid2
::: {.card .ok}
#### 形狀 A：設定檔／基準

使用者**挑**的東西。一個工具有很多支、租戶可以自己上傳、要有版本、派任務時要選。

已有：CINC 基準、GCB 基準。
會來：OpenSCAP 的 SCAP 內容、ZAP 掃描政策、Nmap 腳本組、SonarQube 品質設定檔。
:::
::: {.card .warn}
#### 形狀 B：參考資料庫

**沒人挑**的東西。全機一份、不分租戶、只求新鮮、自動更新。

已有：弱點資料庫（Trivy／Grype／KEV／EPSS）。
會來的判準：**我們自己帶在 Agent 裡、資料要獨立於程式版本更新**的工具。客戶自裝的產品（OpenVAS、Nessus、SonarQube、ZAP）的特徵庫由它們自己更新，不算。短期內沒有明確的第二個。
:::
:::

FR-059 當初就把形狀 A 設計成「不綁工具」：新工具接入零開發，seed 一筆就能用（FR-059 design §5.7）。**形狀 A 的問題已經解掉了。真正沒解的是形狀 B**：弱點資料庫是第一個參考資料庫，被做成一支專用頁、專用服務、專用的 Agent 同步接線。下一個 feed 進來，工程師只能整套複製一份改名，又多一頁。

---

## 分工概述（30 秒版） {#overview nav="概述"}

**整案一句話**：把兩頁收進一個入口「掃描工具資源管理」，兩個分頁、兩種版面；資料不動、後端只加一支紀錄分頁端點；再定一條「新資源只能掛這裡」的規則。

| 階段 | 做什麼 | 產出 | 完成怎麼判定（決策者檢查法） |
|---|---|---|---|
| **第一期：入口合併** | 新選單「掃描工具資源管理」掛合規稽核群組；兩支既有頁面原樣掛進兩個分頁；兩張舊選單收掉、舊網址自動轉向 | 一支選單 migration、FE 一支殼頁、兩條轉向 | 登入後左側選單：合規稽核群組多「掃描工具資源管理」、少「掃描設定檔管理」；系統設定群組少「弱點資料庫」。點進去兩個分頁都能用，功能與今天一樣。在網址列打舊網址會自動跳到新頁對應分頁。用一個只有設定檔權限的帳號登入，只看得到第一個分頁 |
| **第二期：參考資料庫宣告驅動** | 後端開「參考資料庫清單」端點，各工具插件登記自己有哪個資料庫、支援哪些動作；前端照清單長卡片；Agent 心跳與拉包通道改成帶資料庫代號 | 一支清單端點、插件契約加一段、FE 卡片元件、Agent 同步改通用 | 畫面與第一期一樣（只有弱點資料一張卡）。工程師在 DEV 用假的「第二個資料庫」登記一筆，不改前端重整頁面就多一張卡 |

**依賴**：第一期不依賴任何人。第二期等第二個參考資料庫真的要進來時才做（D3）。**決策者功課**：D3、D5、D6 三項裁示。

---

## 決策 {#decisions nav="決策"}

::: {.callout .decided}
**D1 入口頁名稱與位置 — 已拍板**

名稱「**掃描工具資源管理**」，放**合規稽核群組**、排在「工具插件管理」（30）之後、「第三方元件風險」（40）之前，接「掃描設定檔管理」原本的位子 35。

[**理由**：設定檔是稽核員挑來派任務的，不該藏在管理員的系統設定區。系統設定群組的替代案被排除。]{.rec}
:::

::: {.callout .decided}
**D2 權限點名字 — 已拍板：第一期不改**

`system.vulndb.*` 與 `detection.profile.*` 兩組名字都保留。入口選單的可見條件是「**任一組 read 權限**」；各分頁各看自己那組。

[**理由**：改名要連動出貨角色表、前端能力表、客戶已有角色的 pattern，牽動面大但沒換到任何行為。名字留到第二期與「參考資料庫」契約一起整。]{.rec}
:::

::: {.callout .pending}
**D3 第二期（宣告驱動）現在做、還是等第二個資料庫？**

第二期要動後端插件契約、Agent 心跳與拉包通道，比搬選單重得多。

[**建議**：**等**。入口頁版面現在就照「一卡一庫」排好（雛形已如此），機制等第二個參考資料庫立案時一起做。為單一登記者蓋機制，等於為一個客人蓋一棟旅館。而且短期內看不到第二個：Agent 自帶工具裡只有弱點掃描的資料需要獨立更新，OpenSCAP 內容屬於「要挑的設定檔」走第一個分頁，Nmap 特徵隨版本走。反悔條件：任何「我們自己帶、資料要獨立更新」的工具進了排程，第二期就該立刻開。]{.rec}
:::

::: {.callout .decided}
**D4 進行中文件的衝突 — 已拍板：先不管，做完要更新**

FR-156 的 G1 卡（CM-3000）正在另一個 session 寫 SPEC 與使用手冊，內容是「弱點資料庫頁在系統設定底下」。本案入口搬了那份文件就過期。

[**定案**：G1 照寫不擋。本案第一期收尾時**必做**：更新 `docs/spec-site/current/` 弱點資料庫頁與掃描設定檔頁的入口位置、使用手冊對應段。已列入 §6 收尾待辦。]{.rec}
:::

::: {.callout .pending}
**D5 舊網址怎麼處理？**

`/plugin/detection-profile-manage`、`/plugin/detection-profile-manage/versions/:uid/controls`、`/system/vulndb` 三條舊路由。

[**建議**：**前端做永久轉向**到新入口對應分頁（控制項頁轉到新入口下的對應路徑），後端不動。使用手冊與 SPEC 裡的連結同步改。替代「保留舊路由當別名」被排除：兩條路到同一頁會讓選單高亮與麵包屑亂掉。]{.rec}
:::

::: {.callout .pending}
**D6 Agent 同步面板放哪？**

今天弱點資料庫頁下方有一塊「Agent 同步情況」（每台 Agent 的資料日期與落後天數）。

[**建議**：**收進卡片**——卡上一行摘要（幾台已同步、幾台落後、幾台離線），點「明細」展開每台清單（雛形已畫）。它是「這個資料庫送到 Agent 沒有」的資訊，屬於該資料庫，不該是頁面層級的獨立區塊；第二個資料庫進來時每張卡各自有自己的同步狀態，版面才對。]{.rec}
:::

---

## 第一期詳細設計 {#design nav="詳細設計"}

### 4.1 畫面

雛形：[prototype/index.html](prototype/index.html)。重點：

- **頁首**：標題「掃描工具資源管理」＋一句說明。
- **兩個分頁**（PrimeVue TabView）：「設定檔／基準」、「參考資料庫」。各分頁依權限顯示，沒權限的分頁整個不出現；只剩一個分頁時仍顯示分頁列（讓使用者知道這頁有兩類東西）。
- **分頁一**：掛既有 `DetectionProfileManageView.vue`，**零改動**。控制項頁 `DetectionProfileControlsView.vue` 路徑改掛在新入口底下。
- **分頁二**：一卡一庫。卡的版面固定：標題列（名稱、給哪個工具用、狀態膠囊）→ 連不到站的黃字提醒（只在發生時出現）→ 資訊列（資料日期含新鮮度色、來源與站台、自動更新開關、**檢查頻率下拉**（選項來自 `system_menus` 的 `vulndb_check_interval`）、下次檢查、**四個來源明細常駐顯示**、Agent 同步摘要與明細展開）→ 上傳進度條（上傳中才出現）→ 底列（檢查更新、上傳更新包、更新紀錄）。今天只有弱點資料一張，內容照 `VulndbManage.vue` 搬，把原本整頁的版面縮成一張卡。
- **原頁功能一個不少**：搬進卡片是換版面不是減功能。驗收時拿 `VulndbManage.vue` 現有的每個控制項逐一對照（決策者 2026-10-26 審雛形時抓到頻率下拉漏畫）。
- **沒接上的不預告**：設定檔分頁的「工具」下拉只列已接入設定檔庫的工具；參考資料庫分頁只列已登記的資料庫。不放「即將推出」、不放灰掉的選項。
- **更新紀錄**改成對話框（點卡上「更新紀錄」開，按鈕不帶筆數），內有分頁，不再佔頁面下方整塊。後端 `status.recent` 現在固定回 20 筆，改成分頁端點（本案唯一的後端改動，小）。
- **不出現**：任何「即將推出第二個資料庫」的預告。雛形上那張虛線卡只給決策者看形狀。

::: {.callout .warn}
**設計系統自檢**

`grep border-left` 為零；卡片一律 `dark-card`；字級全站基準；狀態只出現一次（標題列膠囊）。
:::

### 4.2 選單與路由（一支 migration）

| 動作 | 對象 |
|---|---|
| 新增 `ui_routes` | `scan-tool-resources`，`/plugin/scan-tool-resources`，父 `group-compliance-audit`，sort 35，icon `pi pi-box` |
| 新增 `route_capabilities` | 綁 `detection.profile.read` 與 `system.vulndb.read`，requirement **ANY**（任一就看得到選單） |
| 改 `ui_routes` | `detection-profile-manage` 與 `vulndb` 兩筆 `enable=0`（**不刪**：升級客戶的 `route_capabilities`、使用手冊、稽核事件都還指著它們） |
| 改 `ui_routes` | `detection-profile-controls` 的 `url` 改為 `/plugin/scan-tool-resources/profiles/versions/:versionUid/controls`，`pid` 改指新入口 |
| bump | `CAPABILITY_CATALOG.VERSION` 加一 |

能力點**不新增、不改名**（D2）。migration 屬主線 `phase=active`，寫完回報「出貨基線待重產」。

### 4.3 前端

| 檔 | 動作 |
|---|---|
| `src/views/plugin/ScanToolResourcesView.vue`（新） | 殼頁：標題、TabView、依權限決定哪些分頁出現、`?tab=` 與 hash 記住分頁 |
| `src/views/detection-profile/DetectionProfileManageView.vue` | 不改。被殼頁當子元件掛進分頁一 |
| `src/views/vulndb/VulndbManage.vue` | 改成卡片形狀：移除頁首與整頁 `card` 外殼，更新紀錄改對話框，Agent 同步面板收進卡（D6）。**邏輯（上傳、檢查、開關）全部不動** |
| `src/components/vulndb/ReferenceDbCard.vue`（新） | 卡片外觀元件：接「標題／用途／狀態／五行資訊／底列按鈕」的 slot，弱點資料是第一個使用者。**第二期**各資料庫共用這張 |
| `src/router` | 新路由 `/plugin/scan-tool-resources`、`.../profiles/versions/:versionUid/controls`；舊三條路由改 `redirect`（D5） |
| `src/config/locales/i18n/*/menu.json` | 加 `scan-tool-resources` 標籤 |

超標提醒：`DetectionProfileManageView.vue` 947 行已超 800 行上限，本案**不往裡加**（它只是被掛進去）。

### 4.4 後端

只有一處：更新紀錄從 `status.recent` 固定 20 筆改成獨立分頁端點 `GET /system/vulndb/updates?page=&size=`（照既有分頁慣例）。其餘兩組端點（`/detection/profiles/*`、`/system/vulndb/*`）照用。

### 4.5 收尾文件（D4）

| 文件 | 動作 |
|---|---|
| `docs/spec-site/current/` 弱點資料庫頁 | 入口位置改「合規稽核 → 掃描工具資源管理 → 參考資料庫分頁」；畫面段改卡片形狀 |
| `docs/spec-site/current/` 掃描設定檔管理頁 | 入口位置改「… → 設定檔／基準分頁」；功能內容不變 |
| 使用手冊 | 兩處入口描述同步 |
| `docs/claude/frontend-overview.md` | 「BE 改什麼會牽動 FE」清單加一行：新工具的設定檔或參考資料庫一律掛掃描工具資源管理，不開新頁 |

---

## 第二期輪廓（不在本期做，先把形狀講清楚） {#phase2 nav="第二期"}

為了讓第一期的版面不會到第二期被推翻，這裡把第二期長什麼樣先講一次。

```{.mermaid cap="圖 1 — 第二期：參考資料庫宣告驅動。前端不認識任何一個資料庫，只問後端清單。"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
  subgraph plugins[各工具插件]
    P1[jedi-source-scan<br/>登記：vulndb]
    P2[未來某個 Agent 自帶工具的插件<br/>登記：它的資料庫代號]
  end
  REG[參考資料庫登記表<br/>代號／名稱／用途／支援的動作]
  API[GET /scan-resources/reference-dbs<br/>回清單＋每個的狀態]
  FE[參考資料庫分頁<br/>一卡一庫，照清單長]
  AG[Agent 心跳：帶每個資料庫的日期<br/>拉包：/agents/reference-dbs/&lt;代號&gt;/bundle]
  P1 --> REG
  P2 --> REG
  REG --> API --> FE
  REG --> AG
```

**契約的五個動作**（每個資料庫宣告支援哪幾個，不支援的按鈕不出現）：看狀態（日期、來源、紀錄）、上傳更新包、檢查更新、自動更新開關與頻率、Agent 同步狀態。弱點資料庫今天五個都有，是契約的樣板。

**不做的事**：不把 `vulndb_updates` 改成通用表。每個資料庫自己的紀錄表自己管，契約只規範「回傳最近 N 筆的形狀」。

---

## 現況接入點盤點 {#inventory nav="現況盤點"}

| 元件 | 現況 | 本案動作 | 期 |
|---|---|---|---|
| `public.ui_routes` 兩筆舊選單 | enable=1 | enable=0，不刪 | 一 |
| `public.ui_routes` 控制項子頁 | pid 指 detection-profile-manage | 改 pid 與 url | 一 |
| `public.capabilities` 兩組六個能力點 | 名字分屬 `detection.profile.*`／`system.vulndb.*` | 不動 | 一（D2） |
| `DetectionProfileManageView.vue` 947 行 | 獨立頁 | 掛進分頁一，零改 | 一 |
| `VulndbManage.vue` 254 行 | 整頁版面 | 縮成卡片，邏輯不動 | 一 |
| `AgentVulndbSyncPanel.vue` | 頁面層級區塊 | 收進卡片明細 | 一（D6） |
| BE `vulndb_settings_app_service.py`、`vulndb_route.py` | 弱點資料專用；紀錄固定回 20 筆 | 加一支更新紀錄分頁端點，其餘不動 | 一；二期抽契約 |
| `core/plugins/_agent_vulndb.py` 心跳接線 | 只認 vulndb | 不動 | 二 |
| `jedi_remote_agent` 心跳回應 `data.vulndb` | 單一欄位 | 不動 | 二（改成帶代號的清單） |
| FR-156 G1 SPEC／手冊（CM-3000，進行中） | 入口寫系統設定 | 等它收完，本案收尾時改 | 一（D4） |

---

## 拆棒（第一期） {#breakdown nav="拆棒"}

四張卡，兩批。

| 卡 | 做什麼 | 改哪些檔 | 批 | 驗收 |
|---|---|---|---|---|
| **A1 選單與路由 migration** | 新入口選單、兩筆舊選單停用、控制項子頁改掛、能力綁定 ANY、bump 版本 | `scripts/sql/2026-10-XX-fr165-scan-tool-resources-menu.sql` | 1 | DEV 套完，`ui_routes` 多一筆、兩筆 enable=0；用只有 `system.vulndb.read` 的帳號登入看得到新選單；回報「出貨基線待重產」 |
| **A2 前端殼頁與弱點資料卡片化** | 殼頁＋TabView＋權限分頁；`VulndbManage` 縮成卡片、紀錄改對話框、Agent 同步收進卡；`ReferenceDbCard` 元件；三條舊路由轉向；i18n | FE：新 `ScanToolResourcesView.vue`、新 `ReferenceDbCard.vue`、改 `VulndbManage.vue`、`router`、`menu.json` | 1 | 對照雛形：兩個分頁、卡片五行資訊、更新紀錄對話框、舊網址轉向。設定檔分頁功能與今天完全一樣（新增、篩選、版本、控制項頁） |
| **A3 更新紀錄分頁端點** | `GET /system/vulndb/updates` 分頁；FE 更新紀錄對話框改打它 | BE `vulndb_route.py`、`vulndb_settings_app_service.py`、jedi-source-scan repo 加分頁查詢；FE `VulndbUpdateHistory.vue` | 1 | curl 帶 page/size 回正確筆數與 meta；對話框翻頁正常 |
| **B1 收尾文件** | SPEC 兩頁、使用手冊、frontend-overview 規則一行 | `docs/spec-site/current/...`、`docs/user-manual/...`、`docs/claude/frontend-overview.md` | 2 | 等 FR-156 G1（CM-3000）收完才派；grep 兩份 SPEC 無「系統設定 → 弱點資料庫」字樣 |

A1、A2、A3 同批：A1 只動 SQL、A2 只動 FE 殼與卡、A3 動 BE 與紀錄元件，不撞檔；A2 的對話框先接現有 `status.recent`，A3 做完再換端點（卡內寫明）；A2 的路由名要與 A1 的 `ui_routes.name` 一致（`scan-tool-resources`），卡內寫死。

---

## 收尾待辦 {#closing nav="收尾待辦"}

- [ ] **D4**：FR-156 G1 收完後，更新 SPEC 兩頁與使用手冊的入口位置（B1 卡）。
- [ ] 回報「出貨基線待重產」（A1 migration 屬主線）。
- [ ] `docs/claude/frontend-overview.md` 加規則：新工具資源一律掛掃描工具資源管理。
- [ ] FR 登記表 `docs/features/README.md` 加一列（本討論稿落地時一併做）。
