# Compliance Manager 四階段稽核流程

## 角色

| 角色 | 說明 |
|------|------|
| 管理者 (manager) | 編輯 SSP、指派人員、管理設定、審核、瀏覽 |
| 審核人員 (reviewer) | 任務完成後審查證據，判定通過或退回 |
| 稽核人員 (auditor) | 外部稽核時瀏覽資料 + 寫 finding |
| 觀察者 (viewer) | 僅瀏覽 |

角色由上往下繼承（專案 → 群組 → 控制項），下層可覆寫。
Job 層級只有「被指派 = 執行者」和「is_approver = 問卷核准者」。

---

## 資料架構

### 專案與稽核週期的關係

一個專案 = 一個組織對一套合規框架的持續管理，不會因為稽核結束就關閉。
每次外部稽核來就是新增一個 AP（Assessment Plan），不是開新專案。
每個 AP 對應一輪完整的 Phase 1-4 流程。

```
Project（永久存在）
├─ SSP（持續更新的活文件，跨 Round 共用）
├─ Profile（不變）
│
├─ AP #1 (2025 年度稽核) ← project_assessment_plan_mapping
│   ├─ ap_groups → ap_controls → ap_tasks（從 Profile snapshot）
│   ├─ workflow_executions + job_executions + job_evidences
│   ├─ review_marks（內部審核記錄）
│   ├─ AR #1（外部稽核結果：ar_controls + ar_findings + ar_evidences）
│   │   ├─ ar_data run_no=1（首次稽核）
│   │   ├─ ar_data run_no=2（覆核，verdict 繼承/重置）
│   │   └─ ar_data run_no=N...
│   └─ POA&M #1（矯正追蹤：自動從 not-satisfied findings 產生）
│
├─ AP #2 (2026 年度稽核) ← 第二筆 project_assessment_plan_mapping
│   ├─ ap_groups → ap_controls → ap_tasks（重新 snapshot，反映最新 SSP）
│   ├─ workflow + job + evidence（全新的，跟 AP #1 完全獨立）
│   ├─ AR #2
│   └─ POA&M #2
│
└─ AP #3 (2027) ...
```

### 核心原則

- 每一輪的 AP、job、evidence、AR、POA&M 都是獨立的一整組資料，互不干擾
- 執行人員看到的永遠是當前 Round 的任務，不會跟歷史 Round 混在一起
- 歷史 Round 的資料完整保留，管理者可以切換查看改善軌跡
- GRC API 以 `ap_uid` 為核心查詢參數，決定查看哪一輪的資料

### API 查詢模式

所有 GRC 控制項相關 API 的 URL 結構：

```
/grc/project/<project_uid>/ap/<ap_uid>/control-groups/list
/grc/project/<project_uid>/ap/<ap_uid>/control-group/<group_uid>/controls/list
/grc/project/<project_uid>/ap/<ap_uid>/task-setup/tree
...
```

- `project_uid`：用於權限驗證（確認使用者有權限存取該專案）
- `ap_uid`：用於決定查詢哪一輪稽核的資料（查 AP → groups → controls → tasks → jobs）

前端進入專案後，先呼叫 AP 列表 API 取得所有稽核輪次，再以選定的 `ap_uid` 查詢後續資料。

---

## Phase 1：專案規劃（AP status = preparing）

**操作者：管理者**

### 首次建立專案

1. 管理者建立專案，選定 Profile（如 CMMC L2 baseline）
2. 系統執行 `create_project`（`POST /api/1.0/grc/projects/create`）：
   - 從 Profile snapshot：ap_groups → ap_controls → ap_tasks
   - 建立空白 SSP（或關聯既有 SSP）
   - 建立 Assessment Plan（AP #1），**status = `preparing`**
   - 初始化 SSP control implementations（每個控制項的實作狀態追蹤）
   - 建立 workflow_executions + job_executions（每個 AP task 一個 workflow）
   - 建立 project_assessment_plan_mapping
   - **不建立 AR**（Phase 3 才建立）
