# Spec 2 Phase C 交接 Prompt — FE Banner + composable + service

> 給下一個 FE session 用。複製整段「〇、起手語」往下到 session 開頭。
> Phase B（BE 全做完，5 commits 待 push）的細節在最後段 §六「Phase B 已交付摘要」可查。

---

## 〇、起手語（直接複製這段給新 session）

我要在新 FE session 接 Spec 2「階段抽象整合」Phase C — FE Banner 元件 + composable + service。
保持 BE 主導模式（與 Spec 1 / Phase B 同 pattern；BE 已先做完，FE 只接 API）。

### 前置狀態：Spec 2 Phase B 已完成（BE）

Phase B 5 commits 已上 BE branch `feature/project-flow-engine-integrate`（**領先 origin 5 個 commit，user 視 smoke test 結果決定 push 時機**）：

| Commit | 內容 |
|---|---|
| `180be60` | B.1+B.2：OSCAL Stage Handlers + Preconditions（4+3 個 Singleton 註冊到 stage_registry） |
| `6a3eea5` | B.3：StageAdvanceService + `complete_main_workflow_job` |
| `a7fd578` | B.4：Stage Advance Route + Schemas |
| `186828e` | B.5：`start_oscal_project` Step 22（建 AP 同步啟動 main workflow + 寫 AP ext） |
| `4646b4c` | B.6：刪除暫態 ExtAssessmentPlanRepo + EndEvent reconciliation |

### ⚠ BE → FE 接口已 freeze 的 2 個 endpoint（Phase B.4 產出）

**Base URL prefix**：`/api/1.0`

| Method | URL | Body / Query | Response data shape |
|---|---|---|---|
| GET  | `/project/<project_uid>/ap/<ap_uid>/stage/info` | – | StageInfoResponseSchema |
| POST | `/project/<project_uid>/ap/<ap_uid>/stage/advance` | `{ "force": bool, "ctx": {} }` | StageAdvanceResponseSchema |

#### StageInfoResponseSchema 完整範例（GET stage/info）

```json
{
  "status": true,
  "data": {
    "current_stage": {
      "code": "planning",
      "name_i18n": {"zh_Hant_TW": "規劃", "en": "Planning"},
      "kind": "routed",
      "complete_button_label_i18n": {"zh_Hant_TW": "啟動專案", "en": "Activate"},
      "complete_handler_key": "activate_project",
      "precondition_key": null,
      "main_roles": ["manager"]
    },
    "user_can_advance": true,
    "user_role": "manager",
    "precondition": {
      "passed": true,
      "reason_i18n_key": null,
      "context": {}
    },
    "progress": [
      {"code": "planning", "name_i18n": {"zh_Hant_TW": "規劃"}, "status": "current"},
      {"code": "task_execution", "name_i18n": {"zh_Hant_TW": "執行任務"}, "status": "pending"},
      {"code": "audit", "name_i18n": {"zh_Hant_TW": "稽核"}, "status": "pending"},
      {"code": "poam", "name_i18n": {"zh_Hant_TW": "缺失改善"}, "status": "pending"}
    ],
    "workflow_execution_uid": "...",
    "workflow_status": "PROCESSING",
    "job_id": "UserTask_planning"
  }
}
```

#### StageAdvanceResponseSchema（POST stage/advance）

```json
{
  "status": true,
  "data": {
    "advanced": true,
    "handler_result": {"ap_uid": "...", "status": "active", "notified_count": 3},
    "current_stage_info": { ... 同上 stage/info 結構 ... }
  }
}
```

如果 handler 返回 warning（如 `launch_audit` 在有未完成 task 時且 `force=false`）：

```json
{
  "status": true,
  "data": {
    "advanced": false,
    "handler_result": {
      "warning": true,
      "incomplete_tasks": 12,
      "message": "尚有 12 個未完成的任務，確認要啟動稽核？"
    },
    "current_stage_info": { ... }
  }
}
```

