手冊首頁 / 專案與任務 / 控制項/AO 現況編輯與程序書

控制項/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 start gate 輪次 = planning? start->gate ro 表單 disabled+唯讀 banner (launch-audit 後凍結) gate->ro pick 左樹點選 控制項 或 AO gate->pick edit 右面板編輯: 實作狀態下拉+現況描述 (AO 另有備註) pick->edit doc (可選)上傳/關聯程序書 POST /file/upload → 關聯 API edit->doc save 點「儲存」 PUT control-implementation/objective edit->save doc->save perm BE 檢查: 使用者是專案 manager? save->perm deny 403 GRC_403031 perm->deny ok props 更新(upsert) 樹徽章+SSP 進度卡更新 perm->ok
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 start pick 選控制項或 AO 節點 (決定關聯層級:控制項層 / AO 層) start->pick edit 有編輯權? (FE canEdit 三層遞進;BE require_manager) pick->edit deny 無編輯權:FE 隱藏按鈕/BE 擋 edit->deny src 新上傳 or 從程序書池挑? edit->src upload 上傳檔案 POST /file/upload (upload_type=REFERENCE_DOCUMENT)→ file_uid src->upload 新上傳 pool 從程序書池挑已上傳檔 (取既有 file_uid) src->pool 池挑選 assoc POST .../reference-documents 關聯到控制項層 / AO 層 upload->assoc pool->assoc mapping GET .../document-mappings 面板反映該層關聯清單 assoc->mapping remove DELETE .../reference-documents 移除關聯(不刪實體檔) mapping->remove 之後可移除
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 start node0 選群組節點 or 控制項節點 start->node0 gate canManageGroupParticipants / canManageControlParticipants? node0->gate deny 無管理權:面板不提供指派操作 gate->deny act 新增 / 修改 / 移除? gate->act add POST /control-group-participant 或 /project-control-participant act->add 新增 upd PUT(改角色/範圍) act->upd 修改 rm DELETE(移除人員) act->rm 移除 eff 影響該群組/控制項的三層編輯權 (canEdit 遞進,見 §3) add->eff upd->eff rm->eff
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):

專案規劃頁 Tab[0] 控制項實作 — 現況編輯與程序書子頁(右面板依左樹選中節點切換) 左樹導覽 群組 → 控制項 → AO 搜尋/完成度篩選 ▸ AC 存取控制(群組) ▸ AC.L1-3.1.1(控制項) • _obj.1(AO) • _obj.2(AO) (樹導覽/完成度 hub §5/§10) ① 控制項/AO 現況說明(Control 面板 / AO 面板,各自獨立儲存) 實作狀態 Dropdown(implemented/partial/planned/alternative/not_applicable) 現況描述 Textarea ・ 備註 Textarea(AO 層另存 remarks) GET/PUT /ssp/{uid}/control-implementation/{cid} PUT …/objective/{stmt}(AO 層,upsert) → 本頁 §6.2/UC-01 ② 程序書關聯(控制項層 / AO 層兩層 context) 新上傳(/file/upload 拿 file_uid)或從程序書池挑 → 關聯到選中層 POST/DELETE …/reference-documents(控制項/AO 兩層) GET …/document-mappings → 本頁 §6.3/UC-05;程序書池見證據管理群 ③ 群組/控制項層參與人員(選群組或控制項節點時出現) 指派 Dialog:使用者 + 角色(manager/reviewer/auditor/viewer) → 直接影響該節點三層遞進編輯權 canEdit(見 §3) POST/PUT/DELETE /control-group-participant POST/PUT/DELETE /project-control-participant → 本頁 §6.4/UC-08 綠/藍/粉=本頁三功能區塊(標代表性 API)|灰=左樹導覽(hub 描述)|虛線框=依選中節點型別才出現的面板
控制項/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 圖

planning_er_ssp cluster_struct 控制項結構(唯讀) cluster_write SSP 現況(本頁寫入) ssp oscal.system_security_plans (living SSP) pimports oscal.profile_imports ssp->pimports import_profile_id cimpl oscal.ssp_control_implementations ssp->cimpl 1:1 cctrl oscal.catalog_controls 控制項 pimports->cctrl source_catalog_id cpart oscal.catalog_control_parts AO(assessment-objective) cctrl->cpart 1:N ir oscal.ssp_implemented_requirements 控制項現況(props:狀態/描述) cimpl->ir 1:N(control_id 對 token) stmt oscal.ssp_statements AO 現況(props:狀態/描述) ir->stmt 1:N(statement_id=_obj.N) refdoc oscal.ssp_reference_documents 程序書關聯 ir->refdoc context=control stmt->refdoc context=objective files public.upload_files refdoc->files file_id
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 任務配置與啟動;批次匯入見 批次維護;程序書池見 程序書池