web: port Sync page login + sync to garminconnect backend

garminconnect_backend gains web-friendly auth: resume() (token restore with
API validation), begin_login()/complete_mfa() (two-step MFA handshake via
return_on_mfa), user_label(), and patch_garth() split out of activate().

5_Sync.py drops the garth login flow (Cloudflare-blocked) for the new
backend; the authenticated client is cached in st.session_state. Verified
headlessly with streamlit AppTest: token restore, sync-button click, full
incremental sync, no exceptions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 07:38:50 -04:00
parent dd2b8ef1bd
commit 87f73ad36b
3 changed files with 115 additions and 36 deletions

View File

@@ -33,8 +33,16 @@ architecture and conventions. Delete this file when the list is done.
fallback in gc.login (main() parks it as .bak first).
- DB after sync: 385 activities (→ 2026-06-02), all ISO timestamps on new
rows, 356 FITs linked, 364 TIZ rows, wellness through 2026-06-12.
The 18 legacy epoch-ms rows remain (P2). Web Sync page still uses the
garth login flow — port it to the gc backend (or hide login) later.
The 18 legacy epoch-ms rows remain (P2).
- **Web Sync page ported to the gc backend** (same session): login + MFA
round-trip + sync button all run on garminconnect; verified headlessly via
streamlit AppTest (login restore, button click, full sync, no exceptions).
`openrun.ingest.auth` (garth) remains only for `--backend=garth`.
- **New goal (user, 2026-06-12): shareable web UI** — let others run the
openrun web app against their own Garmin account. Known gaps: per-user
token store + DB (everything is cwd-relative single-user today), per-user
openrun.toml (zones/races — openrun-init helps), and deploy story
(`streamlit run` is single-process; secrets must stay server-side).
- `race_plan` table is EMPTY and `manual_activities` empty, but openrun.toml
has races: 30K 2026-06-13, 50K 2026-07-25, 50 MILE 2026-09-12.
- Known bugs: 18 activities have epoch-ms floats in `start_time_local`