# FR-040 稽核計畫填寫(ap-authoring)優化 — 換 session 交接

| 項目 | 值 |
|------|-----|
| 緣由 | AP 稽核計畫填寫頁優化：查核方法可擴充 + 行程(task)鉤稽控制項/受評對象/稽核人員 |
| Branch（三 repo 都同名）| `FR-040-AP-improvement`（BE / FE / jedi monorepo 皆是）|
| 狀態 | **實作完成、單元測試綠、build 過、DEV DB 已遷移；但未經 user 手測驗收、未 push、套件未發版** |
| 接手前必讀 | 本檔 §0 讀序（design.md 全讀是硬 gate）|
| 預估時間 | 驗收 0.5h；若做 Phase 7（說明改結構化 steps）+2~3h |
| 環境關鍵 | BE 要重啟；`jedi_oscal_v2` 走 **symlink**（**勿跑 `poetry install`** 會還原 pin 2.0.0 炸掉）|

---

## 🧭 原始需求 / WHY（先讀，置頂）

稽核員在「稽核計畫填寫」頁(`/project/projects/:id/round/:roundUid/ap-authoring`)規劃一輪稽核。痛點與目標：

1. **查核方法太少且寫死** → 改 `system_menu`(group `AUDIT_METHOD`)驅動，後台可增刪。
2. **行程(task)跟控制項/對象/人員沒連結** → 讓一條行程能多對多鉤稽「**要查哪些控制項 / 受評哪些對象(設備·系統·人員) / 哪些稽核人員執行**」，外加時間與方法。
   - 使用者價值：**受評單位看一條行程就知道「幾點、稽核方誰會來、要查什麼控制項、要準備/檢視哪些設備文件、我方誰要到場」**，據此準備人與物。
3. **受評方 vs 稽核方要分清楚**（這是整個 arc 反覆釐清的核心）：
   - **受評對象 = 受評方**（被查的標的）：系統元件、資產設備、**SSP 內的人員/單位** → 來源 **SSP parties**（`import-ssp` 帶入）。
   - **稽核人員 = 稽核方**（執行的人，含外部稽核員）→ 來源 **AP 自己的 `metadata.parties`**，可在 AP 階段就地新增。

**OSCAL 模型（已用官方範例 `oscal-content/examples/ap/json/ifa_assessment-plan.json` 證實，務必先懂）**：
```
assessment-plan
├── import-ssp                 → 受評方（SSP parties = 受評對象）
├── reviewed-controls          → 受評控制項母體(Tab1)
├── assessment-subjects        → 受評對象母體(Tab2)
├── metadata.parties + roles   → 稽核團隊(assessor)  ← 稽核人員在這！(非 SSP、非專案參與者)
├── local-definitions.activities → 一個「方法 + 一組控制項」的查核程序
│     └ related-controls(控制項) / props.method(方法) / steps(查核步驟)
└── tasks                      → 行程(timing)
      ├ associated-activities[].activity-uuid  → 引用 activity
      ├ subjects[]             → 該行程受評對象
      └ responsible-roles[]    → 該行程稽核人員(role-id=assessor + party-uuids)
```
> 1 task = 1 activity（本期 1:1）。method 放 `activity.props`（OSCAL 標準，非硬塞）。

---

## §0 接手讀序（按序，前 3 個是「先懂需求」硬 gate）

1. 🔒 **本檔「🧭 原始需求」全讀** —— 不懂 受評方/稽核方 區別、OSCAL task→activity 模型，別碰 code。
2. 🔒 `docs/features/FR-040-2606-ap-authoring-improvement/design.md`（**全讀**，尤其 §4 儲存落點、§10 稽核人員=AP parties）
3. 🔒 `docs/analysis/2026-06-20-ap-task-control-subject-linkage.md`（決策軌跡：為何 props/link 表/AP parties，被排除選項）
4. `docs/features/FR-040-2606-ap-authoring-improvement/implementation-plan.md`（Phase 0~6 + Phase 7 提案）
5. 主嫌路徑檔（見 §5）

**冷接自檢 4 問（答不出回去讀）**：
- (a) 受評對象 和 稽核人員 各從哪來、為什麼不同源？
- (b) 一條行程的「控制項」存哪張表哪個欄？為什麼不是存 task？
- (c) method 為什麼放 props 而不是開欄？
- (d) 為什麼 BE 改套件不會炸但「跑 poetry install」會炸？

---

## §1 現況（已完成 + 行為）

整個 FR-040 已 **end-to-end 實作**，分四塊：

### 1.1 查核方法 → system_menu（已上線於 DEV）
- BE seed `AUDIT_METHOD`(6 法：檢視/訪談/測試/文件檢查/電腦設定比對/門禁系統設定比對)。
- FE 下拉抓 `GET /system/menu/AUDIT_METHOD`，label 走 i18n(`method_<value>`)fallback DB key。

