# FR-048 Phase 4a 交接 prompt（軸④ capability guard＋過渡名單換裝）

> 下面整段是給執行 session 的 prompt。前置：Phase 3 過渡名單已齊（矩陣 §6.3）。
> 與 4b（signed-token）檔案面不重疊，但不要同時跑（同一 working tree）。

---

【接手主題】FR-048 Phase 4a — 建 `common/authz/capability.py`（軸④ RBAC 能力點守門）、seed 能力點、把 Phase 3 的 `@require_super_admin_route` 過渡名單逐支換 `@require_capability`

必讀（照順序）：
1. `docs/analysis/2026-07-07-unified-auth-guard-design.md` §3.3（P3 拍板：不 enrich context，per-request 查＋flask.g 快取）、§4（capability guard 形狀）、§2.0（super-admin 降格 break-glass）
2. 矩陣 §6.3 **過渡名單＝工作清單**（各端點群的建議能力點名都列好了）
3. `docs/claude/sql-migration-conventions.md`＋權限 SOP（`docs/system-design/permission/`，5 步驟：capabilities → ui_routes → route_capabilities → role_capabilities）
4. 可抄模板：`scripts/sql/2026-06-19-fr039-file-agent-manage-permission.sql`（caps+role_capabilities 灌法）、`2026-06-29-platform-capability-flag-and-guard.sql`（is_platform）

【branch】fix/v1.8.0-bugs，禁止切 branch。**不動 jedi-* 套件**（capability 查詢用 jedi-auth 既有 service/association 唯讀，先 grep 既有查法——web-menu 的 user→roles→role.capabilities 鏈就是現成的，禁另寫查詢路徑）。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【1. `common/authz/capability.py`】

```python
def require_capability(*names, mode="any"):
    """Route decorator（軸④）：當前 user 經 user→roles→role_capabilities 需持有指定能力點。"""
```

設計要點（P3 拍板 + §2.0）：
- **查詢**：guard 內委派 DI 注入的 CapabilityGuard service（自帶 `@transaction`），走 jedi-auth 既有 user/role 查詢鏈取能力點名集合；結果存 `flask.g` per-request memoize（同 request 第二次守門不再查）。
- **break-glass**：`viewer_is_super_admin()` 為 True 直接放行（super-admin 是旁路 flag，防止換裝後把平台操作者鎖在門外——帳號層 super_admin 不必然持有 Administrator 角色）。docstring 寫明此語意。
- 掛法順序同既有慣例：`@jwt_required()` 外、`@require_capability(...)` 內、`@inject` 最內。
- 錯誤碼：`GRC_CAPABILITY_REQUIRED`（`grc_error_code.py` 403 序號續編，新增）。
- 單元測試：有能力點過／無能力點 403／super-admin bypass／memoize（同 request 只查一次）。

【2. Seeding SQL migration（一支檔案）】

- 對照矩陣 §6.3 建議能力點名（`user.manage`、`role.manage`、`org_unit.manage`、`system_config.manage`、`system_menu.manage`、`device.manage`、`information_system.manage`、`bulletin.manage`、`notification.test`、`auth_provider.manage`、`remote_agent.manage`、`feedback.export`、`module_frame.manage`、survey/flow_template 依 §6.3 完整名單），**先 SELECT 現有 `capabilities` 表比對**，缺的才 INSERT（幂等：`WHERE NOT EXISTS`）。
- `role_capabilities` 配給 `Administrator` 系統角色（`tenant_id IS NULL`，跨環境用 name 查不 hardcode id）。
- **同步 seed 軸①的 platform 級能力點**（`is_platform=true`，如 `tenant.manage`、`log.manage`——為 Phase 5 併軸鋪路），**但軸① decorator 本波不換**（仍 `@require_platform_admin_route`）。
- SQL 鐵則照 conventions：檔頭 `-- Date:`、逐語句日期註解、新表才需 GRANT（本波無新表）、收尾 `INSERT public.schema_migrations`、`psql --single-transaction -v ON_ERROR_STOP=1` 用 `cmmgr` 套 DEV。**只套 DEV**，STG/POC 列入交付清單等 user 指示。

【3. 過渡名單換裝】

- 矩陣 §6.3 逐端點群：`@require_super_admin_route` → `@require_capability("<能力點>")`（一行換一行）。
- 換完 `grep -rn "require_super_admin_route" api/` 應**只剩零星未定調者**（若剩，列清單回報）；矩陣 §6.3 逐列銷帳。
- **語意變化要點（寫進手測 checklist）**：換裝後判定從「帳號層 super_admin」變「持有能力點（或 super_admin bypass）」——**持 Administrator 角色的一般帳號現在也能過**（原本會 403）。這是放寬到 RBAC 正軌，符合設計；但要在回報中明示，讓 user 知道權限面變了誰。

【4. 驗證】

- 單測＋baseline worktree 集合 diff（新增失敗必須 0）。
- DEV 實測（migration 套完後）：無能力點的一般帳號打 system_config 寫入 → 403 `GRC_CAPABILITY_REQUIRED`；配了能力點的角色帳號 → 過；super_admin → 過。
- FE 角色管理 UI 打開能看到新能力點可勾（`capabilities` 表 UI 直讀）；名稱顯示若是 raw name 需不需要 i18n → 查 FE 現有 capability 顯示慣例後回報（不擅自加翻譯管線）。

【commit】分批：① capability.py＋測試；② SQL migration；③ 換裝（可按模組再分）。顯式 add、禁 -am、不 push。收尾：矩陣銷帳＋一句話 status＋手測 checklist（含語意變化說明），收尾動作等 user 下令。
