Skip to content

Fitness Dashboard

  • URL: https://fitness.justinsforge.com (CF Access, allowlist [email protected], same policy shape as finances)
  • App: forge/scripts/forge_fitness_app.py (Flask, 127.0.0.1:8093) + forge_fitness_dashboard.html (read at request time, edit without restart)
  • Unit: forge-fitness-app.service (systemd, enabled)
  • Ingress: VR Alliance tunnel (Console), added via forge_cloudflare_cf.py add fitness justinsforge.com http://127.0.0.1:8093 --tunnel "VR Alliance"
  • Data sources (all read-only): data/context.db facts_wellness (Eight Sleep + Garmin via ha_poller), data/hevy/raw_hevy_workouts.jsonl + exercise_templates.json (reuses forge_hevy_read._aggregate), data/training_thresholds.json
  • Recommendation band is the deterministic half of forge_training_recommendation.py (readiness band + HRV/stress/body-battery/recovery corrections), recomputed per request, no LLM
  • Eight Sleep side mapping: backfilled rows are left/right (Justin = right), live rows justin/krystal; app merges with justin winning
  • Garmin card falls back to the latest date with >=3 metrics and flags "last sync MM-DD" when the watch has not synced today
  • Monitored: business_urls.fitness in monitor_expected_state.json + tile in Dashboards section of the justinsforge.com landing
  • Companion one-off: scripts/forge_wellness_gap_repair.py rebuilds Wellness Daily Notion rows from facts_wellness after backfills
  • v2 sections (2026-06-10 evening): strength est-1RM chart + all-time PR table + 90d recent PRs (Epley, reps capped 12, computed from raw Hevy jsonl, 10-min cache); InBody body comp trend; nutrition card from Notion Food Log (forge_food_log reuse, 5-min cache); Hevy body_measurements API (pageSize max 10, 1h cache)
  • v3 drill-downs (2026-06-10 night): modal layer; cards with a + h2 prefix are clickable. Endpoints: /api/detail/sleep + /api/detail/garmin (180d series + 30-night/activity tables), /api/detail/exercise/<name> (full e1RM history + per-session sets), /api/detail/workout/<id> (all sets + matched Garmin). PR rows and session rows open modals; Escape/backdrop closes.
  • Garmin activities pipeline: forge_garmin_poll.py now dumps last 30 activities (HR, max HR, training load, calories, TE) merged by activity_id into data/garmin/activities.jsonl every poll. Dashboard matches them to Hevy workouts by >5-min time overlap (_match_activity); matched HR shows in the sessions table and workout modal.
  • InBody record keeping: scripts/forge_inbody_log.py add --date ... --weight-lb ... writes facts_wellness source=inbody via /ingest (idempotent). 8 scans imported 2026-06-10: 6 from Drive sheet "2023-09-12_InBody-Scan-Results.xlsx" (2022-11..2023-09) + 2026-03-24 InBody570 + 2026-06-09 InBody580 Onnit. New scan = run the CLI (or ask a session); no Notion copy, forge is canonical per routing test

Related: [[wellness-pollers]], [[hevy-pipeline]], [[training-recommendation]]

[Claude Code]