### 1.2 行程鉤稽控制項/受評對象/稽核人員（核心）
- **控制項** → `ap_assessment_activities.related_controls`（profile in-scope，Tab1 子集）
- **受評對象** → `ap_task_subjects`（新 link 表；Tab2 子集；下拉/chip 已依類型分組+小標）
- **稽核人員** → AP `metadata.parties`（`oscal.parties` scope=ap.metadata_id），per-task 存 `ap_task_participants`；可「＋新增」就地建 party（固定 person、role=assessor 隱藏、含 email/電話）
- **方法** → `ap_assessment_activities.props`(name=method) / **時間** → `ap_tasks.timing`

### 1.3 行程 CRUD UI（已改）
卡片化：卡頭(序號+標題+類型+時間+刪)+ 卡身標籤式欄位(方法/控制項/受評對象/稽核人員/說明)。說明已改多行 Textarea。

### 1.4 DB（DEV 已套）
- `scripts/sql/2026-06-20-audit-method-menu.sql`（AUDIT_METHOD seed）
- `scripts/sql/2026-06-21-fr040-ap-task-link-tables.sql`（`oscal.ap_task_subjects` / `ap_task_participants`）
- 稽核人員重用既有 `oscal.parties`/`roles`，**零新表**。

---

## §2 前次教訓（本 arc 已踩，別重蹈）

- **稽核人員資料源換過兩次**：專案參與者(錯)→ SSP parties(錯,那是受評方)→ **AP metadata.parties(正解)**。別再退回專案參與者/SSP parties。
- **method/受評對象/稽核人員不要存自由文字**：一律建真 entity 拿 uuid 再引用（OSCAL party uuid / control-id）。
- **role/party_type 過度暴露**：稽核人員固定 person + role=assessor（UI 隱藏），別加回下拉除非 user 要多角色。
- **過渡資料**：commit `1e8c231`(稽核人員=SSP parties)存過的行程，participants 是 SSP party uuid，在現行 AP-parties 下拉解析不到 → dev 重存即可。

---

## §3 待辦 / 下一棒可能做的（非 bug，是 follow-up）

1. **驗收**（最優先）：見 §6 手測 checklist。
2. **Phase 7（設計完成 design §11 + plan Phase 7，待 user 拍板實作）**：「說明」改**結構化每方法查核指引**（OSCAL `activity.steps`，step↔method 用 props 綁定，step.description=該方法看什麼怎麼看）。目前是多行 Textarea(commit `0103997`)當過渡。欄位 `ap_assessment_activities.steps` 已存在、零新表。BE/FE 改動步驟見 design §11.6 / plan Phase 7。**直接照 design §11 開工即可**。
3. **OSCAL 匯出**（未做）：mapper 把 `ap_assessment_activities`/`ap_tasks`/link 表/AP parties → OSCAL JSON(local-definitions.activities / task.subjects / responsible-roles / metadata.parties)。本期未做匯出。
4. **收尾未做**（等 user 驗收後下令）：changelog、Notion 任務、push、套件發版。
5. design §9 DEFERRED：AO/statement 層精準、行程↔活動 1:N。

---

## §4 開工順位

1. 跑 §6 pre-flight（branch/working tree/symlink/pytest/build）。
2. 跑 §6 手測 checklist 驗收現況（這是 user 要的下一步）。
3. 若做 Phase 7：先讀 design §10 + `ap_assessment_activities` model(`steps` 欄)，再 FE 動態 per-method 指引欄 + BE `set_tasks` 寫 steps。
4. 改完：BE 重啟提醒 user、給手測、**等 user 下令才收尾/push**。

---

## §5 該讀 / 會改的檔案

**BE**（`~/Projects/Billows/Audit-Manager/compliance-manager-be/`）
- `app/grc/service/assessment_plan_app_service.py` — 核心：`set_tasks`(寫 activity+task+link)/`_ap_detail`(還原)/`list_ap_parties`/`add_ap_party`
- `api/project/routes/audit_round_route.py` — `ApTasksRoute` / `ApPartiesRoute`
- `api/project/serializers/audit_round.py` — `_TaskItem` / `ApPartyAddRequest`
- `test/test_fr040_ap_task_linkage.py` — 9 測試（orchestration + AP party）

**套件**（`~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal-v2/`）
- `jedi_oscal_v2/infra/model/ap/oscal_ap_task_subjects.py` / `oscal_ap_task_participants.py`（+ entity/mapper/repo 同名）
- 稽核人員重用 `oscal_party.py` / `party_repo_impl.py`（metadata-scoped）

**FE**（`~/Projects/Billows/Audit-Manager/compliance-manager-fe/`）
- `src/views/project/RoundApAuthoringView.vue` — Tab3 行程 UI + options + 新增 party dialog
- `src/config/locales/i18n/{zh-tw,en}/ap-authoring.json`

---

## §6 Pre-flight + 手測 checklist（可複製貼）

