Commit Graph

32 Commits

Author SHA1 Message Date
e2b2bf9611 refactor: merge internal/sync into internal/garmin, regroup api files and routes
Garmin auth/sync routes move under /api/garmin/*; sync.Service becomes
garmin.Sync with garmin.SyncConfig/ClientConfig; applog becomes
internal/log; the test mock moves into the garmin package as MockClient
(breaking the test-only import cycle the merge created); stale test
URLs and type names updated to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 16:04:18 +02:00
eb24dcd89d docs: spec for application vs environment configuration
Design for the 'configuration' backlog idea: instance-global key/value
config table (overrides only, cold reload), env-var renames, /api/config
GET/PUT, and the /config page with header icon buttons.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 23:47:57 +02:00
b5cd47c219 docs: add implementation plan for permanently-missing-workout handling
4 tasks: mark a wrapper-level 404 as not_found, expose it as
garmin.ErrNotFound in the Go client, add a workout_not_found_at
column + store query updates, then have fillPendingWorkouts stop
retrying a confirmed-404 workout instead of retrying forever.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 18:45:11 +02:00
67f4ec27ab docs: add design spec for permanently-missing-workout handling
A workout deleted on Garmin's side after being linked to an activity
404s forever on get_workout_by_id, and today's fillPendingWorkouts
retries it every sync indefinitely with no user-visible feedback --
just a perpetual "1 more workout pending" nudge. Distinguishes a
definitive 404 (via garminconnect's own GarminConnectNotFoundError)
from a transient failure, and stops retrying the former.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 18:00:38 +02:00
3bf11ae6bf docs: add implementation plan for modern error displays
11 tasks: the shared banner store + renderer, a friendlier
network-unreachable message in client.ts, then migrating every
existing inline error site (GarminConnection, SyncModal, Profile,
Activities, Analysis, TrainingTypesCard, LoginGate, OnboardingWizard)
to it, finishing with dead-CSS cleanup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 09:31:57 +02:00
b2c705ce29 docs: add design spec for modern error displays
Replaces every page/component's ad-hoc inline error paragraph with a
shared, module-level banner store (red/orange/blue/green, stacking,
auto-dismiss + manual close) -- from docs/IDEAS.md's backlog item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 09:22:47 +02:00
aac9359b02 docs: add implementation plan for improved synchronization UX
Six tasks: remove dead Backfill/IncrementalSync wrappers, add
ActivitiesMissingWorkout/CountActivitiesMissingWorkout, split
FillPendingDetails into phase-aware activities/workouts passes,
reshape GET /api/sync/status, add SyncModal, wire it into
GarminConnection.tsx.
2026-07-26 23:05:43 +02:00
a828055c30 docs: fold dead Backfill/IncrementalSync wrapper cleanup into sync spec
Discovered while verifying the sync design with the user: these two
exported methods are dead in production (only FullSync's *Core calls
are actually used), kept alive only by tests, and their doc comments
still reference the background sync loop removed in 4d2cbe4.
2026-07-26 22:45:59 +02:00
7f5618ce49 docs: add design spec for improved synchronization UX
Phase-aware sync progress (discovering/activities/workouts), a new
/api/sync/status shape, and a blocking SyncModal replacing the Profile
page's inline sync text -- implementing the "improve synchronization"
idea from docs/IDEAS.md.
2026-07-26 22:09:49 +02:00
77f9588c2d refactor(config): rename default Garmin token-store dir to .garmin
Shorter, more conventional dotdir name than garmin-tokenstores. Restore
the "next to DBPath" join that got dropped when the default was
inlined via getEnvDefault -- an explicit GARMIN_TOKENSTORE still wins
verbatim, but the implicit default must still resolve relative to the
DB file's directory, not the process's CWD.

internal/garmin/client.go's GARMIN_TOKENSTORE env var is now always
set (TokenStorePath can no longer be empty), so the conditional that
only appended it when non-empty is dead code.
2026-07-26 21:25:39 +02:00
7346e2eadd docs: add implementation plan for structured JSON logging 2026-07-26 14:36:04 +02:00
501d951e5b docs: add design spec for structured JSON logging 2026-07-26 14:22:28 +02:00
2fbe762290 docs: add implementation plan for deferred-commit onboarding wizard 2026-07-26 14:12:44 +02:00
a1eaa42d42 docs: add design spec for deferred-commit onboarding wizard 2026-07-26 13:17:59 +02:00
35eff03509 docs: add implementation plan for improved first-connection flow 2026-07-26 12:29:26 +02:00
50d65b40c2 docs: add design spec for improved first-connection flow 2026-07-26 12:09:35 +02:00
d7202eb9bb docs: add implementation plan for profile deletion 2026-07-26 10:23:32 +02:00
c5faaf5a17 docs: add design spec for profile deletion 2026-07-26 10:06:04 +02:00
d73c841ab7 docs: add implementation plan for the OIDC callback redirect fix
Two small tasks: add config.Config.FrontendURL (Task 1), then thread it
through api.SessionConfig and handleSessionCallback's five redirects
(Task 2).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:49:02 +02:00
fe4978dbea docs: add design spec for fixing OIDC callback redirect origin
handleSessionCallback's relative redirects resolve against the backend's
own origin, which 404s in this project's own supported split-origin local
dev setup (frontend on Vite, backend on geniusrund, bridged by CORS). Adds
GENIUSRUN_FRONTEND_URL, defaulting to PublicBaseURL for the common
single-origin production case, as the fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:42:50 +02:00
de48c44858 docs: add implementation plan for the direct Garmin wrapper
Task-by-task TDD plan for docs/superpowers/specs/2026-07-25-garmin-direct-wrapper-design.md:
Python wrapper + tests, Go transport scaffolding, auth methods, data-fetch
methods, config changes, wiring/docs, and final dependency cleanup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:30:05 +02:00
0936d98161 docs: embed the garmin wrapper script instead of configuring its path
Since wrapper.py now lives inside this repo, its location is no longer a
deploy-time concern -- go:embed it into the binary and drop the
GARMIN_WRAPPER_SCRIPT env var entirely. Only the Python interpreter choice
remains configurable, and now optionally so (defaults to "python3").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:14:36 +02:00
961a7d8aca docs: add design spec for dropping MCP in favor of a direct Garmin wrapper
Replaces internal/garmin's MCP-based mcp-garmin integration with a custom
newline-delimited-JSON subprocess protocol around python-garminconnect
directly, folded into this repo. MCP's dynamic tool-discovery value is
unused here (fixed call sites, no LLM choosing tools), and both projects
are owned by the same person, so the extra protocol layer and two SDK
dependencies (mcp-go, mcp[cli]) were pure overhead -- especially given
plans to containerize the backend.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:04:18 +02:00
1329387528 Merge branch 'worktree-per-user-profile' 2026-07-25 19:00:04 +02:00
f82549524b docs: update Task 3 design for removed dead-code scenario
Update the per-user-profile plan document to reflect the corrected Task 3
design: remove the now-unreachable TestClaimLegacyOwner_NoOpOnGenuinelyFreshInstall
test from the code example, update the ClaimLegacyOwner implementation example to
remove the dead-code branch and false doc comment about fresh installs, and fix
the commit message to match the corrected design.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:05:37 +02:00
033e412cb7 docs: add per-user profile implementation plan
Copied into this worktree so subagent-driven-development can operate on
it; the plan was written and reviewed on main before this branch existed.
2026-07-25 10:13:12 +02:00
d29f69903d docs: design per-user profile and data isolation
Reverses the "single active profile, OIDC is access-only" decision from
2026-07-24 now that login needs to map each user to their own dataset
instead of a shared singleton.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 09:20:37 +02:00
f9d85e16ef Rename smartrun to geniusrun throughout the codebase
Updates the Go module path, cmd/smartrund -> cmd/geniusrund, the
smartrun-dev skill, .gitignore, and every reference in docs/CLAUDE.md
to match.
2026-07-24 21:08:07 +02:00
70c6d143e1 Add implementation plan for the OIDC login gate
Task-by-task TDD plan covering config, the new internal/auth package
(session cookies, Keycloak OIDC verifier, RequireSession middleware),
wiring into internal/api and cmd/geniusrund, and the frontend
LoginGate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 21:02:42 +02:00
fd80065e81 Add design doc for OIDC-based app login gate
Adds an access-gate authentication design: Keycloak OIDC via a
backend-driven Authorization Code flow, restricted by realm role,
with geniusrun minting its own session cookie. No data model or
multi-profile changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 20:45:46 +02:00
5fbc574d34 docs: merge plan tasks 9-11 into one so every commit typechecks cleanly 2026-07-17 18:38:14 +02:00
f689f74ae0 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>
2026-07-17 18:33:06 +02:00