FE 收到 `advanced=false` + `handler_result.warning=true` → 開 ConfirmDialog 讓 user 二次確認；確認 → 再次 POST 同 endpoint 帶 `{"force": true}`。

#### Error 範例

| Status | error code | 情境 | response data 額外欄位 |
|---|---|---|---|
| 412 | `GRC_412021` (GRC_STAGE_PRECONDITION_FAILED) | precondition fail 且 `force=false` | `data.context` 含 `reason_i18n_key + context` |
| 403 | `GRC_403050` (GRC_STAGE_ROLE_FORBIDDEN) | user 角色不符 stage main_roles | – |
| 404 | `GRC_404029` (GRC_AP_NO_WORKFLOW_BINDING) | AP 沒綁 workflow_execution（既有 AP 未跑 Step 22 backfill 才會發生） | – |
| 400 | `GRC_400052` (GRC_STAGE_OBJECT_NOT_BOUND) | BPMN UserTask 沒 `stage_object_code` extension property | – |
| 400 | `GRC_400051` (GRC_STAGE_HANDLER_NOT_REGISTERED) | stage_object.complete_handler_key 對應 handler 沒註冊 | – |

### 主任務：Spec 2 Phase C — FE Banner 元件 + composable + service

**Phase C 範圍**（implementation-plan.md §五）：

| Sub | 內容 | Plan §參照 |
|---|---|---|
| **C.1** | API service：`src/service/StageService.js`（繼承 BaseService） | §C.1 |
| **C.2** | Composable：`src/composables/useStageInfo.js` | §C.2 |
| **C.3** | 元件：`src/components/grc/FlowPhaseBanner.vue` + `StageProgressBar.vue` + i18n 補齊 | §C.3 |

Plan 建議 C.1+C.2+C.3 包成 **一個大 commit**（內聚性高，難拆）；可視實際進度視情況拆 2 個 commit（service+composable / 元件）。

### Phase D 預告（Phase C 完成後接 D，本 session 可不做）

| Sub | 內容 |
|---|---|
| D.1 | `ProjectSettingsView.vue` 頂部加 Banner，拆「啟動專案」按鈕 |
| D.2 | `ProjectAuditorOverview.vue` 頂部加 Banner，拆「啟動稽核」按鈕（4 個導航按鈕**不動**）|
| D.3 | `AuditReviewView.vue` 頂部加 Banner，拆「提交稽核」按鈕 |
| D.4 | `PoamView.vue` 頂部加 Banner，拆「完成改善」按鈕 |
| D.5 | `MyTasksView.vue` **不掛** Banner（spec 明確） |
| D.6 | i18n 補齊 + `docs/claude/frontend-overview.md` 加 Banner 元件條目 |

### 開工前必讀（依優先序）

1. **BE 接口完整 spec**（最重要）：
   ```
   ~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/changelog/
   2026-05-12-feat-spec2-phase-b4-stage-advance-route.md
   ```
   含 2 endpoint 完整 request / response / error 範例。

2. **整體脈絡 + 6 條決議**：
   ```
   ~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/
   project-flow-engine-integrate/02-stage-integration/design.md
   ```
   特別看 §四 Banner 元件設計、§五 互動規格、§9 決議。

3. **Phase C 詳細計畫**：
   ```
   ~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/
   project-flow-engine-integrate/02-stage-integration/implementation-plan.md
   ```
   §五（Phase C）全段。

4. **FE 既有規範速查**：
   ```
   ~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/claude/frontend-overview.md
   ```
   API 慣例、design tokens、可重用元件、composables、stores。

5. **FE 工作目錄**：
   ```
   ~/Projects/Billows/Audit-Manager/compliance-manager-fe/
   ```
   含獨立 CLAUDE.md（FE 規範以該 file 為準）。

