# Spec 4 接手指南 v1（M7 起手）

> **建立日期**：2026-05-14
> **撰寫**：raymond（透過 Claude Opus 4.7 session 1）
> **接手對象**：新 session 的開發者 / Claude
> **執行策略**：subagent-driven-development（每 milestone 1 implementer + 1 spec reviewer + 1 code reviewer）

---

## 一、本案脈絡（5 行掃完）

- **目標**：spec 4 在既有 stage_object / BPMN flow template 機制上新增 `review` 階段 + 範本方向性驗證 + 全 stage 共用留言
- **進度**：M0–M6 已完成（BE validator 路徑全通）；M7–M11 待做
- **branch**：`feature/project-flow-engine-review`（HEAD = `1befd7f` 之後）
- **設計文件**：`docs/features/FR-026-2605-project-flow-engine-integrate/04-review-stage-and-flow-validation/design.md` v1.2
- **實作計畫**：同目錄 `implementation-plan.md` v1.1

---

## 二、已完成 milestones（M0–M6）

| M | 內容 | Commit | 交付 |
|---|---|---|---|
| M0 | Pre-flight grep / psql verify | (inline) | DB schema / wiring 假設驗證 |
| M1 | `compliance.stage_objects` 加 4 欄 + seed review | `5613b9b` | DB 5 列含 review (sort=25) |
| M2 | ORM model / entity / mapper 對 4 欄 | `e5a8901` | Python 層讀寫 4 欄 OK |
| M3 | `BpmnTopologyValidator` 純函式 + 20 條 unit test | `2769ba7` + `efd41ae` | pytest 20 pass / 1 expected-defer |
| M4 | builtin BPMN patch + 新 builtin-full-audit-with-review | `fe0bd19` | DB 7 列 flow_templates；M3 test 22 pass |
| M5 | FlowTemplateAppService 整合 validator + 3 error code | `7d79e83` + `c78321a` | create/update 加 topology 守門員；§16 reconciliation 紀錄 err.context limitation |
| M6 | `POST /flow-engine/flow-templates/validate` endpoint | `d6d45ef` + `1befd7f` | 純驗證 endpoint live；happy + fail path smoke 通過 |

### 重要決策軌跡（M0–M6 期間累積）

1. **M3 reverse edge 識別**：extension property `reverse=true` 為 primary，嚴格 anchored regex `^\s*\$\{\s*[A-Za-z_]\w*\s*==\s*['\"]reject['\"]\s*\}\s*$` 為 fallback。fullmatch + 大小寫敏感。
2. **M3 reachability**：forward-only BFS（reverse edge 不計入路徑），seed 從所有 StartEvent。
3. **M5 `find_all` 改為 `list_active()`**：app service 不直接構造 query entity，走 domain service 既有 `list_active()` 入口（DDD-clean）。
4. **M5 `err.context` 是 dead-data**：`jedi_common.handler` 目前不序列化 exception attribute。violations 細節透過 `/validate` endpoint（M6）surfacing；create/update 400 只當守門員。details 在 design.md §16.1 reconciliation 已紀錄。
5. **M6 routing order**：`/validate` 靜態路徑明示排在 `/<string:uid>` 動態之前，避免 URL collision。
6. **M6 schema/route 命名**：`FlowTemplateValidate*Schema` / `FlowTemplateValidateRoute` — 對齊 sibling verb-based naming（M6 review 後 rename 過）。
7. **M4 自訂範本 backfill scan = 0**：dev DB 上沒有 user duplicate 自 `builtin-full-audit` 的範本含未 patch `Flow_poam_audit`，所以 backfill update 0 列；user 環境若有可能要重跑 dry-run。

### 環境狀態

