Files
GarminHealthLab/PROGRESS.md
ericwyuan 9d6ebbe422 ops: 生产从 NAS 整体迁移到甲骨文云主机
NAS 局域网 IP 因重启被 DHCP 换过两次,磁盘/网络稳定性都不如已经跑着好几个
生产服务的甲骨文机器。整体搬迁:应用 + 数据库都搬走,NAS 只保留 Gitea(这个
仓库的源码托管,未动)。

## 迁移过程(已核对无损)

- MariaDB:NAS 导出(10.11 源库,处理了只有新版本才有的 `/*M!999999` 注释)
  → 导入甲骨文 MariaDB 10.3.39,**20 张表逐条精确 COUNT(*) 比对完全一致**
- 冻结 NAS(停服务)后又 dump 一次核对,确认期间零数据差异,才继续删库
- NAS `garmin_health_lab` 已 DROP DATABASE,备份在本地
  `~/Desktop/Work/backups/garmin_health_lab_nas_backup_20260912.sql.gz`
- 应用部署到 `/opt/garmin-health-lab`,systemd 单元(`ubuntu` 用户,非
  root),和这台机器上的 ai-gateway/auth-hub 同一套约定
- 公网:`https://garmin.zichuan.xyz`,DNS + Caddy 反代 + 自动 TLS,替代原来
  `NAS frpc → 甲骨文:8124` 那条隧道(已从 NAS 的 frpc.toml 精确删除对应段,
  其它转发未动,改完逐条复检过没打断)
- auth-hub 回调地址换成新域名,NAS/旧端口那几条历史回调已清掉
- AI 网关配置改本地回环(网关现在同机了),触发真实生成验证过

## 一个当场拦下来的风险

甲骨文部署完默认开着自动同步。迁移窗口期两边并行跑时,若两边的调度器同时去
刷新 Garmin 令牌,会撞上按账号计算的 SSO 限流(`GarminHealthLab` 仓库
2026-09-03 那次事故的根因,那次修复花了一整天)。确认账号级 auto_sync 设置
本来是关的、这次算侥幸没撞上——不是设计上的保险,所以迁移期间显式在甲骨文这边
加了 `AUTO_SYNC=false`,直接在运行进程里验证过生效,确认 NAS 已冻结、数据无
缺口后才打开。

## 文档 / 脚本同步