6. **FE 既有 API service 範例**（C.1 mirror pattern）：
   - `src/service/` 下任一 GRC service（例：`ProjectService.js`、`AuditService.js`）— 確認 BaseService 用法、URL placeholder 替換、return 值結構
   - `src/config/api/api.js` — API endpoint 常數定義

7. **FE 既有 i18n files**：
   - `src/i18n/zh-tw.js` / `src/i18n/en.js` — 需新增 stage_object name + button label + 4 個 precondition reason key

### Phase C 建議實作順序

#### C.1 — API service（先做）

新增 `src/service/StageService.js`：
- `getStageInfo(projectUid, apUid)` → GET `/project/:projectUid/ap/:apUid/stage/info`
- `advanceStage(projectUid, apUid, payload)` → POST `/project/:projectUid/ap/:apUid/stage/advance`

更新 `src/config/api/api.js` 加 2 個常數：
```js
STAGE_INFO: '/project/:projectUid/ap/:apUid/stage/info',
STAGE_ADVANCE: '/project/:projectUid/ap/:apUid/stage/advance',
```

⚠ FE BaseService 的 `return` 慣例請參考既有 service（有些 service 解開 envelope `.data`，有些直接傳整個 response）— 沿用同模組已有 pattern，**不要新發明**。

#### C.2 — composable

新增 `src/composables/useStageInfo.js`：

```js
export function useStageInfo(projectUid, apUid) {
  const stageInfo = ref(null)
  const loading = ref(false)
  const error = ref(null)

  async function fetchStageInfo() { ... }
  async function advance({ force = false, ctx = {} } = {}) {
    // POST → 若 response.advanced=false 且 handler_result.warning=true →
    // emit 'needs-confirmation' event 給呼叫端開 ConfirmDialog；
    // 確認後 caller 再次呼叫 advance({ force: true })
  }

  return { stageInfo, loading, error, fetchStageInfo, advance }
}
```

#### C.3 — Banner 元件

新增 `src/components/grc/FlowPhaseBanner.vue`：
- Props：`project-uid: String` + `ap-uid: String`
- 內部呼叫 `useStageInfo(projectUid, apUid)`
- 顯示元素：當前 stage name（i18n）/ progress bar（4 dot + label） / 提示文字 / 推進按鈕 + tooltip
- 互動：
  - precondition.passed=false → 按鈕 disable + tooltip 顯示 `t(reason_i18n_key, context)`
  - precondition.passed=false + user_role='manager' → 按鈕**不** disable，點下開 ConfirmDialog → 確認 → `advance({ force: true })`
  - 推進成功 → `fetchStageInfo` refresh banner + emit `stage-advanced` 給父 view（讓父 view refresh 自己的資料）
  - 推進失敗 → toast 顯示後端 error msg
- 子元件：`StageProgressBar.vue`（純展示 4 dot + label，CSS only）

#### C.3 i18n key 設計

```js
// src/i18n/zh-tw.js / en.js 新增
flow_engine: {
  precondition: {
    tasks_not_complete: '尚有 {incomplete} / {total} 個任務未完成',
    verdict_incomplete: '尚有 {missing} / {total} 個控制項未填判定',
    poam_not_all_closed: '尚有 {not_closed} / {total} 個缺失未結案',
    ap_not_found: '找不到稽核計畫',
    ar_not_found: '找不到稽核結果',
    ar_data_not_found: '找不到稽核資料',
  },
}
```

⚠ stage_object 的 `name_i18n` / `complete_button_label_i18n` 由 BE 直接回 dict（多語），FE 依當前 locale 取對應字串即可，**不需另設 i18n key**。Locale key 是 `zh_Hant_TW` / `en`（**不是** `zh-tw`，這是 Reconciliation #2）。

### Phase C 完成定義（不掛 view）

- [ ] Banner 元件可獨立 storybook / playground 渲染，mock 4 種 stage 狀態 + 2 種 precondition 狀態
- [ ] `useStageInfo` 在 mock API 下 fetch / advance 都正常
- [ ] `StageService` 兩個 method 在 FE 既有 BaseService pattern 下能呼叫成功
- [ ] i18n key 補齊在 zh-tw + en

