Skip to content

Wellness Postgres Sync (CreatorTrack Fitness data layer)

URL: https://mkdocs.justinsforge.com/memory/general/reference_wellness_pg_sync/

The CreatorTrack Fitness app reads Postgres ONLY (no more node:sqlite/filesystem reads; that dependency is why the dev/prod systemd units had to move to Node 22, now moot). Canonical store: the lifeos wellness schema on CT 109 (lifeos_admin owns, lifeos_app SELECT; single-user, no per-workspace RLS, mirrors the finance.* grant model).

Script

  • ~/forge/scripts/forge_wellness_pg_sync.py: idempotent upsert of the wellness sources into wellness.*. Fail-loud, tolerates a missing source (logs + skips, nonzero exit only on total failure). Writes as lifeos_admin via forge_workspace_db.admin_connect(). Re-run = same state.
  • Tables: wellness_facts (EAV replica of context.db facts_wellness; backs eight_sleep/garmin/inbody, ~55.9k rows), hevy_workouts, hevy_templates, garmin_activities, body_measurements, config (thresholds), sync_state (freshness stamps).
  • Schema migration: forge-suite/db/migrations/20260702T194750_fitness_pg_wellness_pipeline_schema_for_fitness_app.sql.

Timer

  • ~/.config/systemd/user/forge-wellness-pg-sync.{service,timer} (user units, OnCalendar=*:0/15, enabled 2026-07-02). Keeps Postgres current as the wellness pollers (Garmin/Hevy/Eight Sleep) write their sources.
  • The Fitness app's Refresh button also runs a wellness_pg sync step.

Parity

Verified byte-identical between the new PG reads and the prior file-reads across all /api/fitness/data headline values + all 7 detail endpoints (2026-07-02 cutover). The old Flask fitness dashboard (fitness.justinsforge.com) still reads context.db directly and is unaffected; retire on its own schedule.

Hevy API fetch (2026-07-06)

forge_hevy_poll.py was retired 2026-07-03 (Notion decommission) but it was the ONLY thing pulling workouts from the Hevy API; the JSONL + wellness.hevy_workouts + ~/.forge-state/hevy_last_sync froze and forge-monitor fired the 86h wellness_fresh_hevy alert. Fix: forge_wellness_pg_sync.py now owns the fetch. refresh_hevy_raw() pulls ALL workouts + the exercise-template catalog from api.hevyapp.com, rewrites data/hevy/raw_hevy_workouts.jsonl + exercise_templates.json atomically, refuses to overwrite on an empty API response, and stamps hevy_last_sync. Age-gated to 6h so the 15-min timer hits Hevy ~4x/day (the intentional low cadence). Retired forge_hevy_poll cron lines removed from crontab. Commit 3d23ab5.

[Claude Code]