Nathan 54a885120d feat(sparkyfitness): add sparkyfitness stack to heimdall
- 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
2026-05-10 21:58:38 -04:00

150 lines
5.1 KiB
YAML

x-info:
repo: https://github.com/CodeWithCJ/SparkyFitness
releases: https://github.com/CodeWithCJ/SparkyFitness/releases
documentation: https://codewithcj.github.io/SparkyFitness/
# nodes/heimdall/sparkyfitness/compose.yaml
# Deployed via Komodo | Managed by GitOps
# Service: sparkyfitness
# Source: https://github.com/CodeWithCJ/SparkyFitness
networks:
proxy-net:
external: true
sparkyfitness-network:
driver: bridge
services:
# ── Database ────────────────────────────────────────────────────────────────
sparkyfitness-db:
image: postgres:18.3-alpine
container_name: sparkyfitness-db
restart: unless-stopped
networks:
- sparkyfitness-network
environment:
POSTGRES_DB: sparkyfitness_db
POSTGRES_USER: sparky
POSTGRES_PASSWORD: "${SPARKY_FITNESS_DB_PASSWORD}"
PUID: 1000
GUID: 1000
volumes:
- /mnt/appdata/sparkyfitness/data/postgresql:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sparky -d sparkyfitness_db"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ── Backend Server ───────────────────────────────────────────────────────────
sparkyfitness-server:
image: codewithcj/sparkyfitness_server:v0.16.6.1
container_name: sparkyfitness-server
restart: unless-stopped
networks:
- sparkyfitness-network
environment:
# Database connection
SPARKY_FITNESS_DB_HOST: sparkyfitness-db
SPARKY_FITNESS_DB_PORT: 5432
SPARKY_FITNESS_DB_NAME: sparkyfitness_db
SPARKY_FITNESS_DB_USER: sparky
SPARKY_FITNESS_DB_PASSWORD: "${SPARKY_FITNESS_DB_PASSWORD}"
SPARKY_FITNESS_APP_DB_USER: sparky_app
SPARKY_FITNESS_APP_DB_PASSWORD: "${SPARKY_FITNESS_APP_DB_PASSWORD}"
# Security — values sourced from .env (git-crypt)
SPARKY_FITNESS_API_ENCRYPTION_KEY: "${SPARKY_FITNESS_API_ENCRYPTION_KEY}"
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET}"
# Application
SPARKY_FITNESS_FRONTEND_URL: "https://fitness.castaldifamily.com"
SPARKY_FITNESS_LOG_LEVEL: ERROR
NODE_ENV: production
TZ: Etc/UTC
SPARKY_FITNESS_DISABLE_SIGNUP: "false"
SPARKY_FITNESS_FORCE_EMAIL_LOGIN: "true"
ALLOW_PRIVATE_NETWORK_CORS: "false"
PUID: 1000
GUID: 1000
# Garmin microservice (disabled — service not yet stable)
# GARMIN_MICROSERVICE_URL: http://sparkyfitness-garmin:8000
volumes:
- /mnt/appdata/sparkyfitness/data/backup:/app/SparkyFitnessServer/backup
- /mnt/appdata/sparkyfitness/data/uploads:/app/SparkyFitnessServer/uploads
depends_on:
sparkyfitness-db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:3010/ 2>&1 | grep -q '.' || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
cpus: "1.5"
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ── Frontend ─────────────────────────────────────────────────────────────────
sparkyfitness-frontend:
image: codewithcj/sparkyfitness:v0.16.6.1
container_name: sparkyfitness-frontend
restart: unless-stopped
networks:
- proxy-net
- sparkyfitness-network
environment:
SPARKY_FITNESS_FRONTEND_URL: "https://fitness.castaldifamily.com"
SPARKY_FITNESS_SERVER_HOST: sparkyfitness-server
SPARKY_FITNESS_SERVER_PORT: 3010
PUID: 1000
GUID: 1000
depends_on:
sparkyfitness-server:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost:80/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
# Enable Traefik
- "traefik.enable=true"
# HTTPS Router
- "traefik.http.routers.sparkyfitness.rule=Host(`fitness.castaldifamily.com`)"
- "traefik.http.routers.sparkyfitness.entrypoints=websecure"
- "traefik.http.routers.sparkyfitness.tls=true"
- "traefik.http.routers.sparkyfitness.tls.certresolver=cloudflare"
- "traefik.http.routers.sparkyfitness.service=sparkyfitness"
- "traefik.http.routers.sparkyfitness.middlewares=security-headers@file"
# Service definition
- "traefik.http.services.sparkyfitness.loadbalancer.server.port=80"
deploy:
resources:
limits:
cpus: "0.5"
memory: 128M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"