手冊首頁 / 系統管理 / 資訊系統盤點

資訊系統盤點(Information System Manage)

功能群:系統管理|三層 RBAC 權限模型與角色權限基調先讀 功能群總覽

事實基準:2026-07-05 從 FE / BE code 掃出(DDD 層級位於外部套件 jedi-information-system,主專案僅 route + app service 薄殼);API schema 逐條對照 marshmallow serializer 與 service 組裝碼

變更紀錄:2026-07-09 FR-047 已知坑修復 —— 刪除確認框改「停用」語彙(U-3);system_owner / PUT / DELETE「找不到」改結構化 error code(ECODE#5/#6);清理重複 tenant_id 索引(SCHEMA,DEV+STG,POC 待部署)

1. 功能描述

資訊系統盤點頁是租戶層級的稽核範圍系統主檔 CRUD 介面:維護 compliance.information_systems 這張「可被列入稽核範圍的系統基本資料」清冊,欄位設計對應 OSCAL SSP system-characteristics(系統名稱、縮寫、描述、FIPS 199 安全影響等級與 C/I/A 三軸安全目標、系統狀態、部署模型、系統負責人、授權邊界描述)。本頁登記的系統會出現在專案啟動時的系統選單(is_active=true 者),供稽核專案綁定其涵蓋的資訊系統;同一批資料也是 SSP 匯出 system-characteristics 區塊與「系統資產」盤點(asset-type=information_system)的來源。本頁本身是單一 DataTable + 新增/編輯 Dialog 的標準管理頁,無左側樹、無 Tab、無狀態機

主要使用者:系統管理層使用者(頁面可見性由 RBAC 選單控管,見 §3)。

角色速覽

角色 一句話
系統管理層使用者 本頁唯一操作者——選單可見性由 RBAC 控管(見 _overview §2),BE 端點層僅檢查 JWT 登入

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 資訊系統清單(分頁/排序/搜尋) 11 欄 DataTable,lazy 分頁 + 多欄排序;固定套用 is_active=true filter(停用系統不顯示);per-user 查詢狀態持久化(useTableQuery scope=route name) 主表格 §5
2 全域關鍵字搜尋 單一搜尋框,BE 對 name 欄位做 ILIKE 模糊比對 Header 搜尋框 §6.3
3 重置查詢 清空搜尋/排序/分頁回到第一頁 Header「重置查詢」按鈕 §10
4 新增資訊系統 開 Dialog 填寫名稱+C/I/A 安全目標+系統狀態+系統負責人(必填)+ 縮寫/部署模型/描述/授權邊界(選填) Header「新增」→ Dialog UC-IS-01
5 編輯資訊系統 同一 Dialog,帶入既有值後 PUT;system_owner 未變動則不送出(保留原值) 逐列名稱連結 / 「編輯」按鈕 UC-IS-01
6 FIPS-199 安全影響等級自動計算 FE 依 C/I/A 三軸最高值算 High Water Mark(fips-199-low/moderate/highlow/moderate/high),欄位唯讀顯示、隨表單即時更新 Dialog §10
7 刪除資訊系統(單筆,實為軟刪除) 逐列「刪除」按鈕,二次確認;BE 實作是 is_active=False,DB 列不會被實體刪除 逐列「功能」欄 UC-IS-02
8 批次刪除(軟刪除) 勾選多列後批次送出刪除,逐筆 Promise.allSettled,統計成功/失敗數各自 toast 表格 checkbox + Header「批次刪除」 UC-IS-02
9 系統負責人顯示 清單與 Dialog 皆顯示 nickname;BE domain service 層批次 enrich(非 DB JOIN) 清單「系統負責人」欄 / Dialog 下拉 §6.2 §8
10 建立者顯示 顯示 nickname(非 login_name),BE app service 層批次 enrich 清單「建立者」欄 §6.2

UC(§2)展開 1(新增/編輯 CRUD,含 system_owner 解析)、2(刪除=軟刪除語意)這兩條核心操作路徑;其餘(搜尋/排序/分頁/重置/FIPS 自動計算)屬標準行為,於 §10 併述。

2. Use Case

角色速覽

角色 一句話
系統管理層使用者 本頁唯一操作者——選單可見性由 RBAC 控管(見 _overview §2),BE 端點層僅檢查 JWT 登入

流程圖視覺慣例:菱形 = 判斷、橘底 = 例外/擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 可選路徑。

UC-IS-01 新增/編輯資訊系統

項目 內容
角色 系統管理層使用者(頁面可見性由 RBAC 選單控管)
前置條件 已登入;information-system-manage 選單可見
產出 / 後置條件 compliance.information_systems 新增一列或更新既有列;system_owner 若填寫需先解析為 users.id;清單重新整理
infosys_uc_crud start open 開「新增/編輯」Dialog start->open input 填寫名稱/C-I-A 安全目標/ 系統狀態/系統負責人(必填)+ 縮寫/部署模型/描述/ 授權邊界(選填) open->input cia FE 依 C/I/A 三軸最高值 自動算 FIPS-199 安全影響等級 (High Water Mark) input->cia valid FE 前端驗證: 必填欄位皆已填? cia->valid fix 紅字提示,聚焦第一個錯誤欄位 valid->fix submit 送出 POST /information-systems 或 PUT /information-system/{uid} valid->submit fix->input jwt BE 檢查:JWT 已登入? (無角色/租戶檢查) submit->jwt deny 401 未登入 jwt->deny owner BE 解析 system_owner: uid → users.id(IUserLookup) jwt->owner notfound system_owner uid 查得到使用者? owner->notfound ownererr 404 USER_NOT_FOUND notfound->ownererr ok upsert compliance.information_systems 列 回傳最新 InformationSystemResponse (enrich system_owner_name / created_user_name) notfound->ok 是(或未填 system_owner)
UC-IS-01 流程:FE 依 C/I/A 算 FIPS-199 等級 → 前端必填驗證 → 送出 → BE 僅檢查 JWT → 解析 system_owner uid→id(查無使用者回 404)→ upsert

UC-IS-02 刪除資訊系統(單筆 / 批次,實為軟刪除)

項目 內容
角色 系統管理層使用者;⚠️ BE 端點對任意登入者皆開放(見 §3)
前置條件 已登入;該系統列存在於清單
產出 / 後置條件 compliance.information_systems.is_active 設為 False實體刪除,DB 列與歷史稽核專案的關聯不受影響);清單重新整理(因固定 is_active=true filter,該列即從清單消失)
infosys_uc_deactivate start pick 逐列「刪除」/勾選多列「批次刪除」 start->pick confirm 二次確認框: 使用者按下確定? pick->confirm cancel 取消,維持清單不變 confirm->cancel submit 送出 DELETE /information-system/{uid} (批次=逐筆 Promise.allSettled) confirm->submit jwt BE 檢查:JWT 已登入? (無角色/租戶/擁有者檢查) submit->jwt deny 401 未登入 jwt->deny exist uid 存在於 information_systems? jwt->exist notfound 200 data:false (非 404,見 §12 坑 2) exist->notfound ok 軟刪除:is_active=False (非實體刪除,DB 列仍在) 清單重新整理 exist->ok tally 批次:統計成功/失敗筆數各自 toast ok->tally 批次時
UC-IS-02 流程:二次確認 → BE 僅 JWT 無角色/擁有者檢查 → uid 找不到回傳 data:false(非 404)→ 找到則軟刪除 is_active=False → 批次時逐筆統計成功/失敗

