## File: README.md

🌐 Language
    
      
        [English](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=en)
        [简体中文](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=zh-CN)
        [繁體中文](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=zh-TW)
        [日本語](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=ja)
        [한국어](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=ko)
        [हिन्दी](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=hi)
        [ไทย](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=th)
        [Français](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=fr)
        [Deutsch](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=de)
        [Español](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=es)
        [Italiano](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=it)
        [Русский](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=ru)
        [Português](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=pt)
        [Nederlands](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=nl)
        [Polski](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=pl)
        [العربية](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=ar)
        [فارسی](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=fa)
        [Türkçe](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=tr)
        [Tiếng Việt](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=vi)
        [Bahasa Indonesia](https://openaitx.github.io/view.html?user=CodeWithCJ&project=SparkyFitness&lang=id)
      
    
  


# SparkyFitness

A self-hosted, privacy-first alternative to MyFitnessPal. Track nutrition, exercise, body metrics, and health data while keeping full control of your data.




SparkyFitness is a self-hosted fitness tracking platform made up of:

- A backend server (API + data storage)
- A web-based frontend
- Native mobile apps for iOS and Android

It stores and manages health data on infrastructure you control, without relying on third party services.

## Core Features

- 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
- Light and dark themes
- OIDC, TOTP, Passkey, MFA etc.

## How SparkyFitness Compares

**SparkyFitness is source-available, not open source** — the [licence](LICENSE) is non-commercial and requires permission for commercial use.

Most apps do one thing. One good nutrition app runs $40–$100 a year; covering everything SparkyFitness covers means three or four subscriptions, per person, and still no single report across them. SparkyFitness does it in one app, free, for the whole household.

<sub>US list prices, 14 Aug 2026. [Full cost breakdown →](https://codewithcj.github.io/SparkyFitness/features/comparison)</sub>

| | **SparkyFitness** | wger | MyFitnessPal | Cronometer | Hevy | Zero | Flo | Garmin Connect | Google Health |
| --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| Self-hosted, your data stays yours | ⭐ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| No subscription, no ads | ✅ | ✅ | ❌ | 🟡 | 🟡 | ❌ | ❌ | ✅ | 🟡 |
| Nutrition, strength, sleep, fasting, cycle & meds in one place\* | ⭐ | 🟡 | 🟡 | 🟡 | ❌ | ❌ | ❌ | 🟡 | 🟡 |
| Full history & custom date-range reports | ✅ free | 🟡 | 💰 | 💰 | 💰 | 💰 | 💰 | ✅ | 💰 |
| Wearable & health-platform sync | ✅ 8+ services | ❌ | ✅ | ⭐ | ✅ | 🟡 | 🟡 | 🟡 | ✅ |
| Family sharing with granular permissions | ⭐ 7 permissions | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | 🟡 | 🟡 |
| CSV import & free data export | ✅ | 🟡 | 💰 | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ❌ |
| MCP server + bring your own LLM | ⭐ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

⭐ standout &nbsp;•&nbsp; ✅ supported &nbsp;•&nbsp; 🟡 partial &nbsp;•&nbsp; 💰 paid tier only &nbsp;•&nbsp; ❌ not supported

<sub>\* Sleep stages, HRV and blood glucose are imported from your watch, phone or meter. SparkyFitness stores, analyses and charts them rather than measuring them itself.</sub>

> **This table is written by the project being compared, so read it that way.** Checked 14 Aug 2026 against official docs, repos and store listings; some of it is already out of date. If a cell is wrong or unfair to another project, [open an issue](https://github.com/CodeWithCJ/SparkyFitness/issues) — corrections that make SparkyFitness look *worse* are just as welcome.

**[See the full comparison →](https://codewithcj.github.io/SparkyFitness/features/comparison)** — 17 apps across self-hosted, nutrition, specialist and device-ecosystem categories, plus where each of them beats us.

## Health & Device Integrations

SparkyFitness can sync data from multiple health and fitness platforms:

- **Apple Health** (iOS)
- **Google Health Connect** (Android)
- **Google Health API** 
- **Fitbit**
- **Garmin Connect**
- **Withings**
- **Polar Flow** 
- **Oura**
- **Hevy**
- **OpenFoodFacts**
- **USDA**
- **Fatsecret**
- **Nutritionix**
- **Mealie**
- **Tandoor**
- **Strava** (partially tested)
- **Norish**
- **Yazio** (uses unofficial API)
- **Swiss Food Database**
- **Free Exercise DB** (Github)
- **Wger**

Integrations automatically sync activity data such as steps, workouts, and sleep, along with health metrics like weight and body measurements, to your SparkyFitness server.

## Optional AI Features (Beta)

SparkyAI provides a conversational interface for logging data and reviewing progress.

- Log food, exercise, body stats, and steps via chat
- Upload food images for automatic meal logging
- Retains conversation history for follow ups

Note: AI features are currently in beta.

## Installation

Choose one of the two ways to run SparkyFitness:

### 1. Self-Hosted

Get a SparkyFitness server running in minutes using Docker Compose:

```bash
# 1. Create a new folder
mkdir sparkyfitness && cd sparkyfitness

# 2. Download Docker files only
curl -L -o docker-compose.yml https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/docker-compose.prod.yml
curl -L -o .env https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/default.env.example

# 3. (Optional) Edit .env to customize database credentials, ports, etc.

# 4. Start the app
docker compose pull && docker compose up -d

# Access application at http://localhost:8080
```

_Note: For other self-hosted installation methods, refer to the documentation at [https://codewithcj.github.io/SparkyFitness/](https://codewithcj.github.io/SparkyFitness/)._

### 2. Cloud (for non-technical users)

If you are not a technical user and prefer not to run SparkyFitness on your own server, you can deploy a hosted instance in the cloud using one of the following providers.

<a href="https://www.pikapods.com/pods?run=sparkyfitness">
  
</a>

<a href="https://zenith.hosting/host/sparkyfitness?ref=gh">
  
</a>


> **Note:** These are independent third-party services. We encourage you to explore features provided by each provider to determine the one that best fits your needs.
 

## 🎥 Video Tutorial

[](https://www.youtube.com/watch?v=B13IiL2DeQc)

Quick 2-minute tutorial showing how to install SparkyFitness (self-hosted fitness tracker).

## Documentation

For full installation guides, configuration options, and development docs, please visit our [Documentation Site](https://codewithcj.github.io/SparkyFitness/).

### Quick Links

- **[Installation Guide](https://codewithcj.github.io/SparkyFitness/install/docker-compose)** - Deployment and configurations
- **[Features Overview](https://codewithcj.github.io/SparkyFitness/features)** - Complete feature documentation
- **[Development Workflow](https://codewithcj.github.io/SparkyFitness/developer/getting-started)** - Developer guide and contribution process
- **[iOS App Info](https://github.com/CodeWithCJ/SparkyFitness/wiki/Apple-Health-Integration)** and **[Android App Info](https://github.com/CodeWithCJ/SparkyFitness/wiki/Android-Mobile-App)**

### Need Help?

- Post in Github issues/discussion.
- For faster response and get help from other community memebers **[Join our Discord](https://discord.gg/vcnMT5cPEA)**

## Star History

<a href="https://www.star-history.com/?repos=CodeWithCJ%2FSparkyFitness&type=date&legend=top-left">
 
   
   
   
 
</a>

## Translations

**[Weblate Translations](https://hosted.weblate.org/engage/sparkyfitness)**

<a href="https://hosted.weblate.org/engage/sparkyfitness/">

</a>

## Repository activity



## Contributors

<a href="https://github.com/CodeWithCJ/SparkyFitness/graphs/contributors">
  
</a>

## ⚠️ Known Issues / Beta Features ⚠️

SparkyFitness is under active development.
Breaking changes may occur between releases.

- Auto-updating containers is not recommended
- Always review release notes before upgrading

The following features are currently in beta and may not have been thoroughly tested. Expect potential bugs or incomplete functionality:

- AI Chatbot
- Family & Friends access
- API documentation

---

## File: docker/README.md

# SparkyFitness Docker Configuration

This directory contains all Docker-related files for SparkyFitness deployment and development.

Refer to [docs](https://codewithcj.github.io/SparkyFitness/developer/docker) for more details

---

## File: docs/content/1.install/1.docker-compose.md

# Docker Compose [Recommended]

This page provides instructions for installing and running SparkyFitness using Docker Compose. This method is recommended for most users as it simplifies the setup process.

## Prerequisites

Before you begin, ensure you have the following installed:

*   **Docker Desktop**: Includes Docker Engine, Docker Compose, and Docker CLI.
    *   [Download Docker Desktop](https://www.docker.com/products/docker-desktop)

## Installation Steps

1.  **Create a new folder and download Docker files**:
    Create a new directory for SparkyFitness and navigate into it. Then, download the necessary `docker-compose.yml` and `.env` files.
    ```bash
    mkdir sparkyfitness && cd sparkyfitness
    curl -L -o docker-compose.yml https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/docker-compose.prod.yml    
    curl -L -o .env https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/default.env.example
    ```

2.  **Configure Environment Variables**:
    The `docker-compose.yml` file relies on environment variables defined in a `.env` file.
    Open the downloaded `.env` file in a text editor and update the variables to customize your setup. It's crucial to configure these variables correctly for the application to function as expected.

    For a complete list of all available variables and their detailed descriptions, please refer to the example environment file:
    [`.env.example` on GitHub](https://github.com/CodeWithCJ/SparkyFitness/blob/main/docker/.env.example)

    For a comprehensive list of all available environment variables and their detailed descriptions, please refer to the [Environment Variables documentation](/install/environment-variables).

3.  **Start the Application**:
    From within the `sparkyfitness` directory (where `docker-compose.yml` is located), pull the latest images and start the application services:
    ```bash
    docker compose pull && docker compose up -d
    ```
    *   `docker compose pull`: Downloads the latest Docker images for the services.
    *   `docker compose up -d`: Starts the services defined in the `docker-compose.yml` file in detached mode (in the background).

## Services Overview

The `docker-compose.prod.yml` file defines three main services:

*   **`sparkyfitness-db`**:
    *   **Image**: `postgres:15-alpine`
    *   **Purpose**: The PostgreSQL database server for storing application data.
    *   **Data Persistence**: Data is persisted in a Docker volume mapped to `../postgresql` on your host, ensuring your data is not lost if containers are removed.

*   **`sparkyfitness-server`**:
    *   **Image**: `codewithcj/sparkyfitness_server:latest`
    *   **Purpose**: The backend Node.js application server.
    *   **Environment Variables**: Configured with necessary database connection details, logging level, API encryption key, JWT secret, and frontend URL.
    *   **Dependencies**: Depends on `sparkyfitness-db` to ensure the database is running before the server starts.

*   **`sparkyfitness-frontend`**:
    *   **Image**: `codewithcj/sparkyfitness:latest`
    *   **Purpose**: The frontend React application served by Nginx.
    *   **Ports**: Maps host port `3004` to container port `80` (Nginx), making the frontend accessible via `http://localhost:3004` (or your configured domain).
    *   **Dependencies**: Depends on `sparkyfitness-server` to ensure the backend is running.

### Optional Services (Commented out by default)

To enable these services, open your `docker-compose.yml` file and uncomment the relevant blocks.

*   **`sparkyfitness-garmin`**:
    *   **Image**: `codewithcj/sparkyfitness_garmin:latest`
    *   **Purpose**: A dedicated microservice for syncing data directly from Garmin Connect.

## Accessing the Application

Once all services are up and running, you can access the SparkyFitness frontend in your web browser at the URL you configured for `SPARKY_FITNESS_FRONTEND_URL` (e.g., `http://localhost:3004`).

## Stopping and Removing Services

To stop the running services without removing their data volumes:
```bash
docker compose stop
```

To stop and remove all services, networks, and volumes (this will delete your database data!):
```bash
docker compose down -v

---

## File: docs/content/1.install/2.portainer.md

# Portainer Installation Guide

This guide provides step-by-step instructions on how to install and deploy SparkyFitness using Portainer. Portainer simplifies Docker management through a user-friendly web interface.

## Prerequisites

Before you begin, ensure you have:

1.  **A running Docker environment**: Portainer requires Docker to be installed on your server.
2.  **Portainer installed and configured**: Access to your Portainer instance. If you haven't installed Portainer yet, follow the official Portainer documentation.

## Step 1: Create a New Stack in Portainer

1.  **Log in to Portainer**.
2.  Navigate to **Stacks** in the left sidebar.
3.  Click **Add stack**.
4.  **Name your stack** (e.g., `sparkyfitness`).
5.  Select **Upload** for the build method.
6.  **Upload File**: Download the [docker-compose.prod.yml](https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/docker-compose.prod.yml) from the latest release and upload it here.
7.  (Optional) You can also use the **Web editor** method and copy-paste the content if you prefer.
8.  **Environment variables**: For a comprehensive list of all available environment variables and their detailed descriptions, please refer to the [Environment Variables documentation](/install/environment-variables). You will need to add these environment variables directly in Portainer.

## Step 2: Deploy the Stack

1.  After configuring the stack, click the **Deploy the stack** button.
2.  Portainer will now pull the necessary Docker images and create the containers for SparkyFitness. This process may take a few minutes depending on your internet connection.

## Step 3: Access SparkyFitness

Once the stack is successfully deployed and all containers are running, you can access the SparkyFitness frontend in your web browser.

*   Open your web browser and navigate to the URL you configured for `SPARKY_FITNESS_FRONTEND_URL` in your environment variables (e.g., `http://your-server-ip:3004`).

You should now see the SparkyFitness login/signup page.

---

## File: docs/content/1.install/3.synology.md

# Synology Community Guide

This guide provides instructions for installing SparkyFitness on your Synology NAS, provided by the community.

For detailed instructions, please refer to the external guide:

[How to Install SparkyFitness on your Synology NAS by MariusHosting](https://mariushosting.com/how-to-install-sparkyfitness-on-your-synology-nas/)

---

## File: docs/content/1.install/4.proxmox.md

# Proxmox Installation Guide

This guide provides instructions for installing SparkyFitness on Proxmox VE using a script provided by the community.

**Note: This script is provided via community contribution and is not maintained directly by the SparkyFitness.**

For installation instructions and to use the script, please refer to the Proxmox VE Helper-Scripts website:

[SparkyFitness Proxmox VE Helper-Script](https://community-scripts.org/scripts/sparkyfitness?from=scripts&fromQ=sparkyfitness)

If you encounter issues related to the Proxmox installation, please report them using the "Report Issue" option on the page above.

Since I do not personally use Proxmox, I may not be able to provide much help with this installation method, but the script maintainers and community there should be able to assist.

---

## File: docs/content/1.install/5.kubernetes.md

::alert{type="warning"}
**Community Contribution:** The Kubernetes and Helm chart support are community-provided. The SparkyFitness maintainers do not currently use Kubernetes and cannot provide full review or official support for this installation method.
::

## Quick Start (Kubernetes)

Deploy SparkyFitness on Kubernetes using the Helm chart directly from the repository.

```bash
# 1. Install with default settings (bundled PostgreSQL, no ingress)
helm install sparkyfitness oci://ghcr.io/codewithcj/charts/sparkyfitness

# -- OR install directly from source --
git clone https://github.com/CodeWithCJ/SparkyFitness.git
helm install sparkyfitness ./SparkyFitness/helm/chart

# 2. (Optional) Customize values
helm install sparkyfitness ./SparkyFitness/helm/chart -f my-values.yaml

# 3. Access the application in browser via Ingress or HTTPRoute you've specified in values
```

For all configuration options (external database, ingress, OIDC, email, etc.) see the [Helm chart README](https://github.com/CodeWithCJ/SparkyFitness/blob/main/helm/README.md).

---

## File: docs/content/1.install/6.build-from-source.md

# Build from Source

Run SparkyFitness directly on your machine without Docker. You will need Node.js, pnpm, and a running PostgreSQL instance.

## Prerequisites

- **Node.js** 24 or later
- **pnpm** — install with `npm install pnpm`
- **PostgreSQL** 17 or later

## 1. Clone the repository

```bash
git clone https://github.com/CodeWithCJ/SparkyFitness.git
cd SparkyFitness
```

## 2. Install dependencies

```bash
pnpm install
```

## 3. Configure environment variables

Copy the example env file to the repo root and fill in your values:

**Linux / macOS**
```bash
cp docker/.env.example .env
```

**Windows (PowerShell)**
```powershell
Copy-Item docker\.env.example .env
```

Required values to set in `.env`:

| Variable | Description |
|---|---|
| `SPARKY_FITNESS_DB_HOST` | PostgreSQL host — use `localhost` for local installs |
| `SPARKY_FITNESS_DB_NAME` | Database name (e.g. `sparkyfitness_db`) |
| `SPARKY_FITNESS_DB_USER` | Superuser used for migrations (e.g. `sparky`) |
| `SPARKY_FITNESS_DB_PASSWORD` | Superuser password |
| `SPARKY_FITNESS_APP_DB_USER` | App user with limited privileges (e.g. `sparky_app`) |
| `SPARKY_FITNESS_APP_DB_PASSWORD` | App user password |
| `SPARKY_FITNESS_FRONTEND_URL` | Set to `http://localhost:8080` for local builds |
| `SPARKY_FITNESS_API_ENCRYPTION_KEY` | 64-character hex string — generate with `openssl rand -hex 32` or `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` |
| `BETTER_AUTH_SECRET` | Strongly recommended — auto-generated if absent but sessions will not survive server restarts. Signs sessions and encrypts 2FA/TOTP data. **Never change after users have enabled 2FA or they will be locked out.** |

> **Note:** The default `SPARKY_FITNESS_DB_HOST` in the example file is set to a Docker service name. Change it to `localhost` for a local install.

## 4. Set up PostgreSQL

Create the superuser and database that match your `.env` values.

**Linux**
```bash
sudo -u postgres createuser --pwprompt sparky
sudo -u postgres createdb sparkyfitness_db --owner sparky
```

**macOS (Homebrew)** — drop the `sudo -u postgres` prefix if your current user already has PostgreSQL superuser rights:
```bash
createuser --pwprompt sparky
createdb sparkyfitness_db --owner sparky
```

**Windows** — open a terminal and use `psql` as the `postgres` user (adjust the path to match your PostgreSQL install):
```powershell
psql -U postgres -c "CREATE ROLE sparky WITH LOGIN PASSWORD 'yourpassword';"
psql -U postgres -c "CREATE DATABASE sparkyfitness_db OWNER sparky;"
```

The `sparky_app` application user is created automatically by the server on first startup — you do not need to create it manually. Database migrations also run automatically on server start.

## 5. Start the backend server

```bash
cd SparkyFitnessServer
pnpm start
```

The API server starts on port `3010` by default. On first run it applies all migrations and creates the app database user. API docs are available at `http://localhost:3010/api/api-docs/swagger`.

## 6. Start the frontend

Open a second terminal from the repo root:

```bash
cd SparkyFitnessFrontend
pnpm dev
```

The web app starts on port `8080` by default. Open `http://localhost:8080` in your browser.

## Port summary

| Service | Default URL |
|---|---|
| Backend API | `http://localhost:3010` |
| Frontend | `http://localhost:8080` |
| API Docs | `http://localhost:3010/api/api-docs/swagger` |

---

## File: docs/content/1.install/7.environment-variables.md

# Environment Variables

This document provides a comprehensive list and detailed descriptions of all environment variables used by SparkyFitness. Proper configuration of these variables is crucial for the application to function as expected.

For a complete list of all available variables and their detailed descriptions, please refer to the example environment file:
[`.env.example` on GitHub](https://github.com/CodeWithCJ/SparkyFitness/blob/main/docker/.env.example)

::alert{type="warning"}
**Important Note for Docker Compose Users:**
For an environment variable defined in your `.env` file to be recognized by the application running inside a Docker container, it **must** be explicitly passed to that service in your `docker-compose.yml` file. If you add a new variable to your `.env` file that is not already present in the `environment:` section of the `sparkyfitness-server` (or `sparkyfitness-garmin`) service, the application will not see it.
::

## Essential Configuration

The following environment variables are **mandatory** and must be supplied for the application to start correctly. Failure to provide these will result in the server failing to launch.

- **`SPARKY_FITNESS_DB_NAME`**: Your desired PostgreSQL database name (e.g., `sparkyfitness_db`).
- **`SPARKY_FITNESS_DB_USER`**: Your desired PostgreSQL database user (e.g., `sparky`). This user is used for DB initialization and migrations.
- **`SPARKY_FITNESS_DB_PASSWORD`**: A strong password for your PostgreSQL database. This shouldn't be changed after initial setup. If you need to change it, you will need to update the password in the database and update this env variable.
- **`SPARKY_FITNESS_APP_DB_USER`**: Application database user with limited privileges. It can be changed any time after initialization.
- **`SPARKY_FITNESS_APP_DB_PASSWORD`**: Password for the application database user.
- **`SPARKY_FITNESS_FRONTEND_URL`**: The public URL of your frontend (e.g., `http://localhost:8080` for local testing, or your domain like `https://fitness.example.com` for production). This is crucial for CORS security.
- **`SPARKY_FITNESS_API_ENCRYPTION_KEY`**: A 64-character hex string for data encryption. You can generate one using:
  - `openssl rand -hex 32`
  - `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
  - **`SPARKY_FITNESS_API_ENCRYPTION_KEY_FILE`**: (Optional) Path to a file containing the encryption key. Useful for Docker Swarm/Kubernetes secrets. When this variable is set, the application will read the encryption key from the specified file path, allowing for more secure secret management in containerized environments.
- **`BETTER_AUTH_SECRET`**: A secret key used by Better Auth to sign sessions and tokens. Make this a long, random, and secure string. You can generate one using:
  - `openssl rand -hex 32`
  - `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
  - > [!CAUTION]
    > **CRITICAL for 2FA/TOTP:** This secret is used to encrypt Two-Factor Authentication (2FA) data in the database. If you change this variable after users have enabled 2FA, the server will lose access to their codes, and **all 2FA users will be locked out** of their accounts. This variable must be set to a persistent value during initial setup and should never be changed. **If you must change it, you must ensure that ALL users have disabled Two-Factor Authentication (TOTP) first.**

## Mandatory Volume Paths

These paths define where Docker volumes will store persistent data on your host. These are **mandatory** to prevent data loss if containers are removed. You can either define them in the `.env` file or directly in the `docker-compose.yml`.

- **`DB_PATH`**: Path for PostgreSQL database data (e.g., `../postgresql`).
- **`SERVER_BACKUP_PATH`**: Path for server backups (e.g., `./backup`).
- **`SERVER_UPLOADS_PATH`**: Path for profile pictures and exercise images (e.g., `./uploads`).

## Optional Configuration

The following variables are optional and can be used to customize your SparkyFitness installation.

### Front End Variables

These variables control frontend behavior and should be passed to the `sparkyfitness-frontend` service
in your `docker-compose.yml`.

- **`SPARKY_FITNESS_SERVER_HOST`**: Hostname of the backend server.
- **`SPARKY_FITNESS_SERVER_PORT`**: Port on which the backend serer is running.
- **`SPARKY_FITNESS_FRONTEND_URL`**: The frontend URL on which the server will be accessible, useful for reverse proxies.
- **`NGINX_LISTEN_PORT`**: The port on which nginx should listen. Defaults to `80` when running as root and `8080` when running as non-root.
- **`NGINX_ACCESS_LOG`**: The access log path for nginx. Defaults to `/var/log/nginx/access.log` when running as root and `/dev/stdout` when running as non-root.
- **`NGINX_ERROR_LOG`**: The error log path for nginx. Defaults to `/var/log/nginx/error.log` when running as root and `/dev/stderr` when running as non-root.
- **`NGINX_DUMP_CONFIG`**: Always dump the complete nginx configuration on startup. The configuration should
always be dumped if it's invalid. Defaults to "false".

### Server Side Variables

These variables control backend behavior and should be passed to the `sparkyfitness-server` service in your `docker-compose.yml`.

- **`SPARKY_FITNESS_DISABLE_EMAIL_LOGIN`**: Set to `true` to disable email/password login on the login page (overridden by `SPARKY_FITNESS_FORCE_EMAIL_LOGIN`).
- **`SPARKY_FITNESS_LOG_LEVEL`**: Logging level for the server (e.g., `INFO`, `DEBUG`, `WARN`, `ERROR`).
- **`NODE_ENV`**: Node.js environment mode (e.g., `development`, `production`, `test`). Set to `production` for deployment to ensure optimal performance and security.
- **`TZ`**: Server timezone. Use a TZ database name (e.g., `America/New_York`, `Etc/UTC`).
- **`SPARKY_FITNESS_DISABLE_SIGNUP`**: Set to `true` to disable new user registrations.
- **`SPARKY_FITNESS_ADMIN_EMAIL`**: Set the email of a user to automatically grant admin privileges on server startup. If not set, no admin user will be created automatically.
- **`SPARKY_FITNESS_FORCE_EMAIL_LOGIN`**: Set to `true` to force email/password login to be enabled, overriding any in-app settings. This is a fail-safe to prevent being locked out if OIDC is misconfigured.
- **`ALLOW_PRIVATE_NETWORK_CORS`**: Set to `true` to allow Cross-Origin Resource Sharing (CORS) from private network addresses (e.g., `192.168.x.x`, `10.x.x.x`, `127.0.0.1`, `localhost`). Use with caution.
- **`ALLOW_PRIVATE_NETWORK_AI`**: Set to `true` to let non-admin users point custom AI service URLs (`custom`, `ollama`, `openai_compatible`) at private network addresses (e.g., `192.168.x.x`, `127.0.0.1`, `localhost`). Admins and global AI settings can always use private URLs, so most self-hosted setups don't need this. **Warning:** enabling it lets any registered user make the server send requests to your internal network (SSRF) — only enable on a trusted single-tenant deployment. Defaults to `false`.
- **`SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS`**: A comma-separated list of additional URLs that Better Auth should trust (e.g., `http://192.168.1.175:8080`). Use this if you are accessing the app from specific local IPs and `ALLOW_PRIVATE_NETWORK_CORS` is enabled.
- **`SPARKY_FITNESS_DB_HOST`**: The hostname of the PostgreSQL database. For Docker Compose, this defaults to `sparkyfitness-db` (the service name). Only change this if you are using an external database server.
- **`SPARKY_FITNESS_DB_PORT`**: Controls the **host port** exposed for external database access (e.g., pgAdmin). **Important:** Inside Docker, containers always communicate on port `5432`. Changing this value in `.env` will **not** affect container-to-container communication unless you are using an external database server.
  To use this, you must also uncomment the `ports` section under the `sparkyfitness-db` service in your `docker-compose.yml` file.
- **`SPARKY_FITNESS_SERVER_HOST`**: The hostname or IP of the backend server. Primarily used by the internal Nginx proxy (not to be confused with your proxy manager) in the frontend container to route API requests. For Docker Compose, this defaults to `sparkyfitness-server`.
- **`SPARKY_FITNESS_SERVER_PORT`**: The server port (e.g., `3010`). Defaults to `3010`. This is also used by the internal Nginx proxy (not to be confused with your proxy manager) in the frontend container.
- **`SPARKY_FITNESS_PUBLIC_API_DOCS`**: Set to `true` to make the Swagger API documentation (`/api/api-docs`) publicly accessible without logging in. Defaults to `false`.

### Email Settings (Server Side)

Configure these variables to enable email notifications (e.g., for password resets). If not configured, email functionality will be disabled.

- **`SPARKY_FITNESS_EMAIL_HOST`**: SMTP host (e.g., `smtp.example.com`).
- **`SPARKY_FITNESS_EMAIL_PORT`**: SMTP port (e.g., `587`).
- **`SPARKY_FITNESS_EMAIL_SECURE`**: Use `true` for TLS/SSL, `false` for plain text.
- **`SPARKY_FITNESS_EMAIL_USER`**: Your email username.
- **`SPARKY_FITNESS_EMAIL_PASS`**: Your email password.
- **`SPARKY_FITNESS_EMAIL_FROM`**: The 'from' email address.

### Rate Limiting (Server Side)

API keys are rate-limited to prevent abuse. These must be passed to `sparkyfitness-server`.

- **`SPARKY_FITNESS_API_KEY_RATELIMIT_WINDOW_MS`**: Time window in milliseconds. Defaults to `60000` (1 minute).
- **`SPARKY_FITNESS_API_KEY_RATELIMIT_MAX_REQUESTS`**: Maximum number of requests allowed per window. Defaults to `100`.

### Outbound Proxy (Server Side)

Most setups do not need these. They route the server's **outbound** requests (food providers, fitness integrations, AI providers, etc.) through a forward proxy. This is **not** how you serve SparkyFitness over HTTPS or behind a reverse proxy — for that (including the HTTPS the mobile app requires), see the [Reverse Proxy guide](/administration/reverse-proxy).

The standard `docker-compose.yml` already passes these to the `sparkyfitness-server` service; if unset, all requests go direct.

- **`HTTP_PROXY`**: Proxy URL for outbound plain-HTTP requests (e.g., `http://proxy.example.com:8888`).
- **`HTTPS_PROXY`**: Proxy URL for outbound HTTPS requests. Usually still an `http://` URL — it names the proxy to tunnel through, not the proxy's own protocol.
- **`NO_PROXY`**: Comma-separated hosts to reach directly (e.g., `localhost,127.0.0.1,sparkyfitness-garmin`). Suffix match; no CIDR ranges. Keep internal Docker services like `sparkyfitness-garmin` here so container-to-container calls are not sent to the proxy, plus any LAN integrations (Mealie, Tandoor, Ollama, etc.).

SOCKS proxies are not supported.

### OIDC Configuration (Server Side)

These variables configure the environment-based OIDC provider and must be passed to the `sparkyfitness-server` service.

When the following are set, an OIDC provider is created or updated at startup and used with the existing SSO flow.

- **`SPARKY_FITNESS_DISABLE_EMAIL_LOGIN`**: Set to `true` to disable email/password login on the login page (overridden by `SPARKY_FITNESS_FORCE_EMAIL_LOGIN`).
- **`SPARKY_FITNESS_OIDC_AUTH_ENABLED`**: Set to `true` to enable OIDC login, overriding the value from Admin > Authentication Settings.
- **`SPARKY_FITNESS_OIDC_ISSUER_URL`**: Issuer URL (e.g. `https://auth.example.com`). Discovery URL is derived as issuer + `/.well-known/openid-configuration`. Required for env provider upsert.
- **`SPARKY_FITNESS_OIDC_CLIENT_ID`**, **`SPARKY_FITNESS_OIDC_CLIENT_SECRET`**: Client credentials from your IdP. Required for env provider upsert.
- **`SPARKY_FITNESS_OIDC_PROVIDER_SLUG`**: URL-safe provider id (e.g. `authentik`). Required for env provider upsert.
- **`SPARKY_FITNESS_OIDC_PROVIDER_NAME`**: Display name for the provider (optional; defaults to slug).
- **`SPARKY_FITNESS_OIDC_SCOPE`**: Space-separated OIDC scopes (optional; defaults to `openid email profile`).
- **`SPARKY_FITNESS_OIDC_AUTO_REGISTER`**: Set to `true` to automatically create a new user account on first OIDC login (optional; defaults to `true`).
- **`SPARKY_FITNESS_OIDC_LOGO_URL`**: URL to a custom logo for the provider (optional).
- **`SPARKY_FITNESS_OIDC_DOMAIN`**: Organization domain for restricted access (optional; defaults to `slug.env`).
- **`SPARKY_FITNESS_OIDC_TOKEN_AUTH_METHOD`**: Authentication method for the token endpoint (optional; defaults to `client_secret_post`).
- **`SPARKY_FITNESS_OIDC_ID_TOKEN_SIGNED_ALG`**: Algorithm used to sign the ID token (optional; defaults to `RS256`).
- **`SPARKY_FITNESS_OIDC_USERINFO_SIGNED_ALG`**: Algorithm used to sign the UserInfo response (optional; defaults to `none`).
- **`SPARKY_FITNESS_OIDC_TIMEOUT`**: Request timeout in milliseconds (optional; defaults to `30000`).
- **`SPARKY_FITNESS_OIDC_AUTO_REDIRECT`**: Set to `true` to allow auto-redirect to the single OIDC provider when email login is disabled.
- **`SPARKY_FITNESS_OIDC_ADMIN_GROUP`**: Group/claim value from your IdP for admin role mapping. Configure your IdP to send this in token claims; it is used to automatically grant admin privileges.
- **`ALLOW_PRIVATE_NETWORK_CORS`**: Set to `true` to allow Cross-Origin Resource Sharing (CORS) from private network addresses (e.g., `192.168.x.x`, `10.x.x.x`, `127.0.0.1`, `localhost`). This allows standard browser requests from local IPs. Use with caution.
- **`SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS`**: A comma-separated list of additional URLs that Better Auth should trust (e.g., `http://192.168.1.175:8080,http://10.0.0.5:8080`). Use this if you are accessing the app from specific local IPs on your network and `ALLOW_PRIVATE_NETWORK_CORS` is enabled.

### Garmin Integration

If you require Garmin integration, ensure `GARMIN_MICROSERVICE_URL` is passed to both the `sparkyfitness-server` and `sparkyfitness-garmin` services. The other two variables are for the `sparkyfitness-garmin` service.

- **`GARMIN_MICROSERVICE_URL`**: The URL for the Garmin microservice (e.g., `http://sparkyfitness-garmin:8000`).
- **`GARMIN_SERVICE_PORT`**: Used for Garmin Connect synchronization. Must match `GARMIN_MICROSERVICE_URL`.
- **`GARMIN_SERVICE_IS_CN`**: Set to `true` for China region. Defaults to `false`.

### MCP Server Configuration

The Model Context Protocol (MCP) server that connects AI assistants to your health data is now served **in-process** by the main server at `POST /mcp`. It shares the core database variables with the rest of the server, so no MCP-specific transport configuration is required. See the [AI Assistant & MCP Server guide](/features/mcp-server) for client setup.

- **`DEV_TOOLS_ENABLED`**: (Optional) Set to `true` to enable the in-process `/mcp` developer/debugging tools (`sparky_inspect_schema`, `sparky_get_user_info`, `sparky_get_db_stats`). **Requires an admin API key**, and the tools run with elevated database access that bypasses Row Level Security. Off by default; do not enable in production unless you are actively debugging.

The MCP/API-key request rate is governed by the [Rate Limiting](#rate-limiting-server-side) variables (`SPARKY_FITNESS_API_KEY_RATELIMIT_WINDOW_MS` and `SPARKY_FITNESS_API_KEY_RATELIMIT_MAX_REQUESTS`).

### iOS Mobile App Development

These variables configure code signing, bundle identifiers, and shared App Groups for the iOS mobile app ([`SparkyFitnessMobile`](/developer/getting-started)). They are only needed during local iOS development or when building for a physical device or simulator.

* **`EXPO_DEV_APPLE_TEAM_ID`**: The 10-character Apple Developer Team ID used to configure auto-signing in Xcode for dev builds.
* **`EXPO_PROD_APPLE_TEAM_ID`**: The 10-character Apple Developer Team ID used for production builds.
* **`EXPO_DEV_BUNDLE_IDENTIFIER`**: The bundle identifier for the development app (defaults to `org.SparkyApps.SparkyFitnessMobile.dev`).
* **`WIDGET_BUNDLE_IDENTIFIER`**: The bundle identifier for the iOS Widget extension (defaults to `<EXPO_DEV_BUNDLE_IDENTIFIER>.ExpoWidgetsTarget`).
* **`IOS_APP_GROUP_DEV`**: The shared App Group identifier used to pass data between the main app and the widgets during development (defaults to `group.org.SparkyApps.SparkyFitnessMobile.dev`).
* **`IOS_APP_GROUP_PROD`**: The shared App Group identifier used to pass data between the main app and the widgets in production (defaults to `group.com.SparkyApps.SparkyFitnessMobile.shared`).

---

## File: docs/content/1.install/8.external-database.md

# External Database Setup

If you are using your own PostgreSQL instance (e.g., AWS RDS, Azure Database, CloudNativePG, or a local installation) instead of the provided Docker Compose setup, follow these steps to ensure the database is correctly configured.

> [!WARNING]
> **Community Supported Only**
> External and managed database configurations are not officially tested or supported by the core application maintainers. Use this guide at your own risk.

## 1. Database and Users

The application uses two database roles:

1.  **SPARKY_FITNESS_DB_USER**: Used for migrations and schema management.
2.  **SPARKY_FITNESS_APP_DB_USER**: Used by the application components with restricted permissions.

> [!IMPORTANT]
> The application automatically creates the **App User** (`SPARKY_FITNESS_APP_DB_USER`) and grants it all necessary permissions on first startup. The **DB User** (`SPARKY_FITNESS_DB_USER`) must have `CREATEROLE` to do this.

### Option A — Standard Setup (SparkyFitness creates the SPARKY_FITNESS_APP_DB_USER User automatically)

Run the following as a database superuser:

```sql
-- 1. Create the Database
CREATE DATABASE sparkyfitness_db;

-- 2. Create the DB Owner user (referenced in .env as SPARKY_FITNESS_DB_USER)
CREATE USER sparky_admin WITH PASSWORD 'your_secure_password';

-- 3. Grant database ownership so sparky_admin can create schemas and tables
ALTER DATABASE sparkyfitness_db OWNER TO sparky_admin;

-- 4. Grant Role Creation privilege
-- Required so the app can automatically create SPARKY_FITNESS_APP_DB_USER
-- on first startup (see utils/dbMigrations.ts)
ALTER USER sparky_admin CREATEROLE;

-- 5. PostgreSQL 15+ only: the default public schema permissions changed in PG 15.
-- Explicitly grant create rights to the owner:
GRANT ALL ON SCHEMA public TO sparky_admin;
```

### Option B — Reduced Privilege Setup (you create the SPARKY_FITNESS_APP_DB_USER User manually)

If your environment does not allow `CREATEROLE` (e.g., strict managed databases), you can pre-create the App User yourself. The application checks whether the role already exists before attempting to create it — if it finds it, `CREATE ROLE` is skipped entirely and `CREATEROLE` is **not required**.

```sql
-- 1. Create the Database
CREATE DATABASE sparkyfitness_db;

-- 2. Create the DB Owner user (referenced in .env as SPARKY_FITNESS_DB_USER)
CREATE USER sparky_admin WITH PASSWORD 'your_secure_password';

-- 3. Grant database ownership
ALTER DATABASE sparkyfitness_db OWNER TO sparky_admin;

-- 4. PostgreSQL 15+ only
GRANT ALL ON SCHEMA public TO sparky_admin;

-- 5. Pre-create the App User (referenced in .env as SPARKY_FITNESS_APP_DB_USER)
--    The app detects this role already exists and skips CREATE ROLE,
--    so sparky_admin does NOT need CREATEROLE.
CREATE USER sparky_app WITH PASSWORD 'another_secure_password';
```

Set both users in your `.env`:
```bash
SPARKY_FITNESS_DB_USER=sparky_admin
SPARKY_FITNESS_DB_PASSWORD=your_secure_password
SPARKY_FITNESS_APP_DB_USER=sparky_app
SPARKY_FITNESS_APP_DB_PASSWORD=another_secure_password
```

> [!NOTE]
> With Option B, `sparky_admin` still needs database ownership to run migrations (create tables, schemas, functions, indexes). The only privilege that is no longer required is `CREATEROLE`.

## 2. PostgreSQL Extensions

> [!NOTE]
> **No extensions required.** As of v0.17.0 release, SparkyFitness no longer depends on `uuid-ossp`, `pgcrypto`, or `pg_stat_statements`.
>
> - UUID generation uses the built-in `gen_random_uuid()` (PostgreSQL 13+), which requires no extension.
> - Encryption is handled entirely in application code (AES-256-GCM via Node.js `crypto`), not via database functions.
>
> If you are upgrading an existing installation that has these extensions installed, the `20260618000000_remove_superuser_extensions.sql` migration will attempt to remove them automatically. Non-superuser environments will skip the `DROP EXTENSION` step gracefully — the extensions are unused and harmless if left in place.

## 3. Row Level Security (RLS)

The `sparky_admin` user must be the **owner** of the tables to enable and manage RLS policies. Setting `ALTER DATABASE ... OWNER TO sparky_admin` ensures that any tables created during migrations are automatically owned by `sparky_admin`.

## 4. Environment Configuration

In your `.env` file, ensure you point to your external database:

```bash
SPARKY_FITNESS_DB_HOST=your-db-host
SPARKY_FITNESS_DB_NAME=sparkyfitness_db
SPARKY_FITNESS_DB_USER=sparky_admin
SPARKY_FITNESS_DB_PASSWORD=your_secure_password
SPARKY_FITNESS_DB_PORT=5432

# App user — created automatically (Option A) or pre-created by you (Option B)
SPARKY_FITNESS_APP_DB_USER=sparky_app
SPARKY_FITNESS_APP_DB_PASSWORD=another_secure_password
```

> [!IMPORTANT]
> `SPARKY_FITNESS_APP_DB_USER` and `SPARKY_FITNESS_APP_DB_PASSWORD` are **always required** in the `.env` file — the app uses them for the live query connection pool regardless of which setup option you chose.
> - **Option A**: the app creates this role automatically using these values.
> - **Option B**: the role already exists; the password in `.env` must match the one set when you created it manually.

## 5. Security Hardening (applies only to Option A)

The `CREATEROLE` privilege is only required during the **initial installation** or when a future update needs to create a new specialized database role.

### Revoking CREATEROLE

Once the application has successfully started for the first time and you see the log `Successfully created role`, you can revoke this privilege:

```sql
ALTER USER sparky_admin NOCREATEROLE;
```

> [!CAUTION]
> **Potential Issues with NOCREATEROLE**
> If you revoke this privilege, future application updates that require creating new database roles will fail. If you encounter a "Permission Denied" error during a future upgrade, temporarily re-grant `CREATEROLE` or manually create the required role as a superuser, then revoke it again.