1. 基础信息

v1.0 2026-10 · PostgreSQL 14 + Node.js 16 + Express 4
Base URL
https://ry.untra.cn/api/v1
服务器
154.94.234.117 · 已配置 SSL
协议
HTTPS / JSON(UTF-8)
认证
JWT Bearer:Authorization: Bearer <token>
Token 有效期
30 天
健康检查
GET /api/v1/health(无需鉴权)

统一响应格式

{ "ok": true,  "data": { }, "msg": "可选提示" }
{ "ok": false, "error": "错误信息" }

HTTP 状态码

码含义
200成功
400参数错误(缺必填项、格式非法)
401未登录 / token 失效或过期
403权限不足(如学员访问教练接口、删除教练布置的计划)
404资源不存在
500服务器内部错误(error 字段含原因)

2. 演示账号

密码统一为 123456,可直接用于 APP 联调。

手机号角色昵称说明
13800000001coach张教练已绑定 4 名会员,有待确认的饮食计划
13800000002student小明有今日训练计划 + 待确认饮食计划(主演示账号)
13800000003student李雷有饮食计划(含海鲜过敏标注)
13800000004student王芳空数据,适合从零跑通流程
13800000005student赵强走读学员

3. 离线同步协议(核心)

架构原则:服务端 PostgreSQL 是唯一权威数据源;本地 SQLite 只是缓存 + 离线暂存。断网时先写本地并压入 sync_queue,联网后批量 push,再用 pull 增量回写。

3.1 POST /sync/push 需登录

// 请求
{
  "items": [
    {
      "table": "weight_records",        // 白名单内的表名
      "record_id": "<uuid>",
      "operation": "upsert" | "delete",
      "base_version": 3,               // 本地上次同步到的服务器 version
      "data": { /* 记录字段 */ }
    }
  ]
}

// 响应
{ "ok": true, "data": { "results": [
  { "record_id": "...", "status": "accepted",          "server_version": 4 },
  { "record_id": "...", "status": "conflict_resolved", "resolution": "server_wins",
    "server_version": 5, "final_data": { /* 服务器最终数据,客户端必须覆盖本地 */ } },
  { "record_id": "...", "status": "rejected",           "error": "..." }
] }}
冲突判定:当 base_version < 服务器当前 version,说明这条记录在客户端离线期间被别人(或另一台设备)改过,判定为冲突,进入裁决。

裁决策略(按表)

表策略说明
body_composition_testsserver体测数据服务器权威,不接受客户端覆盖
notificationsserver除已读状态外均服务器权威
exercise_favoritesserver收藏以服务器为准
training_plans / plan_itemsmerge时间戳差 < 5 秒时做字段级合并(field_merge)
training_sessions / training_session_itemslww时间戳大者胜,5 秒容差内判服务器胜
meal_records / weight_records / checkinslww同上

可同步表白名单:training_plans、plan_items、training_sessions、training_session_items、meal_records、weight_records、body_composition_tests、checkins、notifications、exercise_favorites。不在白名单的表会被 rejected。

3.2 GET /sync/pull?table=&since=&limit= 需登录

since 为毫秒时间戳,limit 默认 500(上限 1000)。返回 records / next_cursor / has_more。客户端把 next_cursor 写入本地 sync_cursor 表。

3.3 GET /sync/bootstrap 需登录

首次安装或本地数据损坏时全量拉取,一次性返回 plans / sessions / dietPlans / bodyTests / enrollments / server_time。

客户端同步流程

1. push 本地 sync_queue 中的所有待同步记录
2. 用返回的 final_data 覆盖本地冲突记录,回写 version / base_version
3. 对每张表 pull(since = 本地 sync_cursor 值)
4. 写入本地 SQLite,推进 sync_cursor
5. 清空已成功的 sync_queue 条目

3.1 认证 /auth

方法路径说明
POST/auth/register注册。body:phone, password, nickname, role, height_cm, gender, birth_date
POST/auth/login登录,返回 token / role / nickname / avatar_url / is_coach_verified
GET/auth/me 登录我的资料
PUT/auth/me 登录修改资料(nickname / avatar_url / height_cm / gender / birth_date)

3.2 动作库 /exercises

服务器权威数据,APP 侧只读缓存。已内置 36 个三级分类 + 48 个动作,动作含 7 大板块(步骤 / 呼吸 / 感受 / 要点 / 常见问题 / 平替动作 / 禁忌人群)。

