跳轉到

控制項/AO 現況編輯與程序書(Implementation Status)

功能群:專案管理|上層見 專案規劃頁(本頁=其 Tab0「控制項實作」右面板的現況編輯、程序書關聯、節點參與人員)

事實基準:2026-07-06 從 FE / BE code 掃出;表結構對 db_schema.json、endpoint 對 routes.json、欄位對 serializer + service 逐條核|變更紀錄:2026-07-06 FR-047 從 project-planning.md 拆出

1. 功能描述

本頁是專案規劃頁 Tab0「控制項實作」右面板的三塊核心編輯功能:受評方在左樹選中控制項 / AO 節點後,於右面板填寫現況說明(實作狀態 + 描述 + 備註)、關聯程序書(控制項層 / AO 層),並可對群組 / 控制項節點指派參與人員(影響三層遞進編輯權)。編輯的是專案 living SSP(見 _overview §4);launch-audit 凍結後轉唯讀。左樹導覽 / 完成度篩選與進度卡屬 hub 頁級功能,見 規劃頁 §5/§10

主要使用者:專案 manager、群組 / 控制項管理人、被指派填現況的人員。

角色速覽(完整定義見 _overview §3):

角色 一句話
manager(三層任一) 專案 / 群組 / 控制項 manager — 可編此節點下的現況 / 程序書;專案 manager 另可管節點參與人員
參與者 auditor / viewer — 可讀不可寫

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

# 功能 說明 位置 詳述
1 控制項 / AO 現況編輯 逐項填實作狀態(5 種)+ 現況描述(AO 另有備註),各自獨立儲存(upsert) Control / AO 面板 UC-PP-01
2 程序書上傳與關聯 上傳或從程序書池挑,關聯到控制項層或 AO 層,可移除 Control / AO 面板 UC-PP-05
3 群組 / 控制項層參與人員 對群組 / 控制項節點指派管理人員(影響三層編輯權,見 §3) Group / Control 面板 UC-PP-08

UC(§2)展開三條核心路徑:現況編輯 UC-PP-01、程序書關聯 UC-PP-05、節點參與人員 UC-PP-08。左樹導覽 / 進度卡見 規劃頁

2. Use Case

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

UC-PP-01 填寫控制項 / AO 現況說明

項目 內容
角色 專案 manager(或群組 / 控制項 manager,見 §3 差異註記)
前置條件 已登入;輪次狀態 = planning;為專案參與者
產出 / 後置條件 oscal.ssp_implemented_requirements / ssp_statements 的 props 更新(upsert);SSP 進度卡 % 上升

UC-PP-01 流程:planning 階段才可編輯;儲存走 upsert,BE 檢查 manager 角色

UC-PP-05 上傳程序書並關聯到控制項 / AO

