# AWOOOI API 開發 SOP

> **版本**: v1.0
> **建立日期**: 2026-03-20
> **負責人**: CTO
> **狀態**: Phase 0 草稿

---

## 概述

此文件定義 AWOOOI 所有 API 端點的開發標準流程，確保 Contract-First 原則與 CI 強制檢查能夠有效執行。

---

## API 開發流程

### 1. 設計階段 (Design)

```
┌─────────────────────────────────────────────────────────────┐
│ Step 1: OpenAPI 定義                                        │
├─────────────────────────────────────────────────────────────┤
│ 位置: docs/api/openapi.yaml                                 │
│ 工具: Stoplight Studio / VS Code OpenAPI Editor             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│ Step 2: 端點文檔 (Markdown)                                  │
├─────────────────────────────────────────────────────────────┤
│ 位置: docs/api/endpoints/{module}/{endpoint}.md             │
│ 內容: 用途說明、請求範例、回應範例、錯誤碼                    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│ Step 3: PR Review + Approval                                │
├─────────────────────────────────────────────────────────────┤
│ 審核者: CTO / CISO (安全相關 API)                            │
│ 檢查項: 命名規範、版本策略、錯誤處理、安全考量                 │
└─────────────────────────────────────────────────────────────┘
```

### 2. 實作階段 (Implementation)

```python
# apps/api/app/routers/{module}.py

from fastapi import APIRouter, Depends, HTTPException, status
from app.schemas.{module} import {RequestModel}, {ResponseModel}
from app.services.{module} import {ServiceClass}
from app.core.deps import get_current_user, rate_limit
from app.core.cache import cache_response

router = APIRouter(prefix="/v1/{module}", tags=["{module}"])

@router.get(
    "/{endpoint}",
    response_model={ResponseModel},
    summary="端點摘要",
    description="詳細說明",
    responses={
        200: {"description": "成功"},
        400: {"description": "請求格式錯誤"},
        401: {"description": "未授權"},
        403: {"description": "權限不足"},
        404: {"description": "資源不存在"},
        429: {"description": "請求過於頻繁"},
        500: {"description": "伺服器錯誤"},
    }
)
@cache_response(ttl=60)  # 快取策略
@rate_limit(requests=100, window=60)  # 限流策略
async def endpoint_name(
    request: {RequestModel},
    current_user: User = Depends(get_current_user),
    service: {ServiceClass} = Depends()
):
    """
    端點實作邏輯
    """
    pass
```

### 3. 測試階段 (Testing)

```python
# apps/api/tests/test_{module}.py

import pytest
from httpx import AsyncClient
from app.main import app

class Test{Module}API:
    """
    測試命名規範: test_{method}_{endpoint}_{scenario}
    """

    @pytest.mark.asyncio
    async def test_get_endpoint_success(self, client: AsyncClient, auth_headers: dict):
        response = await client.get("/v1/{module}/{endpoint}", headers=auth_headers)
        assert response.status_code == 200
        assert "data" in response.json()

    @pytest.mark.asyncio
    async def test_get_endpoint_unauthorized(self, client: AsyncClient):
        response = await client.get("/v1/{module}/{endpoint}")
        assert response.status_code == 401

    @pytest.mark.asyncio
    async def test_get_endpoint_not_found(self, client: AsyncClient, auth_headers: dict):
        response = await client.get("/v1/{module}/nonexistent", headers=auth_headers)
        assert response.status_code == 404
```

---

## API 版本策略

### URL 版本控制

```
https://api.awoooi.wooo.work/v1/...  # 目前版本
https://api.awoooi.wooo.work/v2/...  # 未來版本 (重大變更時)
```

### 版本升級規則

| 變更類型 | 版本影響 | 範例 |
|---------|---------|------|
| **新增端點** | 不變 | 新增 `GET /v1/metrics/custom` |
| **新增可選欄位** | 不變 | Response 新增 `metadata` 欄位 |
| **移除/重命名欄位** | 升版 | `user_id` → `userId` |
| **變更回應結構** | 升版 | 陣列 → 分頁物件 |
| **變更認證方式** | 升版 | Bearer → OAuth2 |

### 棄用流程

1. **通知** (v1.x): 在回應 Header 加入 `Deprecation: true` + `Sunset: 2026-06-01`
2. **文檔標記**: OpenAPI 加入 `deprecated: true`
3. **過渡期**: 至少 3 個月
4. **移除**: 完全移除舊端點

---

## 命名規範

### URL 路徑

```
# ✅ 正確
GET    /v1/hosts                    # 列表
GET    /v1/hosts/{id}               # 單一資源
POST   /v1/hosts                    # 建立
PUT    /v1/hosts/{id}               # 完整更新
PATCH  /v1/hosts/{id}               # 部分更新
DELETE /v1/hosts/{id}               # 刪除

# ✅ 子資源
GET    /v1/hosts/{id}/metrics       # 主機的指標
POST   /v1/hosts/{id}/actions/scan  # 動作 (非 CRUD)

# ❌ 錯誤
GET    /v1/getHosts                 # 動詞命名
GET    /v1/host_list                # 底線 + 複數不一致
POST   /v1/hosts/create             # 冗餘動詞
```

### 查詢參數

```
# 分頁
?page=1&limit=20

# 排序
?sort=created_at&order=desc

# 篩選
?status=active&host_id=h-001

# 搜尋
?q=keyword

# 時間範圍
?start_time=2026-03-01T00:00:00Z&end_time=2026-03-20T23:59:59Z
```

### 請求/回應欄位

