# Spec 1 流程範本管理 — FE 接手文件

> **BE 狀態**：完成，branch `feature/project-flow-engine-integrate`
> **適用 session**：`compliance-manager-fe` repo 的 FE engineer

## 一、Scope

- 左側選單「流程範本管理」入口（受 RBAC `flow_template.read` 控制）
- 範本列表頁（DataTable + 「內建 / 自訂」filter + name 搜尋 + 分頁）
- 範本編輯頁（BPMN editor + UserTask 屬性面板：階段物件下拉 + 主要角色單選 + **完整 ExclusiveGateway 編輯支援**）
- 範本預覽 Dialog（唯讀 BPMN renderer + UserTask 列表）
- 「複製為自訂」按鈕（builtin 範本可點，跳 Dialog 輸入新名稱）

## 二、API 端點（已實作，BE base url `/api/1.0`）

| Method | Path | 用途 | Capability |
|---|---|---|---|
| GET | `/flow-engine/stage-objects` | 編輯器 UserTask 屬性面板的「階段物件」下拉資料源 | flow_template.read |
| GET | `/flow-engine/flow-templates?page=&size=&name=&is_builtin=` | 列表頁 | flow_template.read |
| GET | `/flow-engine/flow-templates/<uid>` | 編輯頁載入既有範本（含 BPMN XML） | flow_template.read |
| POST | `/flow-engine/flow-templates` | 編輯頁存檔（新建） | flow_template.create |
| PUT | `/flow-engine/flow-templates/<uid>` | 編輯頁存檔（既有自訂範本） | flow_template.update |
| DELETE | `/flow-engine/flow-templates/<uid>` | 軟刪除（builtin 不可刪） | flow_template.delete |
| POST | `/flow-engine/flow-templates/<uid>/duplicate` | 列表頁「複製為自訂」 | flow_template.create |

Response envelope：`{"status": true/false, "data": {...}}`（注意：FE 既有 BaseService 應已處理；不是 `{"code": 1}`）

## 三、BPMN Editor 規格

**Decision C 鎖定（§八 開放問題）：v1 完整 Gateway 編輯**

- 編輯器 palette 含：StartEvent / EndEvent / UserTask / **ExclusiveGateway** / SequenceFlow
- 不需要 ServiceTask / ParallelGateway / CallActivity（Spec 1 範圍）
- UserTask 屬性面板必欄：
  - 「階段物件」下拉 — 選項來自 `GET /flow-engine/stage-objects`，顯示 `name`（i18n resolved），值為 `code`，落到 BPMN `extensionElements > camunda:properties > camunda:property[name=stage_object_code,value=<code>]`
  - 「主要角色」單選 — `manager` / `reviewer` / `auditor` / `viewer`，落到 `camunda:property[name=main_role,value=<role>]`
- Gateway 屬性面板：
  - 「閘道名稱」必填
  - 兩個 outgoing flow 可分別編輯：name（如「有缺失」/「無缺失」）+ conditionExpression（`${has_findings == true}` 等簡單表達式）+ default flag
- 工具列：「儲存」/「另存為新範本」/「預覽」/「離開」按鈕；存檔前 client-side validate（必須有 StartEvent / EndEvent / >=1 UserTask；每個 UserTask 必須選階段物件）

### 內建 builtin 範本參考

3 個 builtin XML 在 BE repo `scripts/sql/seeds/bpmn/builtin-*.bpmn`，可作為 FE 編輯器渲染的對照範本：
- `builtin-internal-check`（簡單線性，2 UserTask）
- `builtin-self-assessment`（線性，3 UserTask）
- `builtin-full-audit`（含 ExclusiveGateway loop back：audit → Gateway →（有缺失）poam → audit /（無缺失）End）

## 四、左側選單註冊

i18n key：`flow-template-manage` — 在 FE `src/config/locales/i18n/zh-tw/menu.json` 與 `en/menu.json` 補：

```json
{
  "flow-template-manage": "流程範本管理"
}
```

```json
{
  "flow-template-manage": "Flow Template Management"
}
```

對應 FE route 在 `src/router/index.js`：路徑 `/flow/template-manage`（與 BE migration 一致），icon `pi-sitemap`。

## 五、Error code i18n 對照

需在 FE `src/config/locales/errorCode.json`（或對應檔案）補：