項目 內容
角色 有編輯權者(專案 / 群組 / 控制項 manager,三層遞進 canEdit;BE require_manager
前置條件 輪次 = planning(FE 唯讀後按鈕隱藏);已選中控制項或 AO 節點
產出 / 後置條件 reference-documents 關聯記錄新增於控制項層或 AO 層;document-mappings 反映;移除只解關聯不刪實體檔

UC-PP-05 流程:選控制項/AO→檢編輯權→新上傳(/file/upload REFERENCE_DOCUMENT 拿 file_uid)或從程序書池挑→POST reference-documents 關聯到對應層→document-mappings 反映(之後可 DELETE 移除)

UC-PP-08 群組 / 控制項層參與人員管理

項目 內容
角色 canManageGroupParticipants / canManageControlParticipants
前置條件 已選中群組或控制項節點
產出 / 後置條件 control-group-participant / project-control-participant 增改刪;直接影響該群組 / 控制項的三層編輯權(見 §3)

UC-PP-08 流程:選群組/控制項節點→檢查管理權→新增(POST)/修改(PUT)/移除(DELETE)對應 participant→影響該節點三層 canEdit 編輯權

3. 權限矩陣

操作 FE 判定 BE 強制 BE 檢查位置
讀現況 / 程序書 參與者即可 require_participant app/oscal/service/ssp_control_implementation_service.py:55,80,141
寫現況 / 程序書 三層遞進 canEdit(專案 → 群組 → 控制項 mgr,ProjectPlanningView.vue:663-679 require_manager(否則 GRC_403051 / AP 不可編 GRC_412028 同檔 :63SspPermissionChecker
群組 / 控制項參與人員管理 canManageGroupParticipants / canManageControlParticipantsProjectPlanningView.vue:303-313 assert_project_manager()(角色向下回退,不符 GRC_403002 common/util/participant_guard.py:16-30

⚠️ FE/BE 權限不對齊(見 §12 坑 1):FE 三層遞進允許「群組 / 控制項 manager」編輯,BE require_manager 守門粒度不同——改權限兩端一起看。

4. 狀態機與前置條件

承接輪次 planning gate(見 規劃頁 §4):

條件 效果 出處
apStatus === 'planning' canEditSsp=true:現況 / 程序書可編 ProjectPlanningView.vue:75
apStatus !== 'planning' 唯讀(launch-audit 後凍結) 同上
BE 寫入 phase guard SSP 寫入本身 phase 檢查(見 §12 坑 3)

5. UI 設計

版面骨架(Tab0 右面板依左樹選中節點型別切換,三功能區塊 + 代表性 API):

控制項/AO 現況編輯子頁版面骨架:左樹 + 右面板三區塊(現況說明 / 程序書關聯 / 群組控制項參與人員)+代表性 API

📸 實機截圖(亮色模式):Control 面板見 規劃頁 §5planning-control-panel.png、AO 面板見 planning-ao-tasks.png(上半現況區)。

狀態呈現:控制項 / AO / 各程序書各自獨立儲存,per-項目 spinner(sspSaving Set);樹節點帶完成度徽章;無 socket,儲存後前端 state 更新。

6. API 規格

Envelope:成功 {"status": true, "data": …}、失敗 {"error_code": "…", "msg": "…"}

6.1 總清單

分類 Method + Path 說明 完整規格
現況 GET/PUT /ssp/{sspUid}/control-implementation/{cid} 控制項現況讀取 / 儲存(upsert) §6.2
現況 PUT .../objective/{stmtId} AO 現況儲存(upsert) §6.2
程序書 POST/DELETE .../reference-documents、GET .../document-mappings(控制項與 AO 兩層) 程序書關聯增刪查 §6.3
程序書 POST /file/upload 檔案上傳(upload_type: REFERENCE_DOCUMENT),拿 file_uid 再關聯 GAI-SD-02
參與人員 POST/PUT/DELETE /control-group-participant 群組層人員增改刪 §6.4
參與人員 POST/PUT/DELETE /project-control-participant 控制項層人員增改刪 §6.4

6.2 現況類

FE 右面板表單欄位(選中控制項 → Control 面板;選中 AO → AO 面板,ProjectPlanningView.vuecanEdit 遞進控制 disabled):

欄位 型別 必填 列舉 / 儲存
控制項 / AO 實作狀態 implementation_status Dropdown implemented / partial / planned / alternative / not_applicable(5 值)
控制項 / AO 現況描述 implementation_description Textarea 實作說明
控制項 / AO 備註 remarks Textarea 補充備註

控制項層與各 AO 層各自獨立儲存(各打對應 PUT,per-項目 spinner);儲存走 upsert(紀錄不存在自動建)。

[GET] /ssp/{ssp_uid}/control-implementation/{control_identifier}

Response data

欄位 型別 說明
uid / control_identifier string 實作紀錄識別
implementation_status string|null implemented / partial / planned / alternative / not_applicable
implementation_description / remarks string|null 現況描述 / 備註
responsible_role / control_origination string|null OSCAL 欄位
objectives[] array AO 現況:{uid, statement_identifier, implementation_status, implementation_description, remarks, reference_documents[], created_at, updated_at}
reference_documents[] array 控制項層程序書:{uid, file_id, file_uid, file_name, file_size, description}
created_at / updated_at / created_user / updated_user 審計欄

出處:api/oscal/serializers/ssp/ssp_control_implementation.py:15-36

[PUT] /ssp/{ssp_uid}/control-implementation/{control_identifier}

Request(全部選填,upsert:紀錄不存在自動建立):

欄位 型別 必填 說明
implementation_status string 允許值同上
implementation_description string 現況描述
remarks string 備註

Response:同 GET。出處:同檔 :38-42ControlImplementationUpdateRequestSchema);service require_managerssp_control_implementation_service.py:63)→ 非 manager GRC_403051 / AP 不可編 GRC_412028

[PUT] /ssp/{ssp_uid}/control-implementation/{control_identifier}/objective/{statement_identifier}

Request:同上三欄(implementation_status / implementation_description / remarks,皆選填)+ reference_documents(array,AO 層程序書)。Response data{uid, statement_identifier, implementation_status, implementation_description, remarks, reference_documents[], created_at, updated_at}。出處:api/oscal/serializers/ssp/ssp_control_impl_objective.py:22-27

6.3 程序書類

程序書關聯在控制項層(implemented_requirement)或 AO 層(statement)兩種 context。流程:先 POST /file/uploadupload_type=REFERENCE_DOCUMENT)拿 file_uid,或從程序書池挑既有 → 再 POST …/reference-documents 建立關聯;移除 DELETE 只解關聯不刪實體檔。GET …/document-mappings 查該節點已關聯清單。屬結構相似的關聯 CRUD,逐欄見 GAI-SD-02 / Swagger。

6.4 群組 / 控制項層參與人員類

對控制群組或單一控制項節點指派管理人員,影響該節點三層遞進編輯權(見 §3)。兩組 endpoint 對稱(單一 path,method 分 POST/PUT/DELETE):

Method Path 說明
POST / PUT / DELETE /control-group-participant 群組層人員 新增 / 改角色 / 移除
POST / PUT / DELETE /project-control-participant 控制項層人員 新增 / 改角色 / 移除

[POST / PUT] /control-group-participant ・ /project-control-participant

Request(Create/Update…ParticipantRequest):

欄位 型別 必填 說明
project_uid / group_uid string 否* 定位(群組層);亦接受 project_id / group_id
control_uid string 否* 僅控制項層;亦接受 control_id
user_uid string 被指派使用者
role string manager / reviewer / auditor / viewer

(*uid 與 id 兩組定位擇一帶足即可。)DELETE body 同上但不含 role。出處:serializer api/participant/serializers/control_group_participant.py:13-36 / project_control_participant.py:15-44

權限 / 寫入:皆走 assert_project_manager()common/util/participant_guard.py:16-30,角色向下回退 控制項→群組→專案,失敗 GRC_403002)。寫入表:群組層 compliance.control_group_participants(PK project_id+group_id+user_id);控制項層 compliance.project_control_participants(PK +control_id)。重複新增:群組 GRC_409002 / 控制項 GRC_409003。出處:service app/participant/service/control_group_participant_service.py:86-156 / project_control_participant_service.py:65-143

