diff --git a/backend/app/api/health.py b/backend/app/api/health.py
index 9898552..ed22e14 100644
--- a/backend/app/api/health.py
+++ b/backend/app/api/health.py
@@ -19,6 +19,7 @@ class HealthMetricOut(BaseModel):
max_hr_day: Optional[float]
avg_hr_day: Optional[float]
hrv_nightly_avg: Optional[float]
+ hrv_weekly_avg: Optional[float]
hrv_status: Optional[str]
hrv_5min_high: Optional[float]
hrv_5min_low: Optional[float]
diff --git a/backend/app/main.py b/backend/app/main.py
index 3182edc..d0dc453 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -70,6 +70,7 @@ async def init_db():
"ALTER TABLE health_metrics ADD COLUMN IF NOT EXISTS sleep_stages JSON",
"ALTER TABLE health_metrics ADD COLUMN IF NOT EXISTS hrv_baseline_low FLOAT",
"ALTER TABLE health_metrics ADD COLUMN IF NOT EXISTS hrv_baseline_upper FLOAT",
+ "ALTER TABLE health_metrics ADD COLUMN IF NOT EXISTS hrv_weekly_avg FLOAT",
]:
await conn.execute(text(stmt))
except Exception as e:
diff --git a/backend/app/models/user.py b/backend/app/models/user.py
index 215b358..bfdf373 100644
--- a/backend/app/models/user.py
+++ b/backend/app/models/user.py
@@ -261,7 +261,8 @@ class HealthMetric(Base):
max_hr_day = Column(Float, nullable=True)
avg_hr_day = Column(Float, nullable=True)
hrv_status = Column(String(32), nullable=True)
- hrv_nightly_avg = Column(Float, nullable=True)
+ hrv_nightly_avg = Column(Float, nullable=True) # last single night's avg (Garmin lastNightAvg)
+ hrv_weekly_avg = Column(Float, nullable=True) # overnight/weekly avg Garmin plots on its HRV Status chart
hrv_5min_high = Column(Float, nullable=True)
hrv_5min_low = Column(Float, nullable=True)
hrv_baseline_low = Column(Float, nullable=True) # Garmin balanced range lower bound (balancedLow)
diff --git a/backend/app/services/garmin_connect_sync.py b/backend/app/services/garmin_connect_sync.py
index 6020fc9..cb2e847 100644
--- a/backend/app/services/garmin_connect_sync.py
+++ b/backend/app/services/garmin_connect_sync.py
@@ -598,6 +598,7 @@ def _parse_day(stats, sleep_data, hrv_data) -> dict:
if hrv_data:
summary = hrv_data.get("hrvSummary") or hrv_data
_set(row, "hrv_nightly_avg", summary.get("lastNight") or summary.get("lastNightAvg"))
+ _set(row, "hrv_weekly_avg", summary.get("weeklyAvg"))
_set(row, "hrv_5min_high", summary.get("lastNight5MinHigh"))
status = summary.get("status")
if status:
diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx
index faa585b..cfec754 100644
--- a/frontend/src/pages/DashboardPage.jsx
+++ b/frontend/src/pages/DashboardPage.jsx
@@ -30,7 +30,7 @@ const STAT_DEFS = {
stat_resting_hr: { label: 'Resting HR', accent: 'red', val: h => formatHeartRate(h.resting_hr) },
stat_sleep: { label: 'Sleep', accent: 'default', val: h => formatSleep(h.sleep_duration_s) },
stat_vo2max: { label: 'VO₂ max', accent: 'blue', val: h => h.vo2max != null ? h.vo2max.toFixed(1) : '--', sub: h => h.fitness_age != null ? `fitness age ${h.fitness_age}` : undefined },
- stat_hrv: { label: 'HRV status', accent: 'purple', val: h => h.hrv_nightly_avg != null ? `${Math.round(h.hrv_nightly_avg)} ms` : '--', sub: h => h.hrv_status ?
HRV