產出日期:2026-05-12 對應 spec:design.md v2、../README.md 對應 plan:implementation-plan.md v1 跨 repo:compliance-manager-be / compliance-manager-fe / compliance-manager-test
從 design.md §二 需求摘要 7 條 + §九 6 條決議萃取,作為測試覆蓋依據。
| AC ID | 條件 | 來源 |
|---|---|---|
| AC-1 | AP 建立時同步寫 compliance.assessment_plan_extensions 列(含 workflow_execution_uid + flow_template_snapshot_uid),1:1 強制 |
design §9.1, plan §B.5 |
| AC-2 | AP 建立完成後 BPMN main workflow 啟動且停在 planning UserTask;AP.status 維持 preparing |
design §9.5, plan §B.5 |
| AC-3 | GET .../stage/info 回傳當前 stage code / name / progress / precondition / user_can_advance |
design §四, plan §B.3 |
| AC-4 | Progress bar 解析 BPMN snapshot 取出 4 stage 序列;已完成標 done、當前標 current、未到標 pending | design §四 |
| AC-5 | POST .../stage/advance 依 stage handler key 呼叫對應 OSCAL API(activate / launch_audit / confirm_audit / close_round) |
design §9.3, plan §B.1 |
| AC-6 | planning 推進 → AP preparing→active;task_execution → active→auditing;audit → auditing→remediation(或 closed if no poam);poam → remediation→closed |
design §二 §9.5, GRC §2.1 |
| AC-7 | 推進前驗證使用者擁有 stage default_main_roles(或 BPMN UserTask 覆寫的 main_roles);不足 → 403 GRC_STAGE_ROLE_FORBIDDEN |
design §9.7, plan §B.3 |
| AC-8 | 推進前跑 precondition.check();fail 且非 force → 412 GRC_STAGE_PRECONDITION_FAILED 含 reason_i18n_key + context |
design §9.2 §9.7 |
| AC-9 | manager 可帶 force=true bypass precondition;非 manager 不可 |
design §9.2 |
| AC-10 | task_execution precondition = TasksThresholdCheck(incomplete > 0 時 fail) | design §9.3 stage map |
| AC-11 | audit precondition = AllControlsVerdictedWithFinding(未判定或 fail/partial 無 finding → 412) | design §9.3, GRC GRC_412003/GRC_412011 |
| AC-12 | poam precondition = AllPoamClosed(仍有 open POA&M → 412) | design §9.3, GRC GRC_412005 |
| AC-13 | AP 未綁 workflow_execution → 404 GRC_AP_NO_WORKFLOW_BINDING |
design §9.7 |
| AC-14 | BPMN 已到 EndEvent / 找不到下一節點 → 400 GRC_STAGE_NO_NEXT_NODE |
design §9.7 |
| AC-15 | Stage handler key 未在 Registry 註冊 → 400 GRC_STAGE_HANDLER_NOT_REGISTERED |
design §9.7 |
| AC-16 | BPMN UserTask 未綁定 stage object → 400 GRC_STAGE_OBJECT_NOT_BOUND |
design §9.7 |
| AC-17 | EndEvent 觸發時不重複改 AP.status(close_round handler 為 single source of truth);移除 raw SQL ExtAssessmentPlanRepoImpl |
design §9.4, plan §B.6 |
| AC-18 | poam on_complete v1 直接走 close_round 結案;loop back 路徑 BPMN 圖可見但 runtime 不走 | design §9.4 |
| AC-19 | Spec 2 使用 hardcode builtin-full-audit 範本;flow_template_snapshot_uid 欄位預留供 Spec 3 user 選範本 |
design §9.6, plan §B.5 |
| AC-20 | FE FlowPhaseBanner 渲染 stage name / progress / hint / 推進按鈕;precondition fail → 按鈕 disable + tooltip;manager 可 ConfirmDialog force | design §四 §9.2 |
| AC-21 | FE 4 個 routed view(settings / overview / audit / poam)掛 Banner;既有 4 個推進按鈕拆除;4 個導航按鈕不動 | design §三, plan §D.1~D.4 |
| AC-22 | task_execution stage Banner 掛在 overview 頁;待辦任務頁不掛 Banner | design §四, plan §D.5 |
| AC-23 | flow_engine 模組不 import grc / oscal;handler 透過 DI container 註冊到 Registry(架構約束) | design §9.3 |
compliance-manager-be/test/)| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_assessment_plan_extension_repo.py |
test_get_by_ap_id_returns_entity |
既有列可查 | AC-1 |
| 同上 | test_get_by_ap_id_not_found_returns_none |
無對應列回 None | AC-1 |
| 同上 | test_get_by_ap_uid_via_join |
透過 AP uid join 查到 ext | AC-1 |
| 同上 | test_add_extension_persists_workflow_uid |
INSERT 後 workflow_execution_uid 寫入 | AC-1 |
| 同上 | test_set_workflow_execution_uid_updates_audit_fields |
updated_user / updated_at 自動更新 | AC-1 |
| 同上 | test_unique_constraint_blocks_duplicate_ap_id |
同 ap_id INSERT 二次拋 IntegrityError | AC-1 |
| 同上 | test_cascade_delete_when_ap_deleted |
AP delete 時 ext 跟著刪 | AC-1 |
test_assessment_plan_extension_mapper.py |
test_entity_to_model_roundtrip |
Mapper 雙向轉換無 lossy | AC-1 |
| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_stage_completion_registry.py |
test_register_handler_then_get_returns_same_instance |
register / get_handler | AC-23 |
| 同上 | test_register_precondition_then_get |
register / get_precondition | AC-23 |
| 同上 | test_get_handler_missing_key_returns_none |
未註冊回 None | AC-15 |
| 同上 | test_register_handler_overwrites_same_key |
同 key 重註冊覆蓋 | AC-23 |
| 同上 | test_precondition_result_default_passed_no_reason |
PreconditionResult dataclass 預設值 | AC-8 |
app/grc/service/oscal_stage_handlers.py)| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_oscal_stage_handlers.py |
test_planning_handler_key_is_oscal_planning_activate |
key 字串對齊 stage_objects.complete_handler_key | AC-5 |
| 同上 | test_planning_handler_execute_calls_activate_project |
mock OscalAuditService.activate_project 被呼叫 + 參數正確 | AC-5, AC-6 |
| 同上 | test_planning_handler_execute_passes_force_flag |
ctx.force=True 傳給 activate_project | AC-9 |
| 同上 | test_task_execution_handler_key_correct |
key=oscal.task_execution.launch_audit |
AC-5 |
| 同上 | test_task_execution_handler_calls_launch_audit |
呼叫 OscalAuditService.launch_audit | AC-5, AC-6 |
| 同上 | test_audit_handler_key_correct |
key=oscal.audit.confirm_audit |
AC-5 |
| 同上 | test_audit_handler_calls_confirm_audit |
呼叫 OscalAuditService.confirm_audit | AC-5, AC-6 |
| 同上 | test_poam_handler_key_correct |
key=oscal.poam.close_round |
AC-5 |
| 同上 | test_poam_handler_calls_close_round |
呼叫 OscalAuditService.close_round | AC-5, AC-6, AC-18 |
| 同上 | test_handler_propagates_oscal_service_exception |
下層 raise → handler 不吞 | AC-5 |
app/grc/service/oscal_stage_preconditions.py)| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_oscal_stage_preconditions.py |
test_tasks_threshold_passed_when_all_complete |
incomplete=0 → passed=True | AC-10 |
| 同上 | test_tasks_threshold_failed_returns_reason_and_context |
incomplete=12, total=50 → passed=False + reason_key + context={"incomplete":12} | AC-10, AC-8 |
| 同上 | test_all_controls_verdicted_passes_when_all_done |
所有控制項 verdicted + fail/partial 有 finding → passed=True | AC-11 |
| 同上 | test_all_controls_verdicted_fails_when_unverdicted_exists |
未判定 → passed=False, reason 對齊 GRC_412003 邏輯 | AC-11 |
| 同上 | test_all_controls_verdicted_fails_when_fail_without_finding |
fail/partial 無 finding → passed=False, reason 對齊 GRC_412011 | AC-11 |
| 同上 | test_all_poam_closed_passes_when_no_open_poam |
open=0 → passed=True | AC-12 |
| 同上 | test_all_poam_closed_fails_with_open_count_in_context |
有 open → passed=False + context={"open_count": N} | AC-12 |
| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_stage_advance_service.py |
test_get_current_stage_info_happy_path |
回傳 current_stage + progress + precondition + user_can_advance | AC-3, AC-4 |
| 同上 | test_get_current_stage_info_progress_marks_done_current_pending |
4 個 stage 狀態正確標記 | AC-4 |
| 同上 | test_get_current_stage_info_user_cannot_advance_when_role_mismatch |
auditor 在 planning → user_can_advance=False | AC-7 |
| 同上 | test_get_current_stage_info_precondition_attached_for_task_execution |
task_execution stage 回傳 precondition 結果 | AC-8 |
| 同上 | test_get_current_stage_info_raises_when_ap_has_no_extension |
AP 無 ext → 404 GRC_AP_NO_WORKFLOW_BINDING |
AC-13 |
| 同上 | test_advance_stage_planning_happy_path_manager |
manager 推 planning → handler.execute 被呼叫 + complete_job 被呼叫 + AP.status → active | AC-5, AC-6 |
| 同上 | test_advance_stage_role_forbidden_auditor_on_planning |
auditor 推 planning → 403 GRC_STAGE_ROLE_FORBIDDEN |
AC-7 |
| 同上 | test_advance_stage_role_forbidden_non_participant |
非專案參與者 → 403 GRC_STAGE_ROLE_FORBIDDEN |
AC-7 |
| 同上 | test_advance_stage_precondition_failed_returns_412 |
task_execution 有未完成 task → 412 GRC_STAGE_PRECONDITION_FAILED + reason |
AC-8 |
| 同上 | test_advance_stage_force_true_by_manager_bypasses_precondition |
manager + force=True → 跳過 check 推進成功 | AC-9 |
| 同上 | test_advance_stage_force_true_by_non_manager_rejected |
auditor 帶 force=True → 仍 403 | AC-9 |
| 同上 | test_advance_stage_calls_handler_before_complete_job |
handler.execute 先於 workflow complete_job(順序保證資料一致) | plan §十一 risk 3 |
| 同上 | test_advance_stage_no_workflow_binding_returns_404 |
AP 未綁 workflow → 404 | AC-13 |
| 同上 | test_advance_stage_handler_key_not_registered_returns_400 |
stage_object.complete_handler_key 在 Registry 找不到 → 400 GRC_STAGE_HANDLER_NOT_REGISTERED |
AC-15 |
| 同上 | test_advance_stage_user_task_not_bound_to_stage_object_returns_400 |
BPMN UserTask 沒 stage code → 400 GRC_STAGE_OBJECT_NOT_BOUND |
AC-16 |
| 同上 | test_advance_stage_bpmn_at_end_event_returns_400 |
已到終點再 advance → 400 GRC_STAGE_NO_NEXT_NODE |
AC-14 |
| 同上 | test_advance_stage_bpmn_uses_user_task_main_role_override |
UserTask 自訂 mainRole=auditor → auditor 可推進;manager 不行 | AC-7 |
| 同上 | test_advance_stage_poam_completion_closes_ap |
poam handler 走 close_round → AP.status=closed | AC-6, AC-18 |
| 同上 | test_advance_stage_audit_no_poam_path_closes_ap |
audit → 無 poam path → AP.status=closed | AC-6, AC-18 |
api/flow_engine/routes/stage_advance_route.py)| Test File | Test Method | Endpoint | 覆蓋 AC |
|---|---|---|---|
test_api_stage_advance_route.py |
test_get_stage_info_200_manager |
GET /project/ /ap//stage/info |
AC-3 |
| 同上 | test_get_stage_info_200_auditor_user_cannot_advance |
GET 同上,response.user_can_advance=False | AC-7 |
| 同上 | test_get_stage_info_404_when_ap_not_found |
AP uid 不存在 | AC-13 |
| 同上 | test_get_stage_info_404_when_ap_no_workflow_binding |
AP 無 ext / workflow_execution_uid 為 NULL | AC-13 |
| 同上 | test_get_stage_info_401_no_jwt |
未帶 token | 安全基本 |
| 同上 | test_post_advance_stage_200_manager_planning_to_active |
POST advance 成功 | AC-5, AC-6 |
| 同上 | test_post_advance_stage_403_auditor_on_planning |
角色擋 | AC-7 |
| 同上 | test_post_advance_stage_403_outsider_no_participant |
非 project 參與者 | AC-7 |
| 同上 | test_post_advance_stage_412_precondition_failed_payload_has_reason_context |
response 含 reason_i18n_key + context | AC-8 |
| 同上 | test_post_advance_stage_200_force_true_manager_bypass |
manager + force=true | AC-9 |
| 同上 | test_post_advance_stage_403_force_true_auditor_rejected |
auditor force=true | AC-9 |
| 同上 | test_post_advance_stage_400_handler_key_not_registered |
400 | AC-15 |
| 同上 | test_post_advance_stage_400_no_next_node |
EndEvent 後再 advance | AC-14 |
| 同上 | test_post_advance_stage_400_user_task_not_bound |
UserTask 無 stage code | AC-16 |
| 同上 | test_post_advance_stage_400_invalid_payload |
force 非 bool / ctx 非 dict | 400 基本 |
start_oscal_project Step 22 修改| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_start_oscal_project_stage_integration.py |
test_start_creates_ap_extension_row |
AP 建立後 compliance.assessment_plan_extensions 有新列 | AC-1 |
| 同上 | test_start_main_workflow_execution_created_and_uid_recorded |
workflow_execution_uid 寫入 ext | AC-1, AC-2 |
| 同上 | test_start_flow_template_snapshot_uid_is_builtin_full_audit |
snapshot uid 對應 builtin-full-audit 範本 | AC-19 |
| 同上 | test_start_workflow_stops_at_planning_user_task |
BPMN 當前節點 = planning UserTask | AC-2 |
| 同上 | test_start_ap_status_remains_preparing |
AP.status 沒被自動推進 | AC-2 |
| 同上 | test_start_workflow_failure_does_not_rollback_ap_creation |
Step 22 try/except:raise → AP 仍建成,log error(同 Step 7 容錯 pattern) | plan §B.5 |
| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_end_event_ap_closure.py |
test_end_event_does_not_modify_ap_status_directly |
mock BPMN engine 觸發 _on_end_event_reached → AP.status 不被改第二次 | AC-17 |
| 同上 | test_ext_assessment_plan_repo_impl_files_removed |
grep 確認 domain/flow_engine/repository/i_ext_assessment_plan_repo.py 與 infra/.../ext_assessment_plan_repo_impl.py 不存在 |
AC-17 |
| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_stage_object_handler_keys_seed.py |
test_planning_handler_key_is_oscal_planning_activate |
查 DB row | AC-5 |
| 同上 | test_task_execution_precondition_key_is_tasks_threshold |
同上 | AC-10 |
| 同上 | test_audit_precondition_key_is_all_controls_verdicted |
同上 | AC-11 |
| 同上 | test_poam_precondition_key_is_all_poam_closed |
同上 | AC-12 |
| Test File | Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|---|
test_stage_registry_di_wiring.py |
test_grc_container_registers_4_handlers_at_startup |
啟動後 Registry 有 4 個 handler key | AC-15, AC-23 |
| 同上 | test_grc_container_registers_3_preconditions_at_startup |
3 個 precondition key | AC-23 |
| 同上 | test_flow_engine_module_does_not_import_grc_or_oscal |
grep domain/flow_engine/ + app/flow_engine/ 不含 from app.grc / from app.oscal import |
AC-23 |
| Error Code | HTTP | 對應測試 |
|---|---|---|
GRC_412021 |
412 | 2.6 test_post_advance_stage_412_precondition_failed_* |
GRC_403050 |
403 | 2.6 test_post_advance_stage_403_* |
GRC_400050 |
400 | 2.6 test_post_advance_stage_400_no_next_node |
GRC_404029 |
404 | 2.6 test_get_stage_info_404_when_ap_no_workflow_binding |
GRC_400051 |
400 | 2.6 test_post_advance_stage_400_handler_key_not_registered |
GRC_400052 |
400 | 2.6 test_post_advance_stage_400_user_task_not_bound |
每個寫入 endpoint 至少三組權限測試:
| Endpoint | manager | auditor | 無 participant |
|---|---|---|---|
POST /stage/advance (planning) |
200 ✓ | 403 ✓ | 403 ✓ |
POST /stage/advance (task_execution) |
200 / 412(依 precondition) ✓ | 403 ✓ | 403 ✓ |
POST /stage/advance (audit) |
視 BPMN UserTask main_role 覆寫;預設 auditor → 角色相反 ✓ | 200 / 412 ✓ | 403 ✓ |
POST /stage/advance (poam) |
200 / 412 ✓ | 403(預設) ✓ | 403 ✓ |
註:stage 預設 main_roles 來自
default_main_roles;audit 預設 main_role=auditor、其他=manager(依 Spec 1 §3.2 定義)。BPMN UserTask 覆寫 case 在test_advance_stage_bpmn_uses_user_task_main_role_override處理。
compliance-manager-fe/,optional)FlowPhaseBanner.vue(src/components/grc/__tests__/)| Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|
renders stage name from i18n key |
mock stageInfo → 顯示中文名 | AC-20 |
renders 4-dot progress bar with current dot highlighted |
progress 解析正確 | AC-4, AC-20 |
shows advance button when user_can_advance=true |
manager / 對應角色 | AC-20 |
hides advance button when user_can_advance=false |
auditor on planning | AC-7, AC-21 |
disables button when precondition.passed=false (non-manager) |
reviewer/auditor 無 force | AC-20 |
shows tooltip with reason_i18n_key and context when precondition fails |
tooltip 文字 | AC-20 |
manager can force-click disabled-looking button → opens ConfirmDialog |
dialog 出現 | AC-9, AC-20 |
confirms force in dialog → emits advance with force=true payload |
payload 正確 | AC-9 |
emits stage-advanced event after successful advance |
parent view 可 refresh | AC-20 |
renders different copy when stage.kind=stateful (task_execution) |
banner 文案差異 | AC-22 |
useStageInfo composable(src/composables/__tests__/)| Test Method | 驗證對象 | 覆蓋 AC |
|---|---|---|
fetchStageInfo populates stageInfo ref |
mock service → ref 更新 | AC-3 |
fetchStageInfo sets error on 404 |
error.value 含 GRC_AP_NO_WORKFLOW_BINDING | AC-13 |
advance with force=false calls service with correct payload |
payload 結構 | AC-5 |
advance with force=true sends force flag |
force 傳出 | AC-9 |
advance refetches stageInfo on success |
call sequence | AC-20 |
loading flag toggles around async ops |
UX 細節 | — |
僅在元件 unit test 不易覆蓋的整合點補;多數 view 改動由 E2E 驗證。
compliance-manager-test/)位置:features/flow-engine/stage-advance.feature
Feature: Spec 2 — 階段抽象整合(Stage Advance)
As a 稽核專案的 PM / 稽核員
I want to 透過 Banner 推進當前階段
So that AP 的 lifecycle 由 BPMN 流程引擎驅動
Background:
Given 系統有一個 manager 帳號 "pm_a" 與 auditor 帳號 "auditor_b"
And 已建立合規框架 "CMMC-2.0-L1" 與專案 "Spec2-E2E-Project"
And 專案套用 default 範本 "builtin-full-audit"
@happy-path
Scenario: 完整 4 stage 推進到結案
Given pm_a 登入並進入專案 "Spec2-E2E-Project" 的 AP 規劃頁(settings)
Then 看到 FlowPhaseBanner 顯示「規劃」階段
And progress 第 1 點 highlighted
When pm_a 點擊 Banner 的「啟動專案」
Then AP.status 變為 "active"
And Banner 階段名變為「執行任務」
When pm_a 進入專案總覽頁
And 所有任務已完成
And pm_a 點擊 Banner 的「啟動稽核」
Then AP.status 變為 "auditing"
When auditor_b 登入並進入稽核頁
And 所有控制項已 verdicted 且 fail 控制項有 finding
And auditor_b 點擊 Banner 的「提交稽核」
Then AP.status 變為 "remediation"
When pm_a 進入缺失改善頁
And 所有 POA&M 已 closed
And pm_a 點擊 Banner 的「完成改善」
Then AP.status 變為 "closed"
And Banner 顯示「已結案」
@precondition-fail
Scenario: task_execution 階段有未完成任務 — 按鈕 disabled + tooltip
Given AP.status=active 且有 12 / 50 任務未完成
When pm_a 進入專案總覽頁
Then Banner「啟動稽核」按鈕為 disabled 狀態
And tooltip 顯示「尚有 12 / 50 任務未完成」
@role-blocking
Scenario: auditor 在 planning 階段看不到推進按鈕
Given AP.status=preparing
When auditor_b 登入並進入專案規劃頁(settings)
Then Banner 顯示「規劃」階段
But 不顯示「啟動專案」推進按鈕
@force-override
Scenario: manager 透過 ConfirmDialog 強制推進
Given AP.status=active 且有 12 / 50 任務未完成
When pm_a 進入總覽頁
And pm_a 點擊 Banner「啟動稽核」(disabled 但 manager 可點)
Then 顯示 ConfirmDialog 列出未完成任務數
When pm_a 確認 ConfirmDialog
Then AP.status 變為 "auditing"
@navigation-buttons-intact
Scenario: 既有 4 個導航按鈕(專案規劃/進入稽核/查看稽核/改善計畫)仍存在
Given AP.status=active
When pm_a 進入專案總覽頁
Then Banner 內不含「啟動稽核」舊按鈕位置(已搬至 Banner)
But 右上角仍可見「導航按鈕:進入稽核」按鈕(沿用既有 v-if 邏輯)
| Step File | Step 摘要 | 對應 Page Object 方法 |
|---|---|---|
steps/flow-engine/stage-advance-steps.js |
Given <role> 登入並進入專案 ".." 的 .. 頁 |
LoginPage::loginAs() + ProjectNavPage::goToSettings() |
| 同上 | Then 看到 FlowPhaseBanner 顯示「<stage>」階段 |
FlowPhaseBannerComponent::getStageName() |
| 同上 | When .. 點擊 Banner 的「<button>」 |
FlowPhaseBannerComponent::clickAdvance() |
| 同上 | Then AP.status 變為 "<status>" |
ApDetailPage::getApStatus() 或 API assertion |
| 同上 | Then Banner「<button>」按鈕為 disabled 狀態 |
FlowPhaseBannerComponent::isAdvanceDisabled() |
| 同上 | And tooltip 顯示「<text>」 |
FlowPhaseBannerComponent::getTooltipText() |
| 同上 | Then 顯示 ConfirmDialog 列出 .. |
ConfirmDialogComponent::isVisible() + getMessage() |
| 同上 | When .. 確認 ConfirmDialog |
ConfirmDialogComponent::confirm() |
| 同上 | Then 不顯示「<button>」推進按鈕 |
FlowPhaseBannerComponent::hasAdvanceButton() |
| 同上 | Then 右上角仍可見「導航按鈕:<text>」按鈕 |
ProjectOverviewPage::getLegacyNavButtons() |
| Page Object | 路徑 | 主要 method |
|---|---|---|
FlowPhaseBannerComponent |
pages/grc/FlowPhaseBannerComponent.js |
getStageName(), getProgressDotStatus(index), clickAdvance(), isAdvanceDisabled(), getTooltipText(), hasAdvanceButton() |
ProjectSettingsPage |
pages/grc/ProjectSettingsPage.js(新增) |
gotoSettings(projectUid), banner: FlowPhaseBannerComponent |
ProjectOverviewPage |
pages/grc/ProjectOverviewPage.js(既有,加 banner ref) |
gotoOverview(), banner, getLegacyNavButtons() |
AuditReviewPage |
pages/grc/AuditReviewPage.js(既有,加 banner ref) |
gotoAuditPage(), banner |
PoamPage |
pages/grc/PoamPage.js(既有,加 banner ref) |
gotoPoamPage(), banner |
ConfirmDialogComponent |
pages/common/ConfirmDialogComponent.js(若無則新增) |
isVisible(), getMessage(), confirm(), cancel() |
ApDetailPage(API helper) |
pages/grc/ApDetailPage.js |
getApStatus(apUid) via REST API(fast assertion,不走 UI) |
Background 透過 BE seeding API(或直接 SQL fixture)建:
builtin-full-audit 範本compliance-manager-test/seeds/spec2-e2e/ 放可重用 SQL fixture| AC ID | BE Unit | BE Integration | FE Component | E2E | 備註 |
|---|---|---|---|---|---|
| AC-1 | ✓ test_assessment_plan_extension_repo.* | ✓ test_start_oscal_project_stage_integration | — | — | DB 層;E2E 不重複 |
| AC-2 | — | ✓ test_start_workflow_stops_at_planning_user_task | — | ✓ Background | |
| AC-3 | ✓ test_get_current_stage_info_happy_path | ✓ test_get_stage_info_200_manager | ✓ useStageInfo.fetchStageInfo | ✓ Happy path | |
| AC-4 | ✓ test_get_current_stage_info_progress_marks_done_current_pending | — | ✓ renders 4-dot progress bar | ✓ progress dot assertion | |
| AC-5 | ✓ test_oscal_stage_handlers.* | ✓ test_post_advance_stage_200_manager_planning_to_active | — | ✓ Happy path | |
| AC-6 | ✓ test_advance_stage_*_happy_path | ✓ test_post_advance_stage_200_* | — | ✓ Happy path | 4 stage 連推 |
| AC-7 | ✓ test_advance_stage_role_forbidden_* | ✓ test_post_advance_stage_403_* | ✓ hides advance button | ✓ @role-blocking | |
| AC-8 | ✓ test_advance_stage_precondition_failed_returns_412 | ✓ test_post_advance_stage_412_* | ✓ shows tooltip with reason | ✓ @precondition-fail | |
| AC-9 | ✓ test_advance_stage_force_true_by_manager_bypasses_precondition | ✓ test_post_advance_stage_200_force_true_manager_bypass | ✓ manager can force-click | ✓ @force-override | |
| AC-10 | ✓ test_tasks_threshold_* | — | — | ✓ @precondition-fail | |
| AC-11 | ✓ test_all_controls_verdicted_* | — | — | ✓ Happy path(implicit) | |
| AC-12 | ✓ test_all_poam_closed_* | — | — | ✓ Happy path(implicit) | |
| AC-13 | ✓ test_get_current_stage_info_raises_when_ap_has_no_extension | ✓ test_get_stage_info_404_when_ap_no_workflow_binding | ✓ useStageInfo.fetchStageInfo error | ⚠️ 無 | 異常路徑,BE 已驗 |
| AC-14 | ✓ test_advance_stage_bpmn_at_end_event_returns_400 | ✓ test_post_advance_stage_400_no_next_node | — | ⚠️ 無 | 異常路徑 |
| AC-15 | ✓ test_get_handler_missing_key_returns_none + test_advance_stage_handler_key_not_registered_returns_400 | ✓ test_post_advance_stage_400_handler_key_not_registered | — | ⚠️ 無 | 異常路徑 |
| AC-16 | ✓ test_advance_stage_user_task_not_bound_to_stage_object_returns_400 | ✓ test_post_advance_stage_400_user_task_not_bound | — | ⚠️ 無 | 異常路徑 |
| AC-17 | ✓ test_end_event_does_not_modify_ap_status_directly + test_ext_assessment_plan_repo_impl_files_removed | — | — | ✓ Happy path(implicit verify AP.status closed once) | |
| AC-18 | ✓ test_advance_stage_poam_completion_closes_ap + test_advance_stage_audit_no_poam_path_closes_ap | — | — | ✓ Happy path | |
| AC-19 | ✓ test_start_flow_template_snapshot_uid_is_builtin_full_audit | — | — | ✓ Background | |
| AC-20 | — | — | ✓ FlowPhaseBanner.* | ✓ Happy path | |
| AC-21 | — | — | ⚠️ 限元件層 | ✓ @navigation-buttons-intact | grep code 確認舊按鈕拆除(人工 / lint) |
| AC-22 | — | — | ✓ stage.kind=stateful copy 變化 | ✓ Happy path(task_execution stage on overview) | MyTasksView 不掛 Banner 由 grep 驗證 |
| AC-23 | ✓ test_flow_engine_module_does_not_import_grc_or_oscal | — | — | ⚠️ 無 | 架構約束,靜態 check |
未覆蓋彙整:
@navigation-buttons-intact scenario 雙重驗證;元件層難覆蓋覆蓋率:23 個 AC,至少有一層 test 覆蓋 = 100%。其中 17 個有 E2E 直接驗、6 個僅靠 BE / 元件層(標 ⚠️)。
1. Pre-flight 假設驗證(implementation-plan.md §〇 5 條 grep)
↓ 全 pass 才開工
2. BE Phase A.1~A.4 → BE pytest 單元測試(2.1 / 2.2 / 2.9)全綠
↓
3. BE Phase B.1~B.7 → BE pytest 整合測試(2.3~2.8 / 2.10~2.12)全綠
↓
4. BE manual smoke(curl + dev DB,4 stage 連推到 closed)
↓
5. FE Phase C → Vitest 元件測試(3.1 / 3.2)全綠
↓
6. FE Phase D → manual smoke(4 個 view 都看到 Banner)
↓
7. E2E(compliance-manager-test)→ Cucumber 5 scenario 全綠
↓
8. Phase F code review(pr-review-toolkit 4-agent parallel)
↓
9. Push + dev DB 完整 rollback / re-migrate / 重啟 BE 重跑 E2E
閘門條件:
明確列出:
compliance.project_extensions.default_flow_template_uid:Spec 3 範圍| 風險 | 影響 | 緩解 / 待釐清 |
|---|---|---|
workflow_executions 表是否支援 main + task 雙層(is_main 欄位) |
高 — 影響 AP build 流程 | Pre-flight \d compliance.workflow_executions 確認;若缺欄位 → 回 plan 修 |
@transaction 嵌套(StageAdvanceService → OscalAuditService.confirm_audit → close_round) |
中 — 可能 commit 衝突 | 既有 confirm_audit→close_round 已嵌套運作;新增 test test_advance_stage_calls_handler_before_complete_job 驗順序 |
BPMN UserTask 自訂 mainRole extension 解析方式 |
中 — 影響角色覆寫測試 | Spec 1 BPMN 編輯器存的 attribute name 待確認(mainRole vs main_roles vs <extensionElements>);test 用 fixture BPMN |
| Precondition reason_i18n_key 與既有 launch_audit error message 對齊度 | 中 — UX 一致性 | 整理 4 個 reason key 對應的既有 GRC error code(412003 / 412005 / 412011);FE i18n file 集中管理 |
| backfill SQL 對既有 dev/stg 環境影響 | 低 | INSERT ... ON CONFLICT DO NOTHING,可重跑;test 環境 fresh DB 不受影響 |
pm_decides_loopback placeholder gateway default 行為 |
中 | Phase B 確認 BPMN engine evaluate 未綁變數的 gateway → 預期走 default flow (→ closed) |
Spec 2 落地後 force=true 觸發既有 launch_audit 內部 force 邏輯 |
低 | OscalAuditService.launch_audit 已支援 force param;handler 直傳即可 |
| Step 22 容錯 (workflow 啟動失敗不 rollback AP) 留下「孤兒 AP」處理 | 中 — UX 問題 | test 涵蓋 test_start_workflow_failure_does_not_rollback_ap_creation;UX 補 retry 入口(follow-up) |
| 層級 | 檔案數 | Test method 數(估) |
|---|---|---|
| BE Repository / Mapper | 2 | 8 |
| BE Domain Registry / Interface | 1 | 5 |
| BE OSCAL Stage Handlers | 1 | 10 |
| BE OSCAL Stage Preconditions | 1 | 7 |
| BE StageAdvanceService | 1 | 19 |
| BE API Route 整合 | 1 | 15 |
| BE start_oscal_project Step 22 | 1 | 6 |
| BE EndEvent / 舊檔移除 | 1 | 2 |
| BE Stage Object Seed | 1 | 4 |
| BE DI Wiring / 架構約束 | 1 | 3 |
| BE 小計 | 11 | 79 |
| FE FlowPhaseBanner 元件 | 1 | 10 |
| FE useStageInfo composable | 1 | 6 |
| FE 小計 | 2 | 16 |
| E2E feature file | 1 | 5 scenario |
| E2E step / page objects | ~7 檔 | — |
| E2E 小計 | ~8 | 5 scenarios |
總計:BE 11 test files / ~79 test methods + FE 2 test files / ~16 test methods + E2E 5 scenarios。
| 版本 | 日期 | 變更 |
|---|---|---|
| v1 | 2026-05-12 | 初版 test-plan(Phase 4 產出,依 design.md v2 §九 + implementation-plan.md v1) |