# 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 ` - `Content-Type: ` Optional headers: - `X-File-Id: ` 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 ` 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 表(預設不啟用)