3. 權限矩陣

頁面可見性依 RBAC 三層模型基調,見 _overview §2。本頁端點層的實際檢查點:

操作 FE 判定 BE 強制 BE 檢查位置
選單 / 頁面可見性 RBAC 選單資料決定(route meta 無 capability 欄位,純靠 ui_routes/capabilities 回傳結果) 不適用(選單層問題,非本頁端點) jedi-auth web-menu(見 _overview §2.1
讀清單 / 讀單筆 / menu 無額外前端判斷 ⚠️ @jwt_required(),無角色/租戶檢查 api/information_system/routes/information_system_route.pyInformationSystemListResource / InformationSystemDetailResource.get / InformationSystemMenuResource
新增 / 編輯 表單前端必填驗證(名稱/C-I-A/系統狀態/系統負責人) ⚠️ @jwt_required(),無角色/租戶檢查;schema 僅做型別驗證,不做業務規則 同檔 InformationSystemCreateResource.post / InformationSystemDetailResource.putapp/information_system/service/information_system_app_service.py
刪除(單筆/批次,軟刪除) 無擁有者判定(任何使用者對任一列皆顯示刪除鈕,與 device-manage 的「僅建立者可見」不同) ⚠️ @jwt_required(),完全無擁有者或角色檢查——deactivate 直接依 uid 軟刪除,任何登入者知道 uid 即可停用任一資訊系統(含他人建立的) 同檔 InformationSystemDetailResource.deleteapp/information_system/service/information_system_app_service.py、jedi-information-system information_system_domain_service.py:84-85deactivate 無條件執行)

⚠️ 已知不一致(維護時注意):本頁刪除連 device-manage 都沒有的「FE 擁有者限定」都沒實作——FE 對任何登入者、任一列都顯示刪除鈕,BE 亦無任何角色或擁有者比對,屬本群目前權限守門最寬鬆的一頁。詳見 §12 坑 1。

4. 狀態機與前置條件

本頁狀態機、無輪次/階段概念(資訊系統是靜態主檔資源,不屬於稽核輪次生命週期)。僅有欄位層級的前置條件:

條件 效果 出處
name / security_objective_confidentiality / _integrity / _availability / system_status / system_owner 為空 FE 表單驗證擋下,紅字提示,不送出 API InformationSystemManage.vue:51-60rules
C/I/A 三軸皆已選 FE 自動算 computedSensitivityLevel(High Water Mark),寫回 security_sensitivity_level InformationSystemManage.vue:238-252
system_owner 為空(編輯時) payload 不含此欄位,PUT 端會跳過(保留原值) InformationSystemManage.vue:138-141
BE 寫入 無任何角色/租戶前置條件檢查InformationSystemCreateSchema/UpdateSchema 只做型別/必填驗證,不做業務規則) api/information_system/serializers/information_system.py
BE system_owner 解析 有填 uid 但查無對應使用者 → NotFound("USER_NOT_FOUND") jedi-information-system app/service/information_system_service.py:30-40_resolve_system_owner