- BE 跑在 **port 8002**（不是 8000，env config 決定）
- DB: `192.168.50.188:25432/guidant_ai_dev`，**cmmgr** 密碼 `jedi@123!`（migration 一律 cmmgr，cm_app 被 RLS 擋）
- BE 啟動方式（避開 `.env` 直接 source 卡 escape）：
  ```bash
  lsof -ti :8000 2>/dev/null | xargs kill -9 2>/dev/null
  lsof -ti :8002 2>/dev/null | xargs kill -9 2>/dev/null
  sleep 1
  nohup python3 -c "from dotenv import load_dotenv; load_dotenv('.env'); import runpy; runpy.run_path('main_socketio.py', run_name='__main__')" > /tmp/be.log 2>&1 &
  sleep 10
  lsof -nP -iTCP -sTCP:LISTEN 2>/dev/null | grep python
  ```
- Login API（注意 dev schema）：`POST /api/1.0/login` body = `{"username": "blsadmin", "password": "Billows@123!", "cf_turnstile_token": "XXXX.DUMMY.TOKEN.XXXX"}`，回 `data.access_token`（不是 `token`）
- 測試帳號：`blsadmin / Billows@123!`（manual）；`blsit / Billows@123!`（pytest）

---

## 三、待做 milestones（M7–M11）

### M7 — `StageAdvanceRequestSchema` + `ReviewDecisionHandler`

**目標**：schema 加 decision/comment 欄位 + 寫新 handler 註冊到 stage_registry。

**Files**:
- Modify: `api/flow_engine/serializers/stage_advance.py` — 加 `decision` (Str, OneOf approve/reject) + `comment` (Str) + `@validates_schema` 強制 reject 必填 comment
- Modify: `app/grc/service/oscal_stage_handlers.py` — 加 `ReviewDecisionHandler` class（key=`review_decision`，純 dispatch decision 不動 AP.status）
- Modify: `di_containers/grc/grc_containers.py` — import + Factory + `register_stage_hooks_to_registry` 加 `registry.register_handler(grc_container.review_decision_handler())`

詳細範本程式碼見 `implementation-plan.md` §M7.1–M7.4。

**Commit msg**: `feat(spec4-M7): StageAdvance schema + ReviewDecisionHandler`

### M8 — `StageAdvanceService` 接 decision/comment + JobComment wiring

**目標**：service 接 decision/comment 參數；推進 BPMN 後寫 GRC JobComment；review stage 走特殊 condition_param。

**Files**:
- Modify: `app/flow_engine/service/stage_advance_service.py`：
  - `advance_stage` signature 加 `decision: Optional[str] = None, comment: Optional[str] = None`
  - 非 review stage 送 decision → log warning + pop ctx["decision"]（design §6.1）
  - `_build_condition_param` 加 review 分支 `{"decision": "approve"|"reject"}`
  - 推進 BPMN 後寫 JobComment：**先查 `JobExecution` by `template_job_id` 拿 `uid` (UUID)**，再傳給 `JobCommentService.add_comment(job_uid=str(job_exec.uid), ...)`
  - `__init__` 加 `job_comment_service` dependency
- Modify: `api/flow_engine/routes/stage_advance_route.py` — 在 `service.advance_stage(...)` call 加 `decision=body.get("decision"), comment=body.get("comment")` kwargs；**不動既有 `ctx` build 邏輯**（保留 `user_ctx.nickname` 取得方式）
- Modify: `di_containers/grc/grc_containers.py` — `stage_advance_service` Factory 加 `job_comment_service=job_comment_service`

**Critical fix 細節**：原 design v1 寫 `job_uid=curr_job_template.id`（BPMN element id）會 silent fail；M5 spec reviewer 抓到並修進 design v1.1 §8.2。正解：

```python
job_exec = self._job_execution_domain_service.get_job_execution(
    JobExecutionQueryEntity(
        workflow_execution_id=wf_ctx["workflow_execution_id"],
        template_job_id=curr_job_template.id,
    )
)
if job_exec is None:
    logger.warning("JobExecution not found ... skip JobComment")
else:
    self._job_comment_service.add_comment(
        job_uid=str(job_exec.uid),  # ← UUID
        content=comment.strip(),
        user_id=user_id,
        author_nickname=ctx.get("user_nickname") or curr_user,
    )
```

詳細 plan: `implementation-plan.md` §M8.1–M8.6。

**Commit msg**: `feat(spec4-M8): StageAdvanceService 接 decision/comment + JobComment 整合`