3. 管理者編輯 SSP：
   - system_characteristics（系統名稱、邊界、FIPS 199 三軸分類）
   - 每個控制項的實作描述（現況說明）
   - 每個 AO（檢查項目）的具體實作方式 + 關聯程序書
4. 管理者定義每個 AP Task 的 job（上傳文件、填問卷等）
5. 管理者指派執行人員到各 job
6. 管理者確認設定完成，點擊「啟動專案」（`POST /api/1.0/grc/project/<pid>/ap/<ap_uid>/activate`）
   - 系統檢查是否所有 task 都有 job（可 force bypass）
   - **AP status → `active`**
   - 通知 BPMN 第一個任務的指派人員（專案名稱 + 任務數量）
   - 後續任務由 `complete_job` 流程推進時自然通知

> **注意**：`preparing` 狀態下 My Jobs 不會顯示該專案的任務，執行人員看不到也無法操作。

### 開啟新一輪稽核（Round 2+）

管理者在既有專案上點擊「開啟新一輪稽核」→ `launch_new_round`：
- 建立新的 AP（基於最新 SSP 重新 snapshot ap_groups / ap_controls / ap_tasks）
- 新增 project_assessment_plan_mapping
- 為新 AP tasks 產生新的 workflow + job（全部空白）
- AP status = `preparing`（需再次 activate）
- 重新走一次 Phase 1 → 2 → 3 → 4

### API 對應

| 步驟 | API | 狀態 |
|------|-----|------|
| 建立專案 | `POST /api/1.0/grc/projects/create` | ✅ 已有（原 `/oscal-project/start`，Stage 5 重新命名） |
| 啟動專案執行 | `POST /api/1.0/grc/project/<pid>/ap/<ap_uid>/activate` | ✅ Stage 5 新增 |
| 編輯 SSP system_characteristics | `POST/PUT /project-system-info` | ✅ 已有 |
| 編輯 SSP 控制項實作 | `POST/PUT /ssp/<uid>/control-implementation/<id>` | ✅ 已有 |
| 編輯 SSP AO 實作 + 程序書 | `POST/PUT /ssp/<uid>/control-implementation/<id>/objective/<stmt>` | ✅ 已有 |
| 新增 job | `POST /grc/project/<uid>/ap/<ap_uid>/assessment-object/<ao_uid>/jobs` | ✅ 已有 |
| 更新 job（指派人員等） | `PUT /grc/project/<uid>/job/<job_uid>` | ✅ 已有 |
| Task Setup 樹狀總覽 | `GET /grc/project/<uid>/ap/<ap_uid>/task-setup/tree` | ✅ 已有 |
| AP 列表（選擇稽核輪次） | `GET /grc/project/<uid>/assessment-plans/menu` | ✅ 已有 |
| 開啟新一輪稽核 | `POST /grc/project/<uid>/launch-new-round` | ❌ 需新增 |

---

## Phase 2：證據收集 + 內部審查（AP status = active）

**操作者：執行人員 + 審核人員**

1. 執行人員收到通知，登入看到被指派的 job 清單
2. 執行人員完成 job：
   - 上傳文件 → job_evidences
   - 填寫問卷 → task_surveys + question_answers
   - 如果問卷需要核准 → 通知 is_approver 的人核准
3. Job 完成後 workflow 自動流轉（`complete_job`）
4. 當某個 AO 底下所有 job 都完成 → 系統自動通知管理者/審核人員
5. 審核人員在 Control 層級審閱：
   - 瀏覽 SSP 描述 + 所有證據（`control/detail` API）
   - 通過 → 標記「審查通過」（review sign-off）
   - 不通過 → 在 job comment 留言說明原因 → 退回該 job（`revert_job`）→ 執行人員收到退回通知重做
6. 管理者在 dashboard 監控進度
7. 管理者確認就緒，點擊「啟動外部稽核」→ 觸發 `launch_audit`

### API 對應

