日期:2026-03-25 狀態:Draft
補齊 Phase 1 → Phase 2 的流程閘門:新建專案後 AP 處於 preparing 狀態,PM 設置完成後明確觸發「啟動專案」,AP 轉為 active,通知第一批任務執行人員。
同時重新命名「新建專案」API,消除 start 命名與「啟動執行」的混淆。
| 決策 | 結論 | 理由 |
|---|---|---|
| AP 初始狀態 | preparing(新增) |
區隔「設置中」與「執行中」,PM 未確認前不通知 |
| 啟動前檢查 | 檢查但可 force bypass | 彈性最好,避免遺漏但不阻擋特殊情況 |
| 通知範圍 | 只通知 BPMN 第一個任務的指派人 | 後續任務由流程推進自然通知 |
| 誰可啟動 | manager 角色 | 啟動執行是 PM 的決定 |
| 新建專案命名 | start → create |
消除與「啟動執行」的歧義 |
| 冪等啟動 | 重複呼叫回傳成功但不重發通知 | 避免併發或重複操作產生多次通知 |
preparing(新增)→ active → auditing → remediation → closed
↑ │
└───────────┘
| 狀態 | 說明 | 可執行操作 |
|---|---|---|
preparing |
PM 設置專案(SSP、任務指派、Job 建立) | 編輯 SSP、建 Job、指派人員。My Jobs 不顯示,complete_job 不可執行 |
active |
內部執行 + 內部審核 | 執行任務、上傳 evidence、reviewer sign-off、launch-audit |
auditing |
外部稽核進行中 | 填 verdict/findings、confirm-audit |
remediation |
改善計劃執行中 | POA&M 管理、close-round |
closed |
本輪結案 | 唯讀 |
| 項目 | Before | After |
|---|---|---|
| URL | POST /api/1.0/oscal-project/start |
POST /api/1.0/grc/projects/create |
| Route Class | OscalProjectStartRoute |
ProjectCreateResource |
| Service method | start_oscal_project() |
create_project() |
| Serializer | OscalProjectStartRequest(api/project/serializers/) |
ProjectCreateRequestSchema(api/grc/serializers/project.py) |
| AP 初始 status | active |
preparing |
舊 URL(/api/1.0/oscal-project/start)保留不刪,避免舊前端立即壞掉。舊 route 內部呼叫相同 service method。
Request / Response 格式不變。
POST /api/1.0/grc/project/<project_uid>/ap/<ap_uid>/activate
權限: manager 角色(複用現有 _check_manager_role 或新增 manager 角色檢查,403 使用既有 GRC_NOT_MANAGER 或通用 forbidden error)
Request:
{
"force": false
}前置條件:
preparing,否則 412active(重複呼叫),回傳成功但不重發通知(冪等)檢查邏輯(force=false 時):
assessment_plan_task_workflow_execution_mapping → job_executions)Response(warning 模式,force=false 且有未設置 task): HTTP 200
{
"code": 1,
"data": {
"ap_uid": "xxx",
"status": "preparing",
"warning": true,
"can_activate": true,
"unassigned_tasks": 3,
"total_tasks": 15
}
}Response(成功啟動): HTTP 200
{
"code": 1,
"data": {
"ap_uid": "xxx",
"status": "active",
"notified_count": 5
}
}啟動動作:
active(使用 SELECT ... FOR UPDATE 鎖定 AP row,防止併發問題)activate API 成功將 AP status 從 preparing 改為 active 後。
只通知 BPMN 流程中第一個任務的指派人員:
workflow_executions(透過 assessment_plan_task_workflow_execution_mapping)type=USER 且 status=TODO 的 job_executiontask_assignees 找到該 job 的指派人員(user email)NotificationService.send_mail_notification 發送[專案名稱] 專案已啟動通知發送失敗不影響 activate 結果(AP 狀態已變更為 active)。記錄 error log,不回滾。
不在本設計範圍。後續任務由 complete_job 流程推進時,現有 workflow engine 自然通知下一個任務的人員。
My Jobs 資料來源為 SQL View public.vw_user_job_queue(定義於 scripts/sql/view/vw_user_job_queue.sql),目前透過 assessment_plan_tasks → assessment_plan_groups 間接關聯 AP,但未直接 JOIN assessment_plans 表。
修改 vw_user_job_queue DDL,新增 JOIN oscal.assessment_plans,並在 WHERE 加過濾:
-- 在 FROM 區塊加 JOIN
LEFT JOIN oscal.assessment_plans ap ON g.assessment_plan_id = ap.id
-- 在 WHERE 區塊加過濾
AND (ap.status IS NULL OR ap.status != 'preparing')使用 IS NULL OR 防護 LEFT JOIN 未匹配的情況。
需要新增 migration 腳本 scripts/sql/stage5_migration.sql,包含:
vw_user_job_queue view新增至 common/code/grc_error_code.py:
| Code | 中文 | Error Code |
|---|---|---|
| GRC_AP_NOT_PREPARING | AP 不在設置階段,無法啟動 | GRC_412009 |
權限檢查(manager 角色)複用現有的 403 error code 模式。
AssessmentPlanStatus enumjedi_oscal/common/enum/status_enum.py 需新增 PREPARING:
class AssessmentPlanStatus(StrEnum):
PREPARING = "preparing" # 新增
DRAFT = "draft"
ACTIVE = "active"
AUDITING = "auditing"
REMEDIATION = "remediation"
COMPLETED = "completed"
ARCHIVED = "archived"
CLOSED = "closed"AP entity default 維持 ACTIVE(jedi-oscal 不改 default),由主專案 create_project 傳入 status="preparing" 覆蓋。
修改 enum 後需重新發版 jedi-oscal 並在主專案 pyproject.toml 更新版本號。
| 檔案 | 變更 |
|---|---|
app/project/service/oscal_project_service.py |
method start_oscal_project → create_project;AP 初始 status 改 preparing;新增 activate_project method |
api/grc/routes/project_route.py |
新增 ProjectCreateResource(從 api/project/ 搬移邏輯);新增 ActivateProjectResource |
api/grc/serializers/project.py |
新增 ProjectCreateRequestSchema(對應舊 OscalProjectStartRequest);新增 ActivateProjectRequestSchema / ActivateProjectResponseSchema |
api/grc/__init__.py |
註冊 URL:api.add_resource(ProjectCreateResource, "/projects/create") 和 api.add_resource(ActivateProjectResource, "/project/<project_uid>/ap/<ap_uid>/activate") |
common/code/grc_error_code.py |
+1 error code |
scripts/sql/view/vw_user_job_queue.sql |
加 JOIN assessment_plans + WHERE 過濾 preparing |
scripts/sql/stage5_migration.sql |
新增 migration 腳本(重建 view) |
di_containers/project/project_containers.py |
activate_project 需要 NotificationService,確認 DI wiring |
| 項目 | 說明 |
|---|---|
api/project/ 模組 |
保留不刪,舊 URL 繼續可用 |
OscalProjectService class 名稱 |
不改,只改 method 名稱 |
| 現有 AP 資料 | 已建立的 AP(status=active)不受影響 |
api/project/ 其他 route |
list / detail / update / delete 不搬 |
Stage 2 的 launch_audit 檢查 AP status = active,邏輯不變。因為新建專案 AP 初始為 preparing,PM 必須先 activate 才能 launch_audit,自然形成正確的流程順序。
preparing 狀態下 My Jobs 不顯示(view 過濾),使用者無法看到或執行任務。即使直接呼叫 API,workflow engine 的 job_execution 仍為 TODO 狀態,不會影響 AP 狀態。
所有 Stage 1-4 的 API 都要求 AP status 為 active / auditing / remediation,preparing 狀態下這些 API 都會被現有的 status 檢查擋住。