- CLAUDE.md: 紅區治理章節 - Skills 01/03: 版本更新 - ADR/Architecture: 標準化 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
179 lines
6.3 KiB
Markdown
179 lines
6.3 KiB
Markdown
# 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 (內部服務整合)
|