| 步驟 | API | 狀態 |
|------|-----|------|
| My Jobs 清單 | `POST /grc/jobs/my/list` | ✅ 已有 |
| 上傳證據 | `POST /flow-engine/job-evidences` | ✅ 已有 |
| 填寫問卷 | task_survey WebSocket + REST | ✅ 已有 |
| 完成 job | `POST /flow-engine/task/complete/<id>` | ✅ 已有 |
| 通知審核人員 | `notify_control_reviewers_on_task_complete()` | ✅ 已有 |
| 審閱控制項 + 證據 | `GET /grc/project/<uid>/ap/<ap_uid>/.../control/<cid>/detail` | ✅ 已有 |
| 審查通過（sign-off） | `POST /grc/project/<uid>/ap/<ap_uid>/control/<cid>/review` | ✅ 已有 |
| 退回 job | `POST /flow-engine/task/revert/<id>` | ✅ 已有 |
| Dashboard | `GET /grc/dashboard/summary` | ✅ 已有 |
| 啟動外部稽核 | `POST /grc/project/<uid>/ap/<ap_uid>/launch-audit` | ✅ 已有（Stage 2） |

---

## Phase 3：外部稽核（AP status = auditing）

**操作者：稽核人員**

### launch_audit 系統動作

- 檢查 AP status = `active`
- 檢查未完成 tasks（可 force bypass）
- 建立 assessment_result_datas（run_no=1）+ 從 AP controls 初始化 ar_controls（verdict=null）
- AP status → `auditing`
- 通知稽核人員

### 稽核流程

1. 稽核人員看到快速瀏覽介面，每個控制項顯示：
   - SSP 實作描述（唯讀）
   - 所有 job_evidences（準備期上傳的佐證）
   - 內部審核的意見（job comments）
   - 關聯的設備和部門
2. 稽核人員逐項審查，寫入 ar_controls verdict：
   - pass → 控制項合規
   - fail / partial → 記錄缺失，建立 ar_findings
3. ar_evidences 引用 job_evidences（不複製檔案）
4. **全部控制項審查完畢後**，管理者確認 AR（`confirm_audit`）：
   - 全部 pass/na → 直接結案（跳過 Phase 4），AP status → `closed`
   - 有 fail/partial → 進入矯正（Phase 4），AP status → `remediation`

### 設計決策記錄

**補件機制：** 稽核期間不即時退回補件，稽核員只做標記和記錄。全部審查完畢後，由 `confirm_audit` 批次處理所有不通過的項目。

**退回粒度：** 以 AO（Assessment Object）為單位退回。一個 AO = 一個 workflow，退回時呼叫現有 `revert_job(revert_to=第一個 job)`，整個 workflow 下所有 job 回到初始狀態。不影響同一控制項下其他 AO。

### API 對應

| 功能 | API | 狀態 |
|------|-----|------|
| 啟動外部稽核 | `POST /grc/project/<uid>/ap/<ap_uid>/launch-audit` | ✅ 已有（Stage 2） |
| AR 控制項列表 | `POST /grc/project/<uid>/ap/<ap_uid>/ar/controls/list` | ✅ 已有（Stage 2） |
| AR 控制項詳情 | `GET /grc/project/<uid>/ap/<ap_uid>/ar/control/<ar_control_uid>` | ✅ 已有（Stage 2） |
| 寫入 verdict | `PUT /grc/project/<uid>/ap/<ap_uid>/ar/control/<ar_control_uid>/verdict` | ✅ 已有（Stage 2） |
| 新增 finding | `POST /grc/project/<uid>/ap/<ap_uid>/ar/control/<ar_control_uid>/findings` | ✅ 已有（Stage 2） |
| 更新 finding | `PUT /grc/project/<uid>/ap/<ap_uid>/ar/finding/<finding_uid>` | ✅ 已有（Stage 2） |
| 刪除 finding | `DELETE /grc/project/<uid>/ap/<ap_uid>/ar/finding/<finding_uid>` | ✅ 已有（Stage 2） |
| 確認 AR | `POST /grc/project/<uid>/ap/<ap_uid>/confirm-audit` | ✅ 已有（Stage 2） |

---

## Phase 4：矯正與結案（AP status = remediation → auditing → closed）

**操作者：管理者 + 執行人員 + 審核人員 + 稽核人員**

