# SparkyFitness **Node:** heimdall **Stack:** `sparkyfitness` **URL:** https://fitness.castaldifamily.com **Version:** v0.16.6.1 **Source:** https://github.com/CodeWithCJ/SparkyFitness **Docs:** https://codewithcj.github.io/SparkyFitness/ --- ## Overview SparkyFitness is a self-hosted, privacy-first fitness and health tracking platform — a full alternative to MyFitnessPal. It stores all data on infrastructure you control with no reliance on third-party services. **Core capabilities:** - Nutrition, exercise, hydration, sleep, fasting, mood, and body measurement tracking - Goal setting and daily check-ins - Interactive charts and long-term reports - Multiple user profiles and family access - Native OIDC, TOTP, Passkey, and MFA support - Health platform integrations: Apple Health, Google Health Connect, Fitbit, Withings, Garmin, Polar, Strava - Food database integrations: OpenFoodFacts, USDA, FatSecret, Nutritionix - Recipe app integrations: Mealie, Tandoor - Optional AI chatbot for conversational food/exercise logging (beta) **Stack architecture:** | Container | Image | Role | |---|---|---| | `sparkyfitness-db` | `postgres:18.3-alpine` | PostgreSQL database | | `sparkyfitness-server` | `codewithcj/sparkyfitness_server:v0.16.6.1` | Node.js backend API | | `sparkyfitness-frontend` | `codewithcj/sparkyfitness:v0.16.6.1` | React frontend (Nginx) | --- ## Node Runs on **heimdall** — the general-purpose applications node. No GPU is required. Workload is typical of a personal web application. --- ## Access | Method | Detail | |---|---| | **URL** | https://fitness.castaldifamily.com | | **Auth** | SparkyFitness native auth (TOTP, passkeys, MFA supported) | | **SSO** | Not configured — OIDC with Authentik can be added via env vars (see `.env.example`) | | **Admin panel** | Set `SPARKY_FITNESS_ADMIN_EMAIL` in `.env` to auto-grant admin on first start | > ⚠️ Set `SPARKY_FITNESS_DISABLE_SIGNUP=true` in `.env` after creating your initial account to prevent open registration. --- ## Appdata All persistent data lives under `/mnt/appdata/sparkyfitness/data/` on the NFS share. | Path | Contents | Backup Priority | |---|---|---| | `postgresql/` | All user data — nutrition logs, workouts, health metrics, accounts | 🔴 Critical | | `uploads/` | Profile pictures and exercise images | 🟡 Important | | `backup/` | App-generated PostgreSQL exports | 🟢 Nice-to-have | Pre-create these directories before first deploy: ```bash mkdir -p /mnt/appdata/sparkyfitness/data/postgresql mkdir -p /mnt/appdata/sparkyfitness/data/backup mkdir -p /mnt/appdata/sparkyfitness/data/uploads ``` --- ## Environment Variables Managed via `.env` (git-crypt encrypted). See `.env.example` for the full reference. ### Required Secrets | Variable | Purpose | How to Generate | |---|---|---| | `SPARKY_FITNESS_DB_PASSWORD` | PostgreSQL superuser password | `openssl rand -base64 24` | | `SPARKY_FITNESS_APP_DB_PASSWORD` | App-role DB password (limited privileges) | `openssl rand -base64 24` | | `SPARKY_FITNESS_API_ENCRYPTION_KEY` | 64-char hex key for external integration encryption | `openssl rand -hex 32` | | `BETTER_AUTH_SECRET` | Signs sessions and encrypts TOTP/2FA data | `openssl rand -hex 32` | > ⚠️ `SPARKY_FITNESS_API_ENCRYPTION_KEY` — changing this after data is stored invalidates all encrypted external integration credentials. > ⚠️ `BETTER_AUTH_SECRET` — changing this after users have enabled TOTP/2FA locks them out. Do not rotate without disabling 2FA first. ### Non-Secret Configuration (hardcoded in compose.yaml) | Variable | Value | Notes | |---|---|---| | `SPARKY_FITNESS_FRONTEND_URL` | `https://fitness.castaldifamily.com` | Used for CORS and session binding | | `SPARKY_FITNESS_DB_HOST` | `sparkyfitness-db` | Internal Docker service name | | `SPARKY_FITNESS_DB_NAME` | `sparkyfitness_db` | Database name | | `SPARKY_FITNESS_DB_USER` | `sparky` | Superuser for migrations | | `SPARKY_FITNESS_APP_DB_USER` | `sparky_app` | Runtime app user (limited privileges) | | `SPARKY_FITNESS_LOG_LEVEL` | `ERROR` | Use `DEBUG` temporarily for troubleshooting | | `NODE_ENV` | `production` | | | `TZ` | `Etc/UTC` | Adjust if local time is needed for date handling | | `SPARKY_FITNESS_FORCE_EMAIL_LOGIN` | `true` | Failsafe — prevents OIDC misconfiguration lockout | --- ## Networking | Network | Type | Used By | |---|---|---| | `proxy-net` | External (Traefik) | `sparkyfitness-frontend` only | | `sparkyfitness-network` | Internal bridge | All three containers | No host ports are exposed. All external traffic enters via Traefik. ### Traefik Routing | Field | Value | |---|---| | **Router** | `sparkyfitness` | | **Rule** | `Host(\`fitness.castaldifamily.com\`)` | | **Entrypoint** | `websecure` (HTTPS) | | **TLS** | Cloudflare cert resolver | | **Middleware** | `security-headers@file` | | **Backend port** | `80` (Nginx inside `sparkyfitness-frontend`) | The frontend Nginx container internally proxies API requests to `sparkyfitness-server:3010` over `sparkyfitness-network`. No separate Traefik route is needed for the API. --- ## Dependencies | Dependency | Type | Notes | |---|---|---| | PostgreSQL 18.3-alpine | Bundled | Self-contained — no shared DB instance | | Traefik | External (core stack) | Must be running on `proxy-net` | | Cloudflare DNS | External | Required for TLS cert resolver | No Redis, GPU, or kernel module dependencies. --- ## Backup & Recovery ### What to Back Up The `postgresql/` directory is the **single source of truth** for all user data. This must be in the backup rotation before going live. ``` /mnt/appdata/sparkyfitness/data/postgresql/ ← Critical /mnt/appdata/sparkyfitness/data/uploads/ ← Important ``` ### Restore Steps 1. Stop the stack: `docker compose down` 2. Restore the PostgreSQL data directory to `/mnt/appdata/sparkyfitness/data/postgresql/` 3. Restore uploads to `/mnt/appdata/sparkyfitness/data/uploads/` 4. Redeploy: `docker compose up -d` 5. Verify the DB is healthy: `docker compose logs sparkyfitness-db` ### Upgrading > ⚠️ Auto-updating containers is **not recommended** by the maintainer. Watchtower should be excluded from this stack. 1. Review release notes at https://github.com/CodeWithCJ/SparkyFitness/releases 2. Take a backup of `postgresql/` 3. Update image tags in `compose.yaml` 4. Commit and push — Komodo will redeploy via webhook 5. Check logs: `docker compose logs --tail=50` --- ## Known Issues / Notes - **Garmin microservice** (`sparkyfitness-garmin`) is still in development upstream. It is commented out of the compose file intentionally. Do not enable until the maintainer marks it stable. - **Auto-update warning**: The maintainer explicitly warns against automated container updates between releases. Ensure Watchtower is not targeting this stack. - **Postgres upgrade notice**: The upstream release notes flag a forthcoming mandatory Postgres upgrade. Monitor release notes and follow the [official Postgres upgrade guide](https://codewithcj.github.io/SparkyFitness/install/postgres-upgrade) when the time comes. - **AI chatbot** is in beta — expect potential bugs if enabled. - **Family & Friends access** is in beta — expect potential bugs if enabled.