api: build per-user garmin.Client/sync.Service via lazy caching

Server no longer holds one fixed Garmin/Sync pair -- garminFor/syncFor
build and cache one instance per user, keyed off their own profile's
Garmin credentials and a per-user token-store subdirectory. The background
incremental sync loop now iterates every provisioned user each tick
instead of syncing one global account.
This commit is contained in:
2026-07-25 18:10:09 +02:00
parent 2cda0adbf8
commit 5930cc4ef5
4 changed files with 216 additions and 92 deletions

View File

@@ -15,6 +15,7 @@ import (
"geniusrun/backend/internal/auth"
authmock "geniusrun/backend/internal/auth/mock"
"geniusrun/backend/internal/garmin"
"geniusrun/backend/internal/garmin/mock"
"geniusrun/backend/internal/store"
appsync "geniusrun/backend/internal/sync"
@@ -37,9 +38,14 @@ func newTestServer(t *testing.T) (*Server, *store.DB) {
}
t.Cleanup(func() { db.Close() })
if _, err := db.ProvisionUser(context.Background(), "test-user", "Test User"); err != nil {
t.Fatalf("ProvisionUser: %v", err)
}
m := &mock.Client{}
svc := appsync.NewService(m, db, appsync.Config{}, func() time.Time { return time.Date(2026, 7, 11, 0, 0, 0, 0, time.UTC) })
return NewServer(db, m, svc, &authmock.Verifier{}, testSessionConfig), db
garminFactory := func(garmin.Config) garmin.Client { return m }
s := NewServer(db, garminFactory, garmin.Config{}, appsync.Config{}, &authmock.Verifier{}, testSessionConfig)
return s, db
}
func doJSON(t *testing.T, handler http.Handler, method, path string, body any) *httptest.ResponseRecorder {
@@ -323,7 +329,7 @@ func TestReviewQueue_PaginatesByCursor(t *testing.T) {
for i := 1; i <= 5; i++ {
activityID, err := db.UpsertActivity(ctx, store.Activity{
GarminActivityID: int64(i),
StartTimeUTC: fmt.Sprintf("2026-07-0%d 06:00:00", i), RawJSON: "{}",
StartTimeUTC: fmt.Sprintf("2026-07-0%d 06:00:00", i), RawJSON: "{}",
})
if err != nil {
t.Fatalf("UpsertActivity: %v", err)
@@ -407,7 +413,7 @@ func TestReviewQueue_FiltersByKindAndUnclassifiedStayPaginated(t *testing.T) {
makeActivity := func(n int64, kindID *int64) {
activityID, err := db.UpsertActivity(ctx, store.Activity{
GarminActivityID: n,
StartTimeUTC: fmt.Sprintf("2026-07-0%d 06:00:00", n), RawJSON: "{}",
StartTimeUTC: fmt.Sprintf("2026-07-0%d 06:00:00", n), RawJSON: "{}",
})
if err != nil {
t.Fatalf("UpsertActivity: %v", err)