### confirm_audit 系統動作（從 Phase 3 進入）

- 從每個 not-satisfied finding 自動建立 POA&M（status=open）
- 對每個有缺失的 AO 呼叫 `revert_job`（退回到第一個 job，整個 workflow 重做）
- AP status → `remediation`
- 通知執行人員開始補件

### POA&M 管理

POA&M 是 finding 的**追蹤視圖**：

```
AR finding（缺失事實）
  → POA&M（自動建立，追蹤狀態）
  → revert AO jobs（實際補件走既有 job 機制）

POA&M 記錄：
  - 缺失來源（對應哪個 AR finding / 控制項）
  - 改善計劃（remediation_plan）、到期日（due_date）、負責人（assignee_uid）
  - 狀態追蹤（open → in_progress → closed）
```

### 矯正流程

1. 管理者填寫改善計劃（remediation_plan、due_date、assignee_uid）
2. 執行人員在 My Jobs 看到被退回的任務
3. 執行人員補上證據 / 重新填寫問卷
4. Job 完成後自動流轉 → 通知審核人員
5. 審核人員驗證矯正到位：
   - 通過 → sign-off
   - 不通過 → 退回重做（同 Phase 2 流程）
6. 管理者將 POA&M 標記為 `closed`

### 多輪覆核（Stage 4）

所有 POA&M 都 closed 後，觸發 `close-round`：

1. 系統建立新的 ar_data（run_no = N+1）
2. 複製 ar_controls 到新一輪：
   - 有 POA&M 的控制項 → verdict=null（需重新稽核）
   - 無 POA&M 的控制項 → verdict 繼承（已通過的不重複稽核）
3. AP status → `auditing`（回到外部稽核）
4. 稽核人員只需覆核失敗的控制項（可參考 `previous_findings`）
5. 再次 `confirm_audit`：
   - 全部通過 → AP status → `closed`（結案）
   - 仍有缺失 → AP status → `remediation`（再次矯正，可多輪循環）

### API 對應

| 功能 | API | 狀態 |
|------|-----|------|
| POA&M 列表 | `POST /grc/project/<uid>/ap/<ap_uid>/poams/list` | ✅ 已有（Stage 3） |
| POA&M 詳情 | `GET /grc/project/<uid>/ap/<ap_uid>/poam/<poam_uid>` | ✅ 已有（Stage 3） |
| POA&M 更新 | `PUT /grc/project/<uid>/ap/<ap_uid>/poam/<poam_uid>` | ✅ 已有（Stage 3） |
| 觸發覆核 | `POST /grc/project/<uid>/ap/<ap_uid>/close-round` | ✅ 已有（Stage 3/4） |
| 稽核輪次列表 | `GET /grc/project/<uid>/ap/<ap_uid>/ar/rounds` | ✅ 已有（Stage 4） |

---

## 狀態設計

### project.status — 由 AP 的狀態推導

| 條件 | project.status | 專案列表顯示 |
|------|---------------|-------------|
| 沒有任何 AP | PENDING | 未開始 |
| 有任何 AP 未結案 | IN_PROGRESS | 進行中 |
| 所有 AP 都已結案 | COMPLETED | 已完成 |
| 管理者手動暫停 | SUSPENDED | 已暫停 |
| 管理者手動封存 | ARCHIVED | 已封存 |

### AP 狀態流轉

```
preparing → active → auditing → remediation → closed
                        ↑           │
                        └───────────┘（close-round 多輪循環）
```

| AP status | 對應階段 | 說明 |
|-----------|---------|------|
| `preparing` | Phase 1 | 管理者規劃任務、指派人員。My Jobs 不顯示 |
| `active` | Phase 2 | 執行人員上傳證據 + 內部審核 |
| `auditing` | Phase 3 | 外部稽核員審查 |
| `remediation` | Phase 4 | 矯正缺失（全部通過時跳過此階段） |
| `closed` | 結案 | 本輪稽核完成，唯讀 |

