# ADR-UI-01: Operator Console Architecture **狀態**:Accepted **日期**:2026-05-03(台北) **決策者**:統帥 **範圍**:AwoooP Operator Console 前端整體架構、與現有 apps/web/ 的整合方式 **關聯**:ADR-106(六合約)、ADR-112(contract governance)、ADR-115(principal mapping) --- ## 背景 AwoooP 需要一個 Operator Console(管理員後台),讓平台管理員可以: 1. 管理 tenant(project)和 principal 角色 2. 查看和管理 contract revisions(六合約的 draft/publish/activate) 3. 監控 runs(run state, saga steps, budget usage) 4. 執行 approval decisions(human approval for WAITING_APPROVAL runs) 現有 `apps/web/` 是 Next.js 14 前端,已有 AI 監控 dashboard。Operator Console 需要在不破壞現有功能的情況下整合。 --- ## 決策 ### D1 — 整合方式:子路由擴展(不建新應用) Operator Console 作為 `apps/web/` 的新路由段: ``` apps/web/src/app/ ├── (existing)/ ← 現有頁面(不動) │ ├── dashboard/ │ ├── incidents/ │ └── ... └── awooop/ ← 新增 Operator Console ├── layout.tsx ← Console layout(sidebar + auth gate) ├── tenants/ ← Tenant 管理 │ ├── page.tsx │ └── [project_id]/ │ ├── page.tsx │ └── principals/ ├── contracts/ ← Contract governance │ ├── page.tsx │ └── [contract_id]/ │ ├── page.tsx │ └── revisions/ ├── runs/ ← Run 監控 │ ├── page.tsx │ └── [run_id]/ │ └── page.tsx └── approvals/ ← Approval decisions ├── page.tsx └── [run_id]/ └── page.tsx ``` ### D2 — Auth Gate(Operator Console 專屬) Operator Console 需要 `platform_subject.roles` 中包含 `admin` 或 `approver`: ```typescript // apps/web/src/app/awooop/layout.tsx import { redirect } from "next/navigation" import { getServerSession } from "@/lib/auth" import { hasOperatorRole } from "@/lib/awooop-auth" export default async function AwoooPLayout({ children }) { const session = await getServerSession() if (!session || !hasOperatorRole(session.user)) { redirect("/unauthorized") } return (
{children}
) } ``` ### D3 — API Client 分層 ``` apps/web/src/lib/ ├── awooop/ │ ├── client.ts ← AwoooP Platform API client(/v1/platform/...) │ ├── types.ts ← TypeScript types(從 API spec 生成) │ ├── runs.ts ← Run 相關 API calls │ ├── contracts.ts ← Contract 相關 API calls │ ├── tenants.ts ← Tenant 相關 API calls │ └── approvals.ts ← Approval 相關 API calls ``` **API base URL**: ```typescript // 從環境變數讀取(禁止 hardcode 內網 IP,feedback_frontend_internal_ip_ban) const AWOOOP_API_BASE = process.env.NEXT_PUBLIC_AWOOOP_API_URL // K8s ConfigMap 設置:NEXT_PUBLIC_AWOOOP_API_URL=https://api.awoooi.com ``` ### D4 — 8 個 UI 模組(Phase 5 實作) | 模組 | 路由 | 功能 | ADR 關聯 | |------|------|------|---------| | M1 Tenant List | `/awooop/tenants` | 列出所有 project,建立/停用 | ADR-115 | | M2 Principal Manager | `/awooop/tenants/[id]/principals` | 角色管理,auto-provision 確認 | ADR-115 | | M3 Contract Dashboard | `/awooop/contracts` | 六合約總覽,active revision 狀態 | ADR-106 | | M4 Contract Editor | `/awooop/contracts/[id]/revisions` | draft/publish/activate 操作 | ADR-112 | | M5 Run Monitor | `/awooop/runs` | 所有 run 的即時狀態 | ADR-114 | | M6 Run Detail | `/awooop/runs/[run_id]` | saga_steps, budget, trace_id | ADR-119 | | M7 Approval Queue | `/awooop/approvals` | WAITING_APPROVAL run 列表 | ADR-114 | | M8 Approval Decision | `/awooop/approvals/[run_id]` | approve/reject + token 生成 | ADR-116 | **各模組的詳細設計在 ADR-UI-02 / ADR-UI-03 / ADR-UI-04。** ### D5 — 設計原則 1. **禁止 emoji,使用 Lucide icon**(feedback_no_emoji_use_icons) 2. **全站統一字體/顏色**(feedback_design_system_consistency) 3. **100% next-intl i18n**(feedback_i18n_zero_hardcode)— 所有文字走翻譯 key 4. **禁止內網 IP**(feedback_frontend_internal_ip_ban)— NEXT_PUBLIC_* 只用公網域名 5. **Logo SVG 與正式環境一致**(feedback_brand_logo_consistency) ### D6 — 即時更新(WebSocket / SSE) Run Monitor(M5)和 Approval Queue(M7)需要即時更新: ```typescript // Server-Sent Events(比 WebSocket 更簡單,適合單向推送) // GET /v1/platform/runs/stream?project_id=awoooi&status=RUNNING,WAITING_APPROVAL const eventSource = new EventSource( `/v1/platform/runs/stream?project_id=${projectId}` ) eventSource.onmessage = (event) => { const update = JSON.parse(event.data) as RunStateUpdate updateRunInCache(update) } ``` --- ## 後果 ### Benefits - 複用現有 apps/web/ 的 auth、i18n、設計系統(不重造輪子) - 子路由設計:現有功能不受影響,可獨立部署 Operator Console 路由 - Phase 5 前,`/awooop/*` 路由可以用 feature flag 隱藏(9 個 feature flag 中的 `ENABLE_OPERATOR_CONSOLE`) ### Costs - 需要在 apps/web/ 建立 `awooop/` 目錄結構(~15 個新檔案) - API client 需要 TypeScript type generation(從 OpenAPI spec) ### Risks - Operator Console 的 auth gate 若有漏洞 → 非管理員可存取敏感操作 - 緩解:auth gate 在 layout.tsx 實作(server-side),不依賴 client-side 隱藏 --- ## 驗收標準 - [ ] `/awooop` 路由在 `apps/web/src/app/` 建立(Phase 5) - [ ] auth gate:非 admin/approver → redirect `/unauthorized`(整合測試) - [ ] `NEXT_PUBLIC_AWOOOP_API_URL` 不含內網 IP(CI lint check) - [ ] 8 個模組全部有對應路由(Phase 5 完成) ## 關聯 - ADR-106(六合約,Contract Dashboard M3/M4 的資料來源) - ADR-112(contract governance API,M4 的操作路徑) - ADR-114(run state,M5 M6 的資料來源) - ADR-115(principal mapping,M1 M2) - ADR-116(approval token,M8 核心功能)