### Phase C → Phase D 之間 manual smoke test（必跑）

- [ ] BE 起動（user 自己）
- [ ] manager 帳號登入 → 進已建專案 → 透過 console 或 mock view 呼叫 `useStageInfo` → 收到 `current_stage.code = 'planning'`
- [ ] 點推進按鈕（manager）→ POST advance → 預期 200 + `advanced=true` + `current_stage_info.current_stage.code = 'task_execution'`（如果有 unassigned task 會回 warning）
- [ ] auditor 帳號登入 → 進同專案 → GET stage/info 收到 `user_can_advance=false`
- [ ] BE log 看 `[stage_advance]` 相關訊息（log path: `~/Projects/Billows/Audit-Manager/compliance-manager-be/log/app.log`）

### ⚠ 4 條累積 reconciliation findings（Phase B 期間發現）— **Phase C 必須對齊**

1. **Handler key 命名跳了 namespace 前綴** — BE handler.key 回 `activate_project` / `launch_audit` / `confirm_audit` / `close_round`（**無**前綴）；DB seed 已對齊；FE 不直接用 handler key 做判斷邏輯（FE 看 `stage_code` + i18n label 就好）。
2. **i18n locale key 是 `zh_Hant_TW`，不是 `zh-tw`** — BE 回的 `name_i18n` dict key 是 `zh_Hant_TW`。FE 取值前若要 normalize：`const label = info.current_stage.name_i18n[currentLocale.replace('-','_')] || info.current_stage.name_i18n['zh_Hant_TW']`。
3. **`complete_job` 不適合 main workflow** — BE 已加 `complete_main_workflow_job` 平行 method（B.3）。FE 無感，沿用 `/stage/advance` endpoint 即可。
4. **`flow_templates` 沒 stable `code` 欄位** — BE Step 22 用 hardcode `"完整稽核流程"` 找預設範本。FE 無感；未來 Spec 3 範本 wizard 才會需要 code 欄位。

### 工作流程約定（與 BE Phase B 相同）

- **BE log 位置**：`~/Projects/Billows/Audit-Manager/compliance-manager-be/log/app.log` — FE 任何 BE call 異常都先 grep 這個
- 改 FE code 後不需要重啟 — Vite HMR 自動 reload
- DB 連線：`192.168.50.188:25432 / guidant_ai_dev`，cmmgr 帳號（密碼 `jedi@123!`）
- 階段性 commit 不用問 — 子 task / milestone 完成直接 commit；user_memory feedback 已說明
- subagent dispatch 必加「git add 顯式檔名，禁用 -am」（user_memory feedback）
- 編輯檔用絕對路徑開頭：`~/Projects/Billows/Audit-Manager/compliance-manager-fe/...`
- FE 改完用 `cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe && npm run dev`（如未已起 dev server）

### FE CLAUDE.md 規範必檢（Phase C 各 commit）

依 `~/Projects/Billows/Audit-Manager/compliance-manager-fe/CLAUDE.md` 規範。重點摘要（**FE CLAUDE.md 為準**）：

- [ ] Service 繼承 BaseService，使用 `import { API } from '@/config/api/api'`
- [ ] Composable 用 `ref` / `reactive`，return reactive refs
- [ ] 元件 props 有 type + 必填標記
- [ ] i18n 字串不 hardcode 中文；參考既有 `t('xxx')` pattern
- [ ] CSS 用 design tokens（顏色 / 間距變數）— 不寫 raw hex
- [ ] PrimeVue 3.53 quirks 留意（Steps active-step、SelectButton unselectable、Dropdown null bug）— FE CLAUDE.md 內有完整列表

### 完成本 session 後的下一步