| 狀態轉換 | 觸發 API | 條件 |
|----------|---------|------|
| `preparing` → `active` | `POST .../activate` | manager 角色，可 force bypass 未設置 task 檢查 |
| `active` → `auditing` | `POST .../launch-audit` | auditor 角色，可 force bypass 未完成 task 檢查 |
| `auditing` → `closed` | `POST .../confirm-audit` | 全部 verdict = pass/na |
| `auditing` → `remediation` | `POST .../confirm-audit` | 有 verdict = fail/partial |
| `remediation` → `auditing` | `POST .../close-round` | 全部 POA&M = closed |

---

## 多輪稽核實際情境：CMMC L2 三年認證週期

### 2025 — 首次認證

| 時間 | 事件 | project.status | AP | AP status |
|------|------|---------------|-----|----------|
| 01月 | 建立專案「XX 公司 CMMC L2」 | PENDING | — | — |
| 01-03月 | 管理者編輯 SSP、建立稽核系統清單 | PENDING | — | — |
| 03月 | 建立 AP #1，指派人員、定義任務 | IN_PROGRESS | AP #1 | preparing |
| 03月底 | 管理者點擊「啟動專案」，通知執行人員 | IN_PROGRESS | AP #1 | active |
| 04-05月 | 執行人員上傳證據 + 內部審核 | IN_PROGRESS | AP #1 | active |
| 06月 | 外部稽核員來，啟動外部稽核 | IN_PROGRESS | AP #1 | auditing |
| 06月底 | 稽核結束，AC-3 和 SC-7 不通過，確認 AR | IN_PROGRESS | AP #1 | remediation |
| 07-08月 | 管理者填改善計劃，執行人員補件 | IN_PROGRESS | AP #1 | remediation |
| 08月 | 全部 POA&M closed，觸發覆核（run_no=2） | IN_PROGRESS | AP #1 | auditing |
| 08月底 | 稽核員確認全部通過，結案 | COMPLETED | AP #1 | closed |
| 09-12月 | 日常維運，持續更新 SSP | COMPLETED | — | — |

### 2026 — 年度複評

| 時間 | 事件 | project.status | AP | AP status |
|------|------|---------------|-----|----------|
| 02月 | 開啟新一輪稽核 → 建立 AP #2 | IN_PROGRESS | AP #2 | preparing |
| 02月底 | 啟動專案，通知執行人員 | IN_PROGRESS | AP #2 | active |
| 03-04月 | 收集 2026 年度新證據 | IN_PROGRESS | AP #2 | active |
| 05月 | 外部稽核員來 | IN_PROGRESS | AP #2 | auditing |
| 05月底 | 全部通過，跳過 remediation，直接結案 | COMPLETED | AP #2 | closed |

### 2027 — 年度複評 + 框架更新

| 時間 | 事件 | project.status | AP | AP status |
|------|------|---------------|-----|----------|
| 01月 | CMMC 2.0 框架更新，管理者更新 Profile | COMPLETED | — | — |
| 02月 | 管理者更新 SSP（補上新控制項的實作描述） | COMPLETED | — | — |
| 03月 | 開啟新一輪稽核 → 建立 AP #3 | IN_PROGRESS | AP #3 | preparing |
| 03月底 | 啟動專案 | IN_PROGRESS | AP #3 | active |
| 05月 | 外部稽核 | IN_PROGRESS | AP #3 | auditing |
| 06月 | 新增 1 條控制項不通過 | IN_PROGRESS | AP #3 | remediation |
| 07月 | 矯正完成，覆核通過，結案 | COMPLETED | AP #3 | closed |
| 某天 | 公司不再需要 CMMC 認證 | ARCHIVED | — | — |

---

## DB 表：compliance.poams

