Files
awoooi/docs/adr/ADR-UI-02-contract-governance-ui.md
Your Name 13e51802fe feat(awooop): Phase 0 全 ADR + Phase 1 control plane schema(含 critic 四項修正)
## 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>
2026-05-04 13:37:11 +08:00

6.7 KiB
Raw Blame History

ADR-UI-02: Contract Governance UI

狀態Accepted 日期2026-05-03台北 決策者:統帥 範圍M3 Contract Dashboard + M4 Contract Editor 的詳細設計 關聯ADR-UI-01Operator Console 架構、ADR-112contract governance、ADR-113outbox


背景

Contract DashboardM3和 Contract EditorM4是 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 revisionlifecycle_status = active
  • ⚠️ None:無 active revision需要初始設定
  • 🔄 Pending Activation:有 published revision 等待 activateapproval 路徑)
  • 🔴 Outbox Lagoutbox 有未送出事件超過 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_routingmcp_gatewayruntime_run_state 三類 contractADR-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 indicatorADR-113若 relay worker 卡住,在 UI 立即可見
  • Diff 視圖activate 前可以比對版本差異,減少誤操作

Costs

  • JSON diff 顯示需要第三方套件或自製(約 100 行)
  • Activation approval flow 需要與 M7/M8 的 Approval 模組配合

驗收標準

  • M3六合約全部顯示狀態 badge 正確Phase 5 整合測試)
  • M4draft → publish → activate 完整流程可操作Phase 5
  • M4路徑 A contract activate → Approval Queue 有對應請求(整合測試)
  • M4JSON diff 視圖可比對版本差異Phase 5

關聯

  • ADR-UI-01Operator Console 整體路由)
  • ADR-112contract governance API
  • ADR-113outboxM3 的 outbox lag indicator