本卡屬 FR-143,第 2 棒:主專案新 app service 與 API。依賴第 1 棒的 task 形狀。
給新頁面用的後端:一次讀回這個稽核次所有不符合的評估目標(含為什麼不符合、底下有哪些任務、原指派人、目前設定);PM 存一條評估目標底下全部任務的設定;按送出時檢查每個任務都填齊了,鎖定計畫,把執行人員和到期日寫回任務,再推進流程(內稽退卡走第 5 棒,外稽進待覆核)。
api/project/__init__.py:109-114 既有 POA&M 路由掛法(/audit-round/<round_uid>/poam-items 等)
api/project/routes/audit_round_route.py:380 既有 POA&M route class(485 行,可加)
pkg/jedi-compliance-audit/.../poam_app_service.py 既有 list_items/get_item(讀 AR finding/risk/observation 的 helper 可沿用)
pkg/jedi-compliance-audit/.../audit_round_app_service.py:522 close_round(送出後呼叫)
app/flow_control/service/not_met_job_redo_service.py 退卡(第 5 棒改)
common/code/flow_control_error_code.py:100-109,285-286 GRC_POAM_*;最大 409 序號 041(:619)
public.workflow_execution_control_mapping 評估目標 → 任務流程的對應(control_id、ao_part_id)
app/flow_control/service/poam_objective_app_service.py(每個 public method @transaction),DI 在 di_containers/flow_control_container.py 接線。不往套件 poam_app_service.py 加。/audit-round/<round_uid>/poam/objectives(可帶 ?pass=):以 FR-140「目前稽核次」取 POA&M;回 {locked, stats:{controls, objectives, planned, pending, jobs, last_due}, tree:[族群→控制項→評估目標]},每條評估目標帶 finding(稽核發現)、risk(等級/說明)、recommendation、auditors、methods、evidence(FR-142 observation 採用清單)、jobs:[{job_uid, name, original_assignees:[{uid,name}], stations:[{name,status}], assignees:[uid], due_date, advice}]、planned(三欄齊)。任務對應:workflow_execution_control_mapping 對到該控制項的流程;有 ao_part_id 者只取對到該評估目標的,否則控制項層全部。/audit-round/<round_uid>/poam/objective/<part_id>:body {jobs:[{job_uid, assignee_user_uids:[], due_date, advice}]};對該 item 的 planned remediation(沒有就建一筆 title「改善計畫」)upsert task(一 job_uid 一筆,props 照第 1 棒形狀);同一 job_uid 在別條評估目標也有 task 時一併套用 assignees 與 due_date;回該控制項狀態與 stats。鎖定時 409 GRC_POAM_SUBMITTED_LOCKED。/audit-round/<round_uid>/poam/submit:先用第 1 棒 all_items_planned 守門(不過 412,data.blockers:["<控制項> <標籤>:<任務名> 未填:到期日、改善措施"]);然後 risk.status=remediating、risk.deadline=該 item 最晚到期日、poams.status=submitted;再呼叫既有 close_round(round_uid, …)(內稽:其 handler 會跑退卡,第 5 棒改成第一站重跑;外稽:進 pending_reverify)。寫回任務指派人與各站 due_at 由第 5 棒的 job_restart_service 在退卡時做,本棒不重複寫。…/poam/export?format=oscal 接既有 _export_poam;format=xlsx 由第 4 棒接,本棒先留 route 回 501。GRC_POAM_SUBMITTED_LOCKED=("改善計畫已送出,內容不可修改", "GRC_409042")、GRC_POAM_PLAN_INCOMPLETE=("尚有任務未完成規劃", "GRC_412xxx" 接現有最大)。schema 命名照 docs/claude/api-patterns.md。先查再寫:讀 finding/risk/observation 的 helper 在套件 poam_app_service._item_findings/_item_risks/_item_observations,直接呼叫不重寫;任務站清單用 job_execution_domain_service.get_latest_station_jobs;指派人 task_assignee_domain_service.get_all。審計欄位回 created_user_name 等照 CLAUDE.md。
碎片政策:本棒不強制新 unit test;commit 前跑守衛 pytest test/test_module_boundaries.py 與 RLS 形狀測試。
poams.status=submitted,再 PUT 回 409。