A self-hosted fitness tracker for strength training and cardio — built so you own your data and your training feels like progress.
Overload isn't just a workout logbook. It records your lifts and cardio, then turns those numbers into momentum: personal records, streaks, progressive-overload trends, and clear "you vs. last month" views that show you pushing past where you were.
- Strength & cardio first, with room to grow into general activity and nutrition later.
- Local-first: log a full workout at the gym with zero signal; it syncs when you're back online.
- Self-hosted: runs on your own machine via Docker Compose. Your data never leaves your box.
- Installable PWA today; architected so a desktop app and native App Store app can come later.
🏋️ Phase 1 — strength & cardio logging (local-first). You can start a workout, add exercises from a 750-movement catalog, log sets (unit-aware), use a rest timer, and browse history — all offline, syncing to the server when back online. Phases 0–1 are done; next up are PRs & progress trends (Phase 3) and routines (Phase 4). See the roadmap.
Start here:
docs/PLAN.md— vision, architecture, data model, offline/sync design, analytics, cross-cutting concerns, testing, self-hosting.docs/ROADMAP.md— phased milestones from a walking skeleton to full v1 and beyond.docs/FUTURE.md— long-term architecture for the big post-v1 modules (native, multi-user, ML, nutrition, integrations).
| Layer | Choice | Why |
|---|---|---|
| Client | Vite + React installable PWA | Snappy, offline-capable, installs to the home screen |
| Backend | NestJS (TypeScript) | Structured, testable, "full-scale" backend; API-first |
| Data | Prisma + PostgreSQL | Typed access, real migrations, solid analytics queries |
| Shared | packages/core (Zod schemas + domain logic) |
One definition of truth; PR/1RM math runs on client and server |
| Offline | IndexedDB (Dexie) + sync queue | Local-first source of truth, syncs to server |
| Delivery | Turborepo + pnpm monorepo, Docker Compose | One language everywhere; one-command self-hosting |
Full reasoning in docs/PLAN.md.
cp .env.example .env # then set SESSION_SECRET to a long random value
docker compose up --build # web → http://localhost:8080 · API → http://localhost:3000The API applies database migrations and seeds the default user on boot. Open the web app and you'll be prompted to set your instance password (first-run setup), then logged in.
pnpm install
pnpm --filter @overload/db generate # generate the Prisma client
# start Postgres however you like, then point DATABASE_URL at it and:
pnpm --filter @overload/db migrate:dev # apply migrations
pnpm dev # run API + web in watch modeCommon tasks (Turborepo): pnpm build, pnpm lint, pnpm typecheck, pnpm test, pnpm format.
apps/web — Vite + React installable PWA (first client)
apps/api — NestJS API (REST + OpenAPI at /api/docs)
packages/core — shared Zod schemas + domain logic (e1RM, units) used by both ends
packages/db — Prisma schema, migrations, seed
AGPL-3.0 — strong copyleft that also covers hosted/network use, so improvements to a self-hosted app flow back to the community. (License file to be added with the first code.)