2026-04-24 18:21:28 +09:00

365 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# API Spec
本文件定義 File Access Agent 對外 API 邊界,以及它依賴的 Member Center File Access 授權契約。
目前狀態:
- File Access Agent API本文件定義為本專案目標契約。
- Member Center File Access API`../member_center/docs/openapi.yaml` 與相關文件整理,作為本專案整合依據。
## 0. 部署與資料假設
- Single-tenant instance一個 File Access Agent instance 只服務一個 tenant。
- 服務啟動時需設定固定 `INSTANCE_TENANT_ID`;所有請求中的 `tenant_id`token 或 validation 結果)都必須與此值一致。
- 預設無 DB服務維持 stateless。
- Metadata 讀取以 bucket provider 為主,不以本地 DB 作為權威來源。
- 若未來出現審計、replay 防護或特殊索引需求,可再加可選持久化層。
## 1. 角色分工
### File Access Agent
負責:
- 驗證 upload 用的 Member Center JWT access token
- 接收檔案上傳、下載、metadata 查詢、刪除
- 對 delegated download token 向 Member Center 做線上驗證
- 控制實際 bucket / file space 存取
不負責:
- OAuth client 管理
- access token 簽發
- delegated download token 簽發
- 商業規則判斷與版本管理
- 結構化查詢或 metadata 主資料治理
### Member Center
負責:
- 簽發 upload 用的 S2S JWT access token
- 簽發 delegated short-lived opaque download token
- 提供 delegated token validation endpoint
## 2. 授權模型
### 2.1 Upload
- token 來源Member Center `client_credentials`
- audience`file_access_api`
- 必要 scope`files:upload.write`
- 必要 claim`tenant_id`
- 驗證方式File Access Agent 以 Member Center JWKS 驗簽 JWT
### 2.2 Download
- token 來源:業務服務以 `files:download.delegate` 呼叫 Member Center 申請
- token 類型delegated short-lived opaque token
- token 需綁定:
- `tenant_id`
- `user_id`
- `file_id``object_key`
- `method=GET`
- 短效 `exp`
- 驗證方式File Access Agent 呼叫 Member Center validation endpoint 線上驗證
### 2.3 Metadata
建議沿用 upload 類型的 S2S JWT
- audience`file_access_api`
- 必要 scope`files:metadata.read`
- 必要 claim`tenant_id`
### 2.4 Delete
建議沿用 upload 類型的 S2S JWT
- audience`file_access_api`
- 必要 scope`files:delete`
- 必要 claim`tenant_id`
## 3. File Access Agent API
Base path 暫定:`/`
### 3.1 Upload File
- Method: `PUT`
- Path: `/files/{objectKey}`
- Auth: `Bearer` JWT
- Required scope: `files:upload.write`
用途:
- 由業務服務上傳檔案到 File Access Agent
Path parameters
- `objectKey`URL-encoded object key
Headers
- `Authorization: Bearer <access_token>`
- `Content-Type: <mime-type>`
Optional headers
- `X-File-Id: <string>`
Request body
- binary stream
Validation
- JWT signature / `iss` / `aud=file_access_api` / `exp`
- token `tenant_id`
- `scope=files:upload.write`
- request `objectKey` 是否符合允許的 tenant 邊界策略
Object key 命名建議(介接規範):
- Agent 不做複雜命名治理,`objectKey` 由介接服務自行決定。
- 建議 key 結構:`{domain}/{entity}/{yyyy}/{MM}/{dd}/{id-or-uuid}/{sanitized-filename}`
- 建議至少包含一個高唯一性段(例如 `uuid` 或資料庫主鍵),避免只用原始檔名。
- 建議避免使用空白、反斜線與 `..`;上傳前先做檔名 sanitize保留副檔名
- 建議全部使用小寫與固定分隔字元(`/``-`),便於跨服務對齊。
避免重複檔名與版本策略(責任邊界):
- 若上傳相同 `objectKey`Agent 視為覆蓋overwrite不自動做版本保留。
- Agent 不負責「同名檔案改名」或「自動遞增版本號」。
- 若要避免覆蓋,介接服務應在上傳前自行產生新 key例如 `timestamp + uuid`)。
- 若要做版本管理,請由介接服務把每個版本寫成不同 `objectKey`(例如 `.../v0001/...``.../v0002/...`)。
- 若要保留「原始檔名查詢」能力,請在介接服務自己的資料表維護 `display_name -> objectKey` 對照。
Responses
- `201 Created`
- `400 Bad Request`
- `401 Unauthorized`
- `403 Forbidden`
- `409 Conflict`
- `413 Payload Too Large`
Success body
```json
{
"tenant_id": "uuid",
"file_id": "optional-string",
"object_key": "reports/2026/04/file.pdf",
"content_type": "application/pdf",
"size": 12345,
"etag": "optional-string",
"last_modified_at": "2026-04-24T03:10:00Z"
}
```
### 3.2 Download File
- Method: `GET`
- Path: `/files/{objectKey}`
- Auth: delegated download token
用途:
- 由 client 使用 delegated token 下載檔案
Path parameters
- `objectKey`URL-encoded object key
Headers
- `Authorization: Bearer <delegated_download_token>`
Validation
- 將 token 與實際 `tenant_id + file_id/object_key + method=GET` 邊界送到 Member Center validation endpoint
- validation 成功後才允許下載
Responses
- `200 OK` with file stream
- `401 Unauthorized`
- `403 Forbidden`
- `404 Not Found`
### 3.3 Get File Metadata
- Method: `GET`
- Path: `/files/metadata/{objectKey}`
- Auth: `Bearer` JWT
- Required scope: `files:metadata.read`
用途:
- 由業務服務讀取檔案 metadata不回傳檔案內容
Responses
- `200 OK`
- `401 Unauthorized`
- `403 Forbidden`
- `404 Not Found`
Success body
```json
{
"tenant_id": "uuid",
"file_id": "optional-string",
"object_key": "reports/2026/04/file.pdf",
"content_type": "application/pdf",
"size": 12345,
"etag": "optional-string",
"last_modified_at": "2026-04-24T03:10:00Z"
}
```
### 3.4 Head File
- Method: `HEAD`
- Path: `/files/{objectKey}`
- Auth: `Bearer` JWT
- Required scope: `files:metadata.read`
用途:
- 提供較輕量的 existence / metadata header 檢查
Responses
- `200 OK`
- `401 Unauthorized`
- `403 Forbidden`
- `404 Not Found`
### 3.5 Delete File
- Method: `DELETE`
- Path: `/files/{objectKey}`
- Auth: `Bearer` JWT
- Required scope: `files:delete`
用途:
- 由業務服務刪除檔案
Responses
- `204 No Content`
- `401 Unauthorized`
- `403 Forbidden`
- `404 Not Found`
### 3.6 Health
- Method: `GET`
- Path: `/health`
- Auth: none
用途:
- liveness / readiness 的最小檢查
Responses
- `200 OK`
Success body
```json
{
"status": "ok"
}
```
## 4. 與 Member Center 的整合 API
以下端點不屬於本專案提供,但 File Access Agent 需要依賴。
### 4.1 Issue Delegated Download Token
- Provider: Member Center
- Method: `POST`
- Path: `/file-access/download-tokens`
- Required scope: `files:download.delegate`
Request body
```json
{
"tenant_id": "uuid",
"user_id": "uuid",
"file_id": "optional-string",
"object_key": "reports/2026/04/file.pdf",
"method": "GET",
"expires_in_seconds": 300
}
```
Response body
- 由 Member Center 定義;目前至少會回傳 delegated download token 與到期資訊
### 4.2 Validate Delegated Download Token
- Provider: Member Center
- Method: `POST`
- Path: `/file-access/download-tokens/validate`
- Required scope: `files:download.read`
Request body
```json
{
"token": "opaque-token",
"tenant_id": "uuid",
"file_id": "optional-string",
"object_key": "reports/2026/04/file.pdf",
"method": "GET"
}
```
Response body
- 由 Member Center 定義;目前至少需包含 validation success / active 狀態與對應邊界資訊
## 5. 共通錯誤格式
建議本專案統一採用:
```json
{
"error": "string_code",
"message": "human readable message",
"request_id": "uuid"
}
```
建議錯誤碼:
- `invalid_token`
- `insufficient_scope`
- `tenant_mismatch`
- `object_key_mismatch`
- `method_mismatch`
- `file_not_found`
- `payload_too_large`
- `unsupported_media_type`
- `storage_unavailable`
## 6. 待補細節
- `tenant_id` 從 request path、header 或 object key prefix 如何對齊
- `file_id` 是否作為正式主 key或僅保留 `object_key`
- `HEAD /files/{objectKey}` 是否保留,或改以 `GET /files/metadata/{objectKey}`
- upload 是否需要支援 overwrite 策略 header
- 下載是否要支援 `Range` request
- metadata / delete 是否允許 delegated token或只接受 S2S JWT
- 可選持久化是否需要最小 audit / jti 表(預設不啟用)