儲存設定(Storage Config)
功能群:證據管理|兩種「證據」概念與儲存後端總覽先讀 _overview.md §3/§4
事實基準:2026-07-05 從 FE / BE code 掃出;API schema 逐條對照 marshmallow serializer 與 service 組裝碼
1. 功能描述
儲存設定頁是全租戶層級的檔案儲存後端設定頁:租戶管理者在此選擇檔案要存去哪裡(本機磁碟 / MinIO 物件儲存 / 客戶端檔案 Agent),是一份單筆 key-value 設定表單(無列表、無分頁),存檔即時生效——下一次任何檔案上傳/讀取都會照新設定解析後端。本頁設定影響全站兩種「證據」(見 _overview §3)與其他一般檔案上傳共同的儲存路徑,屬系統基礎建設而非業務資料。
主要使用者:租戶管理者(系統設定層級角色,非專案參與者)。
角色速覽(完整定義見 _overview §5):
| 角色 | 一句話 |
|---|---|
| 租戶管理者 | 系統設定層級角色(非專案 manager/auditor),本頁與雲端整合 / 檔案 Agent 管理同屬系統設定選單群組 |
1.1 功能總覽(本頁全部功能)
| # | 功能 | 說明 | 位置 | 詳述 |
|---|---|---|---|---|
| 1 | 儲存類型下拉選擇 | local / minio /
使用 Agent 服務(remote_agent)三選一,選項來自
system_menus(group=STORAGE_TYPE) |
表單頂 | UC-SC-01 |
| 2 | Local 欄位:本地儲存路徑 | base_dir,切回 local 時自動帶入預設值
/tmp/upload/ |
type-conditional 區塊 | §6.1 |
| 3 | MinIO 欄位群 | Endpoint URL / Access Key(密碼型輸入)/ Secret Key(密碼型輸入)/ Bucket 名稱 / secure 開關 | type-conditional 區塊 | §6.1 |
| 4 | Remote Agent 欄位:客戶端檔案 Agent 下拉 | 從本 tenant 啟用中的 agent
清單挑一個(GET /remote-agents),儲存
agent_uid |
type-conditional 區塊 | UC-SC-02 |
| 5 | 表單驗證(依 storage_type 分流) | 三組 vuelidate rule-set(local / minio / remote_agent),只驗當前選中類型的必填欄位 | 存檔前 | §12 坑 1 |
| 6 | 儲存 | 依 storage_type 組裝對應欄位子集送出
PUT,成功後重拍「未儲存變動」快照 |
底部按鈕 | UC-SC-01 |
| 7 | 離開頁面未儲存變動確認 | 比對目前 config 與快照,離開路由前跳 confirm dialog | 全頁(路由守衛) | §12 坑 2 |
UC(§2)展開 1(載入+切換+存檔)與 4(remote_agent 下拉來源)兩條核心路徑;其餘欄位屬同一表單的常規 CRUD 欄位,已在總覽表列完整。
2. Use Case
角色速覽(完整定義見 _overview §5):
| 角色 | 一句話 |
|---|---|
| 租戶管理者 | 系統設定層級角色(非專案 manager/auditor),本頁與雲端整合 / 檔案 Agent 管理同屬系統設定選單群組 |
流程圖視覺慣例:菱形 = 判斷、橘底 = 例外/擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 可選路徑。
UC-SC-01 讀取並儲存儲存後端設定
| 項目 | 內容 |
|---|---|
| 角色 | 租戶管理者 |
| 前置條件 | 已登入;FE 選單可見性由 storage-config capability
判定(§3) |
| 產出 / 後置條件 | public.system_configs(group=STORAGE_CONFIG,
key=CONFIG)該租戶列的 value JSONB
upsert;下一次檔案上傳/讀取即用新設定解析 adapter |
UC-SC-02 選擇 Remote Agent 儲存後端
| 項目 | 內容 |
|---|---|
| 角色 | 租戶管理者 |
| 前置條件 | 本 tenant 已在「檔案 Agent 管理」頁登錄至少一個
enabled=true 的 agent(FR-039) |
| 產出 / 後置條件 | 儲存
{storage_type: 'remote_agent', agent_uid};之後檔案落地到該
agent 對應的客戶端設備 |
3. 權限矩陣
| 操作 | FE 判定 | BE 強制 | BE 檢查位置 |
|---|---|---|---|
| 選單 / 頁面可見性 | ui_routes(name=storage-config)→
route_capabilities(read=ALL, create/update/delete=ANY)→
role_capabilities 授權角色 2/3/37/38(Administrator /
Billows Admin / IT執行人員 / Billows 系統管理員) |
⚠️
無——GET/PUT /system/config/{group}/{key}
僅 @jwt_required(),未做 capability 二次驗證 |
api/system_config/routes/system_config_route.py(SystemConfigGroupRoute.get
/ .put) |
| 讀 / 存設定值 | 同上(頁面級门檻,非欄位級) | 無角色檢查,僅 JWT + tenant RLS(system_configs 有
tenant_id/org_unit_id,讀寫自動收斂到呼叫者租戶) |
同上 |
| Remote Agent 下拉來源 | 無額外判定 | 僅 @jwt_required();資料範圍由 tenant RLS 限縮 |
api/remote_agent/routes/remote_agent_route.py:28-40(RemoteAgentsRoute.get
→ list_enabled_agents) |
⚠️ 已知不對齊(維護時注意):FE 選單門檻走完整 RBAC(capability + role),但 BE 兩支端點本身都只驗證 JWT 登入、不驗證 capability——任何登入使用者若已知
PUT /system/config/STORAGE_CONFIG/CONFIG路徑,即可繞過選單直接改動全租戶的儲存後端設定。此為系統設定類頁面的既有模式(同 my-audits 的audit.read落差),非本次盤點新發現的缺口,但風險層級較高(可改動的是「檔案存哪裡」這種基礎設施設定,非唯讀彙整),詳見 §12 坑 3。
4. 狀態機與前置條件
本頁不涉及輪次 / AP 狀態機——是獨立於稽核業務流程之外的系統設定頁,無 phase gate。
| 條件 | 效果 | 出處 |
|---|---|---|
storage_type === 'local' |
只顯示/驗證 base_dir;切換到 local 時自動帶入
/tmp/upload/ |
StorageConfigForm.vue:149-151(onStorageTypeChange) |
storage_type === 'minio' |
只顯示/驗證 5 個 MinIO 欄位 | 同檔 :284-343 |
storage_type === 'remote_agent' |
只顯示/驗證 agent_uid;下拉選項來自
GET /remote-agents(僅本 tenant 啟用中 agent) |
同檔 :100-107,346-362 |
| GET 讀取 404(尚未設定過) | FE 僅 console.log,保留 config
預設值(local +
/tmp/upload/)當初始表單值 |
同檔 :133-147;BE 對應
SystemConfigService._load_config 同樣以
NotFound 時回退
LocalFileUploadConfigDTO()(managed_file_upload_service.py:69-75) |
5. UI 設計
📸 實際畫面截圖待補(一律亮色模式拍攝):以 playwright 對 STG 擷取,預計補以下畫面到
assets/img/: ① 整頁 — storage_type=local 顯示狀態storage-config-local.png② storage_type=minio 顯示狀態(欄位群展開)storage-config-minio.png③ storage_type=remote_agent 顯示狀態(Agent 下拉)storage-config-remote-agent.png
版面骨架與區塊職責(單一 Card 表單,無左側樹、無 Tab,下方欄位群依上方下拉選擇的類型三選一切換;彩色區塊可點跳本頁小節錨點,API 僅標代表性):
狀態呈現:進頁 LoadingState(card
範圍,依序等待選單/Agent清單/設定三支 API 都回來才收起);存檔中
Button :loading="submitted";無 per-欄位 spinner;無
socket,存檔成功僅 toast
提示、不重新整理頁面。密碼型欄位(minio_access_key /
minio_secret_key)用 PrimeVue
Password(:feedback="false",純遮罩輸入框,非強度檢核)。
6. API 規格
Envelope:成功 {"status": true, "data": …}、失敗
{"status": false, "error_code": "…", "msg": "…"}。
6.1 總清單(本頁呼叫的全部 endpoint)
| 分類 | Method + Path | 說明 | 完整規格 |
|---|---|---|---|
| 載入 | GET /system/menu/STORAGE_TYPE |
儲存類型下拉選項(system_menus
group=STORAGE_TYPE) |
§6.2 |
| 載入 | GET /remote-agents |
本 tenant 啟用中的 Remote Agent 清單(storage_type=remote_agent 下拉用) | §6.2 |
| 載入 | GET /system/config/STORAGE_CONFIG/CONFIG |
讀目前儲存設定 | §6.3 |
| 儲存 | PUT /system/config/STORAGE_CONFIG/CONFIG |
更新儲存設定(依 storage_type 送對應欄位子集) | §6.3 |
本頁只有 4 支 endpoint、無分頁、無 detail 頁、無刪除操作(
SystemConfigGroupRoute雖有delete方法但本頁 UI 未使用)。
6.2 選單載入類
[GET] /system/menu/{group}(group=STORAGE_TYPE)
Response
data(陣列):{key: string, value: string}——key
是下拉直接顯示的 label(無 i18n,FE
optionLabel="key"),value 是實際存入
storage_type 的值(local / minio
/ remote_agent)。資料來源
public.system_menus(group=STORAGE_TYPE),目前三筆:本地磁碟/local、Minio 物件儲存/minio、使用 Agent 服務/remote_agent(後者由
FR-039 seed,見
scripts/sql/2026-06-18-fr039-storage-type-remote-agent-menu.sql)。出處:app/system_menu(常規
CRUD,細節見 GAI-SD-02 / Swagger)。
[GET] /remote-agents
無 query 參數。Response data(陣列,只回 2
欄,不曝光內網 base_url):
| 欄位 | 型別 | 說明 |
|---|---|---|
| uid | string | Remote Agent 識別碼,存進 agent_uid |
| name | string | 顯示名稱(下拉 optionLabel) |
出處:api/remote_agent/serializers/remote_agent.py:4-7(RemoteAgentResponse)、api/remote_agent/routes/remote_agent_route.py:28-40(RemoteAgentsRoute.get
→ RemoteAgentService.list_enabled_agents →
domain.get_remote_agents(enabled=True),app/remote_agent/service/remote_agent_service.py:56-59)。
6.3 儲存設定類(本頁核心)
[GET] /system/config/{group}/{key}
group='STORAGE_CONFIG', key='CONFIG'。無
body。
Response data:
| 欄位 | 型別 | 說明 |
|---|---|---|
| uid | string | system_configs.uid(本設定列的識別碼,FE 未使用) |
| group / key | string | 固定 STORAGE_CONFIG / CONFIG |
| value | object | 依 storage_type 形狀不同,見下表 |
| created_at / updated_at | datetime | 審計欄 |
value 依 storage_type 的三種形狀:
| storage_type | 欄位 |
|---|---|
local |
{storage_type: "local", base_dir: string} |
minio |
{storage_type: "minio", minio_endpoint, minio_access_key, minio_secret_key, minio_bucket, minio_secure: bool} |
remote_agent |
{storage_type: "remote_agent", agent_uid: string}(另有
legacy 相容欄位 base_url,見 §12 坑 4) |
出處:api/system_config/serializers/system_config.py:9-15(SystemConfigResponse,value
為 fields.Raw 未強型別,形狀由 BE service 層 JSONB
直通);BE 讀取時的欄位語意對照見
app/upload_file/service/managed_file_upload_service.py:21-41(docstring
明列三種 JSONB 形狀)。
[PUT] /system/config/{group}/{key}
Request body(無獨立 marshmallow schema
強制欄位,SystemConfigRequest 僅寬鬆 wrapper;實際依
storage_type 送出對應欄位子集,FE 組裝邏輯):
| storage_type | 送出欄位 |
|---|---|
local |
storage_type, base_dir |
minio |
storage_type, minio_endpoint,
minio_access_key, minio_secret_key,
minio_bucket, minio_secure |
remote_agent |
storage_type, agent_uid |
行為:upsert by
group+key(update_config_by_group_key
內部若不存在會建立,見 domain service),非本欄位級 partial
update——每次送出都是該 storage_type 對應欄位的完整覆蓋
value(未送出的其他 storage_type 專屬欄位不會殘留在新 value
裡,因為 FE 每次都重組一份全新 payload object)。Response:同 GET。
出處:api/system_config/routes/system_config_route.py:107-119(SystemConfigGroupRoute.put)→
SystemConfigService.update_config_by_group_key(jedi_system_config/app/service/system_config_service.py:142-149);FE
組裝邏輯
StorageConfigForm.vue:202-227(update())。
7. 前端檔案地圖(compliance-manager-fe/)
| 檔案 | 角色 |
|---|---|
src/views/storage-config/StorageConfigForm.vue |
唯一檢視(約 370 行;下拉切換、三組驗證、載入/存檔) |
src/config/router/index.js:288-299 |
route storage-config,path
/system/storage-config |
src/config/api/api.js:328,330 |
SYSTEM_CONFIG →
/system/config;REMOTE_AGENTS →
/remote-agents |
src/stores/menuStore.js:196-204 |
fetchStorageTypeMenu——每次進頁重抓(不用舊快取,避免新增
storage_type 選項時被持久化清單擋住) |
src/service/BaseService.js |
axios 封裝(本頁 get() / put()) |
src/config/locales/i18n/{zh-tw,en}/storage-config.json |
頁面 i18n(欄位 label / placeholder / 驗證訊息) |
8. 後端檔案地圖(本頁核心鏈路)
| 鏈路 | Route | App Service | 底層 |
|---|---|---|---|
| 讀 / 寫儲存設定 | api/system_config/routes/system_config_route.py::SystemConfigGroupRoute(GET/PUT
/system/config/{group}/{key}) |
jedi_system_config 套件
SystemConfigService.get_system_config_by_key /
update_config_by_group_key(@transaction) |
SystemConfigDomainService →
SystemConfigRepoImpl →
public.system_configs(tenant RLS) |
| Remote Agent 下拉 | api/remote_agent/routes/remote_agent_route.py::RemoteAgentsRoute(GET
/remote-agents) |
app/remote_agent/service/remote_agent_service.py::RemoteAgentService.list_enabled_agents(@transaction) |
RemoteAgentDomainService.get_remote_agents(enabled=True)
→
infra/remote_agent/repository/remote_agent_repo_impl.py |
| 儲存類型選單 | api/system_menu/routes/system_menu_route.py |
jedi_system_menu 套件
SystemMenuService.get_system_menu(group) |
public.system_menus(無 tenant
欄位,全域共用選單) |
| 消費端(本頁設定的下游) | 不在本頁鏈路內 | app/upload_file/service/managed_file_upload_service.py::ManagedFileUploadService._load_config |
每次檔案操作時即時讀 STORAGE_CONFIG/CONFIG 組
UploadConfigDTO → 選對應 IUploadFileProvider
adapter(jedi-file-upload 套件) |
DDD 提醒:SystemConfigGroupRoute 是
jedi_system_config 套件內建的通用 CRUD route,非本專案
api/ 層另寫的業務
route——套件本身不認識「STORAGE_CONFIG」這個 group 語意,語意詮釋(三種
value 形狀、remote_agent 二擇一解析)全部在主專案
ManagedFileUploadService 完成。新增本頁欄位時只需改 FE
payload 組裝 + _build_config_dto
的形狀解析,不要在套件層加 STORAGE_CONFIG
專屬邏輯(違反套件不認識 caller 業務知識的既有分工,見 CLAUDE.md
外部套件異動規範)。
9. DB
9.1 資料表總清單(本頁讀寫的全部表)
| 表 | 讀/寫 | 說明 | 欄位詳述 |
|---|---|---|---|
| public.system_configs | 寫(upsert by group+key) | 儲存設定值本體(本頁唯一寫入表;JSONB value 形狀依
storage_type 而異) |
§9.3 |
| public.system_menus | 讀 | 儲存類型下拉選項(group=STORAGE_TYPE,全域共用、無
tenant 欄位) |
§9.3 |
| compliance.remote_agents | 讀 | Remote Agent 下拉來源(僅 enabled=true,tenant RLS
收斂) |
§9.3 |
表名已對照
scripts/deliverables/out/db_schema.json驗證:system_configs在publicschema(非compliance),無獨立storage_configs表——是通用 key-value 設定表的其中一列(group='STORAGE_CONFIG', key='CONFIG'),不是專屬儲存設定的表。
9.2 ER 圖(本頁讀寫範圍)
9.3 核心表欄位(取自 DEV DB dump,含 DB comment)
public.system_configs — 系統配置表(本頁唯一寫入表)
DB
comment:「系統配置表:儲存系統設定參數,以群組和鍵值對方式組織」。本頁只碰
group='STORAGE_CONFIG', key='CONFIG'
這一列(每租戶各自一列,tenant_id 由 RLS/db_mw
自動注入,非本頁欄位)。
| 欄位 | 型別 | 說明 |
|---|---|---|
| id | integer | 主鍵 |
| uid | varchar(50) | 配置唯一識別碼 UUID |
| group | varchar(255) | 配置群組(本頁固定 STORAGE_CONFIG) |
| key | varchar(255) | 配置鍵名(本頁固定 CONFIG) |
| value | jsonb | 配置值——本頁讀寫的實際內容,形狀依
storage_type 而異(見 §6.3) |
| tenant_id | integer|null | RLS 租戶欄(TenantScopedMixinModel 帶入,非 API
欄位) |
| org_unit_id | integer|null | RLS 部門欄(同上) |
| created_at / updated_at | timestamp | 審計欄(無 tz) |
無
created_user/updated_user欄位——system_configs表本身未含審計使用者欄,套件層未實作(本頁不受「審計欄位回傳規範」約束,因為欄位根本不存在)。
public.system_menus — 系統選單表(本頁只讀,供下拉)
DB comment:無獨立表註解(欄位皆有 comment,見下)。無 tenant 欄位——是全域共用的選單資料,非租戶層設定。
| 欄位 | 型別 | 說明 |
|---|---|---|
| group | varchar(255) | 菜單群組(本頁固定 STORAGE_TYPE) |
| key | varchar(255) | 菜單鍵名(下拉顯示文字,無 i18n) |
| value | varchar(255) | 菜單值(存入 storage_type 的實際值) |
| sort | integer | 排序順序 |
| enable | integer | 是否啟用:1 啟用,0 停用 |
| public | integer | 是否公開:1 公開,0 私有 |
compliance.remote_agents — Remote Agent registry(本頁只讀,供下拉)
FR-039 客戶端檔案 Agent registry;完整欄位與管理操作見 檔案 Agent 管理。本頁只用到:
| 欄位 | 型別 | 說明 |
|---|---|---|
| uid | varchar(50) | Agent 識別碼 → response uid,存入本頁
agent_uid |
| name | varchar(255) | 顯示名稱 → response name |
| enabled | boolean | 本頁下拉只列 enabled=true 的 agent |
| tenant_id | integer | RLS 收斂到呼叫者租戶 |
base_url(Agent
內網位址)欄位存在於表中,但本頁下拉刻意不回傳(RemoteAgentResponse
只 dump
uid/name,避免內網位址曝光給前端)。
10. 頁面邏輯與資料對應
載入時序(三支 API 依序等待,非平行):
關鍵欄位對應(API ↔︎ 畫面):
| 畫面元素 | FE state | API 欄位 |
|---|---|---|
| 儲存類型下拉 | config.storage_type |
GET/PUT value.storage_type;選項來自
/system/menu/STORAGE_TYPE 的 {key,value} |
| 本地儲存路徑 | config.base_dir |
value.base_dir |
| MinIO 5 欄 | config.minio_endpoint / minio_access_key /
minio_secret_key / minio_bucket /
minio_secure |
value.minio_* 同名欄位 |
| Agent 下拉 | config.agent_uid;選項來自
remoteAgents(/remote-agents 回傳) |
value.agent_uid |
| 「未儲存變動」判定 | originalConfig(載入/存檔成功時的 JSON 字串快照)vs
當前 config |
純 FE state,無對應 API 欄位 |
儲存流程:無整頁多欄位合併儲存的概念——onSaveClick
先依 storage_type 跑對應 vuelidate rule-set,全數通過才呼叫
update();update() 依
storage_type 重新組裝一份只含該類型欄位的
payload(送出的物件不含其他兩種類型的殘留欄位)→ PUT 覆蓋
value。存檔成功後重拍 originalConfig
快照(離開頁面的未儲存變動判定基準),並顯示成功 toast。
錯誤對應:GET 讀取失敗(含 404 尚未設定過)僅
console.log,不顯示
toast、表單維持預設值(local +
/tmp/upload/);PUT 存檔失敗走 .finally() 收
loading 但未見顯式 catch 顯示錯誤
toast——與其他頁面統一走 axios 全域 axios-error
toast 的慣例一致(本頁未額外攔截,失敗會落到全域 interceptor),細節見
§12 坑 5。
11. 背景行為與外部依賴
| 類型 | 內容 |
|---|---|
| 通知 | 無——本頁不觸發、也不消費任何通知 |
| Socket | 無 socket / 輪詢;純表單載入 + 存檔 |
| jedi-* 套件 | jedi-system-config(system_configs 表 CRUD
通用套件)、jedi-system-menu(system_menus
通用套件)、jedi-file-upload(IUploadFileProvider
adapter 介面,本頁設定的下游消費者)、jedi-auth(JWT) |
| 系統參數 | 無 feature flag;STORAGE_TYPE
選單本身是可調整的系統參數(新增儲存類型需先在 system_menus
seed,再擴充 FE type-conditional 區塊與 BE
_build_config_dto 解析) |
| 消費端(重要但不在本頁鏈路) | 任何檔案上傳/下載/轉檔操作(ManagedFileUploadService)都會即時讀本頁寫入的設定值決定
adapter;本頁存檔生效無延遲、無快取(每次操作都重讀
system_configs,見 CLAUDE.md 對此頁的既有描述「per-tenant
RLS、re-read each request」) |
12. 邊界情況與已知坑
- 表單驗證僅擋當前選中類型的必填欄位,其餘類型欄位不驗證也不清空:切換
storage_type 時舊欄位值仍留在
configstate 裡(僅local有特殊「切回時重設 base_dir」邏輯),但因update()組裝 payload 時只挑當前類型欄位送出,不會誤存其他類型的殘留值——UI 顯示雖可能有「幽靈」舊值殘留在未顯示的欄位,但不影響實際存檔內容 - 「未儲存變動」判定用 JSON 字串比對整個 config
物件:
originalConfig/isDirty()是全物件序列化比對,換言之即使只是點開下拉又選回原值,只要物件序列化結果不同(如 key 順序,理論上同一物件不會變動順序,實務風險低)都可能誤判有變動;此為 FE 已知取捨(解決舊版「存檔後沒歸位」等三種誤判),非新發現的 bug - BE 兩支端點都無角色/capability 檢查(僅 JWT):見 §3 ⚠️——任何已登入使用者原則上都能直接打 API 改動全租戶儲存後端設定,繞過 FE 選單的 RBAC 門檻。因涉及基礎設施設定(儲存後端切換可能造成既有檔案「找不到」的表面故障),風險層級高於純讀頁面(如 my-audits 的類似落差),若日後要補強建議在 route 層加 capability 檢查而非僅靠選單隱藏
- remote_agent 的
value有兩種形狀(inline vs registry):ManagedFileUploadService._resolve_agent支援舊版{storage_type:'remote_agent', base_url:'...'}(inline,FR-039 Phase 2 demo 遺留相容)與新版{storage_type:'remote_agent', agent_uid:'...'}(registry,FE 本頁實際只會存這種)——若 DB 裡殘留舊版 inline 格式的 row,本頁 GET 讀回來的value不會有agent_uid,下拉會顯示未選中狀態,儲存後即覆蓋為新版格式 - PUT 失敗無顯式錯誤提示:
update()的.then()只處理成功情境,.finally()只收submittedloading 旗標,未見顯式.catch()顯示錯誤訊息——若全域 axios interceptor 沒攔截到,使用者可能存檔失敗卻只看到 loading 消失、無任何提示 - 本頁與雲端整合 / 檔案 Agent 管理同群但概念獨立:儲存設定只決定「檔案的位元組存在哪個後端」,Google Drive OAuth 連接(雲端整合)與 Remote Agent 的註冊/生命週期管理(檔案 Agent 管理)是另外兩個獨立頁面——本頁只消費「已註冊的 agent 清單」做下拉選擇,不做 agent 的新增/撤銷/心跳管理
13. 開發與驗證
- 跑起來:BE
python main_socketio.py(port 8000,log 在log/app.log);FE 在compliance-manager-fe/起 Vite dev server。BE 改 service code 後必須重啟(無 hot reload) - 測試帳號:dev 環境租戶管理者角色帳號(密碼見
.env/ 部署文件) - 導航路徑:登入 → 側邊選單「系統設定」群組 →
「儲存設備設定」(
/system/storage-config) - 前置資料:測試
remote_agent選項前,需先在「檔案 Agent 管理」頁登錄至少一個enabled=true的 agent(FR-039),否則下拉為空、選中該類型會被必填擋下無法存檔 - E2E:
compliance-manager-test/repo(Cucumber + Playwright);本頁相關 feature 檔以儲存設定/storage-config搜尋 - 相關文件:FR-039(分散式檔案
Agent,
docs/features/FR-039-2606-distributed-file-agent/)、FR-042(系統儲存 scope,app/upload_file/service/managed_file_upload_service.pydocstring);DB / API 全量見 GAI-SD-02/03;docs/api/system-config/frontend-spec.md(舊文件,僅供背景參考,完整度不保證)