# ADR-024: API 分層架構 (Phase 16 絞殺者模式) | 項目 | 內容 | |------|------| | **狀態** | ✅ 已採用 (Phase R-R2 完成,2026-04-01) | | **日期** | 2026-03-26 | | **決策者** | 首席架構師 + 統帥 | | **Phase** | Phase 16 | ## 背景 Phase 16 架構大掃除需要明確的 API 分層規範,以支援絞殺者模式 (Strangler Fig Pattern) 的漸進式重構。 當前問題: - Router 層存在業務邏輯 (32 項違規) - 配置分散在多處 - 缺乏明確的層級邊界 ## 決策 採用 **四層架構** 標準: ``` ┌─────────────────────────────────────────────────┐ │ Router Layer (api/v1/*.py) │ │ - HTTP 轉發 ONLY │ │ - 參數驗證 (Pydantic) │ │ - 權限檢查 (Depends) │ │ - ❌ 禁止: Redis/DB/外部 API 直接呼叫 │ └─────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────┐ │ Service Layer (services/*.py) │ │ - 業務邏輯 │ │ - 外部 API 封裝 │ │ - 快取策略 │ │ - ✅ 可呼叫: Repository, 其他 Service │ └─────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────┐ │ Repository Layer (repositories/*.py) │ │ - 資料存取抽象 │ │ - SQL/ORM 操作 │ │ - Redis 快取 │ │ - ✅ 可呼叫: Model, Redis, PostgreSQL │ └─────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────┐ │ Model Layer (models/*.py) │ │ - Pydantic Schema │ │ - SQLAlchemy ORM │ │ - 純資料結構,無邏輯 │ └─────────────────────────────────────────────────┘ ``` ## Router 層禁止清單 ```python # ❌ 禁止在 Router 層做的事 # 1. 直接 Redis 存取 from src.core.redis_client import get_redis # ❌ # 2. 直接 DB Session from src.db.base import get_session # ❌ # 3. 直接外部 API 呼叫 async with httpx.AsyncClient() as client: # ❌ response = await client.get(external_url) # 4. 內嵌 Lua 腳本 LUA_SCRIPT = """...""" # ❌ # 5. 複雜業務邏輯 (>10 行) if condition1 and condition2: # ❌ # 複雜處理... ``` ## Router 層允許清單 ```python # ✅ Router 層可以做的事 # 1. 參數驗證 @router.get("/items/{item_id}") async def get_item( item_id: str = Path(...), limit: int = Query(default=10, ge=1, le=100), ) -> ItemResponse: # 2. 權限檢查 async def get_item( current_user: User = Depends(get_current_user), ): # 3. 呼叫 Service service = get_item_service() result = await service.get_item(item_id) # 4. 回傳轉換 (簡單) return ItemResponse.from_orm(result) ``` ## 絞殺者模式四階段 ``` Phase 1: Identify (識別) ├── 標記現有違規代碼 ├── 建立 Service 介面 └── 不改變行為 Phase 2: Deprecate (標記棄用) ├── 新代碼使用 Service ├── 舊代碼加 @deprecated └── 監控舊路徑使用量 Phase 3: Migrate (遷移) ├── 逐步遷移到 Service ├── 每次遷移有測試覆蓋 └── 回滾計畫就緒 Phase 4: Remove (移除) ├── 確認無流量 ├── 移除舊代碼 └── 更新文檔 ``` ## 與 leWOOOgo 積木化的關係 ``` leWOOOgo 六大積木 API 四層對應 ───────────────────────────────────── BRAIN (決策) → Service Layer ACTION (執行) → Service + Repository SENSE (感知) → Repository Layer MEMORY (記憶) → Repository Layer OUTPUT (輸出) → Service Layer SAFETY (安全) → Router (Depends) + Service ``` ## 回滾策略 ```yaml # 功能開關 (core/config.py) USE_NEW_LAYER: bool = Field( default=False, description="True=新分層, False=舊版內嵌", ) # 回滾指令 kubectl set env deployment/awoooi-api USE_NEW_LAYER=false ``` ## 後果 ### 正面 - 清晰的層級邊界 - 可測試性提升 (每層獨立測試) - 漸進式遷移,低風險 ### 負面 - 短期開發成本增加 - 需要團隊學習新規範 ## 執行進度 | Phase | 任務 | 狀態 | Commit | |-------|------|------|--------| | R1 | 絞殺者包裝 (USE_NEW_ENGINE) | ✅ | Phase 16 R1 | | R2 | 移除內嵌重複邏輯 | ✅ | `c7b3f8f` (2026-04-01) | | R3 | 抽取 Repository 層 | ✅ | Phase 22 (repositories/) | | R4 | 瘦身 Router 層 | ✅ | `4118808` (2026-04-01) | > Phase R-R2.1 首席架構師正式審查:72/100 條件通過。 > P0+P1 全部修復。P2 技術債清單見 ADR-046。 > 回滾方式已更新:git revert c7b3f8f d17b67c + kubectl rollout restart (USE_NEW_ENGINE 旗標已失效)。 ## 相關文件 - ADR-005: BFF Architecture - ADR-003: leWOOOgo Module Architecture - ADR-046: 跨套件 Incident 型別統一 (BrainIncident vs local Incident) - `feedback_strangler_fig_pattern.md` - `reference_phase16_architecture.md`