FEParticipantsPanel.vue 指派 Dialog):user_uid(下拉,必填)+ role(Dropdown 4 值,預設 viewer)+ inherited_from(繼承來源 project/control_group/control/null)。API 常數 CONTROL_GROUP_PARTICIPANT / CONTROL_PARTICIPANTapi.js:114,116)。

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

檔案 角色
src/views/project/ProjectPlanningView.vue 主檢視(現況表單、程序書 dialog、節點參與人員 dialog 都在此)
src/components/grc/ParticipantsPanel.vue 群組 / 控制項參與人員指派 Dialog
SspImportDialog / DocumentLinkDialog / ReferenceDocumentList 程序書關聯相關 dialog
src/service/SspService.js control-implementation / objective / reference-documents API 包裝

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

鏈路 Route App Service 底層
SSP 現況寫入 api/oscal/routes/ssp/ssp_control_implementation_route.pySspControlImplementationDetailRoute / SspObjectiveDetailRoute ssp_control_implementation_service.py::update_control_implementation / update_objectiveupsert:IR / statement 不存在自動建) jedi_oscal_v2 SspRepoImpl → props JSONB
節點參與人員 api/participant/ participant routes control_group_participant_service.py / project_control_participant_service.pyassert_project_manager compliance.control_group_participants / project_control_participants

DDD 提醒:現況寫入是 upsert 且權限在 service 層(require_manager);⚠️ SSP 寫入無 phase guard(§12 坑 3),別複製。

9. DB

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

讀/寫 說明 詳述
oscal.ssp_implemented_requirements 控制項現況(props:狀態 / 描述) §9.3
oscal.ssp_statements AO 現況(props:狀態 / 描述) §9.3
oscal.ssp_reference_documents 程序書關聯(控制項 / AO 兩層 context) §9.3
public.upload_files 程序書檔案本體 GAI-SD-03
compliance.control_group_participants / project_control_participants 群組 / 控制項層參與人員 §9.3
oscal.ssp_control_implementations SSP 現況的 containment 根 GAI-SD-03