```bash
# branch / 乾淨度（三 repo 應都 FR-040-AP-improvement、clean）
for d in ~/Projects/Billows/Audit-Manager/compliance-manager-be ~/Projects/Billows/Audit-Manager/compliance-manager-fe ~/Projects/Jedicogy/module/jedi-python-package; do echo "== $d"; git -C "$d" branch --show-current; git -C "$d" status --short; done

# ⚠️ 套件 symlink 必須在（指向源碼，勿 poetry install）
ls -l ~/Projects/Billows/Audit-Manager/compliance-manager-be/.venv/lib/python3.11/site-packages/jedi_oscal_v2

# BE 單元測試（應 9 passed）
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be && .venv/bin/python -m pytest test/test_fr040_ap_task_linkage.py -q

# FE build（應 exit 0）
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe && npx vite build --mode development && rm -rf dist
```

**手測（user 自己起服務；改 BE 後請 user 重啟）**：
1. 進稽核計畫填寫頁 Tab「行程與方法」→ 新增行程 → 5 欄(方法/控制項/受評對象/稽核人員/說明)。
2. 控制項 options = Tab1 勾選的；受評對象 = Tab2 的(下拉分組、chip 帶類型小標)；稽核人員 = AP parties，點「＋新增稽核人員」可就地建(姓名/email/電話)。
3. 存檔 → 重整 → 應原樣還原。
4. 切英文 label 正常；說明可多行。

---

## §7 環境 / 部署狀態

- **DEV DB 已套** 兩支 migration + AUDIT_METHOD seed；**STG/POC/PROD 未套**。
- **`jedi_oscal_v2` = symlink**（site-packages → 源碼），BE 重啟即用新碼；原 pin 備份 `jedi_oscal_v2.pinbak`。**勿 `poetry install`**（會還原 pin 2.0.0、缺新表 model → BE 炸）。
- **未 push**（三 repo）；**套件未 bump version / 未發 Nexus**（部署前流程：套件 bump+發 Nexus → BE pin 新版 → poetry update → 各環境跑 migration）。

---

## §8 行為規範提醒

- 不切 branch（三 repo 已在 FR-040-AP-improvement）；不自動 push（等 user）。
- 改 BE service → 提醒 user 重啟。
- 改套件走 symlink/path dep，發版等 user 明示。
- 跨 repo 各自 commit、顯式 git add、禁 `-am`。
- changelog/Notion/SUMMARY 等收尾 → **等 user 驗收 + 下令才做**。
- 不晶晶體；plan 假設先 verify。

---

## §9 本 arc commits（branch FR-040-AP-improvement，均未 push）

**BE**（FR-040 相關，新→舊）：`e1131c31`(person+email/phone) `27ed00cb`(Phase6 AP parties) `12189f38`(B design) `6286db0e`(源更正) `f09d71a2`(DONE-verify handoff) `7fb60037`(set_tasks 鉤稽) `5d05a5da`(design/plan/analysis) `8de251b6`(AUDIT_METHOD seed) `eae77461`(vw_user_job_queue 控制群組,順手修)
> 註：同 branch 另有 `b1211299`/`e0041bfd`/`cf4e68f7`/`3814c57c`/`e8a2666a` 是 FR-038/FR-039 的早期修正，非 FR-040。

**FE**：`0103997`(說明多行) `0e780e6`(chip 類型小標+去角色) `9861654`(受評對象分組) `e1ca5aa`(party person+email/phone) `ea42fa4`(隱藏 role) `e614b56`(Phase6 AP parties) `1e8c231`(過渡:SSP parties,已被取代) `1996432`(名稱修+改名稽核人員) `d043fcf`(卡片化 UI) `d955f7d`(鉤稽) `f1b2052`(method system_menu) `27c66a1`/`6282fb0`/`ce3b810`(早期 dashboard/輪次 fix,非 FR-040)

**套件**：`8684658`(ap_task_subjects/participants link 表)

---

## §10 不在本期 scope（別順手做）

- OSCAL 匯出/匯入 mapper（Phase 7 之後再議）
- AO/statement 層控制項精準
- 行程↔活動 1:N
- 稽核人員多角色下拉（現固定 assessor）
- 受評對象就地新增（目前只能從 Tab2 選；只有稽核人員支援就地新增）

---

## §11 給 fresh session 的超短 prompt

```
接手 FR-040「稽核計畫填寫優化」。請先讀
docs/features/FR-040-2606-ap-authoring-improvement/handoff/2026-06-21-FR040-ap-authoring-handoff.md
全文（尤其「🧭 原始需求」+ §0 讀序 + design.md 全讀），答得出 §0 冷接自檢 4 問再動工。
現況：已實作完成、未驗收、未 push、套件走 symlink（勿 poetry install）。
先跑 §6 pre-flight + 手測 checklist 驗收；要做 Phase 7（說明改結構化 steps）等我確認。
不切 branch、不自動 push、收尾等我下令。
```
