跳轉到

API 規格

API 概述

Base URL

Production:  https://api.solidfocus.com/v1
Staging:     https://api-staging.solidfocus.com/v1
Development: http://localhost:8000/v1

注意:Base URL 為預想值,需與 SolidFocus RD 團隊確認。

架構設計 (v3.0)

離線優先設計 (Offline-First Design):

  • APP 是運動數據的真實來源 (Source of Truth)
  • Server 扮演歸檔與同步協調者角色 (「數據歸檔中心」)
  • APP 在本地計算所有指標 (卡路里、距離、XP)
  • 使用批次上傳策略進行 session 同步
  • Store-and-Forward 模式:APP 先寫入本地 SQLite,上線後再同步

核心原則:

  • 離線優先 (Offline First):APP 是第一個資料儲存點 (Source of Truth)
  • 異質數據標準化:使用 PostgreSQL JSONB 儲存異質裝置數據 (bike, rower, treadmill)
  • 儲存後轉發 (Store-and-Forward):APP 總是先寫入本地 DB,之後批次同步

以下項目尚未定義 - 需要討論:

  • Content-Type 格式 (假設為 JSON)
  • 日期/時間格式 (假設為 ISO 8601 UTC)
  • Request/Response body 結構
  • 錯誤回應格式
  • HTTP status codes
  • Authentication header 格式

狀態:這些項目應與 SolidFocus RD 團隊討論並達成共識。


身份驗證與授權

預設的身份驗證方式

  • JWT (JSON Web Token) 為基礎的身份驗證
  • Bearer token scheme (預設)
  • Access token + Refresh token 模式 (預設)

狀態:需與 SolidFocus RD 團隊確認:

  • Token 格式與 claims
  • Token 過期時間
  • Authorization header 格式
  • Token 撤銷機制

身份驗證 APIs

目前定義了以下身份驗證端點與描述。尚未提供 request/response 格式

Method Endpoint 客戶描述
POST /auth/register 帳號註冊 (僅限 Email/Password)
POST /auth/login 帳號登入 (回傳 JWT)
POST /auth/password/request-reset 忘記密碼 (寄送驗證碼/信件)
POST /auth/password/reset 重設密碼 (帶入驗證碼)
POST /auth/sso/{provider} SSO 登入 (provider = apple/google/facebook)
POST /auth/logout 登出 (撤銷 Refresh Token)
POST /auth/refresh 刷新 Access Token

POST /auth/sso/{provider} 補充說明 (2025-01-20 更新):