方法路径说明
GET/exercises/categories三级分类树(大类 > 部位 > 子部位)
GET/exercises?category_id&equipment&difficulty&q&page&size动作列表,支持关键词(名称/目标肌肉)+ 分页
GET/exercises/:id动作详情,alternatives 字段返回平替动作
POST/exercises/:id/favorite 登录收藏 / 取消收藏(幂等切换,返回 favorited)
GET/exercises/favorites/mine 登录我的收藏

3.3 训练计划 /plans

方法路径说明
GET/plans?date&from&to&status 登录计划列表(含 item_count)
GET/plans/today?date 登录今日计划(含动作项明细,首页最常用)
GET/plans/:id 登录计划详情 + items(含动作名称、器械、示范图)
POST/plans 登录学员自建计划,body 含 items 数组
POST/plans/:id/read 登录标记已读(消除"教练改了计划"红点)
DELETE/plans/:id 登录软删除;教练布置的计划返回 403

3.4 训练记录 /sessions

方法路径说明
POST/sessions 登录上传一次完整训练(session + items),支持客户端生成 id 幂等重传
GET/sessions?from&to&page&size 登录历史训练列表
GET/sessions/:id 登录训练详情(含每组明细 + 动作名称)
GET/sessions/report/weekly 登录周维度报表(次数 / 组数 / 时长 / 消耗 / 完成率)
POST body 支持两种写法:{session:{...}, items:[...]} 或扁平 {...session字段, items:[...]}。items 以 (session_id, set_number, exercise_id) 做唯一约束,重复上传会被覆盖而非产生重复数据。

3.5 饮食计划 /diet

方法路径说明
GET/diet/current 登录当前生效的饮食计划
GET/diet 登录我的饮食计划列表
GET/diet/:id 登录计划详情
POST/diet/:id/confirm 登录学员确认/拒绝(accept + reason),结果会推送通知给教练
GET/diet/:id/deliveries?date 登录某日配餐交付明细

饮食计划状态:pending(待学员确认)→ confirmed / rejected。只有 confirmed 的计划热量目标才会计入首页缺口环。

3.6 记餐 /meals

方法路径说明
POST/meals 登录记一餐:meal_type, food_items[], total_calories, protein_g, fat_g, carb_g, photo_url, recorded_at
GET/meals?date 或 ?from&to 登录记餐列表
GET/meals/:id 登录单条详情
DELETE/meals/:id 登录软删除
GET/meals/foods/search?q&category&limit食材营养库搜索(含别名匹配)
GET/meals/foods/pull?since食材库增量拉取(离线缓存用)

3.7 体重 /weights

方法路径说明
POST/weights 登录记录称重:weight_kg, body_fat_pct, source, weighed_at
GET/weights?from&to&limit 登录体重曲线数据
GET/weights/latest 登录最新一次 + delta_vs_prev / delta_vs_first / start_weight_kg
DELETE/weights/:id 登录软删除

3.8 体测与身体状况档案 /body

方法路径说明
POST/body/tests 登录提交体测(体重/体脂/水分/蛋白质/骨量/骨骼肌/BMI/BMR/内脏脂肪/评分)
GET/body/tests 登录体测列表(趋势图数据源)
GET/body/tests/latest 登录最近一次体测
GET/body/tests/:id 登录单条详情
GET/body/profile 登录身体状况档案(慢病 / 关节损伤 / 过敏 / 饮食红线 / 运动禁忌 / 经验)
PUT/body/profile 登录新建或更新档案(全量覆盖)

3.9 营地与打卡 /camp

方法路径说明
GET/camp/sessions营期列表(含已报名人数)
GET/camp/my 登录我参加的营期
POST/camp/sessions/:id/enroll 登录报名(幂等)
GET/camp/checkins?from&to&type 登录打卡记录
POST/camp/checkins 登录打卡:type, ref_id, value, camp_session_id, checked_at
GET/camp/courses团课库
GET/camp/gyms健身房

3.10 通知 /notifications

方法路径说明
GET/notifications 登录我的通知(type:plan_changed / checkin_reminder / meal_confirm / body_test)
GET/notifications/unread-count 登录未读数(红点)
POST/notifications/:id/read 登录标记已读
POST/notifications/read-all 登录全部已读

3.11 首页汇总 /summary

方法路径说明
GET/summary/today?date 登录热量缺口环:target / consumed / burned / deficit / ring_percent + 今日计划
GET/summary/daily?from&to 登录历史日汇总
GET/summary/weekly 登录近 7 天周报(days + totals)
缺口公式:deficit = 目标摄入 − 实际摄入 + 运动消耗;ring_percent = deficit / target × 100(钳制在 0~100)。目标摄入取自已确认的饮食计划,未确认时为 0。

