Initial commit: smartrun MVP
Garmin run classification and progression tracker. Go backend (MCP client to mcp-garmin, SQLite store, deterministic rule engine, REST API) and React/TS frontend (Dashboard, Review Queue, Workout Kinds). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
37
backend/internal/store/syncstate.go
Normal file
37
backend/internal/store/syncstate.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// SyncState tracks how far back into Garmin history a backfill has already
|
||||
// reached. Since activities are immutable once recorded, this lets a repeat
|
||||
// backfill skip everything already covered instead of re-fetching it.
|
||||
type SyncState struct {
|
||||
EarliestSyncedDate *string // "YYYY-MM-DD", nil if backfill has never run
|
||||
BackfillComplete bool // true once backfill has reached the configured horizon (or Garmin's own history start)
|
||||
}
|
||||
|
||||
// GetSyncState returns the current backfill watermark (the singleton row,
|
||||
// created by migration 0002).
|
||||
func (db *DB) GetSyncState(ctx context.Context) (SyncState, error) {
|
||||
var s SyncState
|
||||
err := db.QueryRowContext(ctx, `SELECT earliest_synced_date, backfill_complete FROM sync_state WHERE id = 1`).
|
||||
Scan(&s.EarliestSyncedDate, &s.BackfillComplete)
|
||||
if err != nil {
|
||||
return SyncState{}, fmt.Errorf("get sync state: %w", err)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// UpdateSyncState records progress of a backfill run.
|
||||
func (db *DB) UpdateSyncState(ctx context.Context, earliestSyncedDate string, complete bool) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
UPDATE sync_state SET earliest_synced_date = ?, backfill_complete = ? WHERE id = 1`,
|
||||
earliestSyncedDate, complete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update sync state: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user