資訊系統盤點(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/high →
low/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;清單重新整理 |
UC-IS-02 刪除資訊系統(單筆 / 批次,實為軟刪除)
| 項目 | 內容 |
|---|---|
| 角色 | 系統管理層使用者;⚠️ BE 端點對任意登入者皆開放(見 §3) |
| 前置條件 | 已登入;該系統列存在於清單 |
| 產出 / 後置條件 | compliance.information_systems.is_active 設為
False(非實體刪除,DB
列與歷史稽核專案的關聯不受影響);清單重新整理(因固定
is_active=true filter,該列即從清單消失) |
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.py(InformationSystemListResource
/ InformationSystemDetailResource.get /
InformationSystemMenuResource) |
| 新增 / 編輯 | 表單前端必填驗證(名稱/C-I-A/系統狀態/系統負責人) | ⚠️ 僅
@jwt_required(),無角色/租戶檢查;schema
僅做型別驗證,不做業務規則 |
同檔 InformationSystemCreateResource.post /
InformationSystemDetailResource.put、app/information_system/service/information_system_app_service.py |
| 刪除(單筆/批次,軟刪除) | 無擁有者判定(任何使用者對任一列皆顯示刪除鈕,與 device-manage 的「僅建立者可見」不同) | ⚠️ 僅
@jwt_required(),完全無擁有者或角色檢查——deactivate
直接依 uid 軟刪除,任何登入者知道 uid
即可停用任一資訊系統(含他人建立的) |
同檔
InformationSystemDetailResource.delete、app/information_system/service/information_system_app_service.py、jedi-information-system
information_system_domain_service.py:84-85(deactivate
無條件執行) |
⚠️ 已知不一致(維護時注意):本頁刪除連 device-manage 都沒有的「FE 擁有者限定」都沒實作——FE 對任何登入者、任一列都顯示刪除鈕,BE 亦無任何角色或擁有者比對,屬本群目前權限守門最寬鬆的一頁。詳見 §12 坑 1。
4. 狀態機與前置條件
本頁無狀態機、無輪次/階段概念(資訊系統是靜態主檔資源,不屬於稽核輪次生命週期)。僅有欄位層級的前置條件:
| 條件 | 效果 | 出處 |
|---|---|---|
name / security_objective_confidentiality
/ _integrity / _availability /
system_status / system_owner 為空 |
FE 表單驗證擋下,紅字提示,不送出 API | InformationSystemManage.vue:51-60(rules) |
| 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):
狀態呈現: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: true(buildInfoSystemPayload()),其餘欄位本頁
UI 未開放篩選 |
Response data[](每項一個資訊系統,欄位同 §6.3
Response):
| 欄位 | 型別 | 說明 |
|---|---|---|
| id / uid | string | id 為 Method 別名,實際回傳
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-89(InformationSystemResponseSchema);app/information_system/service/information_system_app_service.py:17-24(enrich_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 層仍是選填——BEInformationSystemCreateSchema對這些欄位皆load_default=None, allow_none=True,繞過 FE 直接打 API 可送出缺欄位的資料。
Response:同 §6.2
單筆形狀。出處:api/information_system/serializers/information_system.py:22-37(InformationSystemCreateSchema)、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.py、api/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-172、delete_information_system(jedi-information-system
app/service/information_system_service.py:94-97 →
domain/service/information_system_domain_service.py:84-85 →
infra/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-98(InformationSystemMenuResponseSchema)、jedi-information-system
infra/repository/information_system_repo_impl.py:74-89(get_menu,load_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/manage;meta 無 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/delete 打 API.* |
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_pager
→
InformationSystemDomainService(_enrich_owner)→
InformationSystemRepoImpl(繼承
BaseRepositoryImpl) |
| menu | 同檔 InformationSystemMenuResource |
InformationSystemService.get_information_system_menu(套件層直接處理,不經主專案
app service) |
jedi-information-system
InformationSystemRepoImpl.get_menu(load_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_objs 查
login_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_items(props.asset-type = "information_system"時的系統資產盤點)、ModuleFrame 範本 clone 時的系統資產快照列。
9.2 ER 圖(本頁讀寫範圍 + 跨模組軟引用)
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-systemcommon/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.value 與
pager.value(meta 回填)。使用者
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 最高者反推等級(fipsRank →
rankToSensitivity),watch 觸發後寫回
currentData.security_sensitivity_level |
| 系統負責人下拉 | menuStore.userMenu(optionLabel="nickname",
optionValue="uid") |
Dialog 內選取後 payload 帶
system_owner(僅於使用者明確選取時才送出,見 §6.3) |
| 分頁/排序/搜尋 | pager / multiSortMeta /
filterTable(useTableQuery 提供) |
request payload.{pager, sort, filters} |
儲存流程:onSaveClick 先
v$.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 → 明確
404(return_response(False, {}, msg="Not found"))。本頁無資訊系統專屬
error code——common/code/grc_error_code.py:84 有
GRC_INFORMATION_SYSTEM_NOT_FOUND(GRC_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-auth(UserDomainService 供
IUserLookup 實作、供 nickname
enrich)、jedi-common(BaseRepositoryImpl/transaction/分頁
spec) |
| 系統參數 | 無 feature flag |
| 跨頁 / 跨模組依賴 | GET /information-systems/menu 被專案啟動選單、SSP
系統資產 picker
等頁面引用;InformationSystemEntity.to_oscal_dict() 是 SSP
匯出 system-characteristics
區塊的資料來源;oscal.ssp_inventory_items 的
asset-type=information_system 資產列以 uid soft ref
連結本表;ModuleFrame 範本
clone(module_frame_template_cloner_impl.py)在複製系統資產列時會凍結快照當下的
props;本頁停用(軟刪除)系統不會檢查是否正被任何專案/SSP 引用中 |
12. 邊界情況與已知坑
- 刪除無任何擁有者或角色檢查,且 FE
也未表達擁有者限定語意:與 device-manage「FE 至少想表達擁有者限定、只是
BE 沒守住」不同,本頁 FE 對任一列都顯示刪除鈕(無
isDeletableDevice對等判斷),BEDELETE /information-system/{uid}也完全不比對created_user/created_by——任何已登入使用者知道 uid 即可停用他人建立的資訊系統。修正需額外評估是否要補 tenant/owner 檢查,屬另開 bug/改動 session 的範圍,本頁 spec 僅記錄不修 - 「刪除」實為軟刪除(
is_active=False),非實體刪除——文案已改「停用」語彙(2026-07-09 FR-047 U-3):DB 列會保留,僅從清單(固定is_active=truefilter)消失。對已被稽核專案/SSP 系統資產盤點引用的資訊系統而言,這是刻意設計(避免破壞歷史稽核紀錄的軟引用)。原本單筆 / 批次刪除確認框吃共用 keycommon.confirm_delete(「確定要刪除嗎?」),未說明「停用 vs 刪除」差異;已改用模組專屬 key,按鈕 / 批次 / toast 全換「停用」語彙並說明「既有稽核引用不受影響」 system_owner查無使用者的例外已改結構化 error code(2026-07-08 FR-047 ECODE#5):原本 jedi-information-system_resolve_system_owner寫raise 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 套件一致- 「找不到」訊號大致收斂(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.py的GRC_INFORMATION_SYSTEM_NOT_FOUND(GRC_404020)給 FR-032 F 系統資產ref_id校驗用、本頁 CRUD 不回傳此碼。⚠️ 殘留:GET 單筆詳情(information_system_route.py:127)仍回硬編msg="Not found"404,尚未結構化 - BE 必填驗證比 FE
寬鬆:
InformationSystemCreateSchema/UpdateSchema對 C/I/A、系統狀態、系統負責人皆設allow_none=True,這些欄位「必填」完全是 FEvuelidate rules撐住;直接呼叫 API 可建立缺少這些欄位的資訊系統列,而清單頁 Tag 會顯示— system_owner的 DB comment 與實際型別不符:欄位 comment 寫「系統負責人姓名」,但實際存的是users.id整數(soft ref),姓名/暱稱是透過IUserLookup在讀取時才 enrich 出來的展示欄位(system_owner_name),寫入/查詢時仍以system_owner整數欄位為準system_status的 DB comment 只列 3 個值、實際 enum 有 5 個:compliance.system_status_enum的 DB comment 僅寫operational / under-development / disposition,套件SystemStatusenum 實際多了under-major-modification與other兩值且 FE 下拉也有對應選項——本文件以程式碼 enum 為準,DB comment 屬未同步更新的落差- 只有清單端點經過主專案 app
service:新增/讀單筆/更新/刪除四個端點的 route 直接注入套件層
InformationSystemService,跳過主專案InformationSystemAppService——這代表這四個端點沒有機會做「主專案專屬」的邏輯疊加(例如將來若要加租戶檢查,得在套件層或另外包一層,不能只改 app service) - 兩個等價
tenant_idindex 的重複已清理(2026-07-08 FR-047 SCHEMA,DEV + STG 已套、POC 待部署):原idx_information_systems_tenant_id(手建)與ix_compliance_information_systems_tenant_id(ORMTenantScopedMixinModelcanonical)皆單欄tenant_id索引、歷史重複;已 DROP 手建的idx_information_systems_tenant_id、保留 ORM canonical。migration2026-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有資料(至少一名使用者) - E2E:
compliance-manager-test/repo(Cucumber + Playwright);本頁相關 feature 檔以information-system/資訊系統搜尋 - 相關文件:本頁核心邏輯多數在
jedi-information-system套件(~/Projects/Jedicogy/module/jedi-python-package/jedi-information-system/),改動需先讀套件內對應檔案;OSCAL SSPsystem-characteristics對照見InformationSystemEntity.to_oscal_dict();DB / API 全量見 GAI-SD-02/03;FR-032(device/information-system menu 命名慣例起源)散見docs/changelog/以information_system/FR-032搜尋