| Column | Type | Nullable | 說明 |
|--------|------|----------|------|
| id | SERIAL | PK | |
| uid | VARCHAR(36) | NOT NULL | UUID |
| assessment_plan_id | INTEGER | NOT NULL | soft ref → oscal.assessment_plans.id |
| ar_finding_id | INTEGER | NULL | soft ref → oscal.assessment_result_findings.id |
| control_identifier | VARCHAR(50) | NULL | 對應的控制項代碼 |
| ao_uid | VARCHAR(36) | NULL | 對應的 AO UID |
| status | VARCHAR(30) | NOT NULL | open → in_progress → closed |
| remediation_plan | TEXT | NULL | 改善計劃說明 |
| due_date | DATE | NULL | 到期日 |
| assignee_uid | VARCHAR(36) | NULL | 負責人 UID |
| closed_at | TIMESTAMP | NULL | |
| tenant_id | INTEGER | NOT NULL | |
| org_unit_id | INTEGER | NULL | |
| created_at | TIMESTAMP | NOT NULL | |
| updated_at | TIMESTAMP | NOT NULL | |
| created_user | VARCHAR(50) | NULL | |
| updated_user | VARCHAR(50) | NULL | |

---

## 需調整的現有 API（加入 ap_uid）

| API | 現有 URL | 調整後 |
|-----|---------|--------|
| Control Groups List | `/grc/project/<pid>/control-groups/list` | `/grc/project/<pid>/ap/<ap_uid>/control-groups/list` |
| Control Group Detail | `/grc/project/<pid>/control-group/<gid>` | `/grc/project/<pid>/ap/<ap_uid>/control-group/<gid>` |
| Controls List | `/grc/project/<pid>/control-group/<gid>/controls/list` | `/grc/project/<pid>/ap/<ap_uid>/control-group/<gid>/controls/list` |
| Control Detail | `/grc/project/<pid>/control-group/<gid>/control/<cid>` | `/grc/project/<pid>/ap/<ap_uid>/control-group/<gid>/control/<cid>` |
| Control + AO Detail | `/grc/project/<pid>/control-group/<gid>/control/<cid>/detail` | `/grc/project/<pid>/ap/<ap_uid>/control-group/<gid>/control/<cid>/detail` |
| AO List | `/grc/project/<pid>/.../assessment-objects/list` | 同上加 `ap/<ap_uid>` |
| Job List | `/grc/project/<pid>/.../jobs/list` | 同上加 `ap/<ap_uid>` |
| Job Create | `/grc/project/<pid>/assessment-object/<ao_uid>/jobs` | 同上加 `ap/<ap_uid>` |
| Task Setup Tree | `/grc/project/<pid>/task-setup/tree` | `/grc/project/<pid>/ap/<ap_uid>/task-setup/tree` |
| Review | `/grc/project/<pid>/control/<cid>/review` | `/grc/project/<pid>/ap/<ap_uid>/control/<cid>/review` |
| AO Review | `/grc/project/<pid>/control/<cid>/ao/<ao_uid>/review` | `/grc/project/<pid>/ap/<ap_uid>/control/<cid>/ao/<ao_uid>/review` |
| Dashboard | `/grc/dashboard/summary` | 改為取最新 AP 的統計 |

**不需要改的 API：**
- `GET/PUT/DELETE /grc/project/<uid>` — 專案本身
- `POST /grc/jobs/my/list` — My Jobs（透過 workflow_execution_uid 直查）
- `GET/PUT /grc/project/<uid>/job/<job_uid>` — 單一 job 操作（by job_uid）
- `POST /flow-engine/task/complete/<id>` — 完成 job
- `POST /flow-engine/task/revert/<id>` — 退回 job
- job comment CRUD — by job_execution_uid
- job evidence CRUD — by job_execution_uid

---

## 實作進度

| Stage | 範圍 | 狀態 |
|-------|------|------|
| Stage 1 | 多 AP 基礎建設（URL 加 ap_uid、AP menu API） | ✅ 已完成 |
| Stage 2 | 外部稽核（launch-audit、AR CRUD、confirm-audit） | ✅ 已完成 |
| Stage 3 | POA&M 矯正追蹤（POA&M CRUD、close-round） | ✅ 已完成 |
| Stage 4 | 多輪稽核歷史保留（新 ar_data、verdict 繼承、round 列表） | ✅ 已完成 |
| Stage 5 | 啟動專案執行（preparing → active、通知、API 重新命名） | 🔧 設計完成 |