3.12 教练工作台 /coach coach / admin

全部接口需教练或管理员角色,学员访问返回 403。

方法路径说明
GET/coach/todos工作台待办:待确认饮食计划 / 待复核体测 / 今日配餐 / 3 天未打卡会员
GET/coach/members我的会员(含最新体重、起始体重、weight_delta、最后训练/打卡时间)
POST/coach/members/assign绑定会员(member_id, camp_session_id, role)
GET/coach/members/:id会员详情:档案 + 体测 + 体重 + 训练 + 饮食计划
POST/coach/members/:id/plan下发训练计划(含 items),自动推送通知给学员
POST/coach/members/:id/diet-plan下发饮食计划(状态 pending,等学员确认)
GET/coach/body-tests/pending待复核体测列表
POST/coach/body-tests/:id/confirm复核体测(写入 AI 解读 + 下次体测日期)
GET/coach/meal-deliveries?date某日配餐交付列表
POST/coach/meal-deliveries创建配餐(含食材、重量、做法、冷藏温度、标签、保质期、过敏核对)
POST/coach/meal-deliveries/:id/status更新状态:preparing / delivered / rejected
GET/coach/templates计划模板(我的 + 公开)
POST/coach/templates创建模板
PUT/coach/templates/:id更新模板
DELETE/coach/templates/:id删除模板

3.13 上传 /upload

方法路径说明
POST/upload 登录base64 上传(filename, mime, base64,≤10MB),返回 /uploads/xxx.jpg,通过 https://ry.untra.cn/uploads/ 访问
POST/upload/food-annotation 登录提交食物照片进 AI 标注队列(photo_url, ai_result),等教练复核

4. 服务端数据表清单

表用途同步方式
users用户(student / coach / admin)服务端
exercise_categories / exercises三级分类 + 48 个动作库服务端权威,APP 只读缓存
exercise_favorites动作收藏双向(server 优先)
training_plans / plan_items训练计划与动作项双向(merge)
plan_templates教练计划模板服务端
training_sessions / training_session_items训练记录与每组明细双向(lww)
diet_plans饮食计划(教练下发 → 学员确认)服务端
meal_deliveries配餐交付服务端
meal_records记餐双向(lww)
weight_records称重双向(lww)
body_composition_tests体测双向(server 优先)
health_profiles身体状况档案服务端
checkins打卡双向(lww)
camp_sessions / camp_enrollments营期与报名服务端
coach_member_assignments教练-会员绑定服务端
notifications通知提醒双向(server 优先)
daily_calorie_summary热量缺口日汇总服务端计算
food_nutrition_db食材营养库(22 条)服务端权威
training_courses / gyms团课 / 健身房服务端
food_ai_annotations食物 AI 标注队列服务端
audit_log审计日志(不可变)服务端
同步元数据:服务端每条可同步记录都带 version(更新时数据库触发器自增)、updated_at、updated_by、deleted_at(软删除,永不物理删除)。本地 SQLite 额外带 base_version、server_updated_at、sync_status。

5. 运维与部署

# 服务控制
systemctl status|restart|stop blazecamp-api
journalctl -u blazecamp-api -f

# 数据库直连
PGPASSWORD=<数据库密码> psql -h 127.0.0.1 -U blazecamp -d blazecamp

# 目录
/opt/blazecamp-api           # server.js / src / .env / node_modules
/opt/blazecamp-api/sql       # 01_schema.sql / 02_addendum.sql / 03_seed.sql
/opt/blazecamp-api/uploads   # 上传文件

# nginx
/etc/nginx/conf.d/yunchuang.conf   # /api/v1/ → 127.0.0.1:8788;/api/ 仍指向既有 Python 服务

一键重新部署(本地执行)

cd deploy
python deploy.py    # 打包上传代码 + 执行 SQL + npm install + 重启服务 + 注入 nginx 配置
python verify.py    # 17 项接口冒烟
python e2e.py       # 端到端业务链路(记餐→称重→训练→同步→缺口环→教练下发)
上线前必做:① 修改 .env 里的 JWT_SECRET;② 修改数据库密码并同步 .env 的 DB_PASS;③ 删除或修改演示账号;④ 为 /api/v1/ 增加限流(当前未做);⑤ 确认 audit_log 定期归档策略。