首次 SSO 登入行為(詳見 03.3 Flow 2):

  • Server 檢查 Apple ID/Google ID 是否已註冊
  • 若不存在:自動建立新帳號(gdpr_consent_given = FALSE
  • 建立裝置綁定(bound_device_id = device_id
  • 產生 JWT tokens

Response 必須包含的欄位

  • user_profile.gdpr_consent_given:是否已同意 GDPR consent
  • user_profile.gdpr_consent_version:Consent 版本
  • user_profile.gdpr_consent_date:Consent 時間戳記

  • is_new_user:是否為首次 SSO 登入(Server 剛建立新帳號)

    • true:首次 SSO 登入,Server 剛建立新帳號
    • false:既有使用者,帳號已存在

is_new_user 欄位用途

App 端需要此欄位來判斷使用者不同意 Consent 時是否要刪除帳號:

  • is_new_user = true + 不同意 → 刪除剛建立的帳號(避免孤兒帳號)
  • is_new_user = false + 不同意 → 保留帳號,僅清空 Local 資料(既有使用者可能改變心意)

GDPR Consent 流程:

  • App 端在登入後檢查 gdpr_consent_given(Flow 2 步驟 6)
  • 若為 FALSE:顯示阻擋式 Consent 對話框
  • 使用者同意後:呼叫 POST /users/me/gdpr/consent 更新 consent 狀態
  • Server 建立 UserConsent 稽核記錄
  • 使用者不同意時:根據 is_new_user 決定是否刪除帳號(詳見 03.3 Flow 2

使用者 APIs

目前定義了以下使用者端點與描述。尚未提供 request/response 格式

Method Endpoint 客戶描述
GET /users/me 取得個人資料 (含 UserStat 與 GDPR consent 狀態)
PATCH /users/me 更新身高、體重、暱稱、性別
PATCH /users/me/stats 同步累計數據 (強制以 APP 端的累計里程/XP/等級覆蓋伺服器)
POST /users/me/avatar 上傳大頭貼
GET /users/me/gdpr/consent 檢查使用者的 GDPR consent 狀態與版本
POST /users/me/gdpr/consent 記錄使用者的 GDPR consent (建立 UserConsent 記錄)
POST /users/me/gdpr/delete-account 請求刪除帳號 (硬刪除所有雲端資料)

課程 APIs

目前定義了以下課程端點:

Method Endpoint 客戶描述
GET /trainings 取得課程列表 (支援設備篩選、分頁)
GET /trainings/{id} 取得單一課程詳細設定
  • 支援使用 device_type 參數篩選
  • 回傳課程 metadata,包含影片 URLs
  • 使用 JSONB 儲存彈性的 settingsdetail 欄位 (參見資料庫 schema)

運動紀錄 APIs

目前定義了以下 session 端點:

Method Endpoint 客戶描述
POST /sessions/batch_upload 批次同步 離線生成的運動紀錄
POST /sessions 單筆運動紀錄上傳
GET /sessions 取得歷史運動列表
GET /sessions/{id} 取得運動詳情 (含曲線圖數據)
DELETE /sessions/{id} 刪除運動紀錄

規格架構設計:

冪等性設計 (Idempotency Design):

  • APP 產生 client_session_uuid (UUIDv4)
  • Server 在建立前檢查 client_session_uuid 是否已存在
  • 重複上傳回傳成功 (冪等行為)

批次上傳流程 (來自客戶 sequence diagram):

APP → POST /sessions/batch_upload
     Header: X-Idempotency-Key (規格中提及)

Server 檢查 client_session_uuid
├─ 已存在 → 200 OK (忽略寫入)
└─ 新紀錄 → 201 Created → 更新 UserStats

離線優先模式 (Offline-First Pattern):

  • APP 在本地儲存 sessions,狀態為 Status: PENDING
  • 網路可用時批次上傳
  • 上傳成功後標記為 Status: SYNCED

資料庫 Schema (WorkoutSession model):

  • 使用 PostgreSQL JSONB 儲存裝置無關的 metrics 資料
  • 欄位:client_session_id, device_type, source_type, metrics_summary, time_series_data
  • 完整 schema 請參見 資料模型

Meta APIs

目前定義了以下 meta 端點:

Method Endpoint 客戶描述
GET /meta/schemas 取得各器材 (Rower/Bike) 的數據欄位定義 (供 VUE 後台動態渲染)
GET /meta/app_version 檢查 APP 是否需要強制更新
GET /meta/gdpr/consent-text 取得目前的 GDPR consent 文字與版本

用途:

  • /meta/schemas:提供裝置特定的欄位定義,供後台管理介面動態渲染使用
  • /meta/app_version:檢查版本,判斷是否需要強制更新 APP
  • /meta/gdpr/consent-text:提供最新的 consent 文字與版本號,供 App 顯示 GDPR 同意對話框使用

GDPR 合規說明

App 將在歐盟上架,因此必須符合 GDPR (通用資料保護規則) 合規要求。

核心要求

  1. 首次使用明確同意:使用阻擋式 consent 對話框,使用者必須明確同意才能使用 App
  2. 帳號刪除功能:提供硬刪除所有雲端資料的功能
  3. 刪除稽核日誌:保留刪除行為的稽核記錄,用於合規證明

API 整合方式

SSO 登入 API 回應

  • POST /auth/sso/{provider} 回應包含:
    • gdpr_consent_given (boolean)
    • gdpr_consent_version (string)
    • gdpr_consent_date (timestamp)
    • is_new_user (boolean) - 是否為首次 SSO 登入

使用者資料 API 回應

  • GET /users/me 回應包含相同的 GDPR consent 欄位
  • App 根據 gdpr_consent_given 決定是否顯示阻擋式 consent 對話框

核心流程

1. Consent 同意流程:

使用者登入
檢查 gdpr_consent_given
如果為 false → 顯示阻擋式 consent 對話框
使用者點擊「同意」
呼叫 POST /users/me/gdpr/consent
更新 User.gdpr_consent_given = true
建立 UserConsent 稽核記錄
允許使用 App

2. 帳號刪除流程:

使用者進入設定頁面
點擊「刪除帳號」
輸入 "DELETE" 確認
呼叫 POST /users/me/gdpr/delete-account
Backend 立即執行刪除(同步):
  1. 建立 DeletionRequest 記錄 (status: pending)
  2. Atomic Transaction:
     - 刪除所有 WorkoutSession 記錄
     - 刪除 UserStats 記錄
     - 刪除所有 SocialAccount 記錄
     - 刪除所有 UserConsent 記錄
     - 刪除 User 記錄
     - 更新 DeletionRequest (status: completed, completed_at)
     - 將 tokens 加入黑名單
  3. Transaction 提交
回傳 200 OK
使用者立即登出 (token 失效)

錯誤處理:
  - Transaction 失敗 → 回滾
  - 更新 DeletionRequest (status: failed)
  - 回傳 500 錯誤

資料模型

GDPR 相關的資料模型包含:

  • User Model 新增欄位:gdpr_consent_givengdpr_consent_versiongdpr_consent_date
  • UserConsent Model:記錄每次 consent 的稽核日誌
  • DeletionRequest Model:記錄帳號刪除請求的稽核日誌

完整 schema 請參見 資料模型


內容總結

目前已定義:

  1. Endpoint 路徑與 HTTP methods
  2. 高階描述 (中文)
  3. 資料庫 schema (SQLModel classes 與欄位型別)
  4. 架構概念 (Offline-First, Store-and-Forward, JSONB 使用)
  5. Sequence diagram 顯示同步流程

尚未定義:

  1. Request body 結構
  2. Response body 結構
  3. HTTP status codes (200, 201, 400, 403, etc.)
  4. 錯誤回應格式
  5. 錯誤代碼 (例如:validation_error, duplicate_session)
  6. Header 需求 (除了提及 X-Idempotency-Key)
  7. 分頁細節
  8. Query parameter 格式