9.2 ER 圖

SSP 現況鏈:黃 = 控制項結構(唯讀)、綠 = 本頁寫入;虛線 = context / soft ref

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

oscal.ssp_implemented_requirements — 控制項現況

OSCAL control-implementation.implemented-requirements[]:逐控制項說明系統如何滿足。

欄位 型別 說明
control_implementation_id bigint → oscal.ssp_control_implementations(containment,CASCADE)
control_id varchar(255) OSCAL control token(如 ac-2);跨文件參照存 token 不建 FK
uuid uuid OSCAL 身分
props jsonb 實作狀態與現況描述存這裡implementation-status / implementation-description
remarks text 備註
sort_order int 陣列保序

oscal.ssp_statements — AO 現況

OSCAL implemented-requirement.statements[]。結構同上層:implemented_requirement_id(FK,CASCADE)、statement_id(token,如 ac-2_smt.a;本系統 AO 用 _obj.N)、uuidprops(狀態/描述)、remarkssort_order

oscal.ssp_reference_documents — 程序書關聯

欄位 型別 說明
context_type / context_id varchar(30) / int 兩層掛載:控制項層(implemented_requirement)或 AO 層(statement)
file_id int|null → public.upload_files
description text 檔案說明

compliance.control_group_participants / project_control_participants — 節點參與人員

欄位 型別 說明
project_id / group_id int 定位(控制項層另有 control_id
user_id int 被指派者
role varchar(50) manager / reviewer / auditor / viewer(DB comment)

PK:群組層 (project_id, group_id, user_id);控制項層 (project_id, group_id, control_id, user_id)

10. 頁面邏輯與資料對應

畫面元素 FE state API 欄位
實作狀態下拉 sspStatuses[id] props implementation-status(5 值)
現況描述 sspDescriptions[id] props implementation-description
AO 備註 sspRemarks[aoId] statement remarks
樹完成度徽章 ctrlStatus/ctrlProgress(computed) 由 sspHasDescription 快取推導

儲存流程:各表單獨立儲存(控制項 / AO / 程序書各自 PUT,無整頁 save);儲存後更新本地 state。程序書:先 POST /file/uploadfile_uid → 再 POST 關聯。錯誤對應GRC_403051(非 manager)/ GRC_412028(AP 不可編)/ 參與人員 GRC_403002(非 manager)/ GRC_409002GRC_409003(重複)→ toast。

11. 背景行為與外部依賴

類型 內容
socket (儲存後 state 更新)
節點參與人員影響 群組 / 控制項 participant 直接改該節點三層遞進 canEdit
程序書 檔案本體走 /file/uploadpublic.upload_files;關聯只存 file_id 軟參照
jedi-* jedi-oscal-v2(SSP repo)、jedi-auth(JWT)

12. 邊界情況與已知坑

  1. FE/BE 權限不對齊:FE 用三層遞進(群組/控制項 manager 可編輯),BE SSP 寫入是 require_manager、粒度不同——依 FE 操作可能得到 403,或反之繞過 FE 直接打 API 的權限面比 UI 寬。改權限務必兩端一起改。
  2. SSP 寫入無 phase guardapStatus != planning 的唯讀是 FE 鎖的,BE upsert 照寫。凍結快照後直接打 API 仍會改 living SSP(不會壞快照,但會讓「凍結時的 living 狀態」漂移)。
  3. 無 socket:多人同時編輯互相看不到;後儲存者覆蓋(props 整包 update)。
  4. AO 識別碼 _obj.N、現況真相在 props:實作狀態 / 描述存 props 的 implementation-status / implementation-description,非獨立欄位;改鍵名要同步 mapper。
  5. 節點參與人員即時改編輯權:對群組 / 控制項加 manager 會立刻放寬該節點下的 canEdit,移除則收緊——調權限前留意連鎖影響的節點範圍。

13. 開發與驗證

  • 跑起來:起 BE + FE;登入見 .env / 部署文件測試帳號(需該節點 manager)
  • 導航:規劃頁 Tab0 → 左樹選控制項 / AO → 右面板現況 / 程序書;選群組 / 控制項節點 → 參與人員面板
  • 前置資料:AP=planning 的專案(有 living SSP);備幾個 user 測節點參與人員 + 三層編輯權連動
  • 相關:任務見 AO 任務配置與啟動;批次匯入見 批次維護;程序書池見 程序書池