No description
  • Python 50.6%
  • HTML 49.2%
  • Dockerfile 0.2%
Find a file
David Hammond 043e09f8bc Add core features built during initial development
- Points system based on MET values from the Compendium of Physical
  Activities, with HR-based intensity multiplier and elevation bonus.
- Trophy/achievement system with 36 milestones across 10 categories.
- Direct messaging between users with HTMX-powered chat and unread
  notification badges.
- Public user profiles linkable from leaderboards and chats.
- Strava sport_type mapping expanded to cover all 47 Strava types
  (was 12), plus --force-update and --prune-stale sync flags.
- REST API for HealthKit / Health Connect ingestion via Bearer token,
  with per-user token management in the profile UI.
- Per-challenge chat threads.
- Email/password registration alongside PocketID SSO.
- Hourly Strava sync added to the scheduler.
- Challenge editing for creators (every field, with leaderboard recalc).
- Family invite codes switched to name-based slugs.
- Charts (line, donut, stacked bar) for family activity comparison.
- 404/403/500 branded error pages.
- ADMIN_EMAILS env var replaces hardcoded admin promotion.
2026-05-21 21:09:22 -04:00
accounts Add core features built during initial development 2026-05-21 21:09:22 -04:00
activities Add core features built during initial development 2026-05-21 21:09:22 -04:00
challenges Add core features built during initial development 2026-05-21 21:09:22 -04:00
dm Add core features built during initial development 2026-05-21 21:09:22 -04:00
families Add core features built during initial development 2026-05-21 21:09:22 -04:00
static Initial commit 2026-05-11 00:59:12 -04:00
templates Add core features built during initial development 2026-05-21 21:09:22 -04:00
trophies Add core features built during initial development 2026-05-21 21:09:22 -04:00
workoutharder Add core features built during initial development 2026-05-21 21:09:22 -04:00
.dockerignore Initial commit 2026-05-11 00:59:12 -04:00
.env.example Add core features built during initial development 2026-05-21 21:09:22 -04:00
.gitignore Initial commit 2026-05-11 00:59:12 -04:00
backup_db.py Initial commit 2026-05-11 00:59:12 -04:00
blog-post.md Add core features built during initial development 2026-05-21 21:09:22 -04:00
docker-compose.yml Initial commit 2026-05-11 00:59:12 -04:00
Dockerfile Initial commit 2026-05-11 00:59:12 -04:00
LICENSE Initial commit 2026-05-11 00:59:12 -04:00
manage.py Initial commit 2026-05-11 00:59:12 -04:00
README.md Add core features built during initial development 2026-05-21 21:09:22 -04:00
requirements.txt Initial commit 2026-05-11 00:59:12 -04:00
scheduler.py Add core features built during initial development 2026-05-21 21:09:22 -04:00

Workout Harder

A self-hosted family fitness challenge app. Create challenges, compete on shared leaderboards, and track each other's progress. Activities sync automatically from Strava.

Workout Harder. Be Kinder.

Features

  • Strava sync — OAuth connect, real-time webhook for new activities, periodic backfill
  • PocketID SSO — single sign-on via your own self-hosted OIDC provider
  • Challenges — pick a metric (distance / duration / elevation / activity count / calories), an activity type, a date range, and an optional goal target. Share via invite code or link.
  • Family groups — shared space for a household. Everyone in a group is auto-added to any challenge a member creates.
  • Live leaderboards per challenge and per family
  • Imperial / metric toggle per user — each family member sees their own units regardless of others' preferences
  • Weekly digest emails — every Sunday at noon (local TZ), each member gets their family's recap with leaderboard, top performer, and challenge progress
  • Automatic DB backups — gzipped SQLite snapshots on every container start and daily at 3 AM, kept 30 days

Stack

  • Django 5.1 + Gunicorn
  • SQLite (bind-mounted, easy to back up / migrate to Postgres later)
  • Tailwind CSS via CDN, HTMX for dynamic bits
  • WhiteNoise for static files
  • Pure-stdlib scheduler container for cron-like tasks

Quick start

1. Configure

git clone https://github.com/YOUR_USER/workoutharder.git
cd workoutharder
cp .env.example .env
# edit .env with your secrets

You'll need:

Set the OIDC redirect URI in your PocketID admin to: https://YOUR_HOST/accounts/pocketid/callback/

Set the Strava callback URL to: https://YOUR_HOST/accounts/strava/callback/

2. Run

docker compose up -d --build

The web app listens on port 4598. Reverse-proxy it behind your TLS terminator.

3. Sign in

Visit https://YOUR_HOST/ and sign in with PocketID. Then connect Strava from the profile page.

Operating it

Manual digest send

docker exec workoutharder python manage.py send_weekly_digests --dry-run  # preview
docker exec workoutharder python manage.py send_weekly_digests            # send for real

Backups

docker exec workoutharder python manage.py backup_db          # create one now
docker exec workoutharder python manage.py restore_db --list  # list snapshots
docker exec workoutharder python manage.py restore_db latest  # restore most recent
docker compose restart web                                    # apply restore

Backups live in ./backups/ on the host as db_YYYYMMDD_HHMMSS.sqlite3.gz.

Strava sync

docker exec workoutharder python manage.py sync_strava --days 30

The Strava webhook posts to /activities/webhook/strava/. Register your webhook subscription with verify_token = first 16 chars of your SECRET_KEY.

Data model

  • accounts.UserProfile — extends auth.User with Strava tokens, PocketID sub, unit preference, and stats cache
  • families.Family + FamilyMembership — group + role join table
  • challenges.Challenge + ChallengeParticipant — challenge config + per-user progress
  • activities.Activity — synced Strava activities

Project layout

.
├── accounts/      # auth, profile, PocketID, Strava OAuth, unit conversion tags
├── activities/    # Strava sync, webhook, management commands (backup, digest, sync)
├── challenges/    # challenge CRUD, leaderboard recalculation
├── families/      # groups, invite links, auto-add to challenges
├── workoutharder/ # Django project (settings, urls, wsgi)
├── templates/     # all UI templates (Tailwind via CDN)
├── backup_db.py   # standalone SQLite backup script
├── scheduler.py   # cron-like loop: daily backup + weekly digest
└── docker-compose.yml

License

MIT