- Compose file with pinned images (v0.16.6.1), healthchecks, Traefik routing - .env.example with all required variables and generation commands - README covering access, appdata, backup scope, upgrade procedure - KBA-002: deployment reference with verification and rollback steps - repo-deploy.prompt.md: reusable end-to-end deployment workflow prompt - Session snapshot 2026-05-10 Source: https://github.com/CodeWithCJ/SparkyFitness
182 lines
7.1 KiB
Markdown
182 lines
7.1 KiB
Markdown
# 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.
|