5. UI 設計

📸 實際畫面截圖待補(一律亮色模式拍攝):以 playwright 對 STG 擷取,預計補以下三張到 assets/img/: ① 整頁(搜尋框 + DataTable 11 欄 + 批次刪除/新增按鈕)infosys-overview.png ② 新增 / 編輯資訊系統 Dialog(C/I/A 三軸 + 部署模型/系統狀態 + 系統負責人下拉)infosys-edit-dialog.png ③ 安全影響等級自動計算特寫(Tag 顏色隨 C/I/A 選擇即時變化)infosys-fips-tag.png

版面骨架(單欄:Header 搜尋/動作 + DataTable + Dialog,無左側樹、無 Tab):

Header:關鍵字搜尋(name ILIKE)+ 重置查詢 + 批次刪除(checkbox)+ 新增資訊系統 單欄版面:無左側樹、無 Tab;固定 filter is_active=true 開啟:資訊系統盤點 §6 API 規格 資訊系統清單 DataTable:11 欄(名稱/縮寫/C-I-A/部署模型/系統狀態/系統負責人…) POST /information-systems/list (分頁清單,固定 is_active=true) GET /information-systems/menu (供專案啟動系統選單引用) 安全影響等級 / C-I-A / 部署模型 / 狀態以 Tag 分色呈現 → #6-api-規格(點我開啟) 開啟:UC-IS-01 新增/編輯資訊系統 新增/編輯資訊系統 Dialog 名稱*/C-I-A*/系統狀態*/系統負責人*(FE 必填,BE 選填) POST /information-systems ・ PUT /information-system/{uid} FIPS-199 等級由 C/I/A 自動算 High Water Mark(唯讀) → UC-IS-01(點我開啟) 開啟:UC-IS-02 刪除資訊系統(實為軟刪除) 刪除資訊系統(單筆/批次)二次確認 任一列皆顯示刪除鈕(FE 無擁有者判定,比 device 更寬鬆) DELETE /information-system/{uid}(實為 is_active=False 軟刪) DB 列保留、歷史 SSP 系統資產軟引用不受影響 → UC-IS-02(點我開啟) 彩色=可點跳轉本頁 §6/UC 的區塊|灰=本頁結構描述|虛線=Dialog/條件顯示層 API 僅列代表性 2~3 條,完整規格見 §6
資訊系統盤點頁版面骨架:Header 搜尋/批次刪除/新增、DataTable 11 欄(連 §6 API)、新增/編輯 Dialog(C/I/A + 部署模型/系統狀態 + 系統負責人,連 UC-IS-01)、刪除單筆/批次確認(實為軟刪除,連 UC-IS-02)

狀態呈現:DataTable listLoading 遮罩載入中;批次刪除單獨 batchDeleting loading 狀態,不阻塞整頁;各分類欄位(安全影響等級/C-I-A/部署模型/系統狀態)以 PrimeVue Tag 呈現,顏色依值分級(見 §10);無值時顯示 ;無 socket,操作後皆重打 getSystems() 重新整理。查詢狀態(搜尋關鍵字/排序/分頁)以 useTableQuery 依 route name scope 持久化於 queryStore,換使用者或重新登入會自動重新查詢(InformationSystemManage.vue:72-76)。

6. API 規格

Envelope:成功 {"status": true, "data": …}(頂層由 return_response 統一組裝,見 common/util/response_util.py);失敗為 4xx/5xx + {"error_code": "…", "msg": "…"} 或 marshmallow 驗證錯誤 400。

6.1 總清單(本頁涉及的全部 endpoint)

分類 Method + Path 說明 完整規格
清單 POST /information-systems/list 分頁清單(本頁主要資料來源,payload={pager, sort, filters},固定帶 filters.is_active=true §6.2
清單 GET /information-systems/menu 輕量選單(供專案啟動時的系統選單、其他頁面 SystemPicker 引用;本頁不直接呼叫) §6.4
CRUD GET /information-system/{uid} 取單筆(本頁未直接呼叫,供除錯 / 他頁引用) GAI-SD-02
CRUD POST /information-systems 新增資訊系統 §6.3
CRUD PUT /information-system/{uid} 更新資訊系統(欄位選填更新,system_owner 省略即保留原值) §6.3
CRUD DELETE /information-system/{uid} 停用資訊系統(軟刪除 is_active=False,無擁有者/角色檢查,見 §3) §6.4

以下 §6.2~6.4 為核心 endpoint 完整規格(欄位逐條對照 marshmallow serializer / service 組裝碼,出處標在各段末);標 GAI-SD-02 者屬常規 CRUD,細節見 API 規格書或 Swagger /swagger-ui/

6.2 清單類

[POST] /information-systems/list

Request payload

欄位 型別 必填 說明
pager object {page, page_size, with_total}
sort array [{field, order}],多欄排序
filters object {search, is_active, security_sensitivity_level, system_status};本頁固定帶 is_active: truebuildInfoSystemPayload()),其餘欄位本頁 UI 未開放篩選