| Code | zh-tw | en（自行翻譯） |
|---|---|---|
| GRC_404027 | 流程範本不存在 | Flow template not found |
| GRC_404028 | 階段物件不存在 | Stage object not found |
| GRC_400040 | BPMN XML 格式無效 | Invalid BPMN XML format |
| GRC_403040 | 內建範本不可編輯或刪除 | Built-in template is read-only |
| GRC_403041 | 無流程範本管理權限 | No permission for flow template management |
| GRC_409030 | 流程範本名稱已存在 | Flow template name already exists |

## 六、權限提示（FE component-level）

依 user 從 web-menu API 取得的 `capabilities`：

- `flow_template.create` 缺：列表頁的「新增 / 複製為自訂」按鈕 disable
- `flow_template.update` 缺：列表頁的「編輯」按鈕 disable（同時編輯頁打開時禁止存檔）
- `flow_template.delete` 缺：列表頁的「刪除」按鈕 disable

builtin 範本一律：編輯 / 刪除按鈕 disable，但「複製為自訂」可用；預覽永遠可用。

## 七、列表頁設計細節

- DataTable cols：名稱 / 描述 / 內建 or 自訂 / 建立時間 / 更新時間 / 建立者（顯示 nickname `created_user_name`）/ 操作
- Filter：top bar 一個 ToggleButton group「全部 / 內建 / 自訂」（對應 query `is_builtin` undefined / true / false）
- Search：name 模糊搜尋輸入框（debounce 300ms）
- Pagination：頁碼 + size 切換（10 / 20 / 50）

## 八、與既有 jedi-flow-engine workflow 模組的關係

注意：不要混淆兩種「範本」：
- **舊**：`workflow_templates` table（jedi-flow-engine 套件提供）— AO-level 任務問卷流程，per-AO 綁定一個
- **新（本 Spec）**：`compliance.flow_templates` table — project-level AP lifecycle 流程，per-AP 綁定一個（Spec 2/3 接手）

兩張表結構不共用、不繼承，不要試圖統一 service / repo。

## 九、Out of scope（本 Spec 不做）

- AP 套用範本（→ Spec 3 的 ProjectCreateView + ProjectApListView wizard）
- Stage 推進 runtime / Banner UI（→ Spec 2）
- 既有 5 個 view 改動（→ Spec 2）
- 階段物件 CRUD UI（→ 後續 spec，本 spec 只 seed 4 個 builtin）
- 範本「儲存草稿 vs 發佈」狀態（v1 不分）
- 範本分類 / tag（v1 不做）
- 跨 tenant 範本分享（v1 強制隔離）

---

## 十、BE 接手狀態 / Manual test 結果（2026-05-12）

### 10.1 BE 全部可測，10/10 場景通過

| # | 場景 | 結果 |
|---|---|---|
| 1 | blsadmin (Administrator) 登入取 JWT | ✅ access_token 長度 521 |
| 2 | `GET /user/web-menu` 含 `flow-template-manage` 節點 + 4 caps | ✅ |
| 3 | `GET /flow-engine/stage-objects` → 4 個 stage object | ✅ planning / task_execution / audit / poam |
| 4 | `GET /flow-engine/flow-templates` → 3 個 builtin（含分頁 envelope） | ✅ total=3 |
| 5 | `GET /flow-engine/flow-templates/<uid>` → 詳情含 BPMN XML | ✅ bpmn_xml 3821 chars、含 `bpmn:exclusiveGateway` 與 `stage_object_code` |
| 6 | `POST /flow-engine/flow-templates/<uid>/duplicate` 複製 builtin | ✅ 新 uid、is_builtin=false、bpmn_xml 完整 copy |
| 7 | `PUT /flow-engine/flow-templates/<uid>` 更新自訂 | ✅ name + description + bpmn_xml 都更新 |
| 8 | `PUT` builtin → 預期 403 | ✅ HTTP 403, error_code=`GRC_FLOW_TEMPLATE_BUILTIN_READONLY` (GRC_403040) |
| 9 | `DELETE` 自訂範本 | ✅ data.deleted=true |
| 10 | `DELETE` builtin → 預期 403 | ✅ HTTP 403, error_code=`GRC_FLOW_TEMPLATE_BUILTIN_READONLY` |

