Move backfill horizon from a startup env var into the editable profile

SMARTRUN_BACKFILL_HORIZON_DAYS was a server-startup-only env var with no UI,
defaulting to 3 years -- so editing the unrelated "Rolling window" profile
field (for classification, not sync) had no effect on how far back Sync Now
reached. Backfill horizon is now Profile.BackfillHorizonDays, read fresh on
every Backfill call, with its own field on the Profile page.
This commit is contained in:
2026-07-19 12:57:18 +02:00
parent 93746666b5
commit 249826afc0
10 changed files with 84 additions and 37 deletions

View File

@@ -11,8 +11,14 @@ type Profile struct {
GarminEmail string
GarminPassword string
RollingWindowDays int
MaxHeartRate *float64
RestingHeartRate *float64
// BackfillHorizonDays bounds how far back "Sync now" reaches when
// walking backward from today; it's read fresh on every sync (not fixed
// at server startup), so changing it here takes effect on the next
// click. Unrelated to RollingWindowDays, which is for the (not yet
// implemented) relative classification window.
BackfillHorizonDays int
MaxHeartRate *float64
RestingHeartRate *float64
HRZone1MinPct, HRZone1MaxPct float64
HRZone2MinPct, HRZone2MaxPct float64
@@ -30,7 +36,7 @@ type Profile struct {
}
const profileColumns = `
garmin_email, garmin_password, rolling_window_days, max_heart_rate, resting_heart_rate,
garmin_email, garmin_password, rolling_window_days, backfill_horizon_days, max_heart_rate, resting_heart_rate,
hr_zone1_min_pct, hr_zone1_max_pct, hr_zone2_min_pct, hr_zone2_max_pct,
hr_zone3_min_pct, hr_zone3_max_pct, hr_zone4_min_pct, hr_zone4_max_pct,
hr_zone5_min_pct, hr_zone5_max_pct,
@@ -42,7 +48,7 @@ const profileColumns = `
func (db *DB) GetProfile(ctx context.Context) (Profile, error) {
var p Profile
err := db.QueryRowContext(ctx, `SELECT `+profileColumns+` FROM profile WHERE id = 1`).Scan(
&p.GarminEmail, &p.GarminPassword, &p.RollingWindowDays, &p.MaxHeartRate, &p.RestingHeartRate,
&p.GarminEmail, &p.GarminPassword, &p.RollingWindowDays, &p.BackfillHorizonDays, &p.MaxHeartRate, &p.RestingHeartRate,
&p.HRZone1MinPct, &p.HRZone1MaxPct, &p.HRZone2MinPct, &p.HRZone2MaxPct,
&p.HRZone3MinPct, &p.HRZone3MaxPct, &p.HRZone4MinPct, &p.HRZone4MaxPct,
&p.HRZone5MinPct, &p.HRZone5MaxPct,
@@ -61,14 +67,14 @@ func (db *DB) GetProfile(ctx context.Context) (Profile, error) {
func (db *DB) UpdateProfile(ctx context.Context, p Profile) error {
_, err := db.ExecContext(ctx, `
UPDATE profile SET
garmin_email=?, garmin_password=?, rolling_window_days=?, max_heart_rate=?, resting_heart_rate=?,
garmin_email=?, garmin_password=?, rolling_window_days=?, backfill_horizon_days=?, max_heart_rate=?, resting_heart_rate=?,
hr_zone1_min_pct=?, hr_zone1_max_pct=?, hr_zone2_min_pct=?, hr_zone2_max_pct=?,
hr_zone3_min_pct=?, hr_zone3_max_pct=?, hr_zone4_min_pct=?, hr_zone4_max_pct=?,
hr_zone5_min_pct=?, hr_zone5_max_pct=?,
warmup_minutes=?, cooldown_minutes=?,
updated_at=datetime('now')
WHERE id = 1`,
p.GarminEmail, p.GarminPassword, p.RollingWindowDays, p.MaxHeartRate, p.RestingHeartRate,
p.GarminEmail, p.GarminPassword, p.RollingWindowDays, p.BackfillHorizonDays, p.MaxHeartRate, p.RestingHeartRate,
p.HRZone1MinPct, p.HRZone1MaxPct, p.HRZone2MinPct, p.HRZone2MaxPct,
p.HRZone3MinPct, p.HRZone3MaxPct, p.HRZone4MinPct, p.HRZone4MaxPct,
p.HRZone5MinPct, p.HRZone5MaxPct,