Phase C 完成（service + composable + 元件 + i18n）後，在本目錄 `02-stage-integration/` 內產出 `handoff-prompt-phase-d.md`（mirror 本檔格式），交給下一個 FE session 做 Phase D（4 個 view 掛 Banner + 拆按鈕）。

或本 session 直接接 Phase D（D.1~D.6，5 commits）— 視 context budget 而定。

---

## 一、Reconciliation 紀錄（給未來讀者，目前累積 4 條）

1. ✅ Handler key 命名（DB 用無前綴）— Phase B.1+B.2 已對齊
2. ✅ locale key = `zh_Hant_TW`（非 `zh-tw`）— Phase C 上下傳遞時注意 normalize
3. ✅ `complete_job` AP-task 假設 → 新增平行 `complete_main_workflow_job` — Phase B.3 已落地
4. ✅ `flow_templates` 無 `code` 欄位 → 單點 hardcode `"完整稽核流程"` — Phase B.5 已落地

Phase C / D 完成後若有新 reconciliation，補進 design.md §十 段（mirror Spec 1 §九 pattern）。

---

## 二、Phase B 已交付摘要（給 FE session 參考）

| 範圍 | 檔案位置 |
|---|---|
| 4 個 stage handler | `app/grc/service/oscal_stage_handlers.py` |
| 3 個 precondition check | `app/grc/service/oscal_stage_preconditions.py` |
| StageAdvanceService | `app/flow_engine/service/stage_advance_service.py` |
| Route + Schema | `api/flow_engine/routes/stage_advance_route.py` / `api/flow_engine/serializers/stage_advance.py` |
| Step 22 (build AP → start workflow → write ext) | `app/project/service/oscal_project_service.py:_bind_main_workflow_to_ap` |
| DI registration | `di_containers/grc/grc_containers.py:register_stage_hooks_to_registry` (called from `core/app_factory.py` after wire) |
| 6 個 error code | `common/code/grc_error_code.py` (`GRC_412021` ~ `GRC_400052`) |
| DB schema | `compliance.assessment_plan_extensions` (1:1 of `oscal.assessment_plans`)，已 backfill 149 列 |
| Stage object seed | `compliance.stage_objects` 4 列含 handler_key + precondition_key + default_main_roles |
| Builtin BPMN | `compliance.flow_templates` 含「完整稽核流程」(Process_builtin_full_audit) 4 個 UserTask 帶 `stage_object_code` + `main_role` extension property |

### 已知 Phase B 待 push（user 視 smoke test 結果決定時機）

```bash
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git log --oneline origin/feature/project-flow-engine-integrate..HEAD
# 預期：5 commits
```

`git push origin feature/project-flow-engine-integrate` 由 user 決定時機，FE session 不主動 push BE。

### 已知 Phase B 待 manual smoke test 項目

依 `2026-05-12-feat-spec2-phase-b1-b2-handlers-preconditions.md` ~ `2026-05-12-tweak-spec2-phase-b6-delete-legacy-ext-ap-repo.md` 6 個 changelog 內提到的 test 項目：

1. 重啟 BE：`lsof -ti :8000 | xargs -r kill -9 && python main_socketio.py`
2. 建新專案 + AP：POST `/api/oscal/projects/start`
3. 查 DB：`SELECT workflow_execution_uid, flow_template_snapshot_uid FROM compliance.assessment_plan_extensions WHERE assessment_plan_id = <new_ap_id>;` 預期非 NULL
4. GET `/api/1.0/project/<uid>/ap/<apUid>/stage/info`：預期 `current_stage.code='planning'` + `user_can_advance=true`（manager 帳號）
5. precondition fail：在 task_execution stage 推進（有未完成 task）→ 412
6. force=true bypass：同上加 `{"force": true}` → 200
7. 角色擋：auditor 帳號在 planning 推進 → 403
8. 完整推進 4 stage 到 EndEvent → AP.status='closed'

FE session 不需親跑這些，但若 Banner 元件行為怪異請先確認 user 已跑過上述基本 smoke。