### 10.2 真實 response sample（直接照抄即可，FE 不用猜 schema）

**`GET /flow-engine/stage-objects`** （一筆樣本）：
```json
{
  "status": true,
  "data": {
    "items": [
      {
        "uid": "d737b4b4-9225-4c14-8ba6-1a5cd80ffceb",
        "code": "planning",
        "name": "規劃",
        "kind": "routed",
        "route_pattern": "/project/projects/:projectUID/settings",
        "complete_button_label": "啟動專案",
        "complete_handler_key": "activate_project",
        "precondition_key": null,
        "default_main_roles": ["manager"],
        "is_builtin": true,
        "sort": 10
      }
      // ...(task_execution / audit / poam)
    ]
  }
}
```

**`GET /flow-engine/flow-templates` 分頁列表**：
```json
{
  "status": true,
  "data": {
    "items": [
      {
        "uid": "da8c2b81-e628-44ee-9096-c3f0b542b61f",
        "name": "builtin-full-audit",
        "description": "完整稽核流程：規劃 → 執行 → 稽核 → 缺失改善 → 結案",
        "is_builtin": true,
        "bpmn_xml": null,    // 列表不帶 XML，呼 detail 才有
        "created_user": "system",
        "created_user_name": "系統",
        "updated_user": "system",
        "updated_user_name": "系統",
        "created_at": "2026-05-12T19:04:40.904716+08:00",
        "updated_at": "2026-05-12T19:04:40.904716+08:00"
      }
      // ...(builtin-internal-check / builtin-self-assessment)
    ],
    "total": 3,
    "page": 1,
    "size": 10
  }
}
```

**`GET /flow-engine/flow-templates/<uid>` 詳情**：
schema 同上 list 單筆，但 `bpmn_xml` 欄位填滿完整 BPMN 2.0 XML 字串（builtin-full-audit ~3.8K chars）。

**錯誤 envelope**（builtin 守門）：
```json
{
  "status": false,
  "msg": "內建範本不可編輯或刪除",
  "error_code": "GRC_403040"
}
```

### 10.3 開工前先讀（plan-vs-reality drift）

| 主題 | spec / plan 說 | 實際 |
|---|---|---|
| Dev DB 名 | CLAUDE.md memory 說 `guidant_ai_stg` | **實際 `.env` 是 `guidant_ai_dev`**。BE 連 `guidant_ai_dev`。第一次跑 migration 不小心跑到 `_stg` 會 deploy 不到 BE。FE 開發時 dev BE 已連對 |
| Login API path / payload | spec 說 `/auth/login` + `{login_name, password}` | 實際是 **`POST /api/1.0/login`** + `{username, password, cf_turnstile_token}`。前 2 個必填，turnstile token dev 用 `"XXXX.DUMMY.TOKEN"` always pass（`.env` 的 `TURNSTILE_SECRET_KEY` 是 Cloudflare always-pass test secret） |
| Response envelope | CLAUDE.md 寫 `{"code": 1, "data": ...}` | 實際是 **`{"status": true/false, "data": ...}`**。`return_response()` 的真實 shape。FE BaseService 應該已處理（測試帳號 login response 就是這格式） |
| 登入回的 JWT 欄位名 | — | `access_token`（不是 `token`）+ `refresh_token` |
| `X-Tenant-ID` header | 不要忘記 | dev 環境 `X-Tenant-ID: 102` 對應 tenant=Billows Tech；不帶 header 也能跑（fallback 到 user default tenant） |
| 角色 mapping | spec 寫 `Administrator` 系統角色 | dev 環境 blsadmin 實際是 **`Billows Admin` (role_id=3, tenant 102)**，**不是** Administrator。Spec 1 migration 只 grant Administrator，dev 上需手動補 grant 給 Billows Admin（見 §10.5 known gap） |

### 10.4 BE 啟動方式（zsh `source .env` 會炸 JSON 大括號）

`.env` 內 `JWT_SECRET={ "jwt_secret": "..." }` 之類 JSON 值的 `{` `}` 會被 zsh/bash 當特殊字元 parse 失敗。用 Python 載 env 是穩定方法：

