# ADR-005: 導入 BFF (Backend-For-Frontend) API 閘道模式 > **狀態**: Accepted > **日期**: 2026-03-19 > **決策者**: CTO + CIO ## 背景 AWOOOI 的底層是由 leWOOOgo Engine 驅動的微服務/Plugin 架構。如果讓 Next.js 前端直接呼叫: - 多個分散的 Plugin API - Ollama / Claude API - PostgreSQL / Redis - K8s API 會導致: 1. 前端邏輯過於肥大 2. 極高的資安外洩風險 3. 難以實施統一的身分驗證與權限控制 ## 決策 **強制實施 BFF (Backend-For-Frontend) 架構** ``` ┌─────────────────────────────────────────────────────────────────┐ │ AWOOOI 架構 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────┐ ┌─────────────────┐ │ │ │ Next.js │ ──────→ │ FastAPI BFF │ │ │ │ 前端 │ HTTPS │ Gateway │ │ │ └─────────┘ └────────┬────────┘ │ │ │ │ │ ┌───────────────────┼───────────────────┐ │ │ ↓ ↓ ↓ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ leWOOOgo │ │ OpenClaw │ │ PostgreSQL │ │ │ │ Plugins │ │ (Ollama) │ │ Redis │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ════════════════════════════════════════════════════════════ │ │ DMZ (前端無法直達) │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 核心規則 | 規則 | 說明 | |------|------| | **單一入口** | 前端只能打 `https://api.awoooi.wooo.work/v1/*` | | **禁止直連** | 前端禁止直連 PostgreSQL、Redis、K8s、Ollama | | **身分驗證** | 所有請求經 BFF JWT 驗證 | | **資料脫敏** | Privacy Shield 在 BFF 層攔截機敏資料 | ### BFF 層職責 ```python # apps/api/src/routes/agent.py from fastapi import APIRouter, Depends from src.auth import require_auth from src.privacy import PrivacyShield from src.services import openclaw_client, approval_service router = APIRouter(prefix="/agent", tags=["Agent"]) @router.post("/chat") async def chat_with_agent( request: ChatRequest, user: User = Depends(require_auth), # 1. 身分驗證 ): # 2. 資料脫敏 sanitized = PrivacyShield.sanitize(request.message) # 3. 聚合多個後端服務 response = await openclaw_client.chat(sanitized, user_id=user.id) # 4. 判斷是否需要 Approval if response.requires_action: approval = await approval_service.create( action=response.suggested_action, user_id=user.id, ) response.approval_id = approval.id return response ``` ### 禁止事項 ```typescript // ❌ 禁止:前端直連資料庫 const client = new Client({ connectionString: 'postgresql://...' }) // ❌ 禁止:前端直接呼叫 Ollama const response = await fetch('http://192.168.0.188:11434/api/generate') // ❌ 禁止:前端直接操作 K8s const k8s = new KubeConfig() // ✅ 正確:透過 BFF API const response = await fetch('https://api.awoooi.wooo.work/v1/agent/chat', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ message: '...' }), }) ``` ## 理由 ### 1. Zero Trust 網路隔離 | 元件 | 網路可達性 | |------|-----------| | Next.js (前端) | Public Internet | | FastAPI BFF | DMZ (僅接受前端) | | PostgreSQL | Internal Only | | Redis | Internal Only | | Ollama | Internal Only | | K8s API | Internal Only | ### 2. 統一關注點 | 關注點 | 處理位置 | |--------|---------| | 身分驗證 | BFF Middleware | | 權限檢查 | BFF Dependency | | 請求限流 | BFF / Nginx | | 資料脫敏 | BFF Privacy Shield | | 審計日誌 | BFF Logger | ### 3. 資料聚合 ```python # 一個 API 呼叫 = 多個後端服務聚合 @router.get("/dashboard") async def get_dashboard(user: User = Depends(require_auth)): # 平行取得多個資料源 agent_status, pending_approvals, recent_alerts = await asyncio.gather( openclaw_client.get_status(), approval_service.list_pending(user.id), alert_service.list_recent(limit=10), ) return DashboardResponse( agent=agent_status, approvals=pending_approvals, alerts=recent_alerts, ) ``` ## 後果 ### 優點 - **Zero Trust** 真正的網路隔離 - **前端精簡** 只負責渲染 UI - **統一治理** 所有安全策略集中管理 - **可觀測性** 單一入口易於監控 ### 缺點 - **開發成本** 新功能需在 BFF 層多寫一層 - **延遲增加** 多一層網路跳躍 (~1-5ms) ### 風險 | 風險 | 緩解措施 | |------|---------| | BFF 成為瓶頸 | 水平擴展 + Redis 快取 | | 開發速度下降 | OpenAPI 自動生成 Client SDK | ## 參考 - [BFF Pattern](https://samnewman.io/patterns/architectural/bff/) - api-contract.yaml (BFF 對外契約) - ADR-001: MCP Protocol (內部服務整合)