## Phase 0(文件層,全部 Accepted) - ADR-106/107:AwoooP 平台架構 + 儲存策略 - ADR-111~118:Bootstrap → RLS 七項核心 ADR - ADR-119~124:SAGA → Singleton Decomposition 六項 ADR - ADR-UI-01~04:Operator Console 四個 UI ADR ## Phase 1(DB schema + migration) - awooop_phase1_control_plane_2026-05-04.sql:7 張新表 + trigger + RLS - Step 1:三角色(platform_admin/migration BYPASSRLS,awooop_app 受 RLS) - Step 13:GRANT awooop_app 最小權限(7 條) - Step 14:RLS fail-closed,移除 __platform__ 後門 - awooop_phase1_batch1_rls_2026-05-04.sql:高流量四表三步式 ADD COLUMN - awooop_phase1_batch1_backfill.py:SKIP LOCKED 分批回填腳本 - awooop_models.py:7 個 SQLAlchemy 2.x models ## Critic 修正(4 Critical + 3 Major) - C-1:ADD CONSTRAINT IF NOT EXISTS → DO 塊 + pg_constraint 查詢 - C-2:__mapper_args__ 字串 list → primary_key=True on mapped_column - C-3:__platform__ RLS 後門 → 全移除,改用 BYPASSRLS role - C-4:awooop_app role 從未建立 → Step 1 + 7 條 GRANT - M-1:active_pointer_guard SECURITY DEFINER(FORCE RLS 跨租戶保護) - M-2:pg_partman create_parent 加冪等防護 - M-3:immutability trigger 新增身份欄位保護(project_id/family/contract_id) ## Task 1.2 修補 - agent_loader.py:硬編碼 Mac 路徑 → AGENTS_DIR 環境變數 - Dockerfile:補 COPY .claude/agents/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.7 KiB
6.7 KiB
ADR-UI-02: Contract Governance UI
狀態:Accepted 日期:2026-05-03(台北) 決策者:統帥 範圍:M3 Contract Dashboard + M4 Contract Editor 的詳細設計 關聯:ADR-UI-01(Operator Console 架構)、ADR-112(contract governance)、ADR-113(outbox)
背景
Contract Dashboard(M3)和 Contract Editor(M4)是 Operator Console 最複雜的模組,需要展示六合約的全貌,並支援 draft → publish → activate 的工作流程。
M3 — Contract Dashboard
頁面設計
路由:/awooop/contracts
主要資訊:
┌─────────────────────────────────────────────────────────────┐
│ Contract Dashboard [+ New Draft] │
├──────────┬──────────────────────┬──────────┬───────────────┤
│ Project │ Contract Family │ Active │ Last Updated │
├──────────┼──────────────────────┼──────────┼───────────────┤
│ awoooi │ policy_routing │ v2.1 ✅ │ 2026-05-03 │
│ awoooi │ mcp_gateway │ v1.3 ✅ │ 2026-04-20 │
│ awoooi │ agent │ v1.0 ✅ │ 2026-03-15 │
│ awoooi │ project_tenant │ v1.0 ✅ │ 2026-01-10 │
│ awoooi │ runtime_run_state │ v1.1 ✅ │ 2026-04-28 │
│ awoooi │ channel_event │ v1.2 ✅ │ 2026-04-15 │
│ ewoooc │ policy_routing │ ⚠️ None │ — │
└──────────┴──────────────────────┴──────────┴───────────────┘
狀態 badge:
✅ v2.1:有 active revision,lifecycle_status = active⚠️ None:無 active revision(需要初始設定)🔄 Pending Activation:有 published revision 等待 activate(approval 路徑)🔴 Outbox Lag:outbox 有未送出事件超過 60 秒(ADR-113 告警)
API 呼叫
// GET /v1/platform/projects/{project_id}/contracts
// Response: ContractSummary[]
interface ContractSummary {
project_id: string
contract_family: ContractFamily
contract_id: string
active_revision_id: string | null
active_version: string | null
lifecycle_status: "active" | "no_active" | "pending_activation"
last_updated_at: string
has_pending_outbox: boolean // ADR-113 outbox lag indicator
}
M4 — Contract Editor
頁面設計
路由:/awooop/contracts/[contract_id]/revisions
頁面佈局:
左側:Revision List 右側:Revision Detail
┌─────────────────────┐ ┌──────────────────────────────────┐
│ policy_routing/ │ │ Revision: v2.1 (Active) │
│ awoooi-sre │ │ │
│ ─────────────────── │ │ [Body JSON] [Signature] [History]│
│ v2.1 ● Active │ →選擇→ │ │
│ v2.0 Published │ │ { │
│ v1.9 Published │ │ "routing_rules": [...], │
│ v1.8 Published │ │ "model_priority": [...] │
│ v0.1 Draft │ │ } │
│ ─────────────────── │ │ │
│ [+ New Draft] │ │ Signature: ✅ Valid │
└─────────────────────┘ │ Published by: admin@awoooi │
│ Published at: 2026-05-03 14:23 │
│ │
│ [Activate] [Revoke] [Diff vs v2.0]│
└──────────────────────────────────┘
操作按鈕邏輯
| 按鈕 | 可見條件 | 行為 |
|---|---|---|
[+ New Draft] |
任何時候 | 建立新 draft revision |
[Publish] |
status=draft | 呼叫 publish API + 簽章驗證 |
[Activate] |
status=published | 路徑 A:送 approval;路徑 B:直接 activate |
[Revoke] |
status=active | 確認對話框 → revoke(回到 no_active 狀態) |
[Diff vs v2.0] |
status=published or active | 顯示與前一版本的 JSON diff |
Activation Approval Flow(路徑 A)
對於 policy_routing、mcp_gateway、runtime_run_state 三類 contract(ADR-112 D3 路徑 A):
點擊 [Activate]
↓
顯示對話框:
「此 contract 需要 approval。
請說明變更原因:[ textarea ]
[提交 Approval 請求] [取消]」
↓
POST /v1/platform/projects/{project_id}/contracts/{contract_id}/activate
Body: { "revision_id": "...", "change_reason": "..." }
↓
API 返回:{ "approval_run_id": "...", "status": "WAITING_APPROVAL" }
↓
頁面顯示:「Approval 請求已送出 → 前往 Approval Queue」
↓
M7 Approval Queue 顯示待審核項目
版本 Diff 視圖
// 使用 react-diff-viewer 或自製 JSON diff
import { DiffViewer } from "@/components/awooop/diff-viewer"
// 對比兩個 revision 的 body_json
<DiffViewer
oldValue={JSON.stringify(oldRevision.body_json, null, 2)}
newValue={JSON.stringify(newRevision.body_json, null, 2)}
splitView={true}
/>
後果
Benefits
- Contract Dashboard 一眼看清六合約的 active 狀態
- Outbox lag indicator(ADR-113):若 relay worker 卡住,在 UI 立即可見
- Diff 視圖:activate 前可以比對版本差異,減少誤操作
Costs
- JSON diff 顯示需要第三方套件或自製(約 100 行)
- Activation approval flow 需要與 M7/M8 的 Approval 模組配合
驗收標準
- M3:六合約全部顯示,狀態 badge 正確(Phase 5 整合測試)
- M4:draft → publish → activate 完整流程可操作(Phase 5)
- M4:路徑 A contract activate → Approval Queue 有對應請求(整合測試)
- M4:JSON diff 視圖可比對版本差異(Phase 5)
關聯
- ADR-UI-01(Operator Console 整體路由)
- ADR-112(contract governance API)
- ADR-113(outbox,M3 的 outbox lag indicator)