fitness-web/README.md
Jacob Hinkle 5584022a23 Single-container AI coach with agent API endpoints and UI polish
- Merge opencode-serve into the web container via entrypoint script
- Add /api/agent/* JSON endpoints for workouts, sets, checkins
- Rewrite fitness-trainer.md to use API instead of markdown files
- Pass recent workouts and check-ins as chat context to the coach
- Show current training phase on dashboard
- Clarify check-ins as morning check-ins (calories/steps = yesterday)
- Add NixOS deployment section to README
- Make all check-in fields explicitly optional in UI
2026-06-29 10:50:01 -04:00

3.0 KiB

Fitness Web

Multi-user fitness tracking web app with AI coaching.

Track workouts, log daily check-ins, explore exercise history, and chat with an AI coach powered by opencode.

Features

  • Workouts — Plan and log workouts with set-level detail (reps, weight, RPE)
  • Exercises — Catalog with body-part filtering and history
  • Check-ins — Daily weight, calories, steps, sleep tracking
  • AI Coach — Chat interface backed by opencode (Big Pickle model, free)
  • Multi-user — Login-based, each user has independent data
  • Calendar view — See your training history at a glance
  • NixOS-ready — Docker-based deploy with provided NixOS module

Quick Start

# Install dependencies
uv sync

# Initialize and seed the database
uv run python scripts/schema.py
uv run python scripts/seed.py

# Start the dev server
uv run uvicorn app.main:app --reload

Open http://localhost:8000, register a user, and you're ready.

Docker

docker compose up -d

NixOS Deployment

A single container runs both the web app and the AI coach (opencode-serve) together, sharing the SQLite database on the same filesystem.

1. Build image

docker build -t fitness-web:latest .

2. NixOS module

Add machines/cj/fitness-web.nix to your nix_config:

{ serverIP, serverIP6 }: {
  fitness-web = {
    image = "fitness-web:latest";
    ports = [ "8688:8000" ];
    environment = {
      TZ = "America/New_York";
      SESSION_SECRET = "change-me-in-production";
    };
    volumes = [
      "/serverdata/fitness-web/data:/app/data"
      "/serverdata/fitness-web/opencode:/root/.config/opencode"
    ];
  };
}

Wire it into configuration.nix:

virtualisation.oci-containers.containers = let
  ips = { ... };
in {
  # ... existing containers ...
  fitness-web = (import ./fitness-web.nix ips).fitness-web;
};

3. Nginx reverse proxy

In nginx.nix, add a vhost:

"fitness.jhink.org" = simpleProxy 8688;

4. Firewall

Add to allowedTCPPorts in firewall.nix:

8688  # fitness-web

5. Deploy

nixos-rebuild switch --flake .#cj

Then access at https://fitness.jhink.org (or your chosen domain).

Architecture

app/
├── main.py          — FastAPI app factory with lifespan
├── config.py        — Settings from environment
├── auth.py          — Auth helpers (hash, verify, session)
├── models/          — SQLAlchemy ORM models
├── routers/         — Route handlers per feature
├── services/        — External service integrations (opencode)
├── templates/       — Jinja2 templates (Pico.css)
└── static/          — CSS overrides
scripts/
├── schema.py        — DB table creation
└── seed.py          — Seed exercises and phases
data/                — SQLite database (gitignored)
  • fitness-agent — Original training repo with markdown logs and Juggernaut history. This web app replaces it.