Response data[](每項一個資訊系統,欄位同 §6.3 Response):

欄位 型別 說明
id / uid string idMethod 別名,實際回傳 obj.uid與清單/新增/更新回應一致,非內部整數 PK
name / abbreviation string / string|null 系統全名 / 縮寫
description string|null 系統描述
security_sensitivity_level string|null low / moderate / high
security_objective_confidentiality / _integrity / _availability string|null FIPS 199 三軸:fips-199-low / fips-199-moderate / fips-199-high
system_status string|null operational / under-development / under-major-modification / disposition / other
deployment_model string|null on-premise / cloud / hybrid / co-location
authorization_boundary string|null 授權邊界描述
system_owner string|null Method 別名,回傳 system_owner_uid(使用者 UID,非內部整數 id)
system_owner_name string|null 系統負責人 nickname(domain service 層批次 enrich,非 DB 直接欄位)
is_active bool 是否啟用
created_by int|null 建立者 users.id(soft ref)
created_user / updated_user string|null login_name(審計欄)
created_user_name / updated_user_name string nickname(app service 層批次查 enrich_audit_nickname_objs enrich)
created_at / updated_at datetime|null YYYY-MM-DD HH:MM:SS

出處:api/information_system/serializers/information_system.py:60-89InformationSystemResponseSchema);app/information_system/service/information_system_app_service.py:17-24enrich_audit_nickname_objs);系統負責人 enrich 在 jedi-information-system domain/service/information_system_domain_service.py:25-38_enrich_owner)。

6.3 CRUD 類

[POST] /information-systems

Request(InformationSystemCreateSchema):