CLAUDE.md 明确写过"部署位置会变,排障前先查、不要凭记忆"——这次是第二次踩中
同一类问题(上次是"NAS 有没有生产环境"判断错),所以把 CLAUDE.md / PROGRESS.md
/ README.md / docs/* 里的部署事实全部更新,NAS 时代的 `deploy/` 脚本加废弃
说明保留参考、不删除,新增 `deploy/push_oracle.sh`(当场跑通一次真实部署)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 23:53:15 +08:00

211 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Garmin Health Lab — 项目进度
## 已完成
### 部署
- [x] 后端从 Node.js 重构为 Python/Flask
- [x] 数据层可插拔:开发用 SQLite生产用 MariaDB
- [x] Gunicorn 生产服务器配置2 workers / 4 threads
- [x] ~~部署到本地 NAS`/volume1/web/garmin-health-lab`),端口 8124~~ 已下线,见下
- [x] ~~frp 隧道配置,通过甲骨文公网 IP 外网访问(`http://129.146.26.249:8124`~~ 已拆除
- [x] ~~开机自启脚本(`deploy/S99garmin.sh`~~ 已移除,脚本保留仅供参考
- [x] ~~甲骨文 iptables 放行 8124 端口~~ 该端口不再使用
### 迁移到甲骨文云主机2026-09-12
NAS 的局域网 IP 因 DHCP 重启换过两次(`.64``.65` → 又变回 `.64`),且磁盘/
网络都不如已经稳定跑着好几个服务的甲骨文机器可靠。整体搬迁NAS 只保留 Gitea
(这个仓库的源码托管,未动)。
- [x] 甲骨文本机新建 MariaDB 库 `garmin_health_lab` + 独立账号 `garmin`(同时建
`garmin@localhost``garmin@127.0.0.1` 两个 host 变体、同密码——MariaDB 视
为两个不同账号,只建一个会导致 TCP 连接失败)
- [x] NAS `mysqldump`10.11 源库,处理了 `/*M!999999` 注释兼容 10.3 目标)→
导入甲骨文 MariaDB 10.3.39**20 张表逐条精确 `COUNT(*)` 比对完全一致**才继续
- [x] 应用部署到 `/opt/garmin-health-lab`systemd 单元 `garmin-health-lab.service`
`ubuntu` 用户,非 root和 ai-gateway/auth-hub 同一套约定)
- [x] DNS腾讯云 DNSPod API 新增 `garmin.zichuan.xyz` A 记录Caddy 反代 +
自动签发 TLS实测已生效
- [x] auth-hub 回调地址改为 `https://garmin.zichuan.xyz/auth/callback`,清掉
NAS/旧公网端口那几条历史回调
- [x] AI 网关配置从公网域名改本地回环 `http://127.0.0.1:5100/v1`(网关和本服务
现在同机),**触发真实生成验证通过**`upstream: gemini`
- [x] 迁移窗口期加了安全阀:甲骨文这边先 `AUTO_SYNC=false`,避免和 NAS 的调度
器同时刷新 Garmin 令牌撞上按账号计算的 SSO 限流(见下方"同步逻辑修复"一节
09-03 那次事故)。确认 NAS 已冻结、数据无缺口后才在甲骨文打开
- [x] 冻结 NAS停 gunicorn→ 补一次终态 dump 核对无数据差异 → 移除开机自启
`DROP DATABASE garmin_health_lab`(备份在本地
`~/Desktop/Work/backups/garmin_health_lab_nas_backup_20260912.sql.gz`
- [x] NAS frpc 配置精确删除 `garmin-health` 转发段,`gitea`/`wordpress`/
`fam-core`/`nexusai` 几条未动,改后逐条复检确认其它站点未受影响
- [x] 新部署脚本 `deploy/push_oracle.sh`key 认证 + systemd校验 PID 变化 +
health 200落地当场跑通一次真实部署
- [x] `CLAUDE.md` 部署章节整体重写NAS 时代的 `deploy/` 脚本加了废弃说明保留
参考,未删除
### 认证
- [x] auth-hub 统一登录接入OAuth2 / OIDC
- [x] 新建 NAS 专用 client`client_id: 996aLPw4T5gl-rYZ`
- [x] 注册 NAS 回调地址 `http://192.168.50.64:8124/auth/callback` 和公网地址 `http://129.146.26.249:8124/auth/callback`
- [x] JWT 令牌签发与验证
- [x] Garmin OAuth 令牌授权(密码不入库,令牌约一年有效)
### 后端功能
- [x] Garmin 数据同步核心逻辑(`services/garmin.py`
- [x] 后台自动同步调度器(`services/scheduler.py`
- [x] 用户设置:身高/体重/出生日期/性别/单位/同步频率/历史范围(`services/settings.py`
- [x] 健康数据分析服务(`services/analysis.py`
- [x] 身体年龄计算(`services/fitness_age.py`
- [x] 运动详情与全天曲线同步(`services/garmin_extras.py`
- [x] 可插拔数据层(`db.py`,支持 SQLite ↔ MariaDB 切换)
- [x] 集中配置管理(`config.py`,从 `.env` 读取)
- [x] 自动同步调度器读取用户 `history_days` 设置(修复前固定 2 天)
### 前端功能
- [x] 仪表板:健康数据概览
- [x] 趋势分析数据可视化与趋势图Recharts
- [x] 数据同步页:同步最新数据 / 同步历史 / 补齐详细数据
- [x] 同步进度轮询与状态展示
- [x] 设置页:个人资料、单位、自动同步、历史范围
- [x] 评分依据:每个评级分段的公开参考值来源
- [x] 数据绑定页Garmin 邮箱+密码输入
- [x] 历史范围选项:自上次同步 / 全部历史 / N 天 / N 年
### 同步逻辑修复
- [x] 自动同步调度器认用户设置的 `history_days`,不再固定 2 天
- [x] 前端 `0`(全部历史)不再被 `||` 吞掉,改为 `??` 处理
- [x] 后端路由和 `sync_data``0` 不再被当成 falsy 回退默认值
- [x] `sync_data``0` → 730 天(全部历史=最大范围)
- [x] 调度器 `0` → 730 天转换
- [x] 「已同步天数」显示数据库实际总天数(`totalDays`),而非上次同步记录数
### 数据库
- [x] MariaDB 数据库创建(`garmin_health_lab`
- [x] 完整表结构:`health_data` / `daily_series` / `activities` / `activity_details` / `users` / `user_settings` / `garmin_tokens` / `sync_status`
- [x] 257 天健康数据已同步2025-12-19 \~ 2026-09-01
### AI 教练2026-09-01
- [x] 特征工程层 `services/insights.py`z 分数28 天个人基线、13 个月趋势
斜率、近 7 天活动量对比,全部服务端算好再交给模型
- [x] 提示词与解析层 `services/coach.py`:晨报 / 趋势归因 / Copilot 三套提示词,
每套都有对应的规则引擎兜底版本
- [x] `services/ai.py` 扩展:多轮 `chat()`、SSE `stream()``extract_json()`
(从推理模型的思维链里取最后一个 JSON
- [x] 接口:`GET /analysis/briefing``GET /analysis/trend-insight`
`POST /analysis/copilot`SSE
- [x] 缓存表 `ai_insights`(按 user + kind + subject数据指纹失效
- [x] 前端:今日页 AI 晨报卡片(后台生成 + 轮询升级)、全局 Copilot 浮窗、
指标详情页 AI 归因面板;`features.ts``ai` 开关已打开
- [x] 接入自建 ai-gateway`https://ai.zichuan.xyz/v1`),实测走通
- [x] 生产者/消费者队列(`services/jobs.py`):优先级队列 + 多 worker 互斥锁
- [x] 数据同步后自动预取所有页面洞察(`prefetch_insights`
- [x] 每日总结和运动详情在后台持续排队生成,不限量(`refill_backlog` + 空闲时自动补充)
> **实测数据2026-09-01**:网关一次晨报生成 **273 秒**(上游 nvidia
> 缓存命中 18 毫秒。网关的**流式**通道比阻塞通道更不可靠——同一条提示词
> 流式 139 秒后返回「所有模型均不可用」,阻塞则成功,因此 `stream_chat()`
> 在流式无输出时会对同一模型退回非流式重试。
### Copilot 浮窗 UI 修复与文档同步2026-09-02
- [x] Copilot 浮窗 UI 修复Framework7 全局 `button { width: 100% }` 把面板内
✕ / 发送按钮拉满父容器,挤坏 flex 布局(输入框缩到 21px、✕ 跑到面板中间)。
`Copilot.css` 显式 `width: auto` 覆盖,重构产物已部署到 NAS :8124 验证。
- [x] 文档与代码对齐生产现状CLAUDE.md / README.md / docs/\* 全部更新为
Python/Flask + NAS :8124 + auth-hub + ai-gateway清除 Node.js 时代与
甲骨文 8123 的过时描述);`config.py` / `.env.example` 默认值同步。
## 待办
### 功能完善
- [ ] 仪表板数据可视化组件完善
- [x] 健康建议 / AI 解读功能AI 教练,见下)
- [ ] 数据分析报告生成
- [ ] 多用户支持完善
### 运维
- [x] `deploy.sh` 自动复制前端构建到 `backend/static/`,避免部署旧版
- [ ] 监控与告警
- [ ] 日志轮转与清理
- [ ] 数据库备份策略
- [ ] HTTPS 证书配置Let's Encrypt
### 文档
- [x] ARCHITECTURE.md 已重写为 Python/Flask 架构 + NAS :8124 部署2026-09-02
- [x] DEVELOPMENT.md 已重写为 Flask/CRA 开发指南2026-09-02
- [x] REQUIREMENTS.md 已更新部署位置与新增需求2026-09-02
- [x] CLAUDE.md / README.md 同步为最新技术栈与部署现状2026-09-02