```json
// ✅ 正確: camelCase (JSON 標準)
{
  "hostId": "h-001",
  "hostName": "web-server-01",
  "createdAt": "2026-03-20T10:00:00Z",
  "isActive": true
}

// ❌ 錯誤: snake_case (Python 內部使用)
{
  "host_id": "h-001",
  "host_name": "web-server-01"
}
```

---

## 回應格式

### 成功回應

```json
// 單一資源
{
  "data": {
    "id": "h-001",
    "name": "web-server-01",
    "status": "healthy"
  },
  "meta": {
    "requestId": "req-abc123",
    "timestamp": "2026-03-20T10:00:00Z"
  }
}

// 列表 (分頁)
{
  "data": [
    {"id": "h-001", "name": "web-server-01"},
    {"id": "h-002", "name": "web-server-02"}
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 45,
    "totalPages": 3
  },
  "meta": {
    "requestId": "req-abc123",
    "timestamp": "2026-03-20T10:00:00Z"
  }
}
```

### 錯誤回應

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "請求參數驗證失敗",
    "details": [
      {
        "field": "email",
        "message": "必須為有效的電子郵件格式"
      }
    ]
  },
  "meta": {
    "requestId": "req-abc123",
    "timestamp": "2026-03-20T10:00:00Z"
  }
}
```

### 錯誤碼對照表

| HTTP Status | Error Code | 說明 |
|-------------|-----------|------|
| 400 | `VALIDATION_ERROR` | 請求參數驗證失敗 |
| 400 | `INVALID_FORMAT` | 請求格式錯誤 |
| 401 | `UNAUTHORIZED` | 未提供認證資訊 |
| 401 | `TOKEN_EXPIRED` | Token 已過期 |
| 403 | `FORBIDDEN` | 權限不足 |
| 404 | `NOT_FOUND` | 資源不存在 |
| 409 | `CONFLICT` | 資源衝突 |
| 422 | `UNPROCESSABLE_ENTITY` | 語意錯誤 |
| 429 | `RATE_LIMITED` | 請求過於頻繁 |
| 500 | `INTERNAL_ERROR` | 伺服器內部錯誤 |
| 503 | `SERVICE_UNAVAILABLE` | 服務暫時不可用 |

---

## 安全規範

### 認證

```http
Authorization: Bearer <jwt_token>
```

### 必要 Headers

```http
Content-Type: application/json
Accept: application/json
X-Request-ID: <uuid>  # 用於追蹤
X-Source: awoooi      # 識別來源 (Kali Scanner 需要)
```

### 敏感資料處理

```python
# ❌ 禁止: 回應中包含密碼、Token
{
  "user": {
    "password": "hashed_value",  # 禁止
    "apiKey": "sk-xxx"           # 禁止
  }
}

# ✅ 正確: 脫敏處理
{
  "user": {
    "hasPassword": true,
    "apiKeyPrefix": "sk-***xxx"
  }
}
```

### 日誌脫敏

```python
# 自動脫敏欄位
SENSITIVE_FIELDS = [
    "password", "token", "api_key", "secret",
    "authorization", "cookie", "credit_card"
]

# 日誌輸出
# ✅ {"user": "admin", "password": "[REDACTED]"}
# ❌ {"user": "admin", "password": "actual_password"}
```

---

## 快取策略

### TTL 分層

| 資料類型 | TTL | 說明 |
|---------|-----|------|
| 靜態配置 | 1 小時 | 系統設定、選單 |
| 聚合數據 | 5 分鐘 | Dashboard 統計 |
| 即時數據 | 30 秒 | 主機狀態、指標 |
| 無快取 | 0 | 審計日誌、敏感操作 |

### 快取 Key 規範

```
awoooi:{version}:{module}:{resource}:{id}:{params_hash}

# 範例
awoooi:v1:hosts:list:abc123
awoooi:v1:hosts:detail:h-001
awoooi:v1:metrics:dashboard:user-001:7d
```

---

## CI 檢查項目

### 自動化檢查

| 檢查項 | 工具 | 失敗處理 |
|-------|------|---------|
| OpenAPI Schema 驗證 | spectral | 阻擋合併 |
| OpenAPI ↔ 程式碼一致性 | openapi-diff | 阻擋合併 |
| 端點文檔存在性 | 自訂腳本 | 阻擋合併 |
| 測試覆蓋率 > 80% | pytest-cov | 阻擋合併 |
| 安全掃描 | bandit | 警告 |

### PR Checklist

```markdown
## API 變更 Checklist

- [ ] OpenAPI 規格已更新 (`docs/api/openapi.yaml`)
- [ ] 端點文檔已更新 (`docs/api/endpoints/...`)
- [ ] 單元測試已撰寫 (覆蓋率 > 80%)
- [ ] 錯誤處理已實作
- [ ] 快取策略已定義
- [ ] 限流規則已設定
- [ ] 日誌已加入 (不含敏感資料)
- [ ] CISO 已審核 (安全相關 API)
```

---

## 文檔工具

### 內部開發

- **Swagger UI**: `http://localhost:8000/docs`
- 用途: 開發階段測試、除錯

### 對外文檔

- **Scalar**: `https://api.awoooi.wooo.work/scalar`
- 風格: Nothing.tech 純白主題
- 用途: 外部開發者文檔

---

## 變更記錄

| 日期 | 版本 | 變更 | 作者 |
|------|------|------|------|
| 2026-03-20 | v1.0 | 初版建立 | CTO |

---

*此文件由 CTO 維護，API 開發者必須遵守此 SOP。*