### M9 — BE integration test

**目標**：寫 4–6 條 integration test 覆蓋 decision/comment + validate endpoint。

**Files**:
- Create: `tests/test_stage_advance_v4.py`
- Create: `tests/fixtures/bpmn/invalid_start_to_poam.bpmn`（inline XML，內容見 plan）

**注意**：implementation-plan.md §M9 提示 `seed_review_ap` / `seed_planning_ap` fixture 不易在 dev DB 上重現；若卡關可退而用 **service-level unit test with mock** — 對齊 Spec 3 §16.1 條 3 的 deferral pattern。重點不是 100% integration coverage，是核心路徑被測過。

**Commit msg**: `test(spec4-M9): StageAdvance decision/comment integration tests`

### M10 — FE Banner + BPMN editor inline warning（**跨 repo**）

**目標**：FE 接 review approve/reject 雙按鈕 + ConfirmDialog comment textarea + editor 拖 sequenceFlow 時呼叫 `/validate` debounce。

**Repo**：`~/Projects/Billows/Audit-Manager/compliance-manager-fe`

**Files**:
- Modify: `src/locales/zh-TW.json` + `src/locales/en.json` — 加 keys（見 design §10.4）
- Modify: `src/components/grc/FlowPhaseBanner.vue`（**沒有 banner/ 子層**）— 加 review 雙按鈕 + Dialog comment textarea（**同一 Dialog 共用所有 stage**，靠 `rejectMode` flag 切換 placeholder 與 disabled 條件）
- Modify: `src/service/FlowPhaseService.js`（或對應 stage advance service）— `advanceStage` 支援 decision/comment
- Modify: `src/views/flow-template/FlowTemplateEditView.vue` — 加 debounced `validateBpmn` call + violation 紅 outline + side-panel warning list
- Modify: `src/views/flow-template/components/BpmnPaletteProvider.js`（或 palette config）— 加 review UserTask 預設 stencil
- New CSS: `.violation-marker` 紅色 stroke

詳細 plan: `implementation-plan.md` §M10.1–M10.7。

**Commit msg**: `feat(spec4-fe): Banner approve/reject + BPMN editor inline warning`（**FE repo 自己 commit**）

**🛑 強烈建議 M10 開新 session**（FE 跟 BE context 不要混；Vue/PrimeVue/bpmn-js 技術棧不同）

### M11 — Manual smoke + BDD + changelog

**目標**：完整 e2e 跑通 + 寫 BDD scenario + BE/FE 各一份 changelog 收尾。

**Repos**：
- BE: `docs/changelog/2026-05-14-feat-review-stage-flow-validator.md`
- FE: 同名 changelog（FE repo）
- Test: `~/Projects/Billows/Audit-Manager/compliance-manager-test` — 新 BDD scenario

**Manual smoke 6 步**（design §12.2）— 需要 browser 操作，subagent 做不到，必須 user 手動或 controller 帶著做。

---

## 四、執行方式提醒

`subagent-driven-development` SOP：
1. 每個 milestone 一個 implementer subagent（餵完整 task text + context；不讓 subagent 自己讀 plan）
2. Spec compliance reviewer subagent（驗實作對齊 spec）
3. Code quality reviewer subagent（驗實作品質）
4. 若 reviewer flag issue → 同 implementer 修 → re-review → 完成才標 milestone done

每個 implementer prompt 必含：
- Task description full text
- Context（working dir / branch / dependencies）
- Files (Create / Modify) 明確路徑
- Before You Begin: 提醒可發問
- Your Job 步驟條列
- Report Format（Status / files / commit SHA / self-review）

CLAUDE.md 規範必貼：
- **commit 用 HEREDOC + Co-Authored-By: Claude Opus 4.7 (1M context)**
- **NEW commit 不用 amend**（即使是 review fix）
- **DO NOT push**（user 還沒指示）
- SQL migration 用 cmmgr 不用 cm_app
- BE restart 必 kill -9（不是 pkill）

---

## 五、已知限制 / Caveat