欄位 型別 必填 說明
name string 是(schema 層 required=True;FE 亦驗證) 系統全名
security_objective_confidentiality / _integrity / _availability string 否(schema 層選填;FE 表單驗證必填 FIPS 199 三軸值
system_status string 否(schema 層選填;FE 表單驗證必填 系統狀態
system_owner string 否(schema 層選填;FE 表單驗證必填 使用者 uid,BE 解析為 users.id;查無使用者 → NotFound("USER_NOT_FOUND")
abbreviation / description / security_sensitivity_level / deployment_model / authorization_boundary string 選填欄位;security_sensitivity_level 由 FE 依 C/I/A 自動算好隨表單送出
is_active bool load_default=True

⚠️ 必填欄位(C/I/A、系統狀態、系統負責人)只在 FE rules/schema 層仍是選填——BE InformationSystemCreateSchema 對這些欄位皆 load_default=None, allow_none=True,繞過 FE 直接打 API 可送出缺欄位的資料。

Response:同 §6.2 單筆形狀。出處:api/information_system/serializers/information_system.py:22-37InformationSystemCreateSchema)、add_information_system(jedi-information-system app/service/information_system_service.py:74-82)。

[PUT] /information-system/{uid}

Request:欄位同 POST(InformationSystemUpdateSchema,皆選填)。Route 層對 load 完的 dict 先過濾掉值為 None 的欄位才傳進 service(api/information_system/routes/information_system_route.py:145),故省略欄位或傳 null 皆視為「不更新該欄」,保留舊值(無 full-replace、無法用 API 清空欄位到 null;若要清空文字欄位需送空字串)。system_owner 省略時 service 層 _resolve_system_owner 會將其設為 None 再 setattr——但因 route 層已濾除 None 值,實務上不會出現「送出但清空 owner」的路徑,FE 亦以此設計(未選新負責人就不送該欄)。

不存在的 uid → jedi-information-system update() 回傳 None,route 層回傳 404 Not found與 device-manage 的「全空物件」不同,本頁 PUT 有明確 404)。出處:app/information_system/service/information_system_app_service.pyapi/information_system/routes/information_system_route.py:150-152、jedi-information-system infra/repository/information_system_repo_impl.py:114-132

[DELETE] /information-system/{uid}

無 body。Response data{}(成功)。實作是軟刪除deactivate(uid) 只將 is_active 設為 False,DB 列與所有既有稽核專案的關聯(如 SSP 系統資產盤點的 uid soft ref)不受影響、不會被清除。uid 不存在時,route 回傳 404 Not found(與 device-manage「200 data:false」不同,見 §12 坑 2)。刪除無任何擁有者或角色檢查(見 §3)。出處:api/information_system/routes/information_system_route.py:161-172delete_information_system(jedi-information-system app/service/information_system_service.py:94-97domain/service/information_system_domain_service.py:84-85infra/repository/information_system_repo_impl.py:134-140)。

6.4 選單 / 輔助類

[GET] /information-systems/menu

無 query。Response data[](陣列,每項一個系統):

欄位 型別 說明
id string 對外識別碼(=uid);FR-032 F 命名慣例:id 對外走 uid、對稱 device menu
pk int 內部 PK(=內部 id);FR-032 F 命名慣例:pk 走內部 PK
name string 系統全名
abbreviation string|null 系統縮寫

僅回傳 is_active=True 的系統,依 name 升序排列。本頁不直接呼叫,供專案啟動選單、SSP 系統資產 picker 等其他頁面下拉使用。出處:api/information_system/serializers/information_system.py:91-98InformationSystemMenuResponseSchema)、jedi-information-system infra/repository/information_system_repo_impl.py:74-89get_menuload_only 限縮欄位)。

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/information-system/InformationSystemManage.vue 唯一檢視檔(約 780 行;無子元件,DataTable + 新增/編輯 Dialog + FIPS-199 計算邏輯全在此)
src/config/router/index.js:608-621 route information-system-manage,path /information-system/managemeta 無 capability 欄位,可見性由 RBAC 選單資料決定
src/config/api/api.js:191-194 INFORMATION_SYSTEMS_MENU / INFORMATION_SYSTEMS_LIST / INFORMATION_SYSTEMS / INFORMATION_SYSTEM 常數
src/service/BaseService.js 本頁未使用專屬 service 檔,直接用 BaseService 泛型 get/post/put/deleteAPI.*
src/composables/useTableQuery.js 共用分頁/排序/搜尋 state(per-scope + per-user 持久化)
src/stores/queryStore.js useTableQuery 背後的 Pinia store(resetCurrent() 供「重置查詢」使用)
src/stores/menuStore.js userMenu(系統負責人下拉資料來源,fetchUserMenu()
src/utils/userUtil.js useUserUtil()userInfo(供頁面 uid watch 觸發重查)
src/config/locales/i18n/{zh-tw,en}/information-system.json 頁面 i18n,namespace lang.information_system_manage.*

8. 後端檔案地圖(本頁核心鏈路)

鏈路 Route App Service 底層
清單 api/information_system/routes/information_system_route.py::InformationSystemListResource app/information_system/service/information_system_app_service.py::get_information_systems_and_pager@transaction jedi-information-system InformationSystemService.get_information_systems_and_pagerInformationSystemDomainService_enrich_owner)→ InformationSystemRepoImpl(繼承 BaseRepositoryImpl
menu 同檔 InformationSystemMenuResource InformationSystemService.get_information_system_menu(套件層直接處理,不經主專案 app service jedi-information-system InformationSystemRepoImpl.get_menuload_only 限縮欄位)
新增 同檔 InformationSystemCreateResource InformationSystemService.add_information_system(套件層,不經主專案 app service 同上鏈路;_resolve_system_owner 解析 uid→id(透過注入的 IUserLookup
讀單筆 / 更新 / 刪除 同檔 InformationSystemDetailResource(GET/PUT/DELETE) InformationSystemService.get_information_system / update_information_system / delete_information_system(套件層,不經主專案 app service 同上鏈路

DDD 提醒:本模組是「主專案薄殼 + 外部套件扛全部 domain/infra」的典型範例——domain/information_system/infra/information_system/ 在主專案僅有一個檔案(infra/information_system/jedi_auth_user_lookup.py,實作套件定義的 IUserLookup 抽象、供 dependency inversion 用),核心 domain/infra 全數在 jedi-information-system 套件內(~/Projects/Jedicogy/module/jedi-python-package/jedi-information-system/)。只有「清單」端點會經過主專案 InformationSystemAppService(因為需要 enrich_audit_nickname_objs 這個主專案專屬的審計欄位 nickname enrich,遵守 CLAUDE.md「審計欄位回傳規範」);新增/讀單筆/更新/刪除都直接呼叫套件的 InformationSystemService,略過主專案 app service 層——這代表這四個端點的 route 直接注入套件 service,並非嚴格意義的「route → app service → domain」三層,是本模組刻意的架構選擇(套件本身已有 @transaction 包裝、且不需要額外的主專案層 enrich)。改資訊系統核心行為(新增欄位、驗證規則、FIPS 分類邏輯)要去 jedi-information-system 套件改,改動需遵守 CLAUDE.md「外部套件異動規範」。route 層無 DB 存取(守規範)。

9. DB

9.1 資料表總清單(本頁讀寫的全部表)

讀/寫 說明 欄位詳述
compliance.information_systems 稽核範圍資訊系統主檔(本頁唯一直接讀寫的表;⚠️ 注意 schema 是 compliance,非 public §9.3
public.users 系統負責人 enrich(domain service 層 IUserLookup 批次查 id → uid/nickname)+建立者/更新者 enrich(app service 層 enrich_audit_nickname_objslogin_name → nickname),皆非 JOIN GAI-SD-03

tenant_id / org_unit_id有 FK(參照 tenants / org_units,非 soft ref;未顯式設 ON DELETE 子句 → 走 Postgres 預設 NO ACTION,效果近似 RESTRICT〔皆阻擋刪除被參照的父列〕但非同一語意);system_owner / created_by 則是無 FK 的 soft ref(參照 users.id,跨套件邊界不建實體外鍵,經 IUserLookup 解耦)。本頁無其他表直接讀寫,但 information_systems.uid 被以下模組以 soft ref 引用(非 FK,見 §11):oscal.ssp_inventory_itemsprops.asset-type = "information_system" 時的系統資產盤點)、ModuleFrame 範本 clone 時的系統資產快照列。

9.2 ER 圖(本頁讀寫範圍 + 跨模組軟引用)

infosys_er information_systems compliance.information_systems (本頁寫入) id (PK) 內部序號 uid 對外 UUID(OSCAL system-id) name / abbreviation 系統全名/縮寫 security_sensitivity_level FIPS-199 安全影響等級 security_objective_c/i/a FIPS-199 C/I/A 三軸 deployment_model 部署模型 system_status 系統狀態 system_owner (soft ref) → users.id,無 FK is_active 軟刪除旗標 tenant_id / org_unit_id 有 FK(RESTRICT) users public.users (讀) id PK uid / login_name / nickname system_owner enrich 來源 information_systems->users system_owner (soft ref,IUserLookup) tenants public.tenants (讀,FK) id PK information_systems->tenants tenant_id (FK RESTRICT) org_units public.org_units (讀,FK) id PK information_systems->org_units org_unit_id (FK RESTRICT) ssp_inventory oscal.ssp_inventory_items (本頁外,跨模組引用) props.asset-type = "information_system" 時\n連結本表 uid 為系統資產 ssp_inventory->information_systems uid soft ref (SSP 系統資產盤點引用)
資訊系統盤點 ER:information_systems 為本頁唯一寫入表;system_owner 為 soft ref(無 FK)連 users;tenant_id/org_unit_id 為真 FK;虛線 = soft ref(非本頁寫入,僅供了解引用面)

9.3 核心表欄位(取自 DEV DB dump,含 DB comment)

compliance.information_systems — 資訊系統主檔

DB comment:「資訊系統表:儲存可被列入稽核範圍的系統基本資料(master data)」。欄位設計對應 OSCAL SSP system-characteristics

欄位 型別 說明
id integer 內部 PK(information_systems_id_seq
uid varchar(50) 對外識別碼;DB comment:「系統唯一識別碼 UUID,對應 OSCAL system-id」;UNIQUE
name varchar(255) NOT NULL;DB comment:「系統全名,對應 OSCAL system-name」
abbreviation varchar(100)|null DB comment:「系統縮寫,對應 OSCAL system-name-short」
description text|null DB comment:「系統描述,對應 OSCAL description」
security_sensitivity_level compliance.security_sensitivity_level_enum|null DB comment:「安全影響等級:low / moderate / high」(enum 值取自 jedi-information-system SecuritySensitivityLevel
system_status compliance.system_status_enum|null DB comment(DB 層文字未列全):operational / under-development / under-major-modification / disposition / other(完整 5 值取自套件 SystemStatus enum,見下方註記)
system_owner integer|null DB comment:「系統負責人姓名」(comment 用詞與實際型別不符,實為 users.id 整數 soft ref,非姓名字串——經 IUserLookup 解析/enrich)
is_active boolean NOT NULL default true;DB comment:「是否啟用;停用後不出現在專案選單」——本頁「刪除」實際上就是把此欄位設 false
created_by integer|null DB comment:「建立者,參照 public.users.id」(soft ref,無 FK)
tenant_id integer NOT NULL;FK → tenants.id(未設 ON DELETE,預設 NO ACTION
org_unit_id integer|null FK → org_units.id(未設 ON DELETE,預設 NO ACTION
security_objective_confidentiality compliance.security_objective_level_enum|null DB comment:「FIPS 199 機密性等級:fips-199-low / fips-199-moderate / fips-199-high」
security_objective_integrity compliance.security_objective_level_enum|null DB comment:「FIPS 199 完整性等級」(值同上)
security_objective_availability compliance.security_objective_level_enum|null DB comment:「FIPS 199 可用性等級」(值同上)
deployment_model compliance.deployment_model_enum|null DB comment:「部署模型:on-premise / cloud / hybrid / co-location」
authorization_boundary text|null DB comment:「授權邊界描述,對應 OSCAL authorization-boundary.description」
created_user / updated_user varchar(50)|null login_name(審計欄,無 DB comment)
created_at / updated_at timestamp NOT NULL,無 comment

system_status 完整 enum 值(DB comment 只列 3 值,實際 5 值)operational / under-development / under-major-modification / disposition / other,取自 jedi-information-system common/enum/information_system_enum.py::SystemStatus(DB comment 文字未同步更新,屬文件與程式碼落差,本文件以程式碼 enum 為準)。

索引:idx_information_systems_is_active(單欄,配合本頁固定 filter)、idx_information_systems_tenant_id + ix_compliance_information_systems_tenant_id(兩個等價單欄 index 共存,疑歷史殘留)、idx_information_systems_uid

10. 頁面邏輯與資料對應

載入時序onMounted 先顯示 listLoading,若 menuStore.userMenu 未載入則先 fetchUserMenu()(系統負責人下拉資料)→ 呼叫 getSystems()buildInfoSystemPayload(){pager, sort, filters:{...filters, is_active:true}}POST /information-systems/list → 填入 systems.valuepager.valuemeta 回填)。使用者 uid 變化(延遲取得或重新登入)會觸發 watch 重新查詢。

關鍵欄位對應(API ↔︎ 畫面):

畫面元素 FE state API 欄位
DataTable 各欄 systems (array) data[] 逐項對應(name/abbreviation/security_sensitivity_level/security_objective_confidentiality/_integrity/_availability/deployment_model/system_status/system_owner_name
安全影響等級 Tag 顏色 sensitivitySeverity() low=success(綠)/moderate=warning(橘)/high=danger(紅)
C/I/A 三軸 Tag 顏色 securityObjectiveSeverity() fips-199-low=success/fips-199-moderate=warning/fips-199-high=danger
部署模型 Tag 顏色 deploySeverity() on-premise=info/cloud=success/hybrid=warning/co-location=info
系統狀態 Tag 顏色 statusSeverity() operational=success/under-development|under-major-modification=warning/disposition=secondary/other=info
建立者欄 直接綁定 created_user_name 優先,created_user(login_name)次之,皆無則
安全影響等級(Dialog,唯讀) computedSensitivityLevel(computed) security_objective_confidentiality/_integrity/_availability 三值取 rank 最高者反推等級(fipsRankrankToSensitivity),watch 觸發後寫回 currentData.security_sensitivity_level
系統負責人下拉 menuStore.userMenuoptionLabel="nickname", optionValue="uid" Dialog 內選取後 payload 帶 system_owner(僅於使用者明確選取時才送出,見 §6.3)
分頁/排序/搜尋 pager / multiSortMeta / filterTableuseTableQuery 提供) request payload.{pager, sort, filters}

儲存流程onSaveClickv$.value.$touch() 觸發前端驗證,失敗則聚焦第一個錯誤欄位並中止;通過後手動組出 10 個欄位的 payload(security_sensitivity_level 優先取 computedSensitivityLevel,其次沿用既有值),system_owner 只在使用者明確選取時才加進 payload;依 currentData.value.uid 是否存在分流 create()(POST)或 update()(PUT),成功後皆重新 getSystems() + 關閉 Dialog(onCancelClick)。刪除/批次刪除皆先 confirm.require 二次確認;批次刪除以 Promise.allSettled 逐一送出 DELETE,統計成功/失敗數各自 toast。

錯誤對應:BE error envelope → toast 顯示(showError(e))。本頁常見狀況:marshmallow 驗證失敗(缺 name)→ 400;system_owner uid 查無使用者 → NotFound("USER_NOT_FOUND")注意此處傳入 NotFound 建構子的是原始字串而非 common/code/ 定義的 ErrorCode 物件,屬套件層寫法、非主專案慣例,見 §12 坑 3);PUT/DELETE 找不到 uid → 明確 404return_response(False, {}, msg="Not found"))。本頁無資訊系統專屬 error code——common/code/grc_error_code.py:84GRC_INFORMATION_SYSTEM_NOT_FOUNDGRC_404020),但該碼是給 FR-032 F 系統資產 ref_id 校驗失敗使用(見同檔 :307 註解),非本頁 CRUD 端點實際回傳的碼;本頁 CRUD 端點的 404 都是路由層手寫的 plain "Not found" 字串,不經 GrcErrorCode

11. 背景行為與外部依賴

類型 內容
通知 無——本頁不觸發、也不消費任何通知
Socket 無 socket / 輪詢;操作後皆重打 getSystems()
jedi-* 套件 jedi-information-system(資訊系統 domain/infra/app service 核心,含 entity/repo/mapper,InformationSystemEntity 內建 to_oscal_dict()/from_oscal_dict() 供 OSCAL SSP system-characteristics 匯出入)、jedi-authUserDomainServiceIUserLookup 實作、供 nickname enrich)、jedi-commonBaseRepositoryImpl/transaction/分頁 spec)
系統參數 無 feature flag
跨頁 / 跨模組依賴 GET /information-systems/menu 被專案啟動選單、SSP 系統資產 picker 等頁面引用;InformationSystemEntity.to_oscal_dict() 是 SSP 匯出 system-characteristics 區塊的資料來源;oscal.ssp_inventory_itemsasset-type=information_system 資產列以 uid soft ref 連結本表;ModuleFrame 範本 clone(module_frame_template_cloner_impl.py)在複製系統資產列時會凍結快照當下的 props;本頁停用(軟刪除)系統不會檢查是否正被任何專案/SSP 引用中

12. 邊界情況與已知坑

  1. 刪除無任何擁有者或角色檢查,且 FE 也未表達擁有者限定語意:與 device-manage「FE 至少想表達擁有者限定、只是 BE 沒守住」不同,本頁 FE 對任一列都顯示刪除鈕(無 isDeletableDevice 對等判斷),BE DELETE /information-system/{uid} 也完全不比對 created_user/created_by——任何已登入使用者知道 uid 即可停用他人建立的資訊系統。修正需額外評估是否要補 tenant/owner 檢查,屬另開 bug/改動 session 的範圍,本頁 spec 僅記錄不修
  2. 「刪除」實為軟刪除(is_active=False),非實體刪除——文案已改「停用」語彙(2026-07-09 FR-047 U-3):DB 列會保留,僅從清單(固定 is_active=true filter)消失。對已被稽核專案/SSP 系統資產盤點引用的資訊系統而言,這是刻意設計(避免破壞歷史稽核紀錄的軟引用)。原本單筆 / 批次刪除確認框吃共用 key common.confirm_delete(「確定要刪除嗎?」),未說明「停用 vs 刪除」差異;已改用模組專屬 key,按鈕 / 批次 / toast 全換「停用」語彙並說明「既有稽核引用不受影響」
  3. system_owner 查無使用者的例外已改結構化 error code(2026-07-08 FR-047 ECODE#5):原本 jedi-information-system _resolve_system_ownerraise NotFound("USER_NOT_FOUND")(裸字串、違反 CLAUDE.md),該套件當時無 error_code enum。已新建 jedi_information_system/common/enum/error_code.py,改用 ErrorCode.USER_NOT_FOUND(碼 INFO_SYSTEM_404001),與其他 jedi 套件一致
  4. 「找不到」訊號大致收斂(2026-07-08 FR-047 ECODE#6):① PUT / DELETE 對不存在 uid 已改由套件層 raise NotFound(INFO_SYSTEM_NOT_FOUND)INFO_SYSTEM_404002),經全域 error handler 傳出結構化碼+i18n,route 層硬編 msg="Not found" 已移除;② system_owner 查無使用者 → INFO_SYSTEM_404001(見坑 3);③ common/code/grc_error_code.pyGRC_INFORMATION_SYSTEM_NOT_FOUNDGRC_404020)給 FR-032 F 系統資產 ref_id 校驗用、本頁 CRUD 不回傳此碼。⚠️ 殘留:GET 單筆詳情(information_system_route.py:127)仍回硬編 msg="Not found" 404,尚未結構化
  5. BE 必填驗證比 FE 寬鬆InformationSystemCreateSchema/UpdateSchema 對 C/I/A、系統狀態、系統負責人皆設 allow_none=True,這些欄位「必填」完全是 FE vuelidate rules 撐住;直接呼叫 API 可建立缺少這些欄位的資訊系統列,而清單頁 Tag 會顯示
  6. system_owner 的 DB comment 與實際型別不符:欄位 comment 寫「系統負責人姓名」,但實際存的是 users.id 整數(soft ref),姓名/暱稱是透過 IUserLookup 在讀取時才 enrich 出來的展示欄位(system_owner_name),寫入/查詢時仍以 system_owner 整數欄位為準
  7. system_status 的 DB comment 只列 3 個值、實際 enum 有 5 個compliance.system_status_enum 的 DB comment 僅寫 operational / under-development / disposition,套件 SystemStatus enum 實際多了 under-major-modificationother 兩值且 FE 下拉也有對應選項——本文件以程式碼 enum 為準,DB comment 屬未同步更新的落差
  8. 只有清單端點經過主專案 app service:新增/讀單筆/更新/刪除四個端點的 route 直接注入套件層 InformationSystemService,跳過主專案 InformationSystemAppService——這代表這四個端點沒有機會做「主專案專屬」的邏輯疊加(例如將來若要加租戶檢查,得在套件層或另外包一層,不能只改 app service)
  9. 兩個等價 tenant_id index 的重複已清理(2026-07-08 FR-047 SCHEMA,DEV + STG 已套、POC 待部署):原 idx_information_systems_tenant_id(手建)與 ix_compliance_information_systems_tenant_id(ORM TenantScopedMixinModel canonical)皆單欄 tenant_id 索引、歷史重複;已 DROP 手建的 idx_information_systems_tenant_id、保留 ORM canonical。migration 2026-07-08-drop-dup-index-information-systems-tenant.sql

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。BE 改 service code 後必須重啟(無 hot reload);改 jedi-information-system 套件本身需依 poetry path dependency 流程(見 CLAUDE.md「外部套件異動規範」)
  • 測試帳號:dev 環境系統管理層角色帳號(密碼見 .env / 部署文件)
  • 導航路徑:登入 → 系統設定選單「資訊系統盤點」(information-system-manage,path /information-system/manage
  • 前置資料:無強制前置資料即可開頁(空清單直接顯示 DataTable 空狀態);Dialog 系統負責人下拉需 menuStore.userMenu 有資料(至少一名使用者)
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);本頁相關 feature 檔以 information-system / 資訊系統 搜尋
  • 相關文件:本頁核心邏輯多數在 jedi-information-system 套件(~/Projects/Jedicogy/module/jedi-python-package/jedi-information-system/),改動需先讀套件內對應檔案;OSCAL SSP system-characteristics 對照見 InformationSystemEntity.to_oscal_dict();DB / API 全量見 GAI-SD-02/03;FR-032(device/information-system menu 命名慣例起源)散見 docs/changelog/information_system / FR-032 搜尋