Commit Graph

5 Commits

Author SHA1 Message Date
ericwyuan
1c48435b9d chore(deploy): NAS 的 ssh 端口是 2222
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 09:05:35 +08:00
ericwyuan
41b7ae82e4 fix(sync): 「全部历史」真的拉全部历史,自动同步不再每次静默失败
四个独立的 bug 叠在一起,表现为「只同步两天、没有进度」:

* 前端 `...(days ? { days } : {})` 把 days=0 当成未传。「全部历史」
  存的就是 0,请求体里根本没有 days,后端退回 7 天默认值。
* scheduler 用 `s[0]` 读 query_one 返回的 dict,抛 KeyError 后被
  per-account 的 except 吞掉。只要用户存过一次设置,每 30 分钟的
  自动同步就一次都没成功过——库里那 2 天全是手动点出来的。
* 增量同步查 `health_daily`(表其实叫 health_data),后台线程直接
  死掉,状态永远卡在 syncing,进度条不动。
* UI 完全不看 /sync 的返回值,rate_limited 时按钮点了没反应;轮询
  结束时又把 rate_limited 归进 else 分支报「同步完成」。

顺带:
* 日循环遇到 429 立即退避并保留已拉到的天数,而不是当成「跳过一天」
  继续往下捶 700 天——这正是之前限流死循环的来源之一。
* 定时循环显式传 SYNC_DAYS。历史范围按 UI 文案只描述手动全量同步,
  让半小时一次的 tick 重拉 730 天必然把限流撞得更深。
* 短同步逐天上报进度(原来每 5 天一次,7 天的同步全程停在 0)。
* /sync 路由重复解析 body,空 body 会 None.get 崩。
* 4 个 StubGarth 缺 configure(),7 个测试在此之前一直是红的。

新增 deploy/push.sh:NAS 只认密码,脚本开一个 ssh 复用连接,密码只
输一次,后面推送 / 重启 / 健康检查全走它。不碰 .env、.venv 和数据库。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 08:11:24 +08:00
ericwyuan
15fba8c25c feat: NAS 部署 + auth-hub 认证 + 同步逻辑修复
部署:
- 后端 Python/Flask,数据层可插拔 SQLite/MariaDB
- NAS 部署路径 /volume1/web/garmin-health-lab,端口 8124
- Gunicorn 生产服务器 (2 workers / 4 threads)
- 开机自启脚本 deploy/S99garmin.sh
- frp 隧道甲骨文 8124 → NAS 8124,外网访问
- 前端构建产物纳入版本管理 (backend/static/)

认证:
- auth-hub OAuth2/OIDC 统一登录接入
- 新建 NAS 专用 client,注册内外网回调地址
- 前端 LoginPage 支持回调路由 /auth/callback
- 数据同步页增加 Garmin 邮箱输入框

同步逻辑修复:
- 自动同步调度器读取用户 history_days 设置,不再固定 2 天
- 前端 0(全部历史)不再被 || 吞掉,改为 ?? 处理
- 后端路由和 sync_data 中 0 不再被当成 falsy 回退默认值
- sync_data 和调度器中 0 → 730 天(全部历史=最大范围)
- 已同步天数显示数据库实际总天数 (totalDays)
- 历史范围新增「自上次同步」增量选项 (days=-1)
- 后端 settings.py HISTORY 添加 -1 值

项目文档:
- 创建 PROGRESS.md 跟踪项目进度
2026-09-01 07:39:09 +08:00
ericwyuan
283d530f82 fix(deploy): 启动脚本等端口真正释放,并确认服务可用后才报成功
上一次部署里旧 worker 没随 master 退出,一直占着 8123。新 master 启动、
打印 started、然后什么都不服务——日志每一行看起来都正常,站点却是挂的。

- stop.sh 等进程真正退出,超时后 -9
- start.sh 停完等端口释放,起来后 curl 健康检查通过才算成功,否则返回非零

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-24 04:23:05 +08:00
ericwyuan
6de7562cd8 [阶段5.1] 开机自启 + 接入真实 garminconnect,修复同步的三处 API 误用
fix(garmin): 同步代码调用的 garminconnect API 全是错的

装上库核对签名后发现(garminconnect 0.2.8),原代码从未被真正
执行过,三处调用都不成立:

1. get_activities(date) —— 该方法签名是 (start, limit),收的是
   分页下标和条数,不是日期。传日期等于在问"第 2026-08-23 条运动",
   而且少传一个参数必然 TypeError。
   改为 get_activities_by_date(start, end),整个窗口一次取回,
   顺带把原来"每天一次调用"减为一次。

2. 睡眠数据不在 get_user_summary 里,是独立的 get_sleep_data(cdate);
   原代码从 summary 里读 sleep 字段,结果会把每一晚都记成无睡眠数据。
   HRV 同理,走 get_hrv_data(cdate)。

3. 字段名不符:实际是 totalSteps / totalKilocalories /
   averageStressLevel,原代码用的是 steps / calories.total /
   stress.average。

其他改进:
- 运动记录改用 Garmin 自己的 activityId 作主键,重复同步同一窗口
  不再产生重复行(原来每次同步都会把同一条运动再插一遍)
- 某天无数据时返回全 None,不再写入空行让读端点再过滤掉
- 原来 bare except 吞掉每天的异常,全部失败也报 success;
  现在全窗口失败会如实返回 error 并记录原因
- 同步天数、是否走 Garmin 中国区改为环境变量可配

tests/test_garmin_sync.py (23 通过):
- 用 StubClient 模拟真实 0.2.8 的接口形状,无需库、凭证或网络
- 回归用例覆盖上述三处误用:活动必须按日期区间一次取回、
  睡眠与 HRV 必须走各自端点
- 重复同步不产生重复的天和重复的运动记录
- 单天失败跳过、全窗口失败报错、登录失败如实上报

部署:
- NAS 安装 garminconnect(pydantic-core 有 cp38 x86_64 轮子,
  无需 gcc)
- 新增 deploy/S99garmin.sh 开机自启脚本,与 NAS 上既有的
  S99frpc.sh 同一套惯例;以 root 启动但降权到 ericwyuan 运行,
  因为服务不需要特权而 .env 里有数据库和 API 凭证
- PID 文件放应用目录而非 /var/run(非特权用户写不了)

NAS 真机全量测试: 240 passed

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-23 19:05:19 +08:00