A self-hosted workout tracking API with an Apple Watch training queue. Store workout history, query analytics, and queue structured workouts for delivery to Apple Watch via WorkoutKit.
Built with FastAPI, PostgreSQL, and SQLAlchemy. Includes an optional MCP (Model Context Protocol) server for AI assistant integration.
- Workout storage — CRUD API for workouts with activity type, distance, duration, heart rate, splits, and arbitrary JSONB data
- Analytics — Summary endpoints with aggregation by week, month, or year
- Training queue — Queue structured workouts (intervals, warmup/cooldown, pace alerts) for sync to Apple Watch via an iOS companion app
- Workout actions — Edit or delete workouts already synced to Apple Watch via pending action queue
- Device inventory — Track what workouts are currently on the user's Apple Watch
- Missed workout feedback — Record and query feedback when users miss scheduled workouts, with pattern detection for coaching
- Training plans — Create and manage training plans with goals, guardrails, phases, and athlete context stored as flexible JSONB metadata
- Health metrics — Bulk upsert daily HealthKit metrics (sleep, HR, HRV, weight, VO2Max, steps, body composition) with date-based upsert
- Plan-workout linking — Link queued workouts to plans (
plan_id) and recorded workouts to their planned counterpart (plan_workout_id) for planned-vs-actual analysis - Dashboard — Built-in web dashboard at
/dashboardwith overview stats, plan progress, health metrics, and API key management - MCP server — Let AI assistants query your training data, create workouts and plans, and correlate health metrics via natural language
- Docker and Docker Compose
git clone https://github.com/YOUR_USERNAME/training-api.git
cd training-api
cp backend/config/.env.example backend/config/.envEdit backend/config/.env and set a random API_KEY:
DATABASE_URL=postgresql+psycopg://training-api:training-api@db:5432/training-api
API_KEY=your-secret-api-key-here
ENVIRONMENT=LOCALmake up # or: docker compose up -dThe API will be available at http://localhost:8001. Database migrations run automatically on startup. A web dashboard is available at http://localhost:8001/dashboard.
curl http://localhost:8001/api/healthAll endpoints (except health) require a Bearer token in the Authorization header matching the API_KEY you configured.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/workouts |
Create or upsert a workout |
GET |
/api/workouts |
List workouts (filters: activity_type, start_after, start_before, plan_workout_id, limit, offset) |
GET |
/api/workouts/summary |
Aggregated stats by period (week/month/year) and activity type |
GET |
/api/workouts/{id} |
Get workout detail |
GET |
/api/workouts/{id}/splits |
Get per-split breakdown |
GET |
/api/workouts/{id}/heartrate |
Get heart rate samples |
DELETE |
/api/workouts/{id} |
Delete a workout |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/queue |
Queue a structured workout |
GET |
/api/queue |
List queue items (filter by status) |
GET |
/api/queue/pending |
List pending items |
PATCH |
/api/queue/{id}/status |
Update item status (pending / fetched / synced / completed) |
DELETE |
/api/queue/{id} |
Delete a queue item |
GET |
/api/workouts/queue |
App-facing: get pending workouts as WorkoutKit compositions |
DELETE |
/api/workouts/queue/{id} |
App-facing: mark item as synced (persists the record) |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/workouts/actions |
List pending edit/delete actions |
POST |
/api/workouts/actions |
Create an edit or delete action |
POST |
/api/workouts/actions/batch |
Create multiple actions at once |
DELETE |
/api/workouts/actions/{id} |
Acknowledge a processed action |
| Method | Endpoint | Description |
|---|---|---|
PUT |
/api/workouts/inventory |
Sync full on-device workout snapshot (idempotent replace) |
GET |
/api/workouts/inventory |
Get stored inventory |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/workouts/feedback |
Record feedback for a missed workout (upsert by workoutId) |
GET |
/api/workouts/feedback |
Retrieve feedback history (filters: since, limit, action) |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/plans |
Create a training plan |
GET |
/api/plans |
List plans (filters: status, activity_type) |
GET |
/api/plans/{id} |
Get plan with metadata |
PATCH |
/api/plans/{id} |
Update plan fields |
DELETE |
/api/plans/{id} |
Delete a plan (queue items keep plan_id set to null) |
GET |
/api/plans/{id}/workouts |
Get all queued workouts for a plan |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/health/metrics |
Bulk upsert daily health metrics (null fields preserved) |
GET |
/api/health/metrics |
Query metrics (required: start_date, optional: end_date) |
| Endpoint | Description |
|---|---|
/dashboard |
Overview — stats, plan progress, recent workouts, health metrics |
/dashboard/plan |
Active plan detail — phases, goals, guardrails, workout list |
/dashboard/settings |
API key (show/copy), database info, endpoint reference |
The mcp/ directory contains a FastMCP server that exposes training data to AI assistants (e.g., Claude).
cd mcp
cp config/.env.example config/.envEdit mcp/config/.env — set TRAINING_API_KEY to match the backend's API_KEY:
TRAINING_API_URL=http://localhost:8001
TRAINING_API_KEY=your-secret-api-key-hereuv run startOr configure it in your MCP client (e.g., Claude Desktop) as a stdio transport.
make up # Start containers
make down # Stop containers
make build # Rebuild images
make logs # Tail container logs
make migrate # Run database migrations manually
# Create a new migration after changing models
make create_migration m="add new column"├── docker-compose.yml # PostgreSQL + API orchestration
├── Makefile # Dev shortcuts
├── backend/
│ ├── Dockerfile # Multi-stage Python 3.13 build
│ ├── pyproject.toml # Dependencies (uv/hatch)
│ ├── config/.env.example # Environment template
│ ├── app/
│ │ ├── main.py # FastAPI app
│ │ ├── config.py # Settings (pydantic-settings)
│ │ ├── auth.py # Bearer token auth
│ │ ├── database.py # SQLAlchemy setup
│ │ ├── models/ # ORM models
│ │ ├── routes/ # API endpoints
│ │ ├── schemas/ # Pydantic request/response models
│ │ └── templates/ # Jinja2 dashboard templates
│ └── migrations/ # Alembic migrations
└── mcp/
├── pyproject.toml # MCP dependencies
├── config/.env.example # MCP environment template
└── app/
├── main.py # FastMCP server
├── tools/ # MCP tool definitions
└── services/ # API client
MIT