ericwyuan
|
cbbff61082
|
[阶段6] 同步 Garmin 全量数据:31 项日指标 + 奖励 + 个人纪录
原来每天只存 7 个指标,而 get_user_summary 一次就返回 60+ 字段,
另有睡眠分期、训练准备度、耐力分等独立端点从未被调用。
db.py:
- health_data 新增 31 列(距离/活动卡路里/基础代谢/爬楼/强度分钟/
久坐时长/最高最低心率/最大压力/身体电量四项/血氧/呼吸/
睡眠深浅REM清醒分期/睡眠血氧/睡眠呼吸/睡眠压力/训练准备度/
VO2max/耐力分)
- 新增 badges 与 personal_records 两张表,均以 (user_id, garmin_id)
为主键,重复同步更新而非累积
- 新增增量迁移: CREATE TABLE IF NOT EXISTS 对已存在的表不生效,
新列必须显式 ALTER,否则生产库上永远不会出现。按列名比对后
逐个补齐,SQLite 与 MariaDB 都幂等
services/garmin.py:
- _extract_daily 改为汇总 user_summary + sleep + hrv +
training_readiness + training_status + endurance_score 五个端点
- 每个可选端点用 _safe 包裹:某项设备不记录时留 NULL,不影响当天其余数据
- 新增 sync_badges / sync_personal_records(账号级,每次同步取一次)
fix(garmin): 个人纪录整批写入失败
- Garmin 在同一份数据里混用 ISO 字符串和 Unix 毫秒时间戳,
prStartTimeGmt 是 1570961412000,写进 DATETIME 列被 MariaDB
以 1292 拒绝,导致 11 项个人纪录一条都没存进去
- 新增 _to_datetime 统一处理 ISO / 毫秒 / 秒三种形状,并优先取
Garmin 自己提供的 *Formatted 字段
services/ai.py:
- 送给模型的 CSV 从 7 列扩到 23 列,纳入身体电量、血氧、呼吸、
训练准备度、耐力分和睡眠分期
接口: GET /api/health/badges、/api/health/personal-records
tests (+13, 共 292):
- 徽章/纪录的往返、重复同步不累积、按用户隔离
- 两个用户可持有同一个 Garmin 徽章 id 而不冲突
- 时间戳三种形状的归一化及无效值不抛异常
NAS 实测: 7 天数据每天 31 项指标、65 个奖励、11 项个人纪录
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
2026-08-23 20:48:49 +08:00 |
|
ericwyuan
|
8e37e5a551
|
[阶段3.1] pytest 测试基建 + auth/health/analysis 单元测试 - 102 用例全绿
测试基建:
- pytest.ini / requirements-dev.txt
- tests/conftest.py: 每个用例独立 SQLite 库,提供
db / app / client / user / auth / seed_health 六个 fixture
tests/test_auth.py (38 通过, 1 跳过):
- 密码哈希: 加盐唯一性、格式自描述、明文不入库、畸形哈希不抛异常
- 回归用例: 无 scrypt 的解释器上也能哈希(覆盖上一个 commit 的 bug)
- JWT: 过期/换密钥/篡改签名均拒绝
- 登录错误不区分"邮箱不存在"与"密码错误"(防用户枚举)
- require_auth: 缺失/畸形/过期 header 一律 401 而非 500
tests/test_health.py (30 通过):
- 日期范围上下界均为闭区间
- 数据按 user_id 隔离,查不到他人数据
- 重复 upsert 同一天不产生重复行
- 各指标端点正确剔除 NULL 行
tests/test_analysis.py (34 通过):
- 5 条建议规则的阈值边界逐条固化(8000 步 / 7 小时 / 50 压力 /
65 静息心率 / 40 HRV)
- 均值按窗口计算而非逐日;只取最近 14 天
- 无睡眠记录的日子不被当作 0 拉低均值
- metric 名走白名单,SQL 注入串不生效
- 建议按 high/medium/low 排序
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
2026-08-23 12:34:18 +08:00 |
|