# Garmin Health Lab — 需求文档 记录所有已提出的需求、理解与进度。**每完成一条:更新本文件的状态 → commit → push。** 状态:`✅ 已完成` · `🚧 进行中` · `📋 待做` · `⏸ 已搁置` 最后更新:2026-08-24 --- ## 一、基础平台 | # | 需求 | 理解 | 状态 | |---|---|---|---| | 1.1 | 新建项目分析佳明海外账号健康数据 | Gitea 自建仓库,Web 应用 | ✅ | | 1.2 | 部署到 NAS (192.168.50.64),用 MariaDB | Flask + gunicorn + MariaDB(socket),SQLite 供开发 | ✅ | | 1.3 | 公网可访问 | frp 隧道 NAS:8123 → Oracle:8123 | ✅ | | 1.4 | 开发过程中写单元测试 | 324 项 pytest | ⏸ 用户 2026-08-24 要求暂停,优先做功能 | | 1.5 | 一任务一 commit,完成即推送 | 已成为固定流程 | ✅ | ## 二、数据同步 | # | 需求 | 理解 | 状态 | |---|---|---|---| | 2.1 | 同步佳明所有数据,不只是运动 | 31 项每日指标 + 运动 + 徽章 + 个人纪录 | ✅ | | 2.2 | 验证码在前端输入(人不在电脑前) | Web MFA:后台线程阻塞在 `prompt_mfa`,验证码经数据库跨 worker 交接 | ✅ | | 2.3 | 同步改为用户手动触发,不自动跑 | 同步是界面动作 | ✅ | | 2.4 | 每小时后台同步最新数据 | `job_locks` 抢占,多 worker 只跑一次 | ✅ | | 2.5 | 「同步最新数据」按钮 | 同步页首要按钮,等待即返回结果 | ✅ | | 2.6 | 同步频率可设置 | 设置页选择,调度器按各账号自己的频率判断是否该同步 | ✅ | | 2.7 | 同步历史范围可设置(多久以前 / 全部) | 设置页选择,同步页「同步历史」按此范围拉取 | ✅ | | 2.8 | 同步界面简化设计 | 两个按钮 + 三格状态,去掉原来四段说明文字 | ✅ | ## 三、界面框架 | # | 需求 | 理解 | 状态 | |---|---|---|---| | 3.1 | 前端推倒重做,要求好看 | Framework7 React (iOS 主题),桌面与手机都要好看 | ✅ | | 3.2 | Tab:今日 / 健康 / 趋势 / 运动 / 设置 | 每日是趋势的子页 | ✅ | | 3.3 | 首页改三圆环:步数 / 睡眠 / HRV | 并列三环,满环=进入参考区间 | ✅ | | 3.4 | 交互流畅、有动画 | 数字滚动、入场揭示、`prefers-reduced-motion` | ✅ | | 3.5 | 删掉各页右上角的半透明椭圆 | 导航栏右侧 `Link`(带 tooltip)渲染出来的,已移除 | ✅ | | 3.6 | 睡眠入口不放右上角,改为点健康页睡眠卡片进入 | 入口跟着内容走;每日入口同样移进趋势页内容 | ✅ | | 3.7 | 主界面切到子界面加 loading 动画 | 顶部进度条,跑到 90% 等页面就位;有最短显示时长,避免快速跳转时闪一下 | ✅ | ## 四、数据展示 | # | 需求 | 理解 | 状态 | |---|---|---|---| | 4.1 | 每日详情模块,看某天所有数据 | 每日页 | ✅ | | 4.2 | 趋势模块,7 天 / 月 / 季 / 年 周期 | 按周期取日均,桶长不同也可比 | ✅ | | 4.3 | 趋势覆盖全部 15 组指标,可自选显示/隐藏 | 指标选择器 | ✅ | | 4.4 | 指标选择器太丑,改成选择弹窗 | 改为 F7 Popup,页面上只留一行「显示指标 n/15」 | ✅ | | 4.5 | 所有卡片可点击进入详情 | `/metric/:id/`:大数值 + 参考区间 + 趋势图 + 统计 + 依据;新增 `lib/metrics.ts` 统一指标注册表 | ✅ | | 4.6 | 今日页左右箭头切换前一天/后一天 | 无记录的日期自动跳过;到边界置灰 | ✅ | | 4.7 | 今日页顶部日期选择控件,可看历史任一天 | 点中间日期开 F7 日历,范围限定在已有数据内 | ✅ | | 4.8 | 点击每个运动看本次运动详情,数据全展示 | 概览/数据/分段/图表四个 Tab,含心率区间条与时间/距离横轴切换 | ✅ | | 4.9 | 健康页增加身体年龄 | 健康页卡片 + `/body-age/` 展示每一步推算过程与出处 | ✅ | ## 四之二、补齐未同步的数据(2026-08-24) 审计:garminconnect 0.2.8 共 57 个 `get_*`,原先只用了 16 个。只读探测后确认 账号里真有数据、却从未入库的部分如下,全部已加入同步模块并配了界面。 | # | 数据 | 接口 | 存放 | 界面 | 状态 | |---|---|---|---|---|---| | 4.10 | 体重与身体成分 | `get_body_composition` | `body_composition` 表 | `/body/` 身体成分 | ✅ | | 4.11 | 血压 | `get_blood_pressure` | `blood_pressure` 表 | `/body/` 内表格 | ✅ 接口通,账号暂无数据 | | 4.12 | 跑步成绩预测 | `get_race_predictions` | `race_predictions` 表 | `/race/` 成绩预测 | ✅ | | 4.13 | 爬坡分 | `get_hill_score` | `health_data.hill_score` | 指标详情 | ✅ | | 4.14 | 饮水与出汗 | `get_hydration_data` | `health_data` 三列 | 指标详情 | ✅ | | 4.15 | 全天曲线(心率/压力/身体电量/呼吸/血氧) | 五个日内接口 | `daily_series` 表 | 每日页「全天曲线」 | ✅ | | 4.16 | 挑战赛 | `get_badge_challenges` 等四个 | `challenges` 表 | `/challenges/` | ✅ | | 4.17 | 设备 | `get_devices` | `devices` 表 | 设置 → 已配对设备 | ✅ | **探测为空、未做界面**:`get_max_metrics`(VO₂max 已从训练状态取到)、 `get_goals`、`get_inprogress_virtual_challenges`。 **判定为重复**:`get_stats`/`get_steps_data`/`get_floors`/`get_stress_data` 等 日聚合接口,数据已在 `health_data`;`get_activities`(分页); `get_device_settings`/`get_gear_defaults` 等配置类接口。 同步开销:日内曲线每天五个请求,因此 14 天以内的同步顺带拉取,更长的历史 交给「补齐详细数据」后台任务,否则一年的同步会多出约 1800 个请求。 ## 五、设置 | # | 需求 | 理解 | 状态 | |---|---|---|---| | 5.1 | 设置项太少:身高/体重/年龄/性别 | 设置页个人资料分组,改动即存,另显示 BMI 与年龄 | ✅ | | 5.2 | 单位设置 | 公制 / 英制,已存储;各页按此显示待接入 | ✅ 设置完成,🚧 全局套用 | | 5.3 | 评分依据要在设置说明中显示 | 设置 → 评分依据 `/rating-basis/`,11 项区间逐条列出处;指标详情页也各带一份 | ✅ | ## 六、AI | # | 需求 | 理解 | 状态 | |---|---|---|---| | 6.1 | 多个大上下文文本模型,可切换 | gateway / gemini-flash / llama-70b / nemotron-49b / mistral-large | ✅ | | 6.2 | 暂时隐藏 AI 模块 | `FEATURES.ai = false` | ✅ | | 6.3 | AI 用来解释,不用来定阈值 | 阈值全部来自公开参考值,AI 只负责解读 | ✅ 已确认为设计原则 | --- ## 已修复的缺陷(实机验证发现) | 现象 | 原因 | 处理 | |---|---|---| | 部署后整站 Network Error | 构建时没带 `REACT_APP_API_URL`,打包进了开发默认值 localhost:5000 | 加 `client/.env.production`,写死 `/api`,不再依赖构建时手输 | | 凌晨打不开当天数据 | 各页用 `toISOString()` 取日期,那是 UTC。UTC+8 每天前 8 小时都在查昨天 | 新增 `lib/day.ts`,全部改用本地日历日期 | | 右上角/返回键的半透明椭圆 | Framework7 9 给 `.navbar .left/.right` 加了 frosted pill | 在 `f7theme.css` 覆盖掉 | | 运动详情四个 Tab 竖着排 | F7 把每个 `