Activities API
活動(跑步紀錄)完整 API — CRUD、留言、反應、合併、串流。
GET /activities
取得活動列表。
Headers
| Header | 值 | 必填 |
|---|---|---|
| `x-api-key` | API Key | ✅ |
Query Parameters
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `user_id` | string | ✅ | 使用者 ID |
| `page_size` | int | ❌ | 每頁數量(預設 20,最大 100) |
| `last_created_at` | number | ❌ | 分頁游標(epoch ms) |
| `start_date` | string | ❌ | 開始日期篩選 |
| `end_date` | string | ❌ | 結束日期篩選 |
Response (200)
| 欄位 | 類型 | 說明 |
|---|---|---|
| `activities` | array | 活動列表 |
| `count` | number | 本頁數量 |
| `page_size` | number | 每頁數量 |
Activity 物件
| 欄位 | 類型 | 說明 |
|---|---|---|
| `activity_id` | string | 活動 ID |
| `user_id` | string | 使用者 ID |
| `activity_type` | string | 活動類型(`running`, `walking`, `cycling`, `strength` 等) |
| `running_type` | string | AI 分類的跑步類型(見下方列表) |
| `distance` | number | 距離(公尺) |
| `duration` | number | 時間(秒) |
| `avg_pace` | number | 平均配速(秒/公里) |
| `avg_hr` | number | 平均心率(bpm) |
| `max_hr` | number | 最大心率(bpm) |
| `calories` | number | 消耗卡路里 |
| `avg_cadence` | number | 平均步頻(spm) |
| `elevation_gain` | number | 累計爬升(公尺) |
| `start_time` | number | 開始時間(epoch ms) |
| `end_time` | number | 結束時間(epoch ms) |
| `source` | string | 數據來源(`garmin`, `strava`, `apple_health`, `manual`) |
| `status` | string | 狀態(`completed`, `scheduled`, `merged`) |
| `ai_summary` | object | AI 分析摘要(如有) |
| `image_urls` | array | 活動照片 URL 列表 |
| `likes_count` | number | 按讚數 |
| `comments_count` | number | 留言數 |
| `created_at` | number | 建立時間(epoch ms) |
Running Type 列表
| 值 | 說明 |
|---|---|
| `easy_run` | 輕鬆跑 |
| `long_run` | 長距離跑 |
| `tempo` | 節奏跑 |
| `interval` | 間歇訓練 |
| `race` | 比賽 |
| `recovery` | 恢復跑 |
| `fartlek` | 法特雷克 |
| `hill` | 坡度訓練 |
| `threshold` | 閾值跑 |
| `warm_up` | 熱身 |
| `cool_down` | 收操 |
| `other` | 其他 |
Running type 由 AI 自動分類(`RunningTypeDetector`),不是使用者手動設定的。
GET /activities/{activity_id}
取得單筆活動完整資料。比列表回傳更多欄位。
額外欄位
| 欄位 | 類型 | 說明 |
|---|---|---|
| `splits` | array | 每公里分段數據 |
| `hr_zones` | object | 心率區間分布(Z1-Z5 時間百分比) |
| `laps` | array | 圈數數據(Garmin) |
| `gps_data` | object | GPS 路線數據 |
Split 物件
| 欄位 | 類型 | 說明 |
|---|---|---|
| `distance` | number | 距離(公尺) |
| `duration` | number | 時間(秒) |
| `avg_pace` | number | 配速(秒/公里) |
| `avg_hr` | number | 平均心率 |
POST /activities
建立新活動。
Request Body
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `user_id` | string | ✅ | 使用者 ID |
| `activity_type` | string | ✅ | 活動類型 |
| `distance` | number | ✅ | 距離(公尺) |
| `duration` | number | ✅ | 時間(秒) |
| `start_time` | number | ✅ | 開始時間(epoch ms) |
| `avg_hr` | number | ❌ | 平均心率 |
| `max_hr` | number | ❌ | 最大心率 |
| `avg_pace` | number | ❌ | 平均配速(秒/公里) |
| `calories` | number | ❌ | 卡路里 |
| `source` | string | ❌ | 數據來源 |
| `splits` | array | ❌ | 分段數據 |
Response (201)
{"activity_id": "abc123", "message": "Activity created"}
PUT /activities/{activity_id}
更新活動。Request body 同 POST,所有欄位為選填。
DELETE /activities/{activity_id}
刪除活動。
Response (200)
{"message": "Activity deleted"}
PATCH /activities/{activity_id}/review
教練標記活動為「已審閱」。
PUT /activities/{activity_id}/reschedule
重新安排計畫活動的日期。
Request Body
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `new_date` | string | ✅ | 新日期(YYYY-MM-DD) |
PUT /activities/{scheduled_activity_id}/merge
合併計畫活動與實際活動。
Request Body
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `actual_activity_id` | string | ✅ | 實際完成的活動 ID |
DELETE /activities/scheduled/cancel
取消計畫活動。
POST /activities/{activity_id}/comments
新增活動留言。
Request Body
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `content` | string | ✅ | 留言內容 |
GET /activities/{activity_id}/comments
取得活動留言列表。
DELETE /activities/{activity_id}/comments/{comment_id}
刪除留言。
POST /activities/{activity_id}/like
對活動按讚。
POST /activities/{activity_id}/unlike
取消按讚。
POST /activities/{activity_id}/reactions
新增表情反應。
Request Body
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `emoji` | string | ✅ | 表情符號(例如 `🔥`, `💪`, `👏`) |
DELETE /activities/{activity_id}/reactions
移除表情反應。
GET /activities/{activity_id}/reactions
取得活動的所有表情反應。
GET /activities/streak
取得連續跑步天數。
Response (200)
{"current_streak": 7, "longest_streak": 30}