| 項目 | 影響 | 後續處理 |
|---|---|---|
| `err.context` 在 jedi_common handler 被吞 | create/update 400 path 只回 error_code+msg，無 violations details | 走 `/validate` endpoint 拿 violations（FE 已對齊）。design.md §16.1 已紀錄；未來 jedi_common patch 才修 |
| M9 integration test fixture seed_review_ap 不易重現 | 可能要 mock 路徑替代 | 對齊 Spec 3 §16.1 條 3 的 deferral pattern |
| BE restart .env source 易卡 JSON escape | 用 `python-dotenv load_dotenv()` preload 包 runpy | 已在 §環境狀態 列指令 |
| Two untracked SQL files 在 working tree | `2026-05-14-feature-project-flow-engine-integrate-deploy.sql` / `spec3_phase6_pr1_audit_completed_projects.sql` | 上一個 task arc 留下來；本 spec 4 commits 一律用 explicit `git add <files>`，不用 `-A` |

---

## 六、檔案 cheatsheet

### 核心改動位置

```
compliance-manager-be/
├── app/flow_engine/
│   ├── service/flow_template_app_service.py   ← M5 加 validator integration
│   ├── service/stage_advance_service.py        ← M8 目標：加 decision/comment
│   └── util/bpmn_topology_validator.py         ← M3 純 function
├── api/flow_engine/
│   ├── serializers/flow_template.py            ← M6 加 validate schemas
│   ├── serializers/stage_advance.py            ← M7 目標：加 decision/comment
│   ├── routes/flow_template_route.py           ← M6 加 validate endpoint
│   └── routes/stage_advance_route.py           ← M8 目標：傳 decision/comment
├── app/grc/service/oscal_stage_handlers.py     ← M7 目標：加 ReviewDecisionHandler
├── di_containers/
│   ├── flow_engine/flow_template_containers.py ← M5 wired stage_object_domain_service
│   └── grc/grc_containers.py                   ← M7/M8 目標：wire review_decision_handler + job_comment_service
├── domain/flow_engine/entity/stage_object_entity.py  ← M2 加 4 欄
├── infra/flow_engine/
│   ├── models/stage_object.py                  ← M2 加 4 欄
│   └── mapper/stage_object_mapper.py           ← M2 加 4 欄 mapping
├── common/code/grc_error_code.py               ← M5 加 GRC_400060/061/062
├── scripts/sql/
│   ├── 2026-05-14-spec4-stage-objects-rules-and-review.sql   ← M1 migration
│   ├── 2026-05-14-spec4-builtin-flow-templates.sql           ← M4 migration
│   └── seeds/bpmn/
│       ├── builtin-full-audit.bpmn                            ← M4 patched reverse
│       └── builtin-full-audit-with-review.bpmn                ← M4 new
└── tests/test_bpmn_topology_validator.py       ← M3 unit tests (22 條)
```

### Spec 1/2/3 既有檔（不要動，了解即可）

- `app/flow_engine/service/workflow_execution_service.py:complete_main_workflow_job` — M8 advance_stage 內部呼叫的 BPMN 推進方法
- `app/grc/service/job_comment_service.py:add_comment(job_uid, content, user_id, author_nickname)` — M8 寫 JobComment 入口（**`job_uid` 是 UUID 不是 BPMN element id**）
- `infra/grc/repository/grc_job_comment_repo_impl.py:30` — filter `JobExecution.uid == job_uid` 驗證點

---

## 七、若 session 卡關 / 中斷

回報 user 並建議：
1. 卡 BE 啟動 → 看 `log/app.log` + `/tmp/be*.log`
2. 卡 subagent 一直跑不過 → 退到 inline 自己做（更快）
3. 卡 DB migration → 確認用 cmmgr，密碼 `jedi@123!`
4. design.md / plan.md 跟實作對不上 → 看 design.md §16 reconciliation 段，加新條目記偏差

---

## 八、文件版本

| 版本 | 日期 | 變更 |
|---|---|---|
| v1 | 2026-05-14 | 初版 — M0–M6 完成、M7 起手交接 |
