- CLAUDE.md: 紅區治理章節 - Skills 01/03: 版本更新 - ADR/Architecture: 標準化 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.3 KiB
6.3 KiB
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
會導致:
- 前端邏輯過於肥大
- 極高的資安外洩風險
- 難以實施統一的身分驗證與權限控制
決策
強制實施 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 層職責
# 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
禁止事項
// ❌ 禁止:前端直連資料庫
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. 資料聚合
# 一個 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
- api-contract.yaml (BFF 對外契約)
- ADR-001: MCP Protocol (內部服務整合)