```bash
# 在 BE repo 根目錄
lsof -i :8000 -t | xargs -r kill -9    # 殺舊 BE，nohup 可能留 orphan
python3 -c "
import os, subprocess
for line in open('.env'):
    line = line.strip()
    if not line or line.startswith('#'): continue
    if '=' in line:
        k, v = line.split('=', 1)
        os.environ[k] = v
subprocess.Popen(['poetry', 'run', 'python', 'main_app.py'],
                 stdout=open('/tmp/be.log', 'w'),
                 stderr=subprocess.STDOUT,
                 env=os.environ.copy())
"
sleep 10 && tail -3 /tmp/be.log
# 應看到 "Running on http://127.0.0.1:8000"
```

### 10.5 Known Gaps / Follow-ups（移交 FE session 接管）

| # | Gap | 應對 |
|---|---|---|
| 1 | **`Billows Admin` (role_id=3) 沒有 flow_template caps** — migration 只 grant 給 `Administrator` (tenant_id IS NULL) | dev 機已手動補 grant（match audit / cloud_integration 既有 pattern）。 **prod / 新 tenant 部署時需要相同手動補 grant，或寫一個專門的 tenant-onboarding migration**。檢視 audit / cloud / notify 三組 caps 的歷史 grant 方式，採同一 pattern |
| 2 | **ORM uid column type bug** — 已 fix (commit `7d36e9e`) | DB schema 用 PG native UUID 但 ORM 原本宣告 String(36)，導致 `filter_by(uid=str)` SQL 比對失敗。已改為 `UUID(as_uuid=False)`。FE 開發不會看到此 bug — 文件記錄供後續 audit 其他模組是否有同問題 |
| 3 | **Webhook turnstile token in prod** | dev `.env` 用 always-pass test key (`1x0000...`)。prod 真實 key 上線時 FE 必須整合 Cloudflare Turnstile widget |
| 4 | **CLAUDE.md memory 中 DB 名稱錯誤** | `reference_dev_db_psql_port.md` 寫 `guidant_ai_stg`，實際是 `guidant_ai_dev`。FE session 開發若要直連 DB（不建議），用 `_dev`，不是 `_stg` |
| 5 | **Login response 欄位是 `access_token`，不是 `token`** | FE BaseService 應該已對齊 — 若 FE 發現拿不到 token，先看欄位名 |

### 10.6 一步到位的 FE 開發 checklist

```
[ ] 1. BE 跑起來確認 GET /flow-engine/stage-objects 回 4 個
[ ] 2. FE menu.json 加 flow-template-manage → 「流程範本管理」/ Flow Template Management
[ ] 3. FE router 加 /flow/template-manage 路由
[ ] 4. FE errorCode.json 加 6 個 GRC_4040xx / GRC_400040 / GRC_409030 訊息
[ ] 5. 列表頁：DataTable + 內建/自訂 ToggleButton filter + name 搜尋 + 分頁
[ ] 6. 「複製為自訂」Dialog：輸入新名稱 → POST .../duplicate
[ ] 7. 範本編輯頁：
       - 載入：GET .../<uid> 取 bpmn_xml
       - BPMN editor 含 ExclusiveGateway palette + UserTask 屬性面板（階段物件下拉 + 主要角色單選）
       - Gateway 屬性面板：name + outgoing flow 的 condition expression
       - 存檔：PUT 自訂 / POST 新建（FE 不可送 PUT 給 builtin — 編輯按鈕應 disable）
       - Client-side validate：必有 StartEvent / EndEvent / >=1 UserTask 含階段物件
[ ] 8. 預覽 Dialog：唯讀 BPMN renderer + UserTask 列表（顯示綁的階段名）
[ ] 9. 權限 disable 規則（§六）
[ ] 10. e2e 在 compliance-manager-test repo（另一 session）
```

### 10.7 Artifacts（FE 開發 reference）

- 3 份合法 BPMN reference XML：`scripts/sql/seeds/bpmn/builtin-{full-audit,internal-check,self-assessment}.bpmn`
- API SA：`docs/api/flow-engine/api-spec.md` Spec 1 段
- API SD：`docs/api/flow-engine/design.md` Spec 1 段
- Changelog：`docs/changelog/2026-05-12-feat-flow-template-management.md`
- Plan：`docs/features/FR-026-2605-project-flow-engine-integrate/01-flow-template-management/implementation-plan.md`
