[{"data":1,"prerenderedAt":754},["ShallowReactive",2],{"search-api":3},[4,18,31,41,48,55,62,76,86,98,112,123,130,137,145,152,161,168,175,183,190,198,205,212,220,227,237,251,260,271,278,285,292,301,311,318,325,332,340,347,358,369,379,389,399,408,415,425,433,442,449,460,468,474,482,493,503,520,535,548,561,573,584,595,607,617,631,638,652,667,676,684,691,698,706,714,722,731,738],{"id":5,"path":6,"dir":7,"title":8,"description":9,"keywords":10,"body":17},"content:0.index.md","\u002F","","Overview","Welcome to the comprehensive documentation for SparkyFitness, a self-hosted alternative to MyFitnessPal with AI-powered nutrition assistance.",[11,12,13,14,15,16],"What is SparkyFitness?","Key Features","Architecture","Documentation Sections","Getting Help","License","  Overview  Welcome to the comprehensive documentation for   SparkyFitness , a self-hosted alternative to MyFitnessPal with AI-powered nutrition assistance.    Disclaimer : While we strive to keep this documentation as accurate and up-to-date as possible, some sections may occasionally become outdated. If you encounter any issues or have questions, please reach out via our   GitHub Discussions  or join our   Discord community  where others can help you.  What is SparkyFitness?  SparkyFitness is a full-stack fitness tracking application that helps you monitor nutrition, exercise, body measurements, and achieve your health goals. Built with modern web technologies and designed for self-hosting, it provides complete control over your fitness data.  Key Features    🍎 Nutrition Tracking  - Log meals, create custom foods, analyze trends   💪 Exercise Logging  - Record workouts, browse exercise database   📏 Body Measurements  - Track weight, measurements, visualize progress   🤖 AI Nutrition Coach  - Chat-based food logging with image recognition   🎯 Goal Setting  - Set and track fitness and nutrition goals   📊 Comprehensive Reports  - Detailed analytics and progress tracking   🔒 Privacy-First  - Self-hosted with complete data control  Architecture  SparkyFitness is built with:    Frontend : React 18 + TypeScript + Vite + Tailwind CSS   Backend : Node.js + Express + PostgreSQL   AI Integration : Multi-provider support (OpenAI, Anthropic, Google)   Deployment : Docker containers with development and production configurations   Security : Row Level Security, JWT authentication, encrypted API keys  Documentation Sections     Getting Started  - Complete setup guide for development and production    Development Workflow  - Developer guide and coding standards    Features Overview  - Complete feature documentation    Database Schema  - Database structure and design    Architecture  - High-level architecture  Getting Help    💬 Discord Community :   Join our Discord   📋 GitHub Discussions : Ask questions and share ideas   🐛 Issues : Report bugs and request features   📚 Documentation : Comprehensive guides in this docs site  License  SparkyFitness is open source software. Please check the repository for license details.",{"id":19,"path":20,"dir":21,"title":22,"description":23,"keywords":24,"body":30},"content:1.install:1.docker-compose.md","\u002Finstall\u002Fdocker-compose","install","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.",[25,26,27,28,29],"Prerequisites","Installation Steps","Services Overview","Accessing the Application","Stopping and Removing Services","  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.\n    Download Docker Desktop  Installation Steps    Create a new folder and download Docker files :\nCreate a new directory for SparkyFitness and navigate into it. Then, download the necessary   docker-compose.yml  and   .env  files.     mkdir   sparkyfitness   &&   cd   sparkyfitness\n   curl   -L   -o   docker-compose.yml   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness\u002Freleases\u002Flatest\u002Fdownload\u002Fdocker-compose.prod.yml      \n   curl   -L   -o   .env   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness\u002Freleases\u002Flatest\u002Fdownload\u002Fdefault.env.example\n   Configure Environment Variables :\nThe   docker-compose.yml  file relies on environment variables defined in a   .env  file.\nOpen 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:\n   .env.example  on GitHub  For a comprehensive list of all available environment variables and their detailed descriptions, please refer to the   Environment Variables documentation .   Start the Application :\nFrom within the   sparkyfitness  directory (where   docker-compose.yml  is located), pull the latest images and start the application services:     docker   compose   pull   &&   docker   compose   up   -d\n    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   ..\u002Fpostgresql  on your host, ensuring your data is not lost if containers are removed.    sparkyfitness-server :    Image :   codewithcj\u002Fsparkyfitness_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\u002Fsparkyfitness: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:\u002F\u002Flocalhost: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 :\n    Image :   codewithcj\u002Fsparkyfitness_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:\u002F\u002Flocalhost:3004 ).  Stopping and Removing Services  To stop the running services without removing their data volumes:     docker   compose   stop\n  To stop and remove all services, networks, and volumes (this will delete your database data!):     docker   compose   down   -v\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":32,"path":33,"dir":21,"title":34,"description":35,"keywords":36,"body":40},"content:1.install:2.portainer.md","\u002Finstall\u002Fportainer","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.",[25,37,38,39],"Step 1: Create a New Stack in Portainer","Step 2: Deploy the Stack","Step 3: Access SparkyFitness","  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:    A running Docker environment : Portainer requires Docker to be installed on your server.   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    Log in to Portainer .  Navigate to   Stacks  in the left sidebar.  Click   Add stack .   Name your stack  (e.g.,   sparkyfitness ).  Select   Upload  for the build method.   Upload File : Download the   docker-compose.prod.yml  from the latest release and upload it here.  (Optional) You can also use the   Web editor  method and copy-paste the content if you prefer.   Environment variables : For a comprehensive list of all available environment variables and their detailed descriptions, please refer to the   Environment Variables documentation . You will need to add these environment variables directly in Portainer.  Step 2: Deploy the Stack   After configuring the stack, click the   Deploy the stack  button.  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:\u002F\u002Fyour-server-ip:3004 ).  You should now see the SparkyFitness login\u002Fsignup page.",{"id":42,"path":43,"dir":21,"title":44,"description":45,"keywords":46,"body":47},"content:1.install:3.synology.md","\u002Finstall\u002Fsynology","Synology Community Guide","This guide provides instructions for installing SparkyFitness on your Synology NAS, provided by the community.",[],"  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",{"id":49,"path":50,"dir":21,"title":51,"description":52,"keywords":53,"body":54},"content:1.install:4.proxmox.md","\u002Finstall\u002Fproxmox","Proxmox Installation Guide","This guide provides instructions for installing SparkyFitness on Proxmox VE using a script provided by the community.",[],"  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  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.",{"id":56,"path":57,"dir":21,"title":58,"description":7,"keywords":59,"body":61},"content:1.install:5.kubernetes.md","\u002Finstall\u002Fkubernetes","Kubernetes",[60],"Quick Start (Kubernetes)","    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.     # 1. Install with default settings (bundled PostgreSQL, no ingress)\n   helm   install   sparkyfitness   oci:\u002F\u002Fghcr.io\u002Fcodewithcj\u002Fcharts\u002Fsparkyfitness\n   \n   # -- OR install directly from source --\n   git   clone   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness.git\n   helm   install   sparkyfitness   .\u002FSparkyFitness\u002Fhelm\u002Fchart\n   \n   # 2. (Optional) Customize values\n   helm   install   sparkyfitness   .\u002FSparkyFitness\u002Fhelm\u002Fchart   -f   my-values.yaml\n   \n   # 3. Access the application in browser via Ingress or HTTPRoute you've specified in values\n  For all configuration options (external database, ingress, OIDC, email, etc.) see the   Helm chart README .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":63,"path":64,"dir":21,"title":65,"description":66,"keywords":67,"body":75},"content:1.install:6.build-from-source.md","\u002Finstall\u002Fbuild-from-source","Build from Source","Run SparkyFitness directly on your machine without Docker. You will need Node.js, pnpm, and a running PostgreSQL instance.",[25,68,69,70,71,72,73,74],"1. Clone the repository","2. Install dependencies","3. Configure environment variables","4. Set up PostgreSQL","5. Start the backend server","6. Start the frontend","Port summary","  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 -g pnpm   PostgreSQL  17 or later  1. Clone the repository     git   clone   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness.git\n   cd   SparkyFitness\n  2. Install dependencies     pnpm   install\n  3. Configure environment variables  Copy the example env file to the repo root and fill in your values:   Linux \u002F macOS     cp   docker\u002F.env.example   .env\n   Windows (PowerShell)     Copy-Item docker\\.env.example .env\n  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:\u002F\u002Flocalhost: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\u002FTOTP 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     sudo   -u   postgres   createuser   --pwprompt   sparky\n   sudo   -u   postgres   createdb   sparkyfitness_db   --owner   sparky\n   macOS (Homebrew)  — drop the   sudo -u postgres  prefix if your current user already has PostgreSQL superuser rights:     createuser   --pwprompt   sparky\n   createdb   sparkyfitness_db   --owner   sparky\n   Windows  — open a terminal and use   psql  as the   postgres  user (adjust the path to match your PostgreSQL install):     psql -U postgres -c \"CREATE ROLE sparky WITH LOGIN PASSWORD 'yourpassword';\"\n   psql -U postgres -c \"CREATE DATABASE sparkyfitness_db OWNER sparky;\"\n  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     cd   SparkyFitnessServer\n   pnpm   start\n  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:\u002F\u002Flocalhost:3010\u002Fapi\u002Fapi-docs\u002Fswagger .  6. Start the frontend  Open a second terminal from the repo root:     cd   SparkyFitnessFrontend\n   pnpm   dev\n  The web app starts on port   8080  by default. Open   http:\u002F\u002Flocalhost:8080  in your browser.  Port summary     Service  Default URL    Backend API   http:\u002F\u002Flocalhost:3010   Frontend   http:\u002F\u002Flocalhost:8080   API Docs   http:\u002F\u002Flocalhost:3010\u002Fapi\u002Fapi-docs\u002Fswagger  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":77,"path":78,"dir":21,"title":79,"description":80,"keywords":81,"body":85},"content:1.install:7.environment-variables.md","\u002Finstall\u002Fenvironment-variables","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.",[82,83,84],"Essential Configuration","Mandatory Volume Paths","Optional Configuration","  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:\n   .env.example  on GitHub    Important Note for Docker Compose Users: \nFor 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:\u002F\u002Flocalhost:8080  for local testing, or your domain like   https:\u002F\u002Ffitness.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:\n    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\u002FKubernetes 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:\n    openssl rand -hex 32   node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"     !CAUTION  CRITICAL for 2FA\u002FTOTP:  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.,   ..\u002Fpostgresql ).    SERVER_BACKUP_PATH : Path for server backups (e.g.,   .\u002Fbackup ).    SERVER_UPLOADS_PATH : Path for profile pictures and exercise images (e.g.,   .\u002Fuploads ).  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\nin 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   \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log  when running as root and   \u002Fdev\u002Fstdout  when running as non-root.    NGINX_ERROR_LOG : The error log path for nginx. Defaults to   \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log  when running as root and   \u002Fdev\u002Fstderr  when running as non-root.    NGINX_DUMP_CONFIG : Always dump the complete nginx configuration on startup. The configuration should\nalways 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\u002Fpassword 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\u002FNew_York ,   Etc\u002FUTC ).    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\u002Fpassword 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:\u002F\u002F192.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.\nTo 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 (  \u002Fapi\u002Fapi-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\u002FSSL,   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 .  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:\u002F\u002Fproxy.example.com:8888 ).    HTTPS_PROXY : Proxy URL for outbound HTTPS requests. Usually still an   http:\u002F\u002F  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\u002Fpassword 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:\u002F\u002Fauth.example.com ). Discovery URL is derived as issuer +   \u002F.well-known\u002Fopenid-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\u002Fclaim 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:\u002F\u002F192.168.1.175:8080,http:\u002F\u002F10.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:\u002F\u002Fsparkyfitness-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 \u002Fmcp . 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  for client setup.     DEV_TOOLS_ENABLED : (Optional) Set to   true  to enable the in-process   \u002Fmcp  developer\u002Fdebugging 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\u002FAPI-key request rate is governed by the   Rate Limiting  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 ). 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   \u003CEXPO_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 ).",{"id":87,"path":88,"dir":21,"title":89,"description":90,"keywords":91,"body":97},"content:1.install:8.external-database.md","\u002Finstall\u002Fexternal-database","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.",[92,93,94,95,96],"1. Database and Users","2. PostgreSQL Extensions","3. Row Level Security (RLS)","4. Environment Configuration","5. Security Hardening (applies only to Option A)","  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 \nExternal 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:    SPARKY_FITNESS_DB_USER : Used for migrations and schema management.   SPARKY_FITNESS_APP_DB_USER : Used by the application components with restricted permissions.    !IMPORTANT \nThe 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:     -- 1. Create the Database\n   CREATE DATABASE sparkyfitness_db;\n   \n   -- 2. Create the DB Owner user (referenced in .env as SPARKY_FITNESS_DB_USER)\n   CREATE USER sparky_admin WITH PASSWORD 'your_secure_password';\n   \n   -- 3. Grant database ownership so sparky_admin can create schemas and tables\n   ALTER DATABASE sparkyfitness_db OWNER TO sparky_admin;\n   \n   -- 4. Grant Role Creation privilege\n   -- Required so the app can automatically create SPARKY_FITNESS_APP_DB_USER\n   -- on first startup (see utils\u002FdbMigrations.ts)\n   ALTER USER sparky_admin CREATEROLE;\n   \n   -- 5. PostgreSQL 15+ only: the default public schema permissions changed in PG 15.\n   -- Explicitly grant create rights to the owner:\n   GRANT ALL ON SCHEMA public TO sparky_admin;\n  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 .     -- 1. Create the Database\n   CREATE DATABASE sparkyfitness_db;\n   \n   -- 2. Create the DB Owner user (referenced in .env as SPARKY_FITNESS_DB_USER)\n   CREATE USER sparky_admin WITH PASSWORD 'your_secure_password';\n   \n   -- 3. Grant database ownership\n   ALTER DATABASE sparkyfitness_db OWNER TO sparky_admin;\n   \n   -- 4. PostgreSQL 15+ only\n   GRANT ALL ON SCHEMA public TO sparky_admin;\n   \n   -- 5. Pre-create the App User (referenced in .env as SPARKY_FITNESS_APP_DB_USER)\n   --    The app detects this role already exists and skips CREATE ROLE,\n   --    so sparky_admin does NOT need CREATEROLE.\n   CREATE USER sparky_app WITH PASSWORD 'another_secure_password';\n  Set both users in your   .env :     SPARKY_FITNESS_DB_USER  =  sparky_admin\n   SPARKY_FITNESS_DB_PASSWORD  =  your_secure_password\n   SPARKY_FITNESS_APP_DB_USER  =  sparky_app\n   SPARKY_FITNESS_APP_DB_PASSWORD  =  another_secure_password\n    !NOTE \nWith 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:     SPARKY_FITNESS_DB_HOST  =  your-db-host\n   SPARKY_FITNESS_DB_NAME  =  sparkyfitness_db\n   SPARKY_FITNESS_DB_USER  =  sparky_admin\n   SPARKY_FITNESS_DB_PASSWORD  =  your_secure_password\n   SPARKY_FITNESS_DB_PORT  =  5432\n   \n   # App user — created automatically (Option A) or pre-created by you (Option B)\n   SPARKY_FITNESS_APP_DB_USER  =  sparky_app\n   SPARKY_FITNESS_APP_DB_PASSWORD  =  another_secure_password\n    !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:     ALTER USER sparky_admin NOCREATEROLE;\n    !CAUTION  Potential Issues with NOCREATEROLE \nIf 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.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":99,"path":100,"dir":21,"title":101,"description":102,"keywords":103,"body":111},"content:1.install:9.postgres-upgrade.md","\u002Finstall\u002Fpostgres-upgrade","PostgreSQL Upgrade (15 to 18.3)","This guide provides a step-by-step tutorial for upgrading your SparkyFitness PostgreSQL database from version 15-alpine to 18.3-alpine.",[25,104,105,106,107,108,109,110],"Default Paths","Assumptions","Part 1: Backup and Shutdown","Part 2: Configuration Update","Update postgres, server, frontend and garmin(if using garmin) section in your compose file to include 1000 for PUID and GUID\nPUID: 1000\nGUID: 1000","Part 3: Restore and Restart","Troubleshooting","  PostgreSQL Upgrade (15 to 18.3)  This guide provides a step-by-step tutorial for upgrading your SparkyFitness PostgreSQL database from version 15-alpine to 18.3-alpine.    !IMPORTANT  Warning : PostgreSQL does NOT automatically upgrade its data. Changing the image version alone will cause the database to fail to start. Follow these steps carefully.  Prerequisites   SparkyFitness installed via Docker Compose.  Basic knowledge of Docker commands.  Things can go wrong and you don't blame me :)  You have a backup of your data before starting the upgrade.  You have a backup of your .env file before starting the upgrade.  You have a backup of your docker-compose.yml file before starting the upgrade.  Default Paths  This guide assumes you are using the default SparkyFitness directory structure. If you have custom paths, replace\n  .\u002Fpostgresql  with your actual path.  Assumptions    Base path : Your SparkyFitness installation directory (where   docker-compose.yml  is located).   Default Database Path :   .\u002Fpostgresql  (relative to the compose file).   Database Username :   sparky  (Verify this in your   .env  file. This is your SPARKY_FITNESS_DB_USER).  **Database Name:   sparkyfitness_db  (this is your SPARKY_FITNESS_DB_NAME. default is sparkyfitness_db)   Part 1: Backup and Shutdown  1. Perform a Full Data Backup  Run this on your host terminal to export all your data into a single SQL file. Replace   [OLD_CONTAINER_NAME]  with your actual container name (e.g.,   sparkyfitness-db  or   postgres15-alpine ):\nrun \"docker ps \" to find the old container name. in the below command sparky is your SPARKY_FITNESS_DB_USER     docker   exec   -i   [OLD_CONTAINER_NAME] pg_dumpall -U sparky   >   .\u002Ffull_backup.sql\n  2. Stop All Containers  Stop the services to prevent any new data from being written during the upgrade.     docker   compose   down\n  3. Backup and Move Old Volume (Host Side)  We'll rename the old volume as a safety measure and create a fresh one for the new version.     cd   your_sparkyfitness_directory\n   # Move old v15 data to a backup folder\n   sudo   mv   .\u002Fpostgresql   .\u002Fpostgresql_v15\n   # Create a fresh folder for the new version\n   sudo   mkdir   -p   .\u002Fpostgresql\n   # Set the correct permissions for the Postgres process (UID 70)\n   sudo   chown   -R   1000:1000   .\u002F  *\n   Part 2: Configuration Update  4. Update your   docker-compose.yml  Modify the   sparkyfitness-db  service to use the new image and the corrected mount point structure required for version 18.3.\nWe are updating the container name to sparkyfitness-db and image to postgres:18.3     version  :   \"3.9\"\n   services  :\n     sparkyfitness-db  :\n       image  :   postgres:18.3-alpine\n       container_name  :   sparkyfitness-db\n  Update the   volumes  section of the   sparkyfitness-db  service to:           -   ${DB_PATH:-.\u002Fpostgresql}:\u002Fvar\u002Flib\u002Fpostgresql\n  4. Update your   docker-compose.yml  Update postgres, server, frontend and garmin(if using garmin) section in your compose file to include 1000 for PUID and GUID\nPUID: 1000\nGUID: 1000  Part 3: Restore and Restart  5. Bring Up All Containers  Start the sparkyfitness db container     docker   compose   up   -d   sparkyfitness-db\n    !IMPORTANT \nWait   30 seconds  for all services to fully initialize before proceeding. If you restore before the app finishes initializing, the app will overwrite your restored data.  6. Restore the Data  Once the db container is running and initialized, run the restore.     cat   .\u002Ffull_backup.sql   |   docker   exec   -i   sparkyfitness-db   psql   -U   sparky\n  if a restore fails try this     cat   .\u002Ffull_backup.sql   |   docker   exec   -i   sparkyfitness-db   psql   -U   sparky   -d   sparkyfitness_db\n  7. Restart All Containers  Restart the services so the app picks up the restored data.     docker   compose   restart\n   Troubleshooting    Permission Denied : If the container fails to start with a permission error, re-run:\n  sudo chown -R 1000:1000 .\u002Fpostgresql  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":113,"path":114,"dir":21,"title":115,"description":7,"keywords":116,"body":122},"content:1.install:10.nixos.md","\u002Finstall\u002Fnixos","Nixos",[25,117,118,119,120,121],"1. Add the flake input","2. Provide the secrets","3. Build and switch","Key options","Local build and development","    Community Contribution:  The Nix flake and NixOS module are community-provided. The SparkyFitness maintainers do not use Nix\u002FNixOS and are unable to test or officially support this installation method. It is provided   as-is  as part of a community contribution.  NixOS  Run SparkyFitness on NixOS   without Docker  using the Nix flake and the\n  services.sparkyfitness  NixOS module. The module runs the backend as a systemd\nservice, optionally provisions a local PostgreSQL database, and serves the\nstatic frontend through nginx with the same reverse-proxy routes (  \u002Fapi ,\n  \u002Fhealth-data ,   \u002Fuploads ,   \u002Fmcp ) the Docker deployment uses.  Prerequisites   A NixOS host with   flakes enabled  (  nix.settings.experimental-features = [ \"nix-command\" \"flakes\" ]; ).   PostgreSQL 15 or later.  The module defaults to   postgresql_16 . Earlier\nversions reject the migrations (which use   UNIQUE NULLS NOT DISTINCT ) with a\nsyntax error near   \"NULLS\" .  1. Add the flake input  Add SparkyFitness as a flake input and import its NixOS module in your system\nconfiguration:     {\n     inputs.sparkyfitness.url = \"github:CodeWithCJ\u002FSparkyFitness\";\n   \n     outputs = { nixpkgs, sparkyfitness, ... }: {\n       nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {\n         system = \"x86_64-linux\";\n         modules = [\n           sparkyfitness.nixosModules.sparkyfitness\n           {\n             services.sparkyfitness = {\n               enable = true;\n               frontendUrl = \"https:\u002F\u002Ffitness.example.com\";\n               # Secrets (DB passwords, encryption key, auth secret) live here:\n               environmentFile = \"\u002Frun\u002Fsecrets\u002Fsparkyfitness.env\";\n               nginx.virtualHost = \"fitness.example.com\";\n             };\n           }\n         ];\n       };\n     };\n   }\n  Use   nixosModules.sparkyfitness  to wire in this flake's package builds\nautomatically, or   nixosModules.default  and set   backendPackage  \u002F\n  frontendPackage  yourself.  2. Provide the secrets   environmentFile  is a systemd   EnvironmentFile  and should contain at least:   SPARKY_FITNESS_DB_PASSWORD=...\nSPARKY_FITNESS_APP_DB_PASSWORD=...\nSPARKY_FITNESS_API_ENCRYPTION_KEY=...   # openssl rand -hex 32\nBETTER_AUTH_SECRET=...\n  Keep this file out of the Nix store (e.g. via   sops-nix  or   agenix ). When\n  database.createLocally = true  (the default),   SPARKY_FITNESS_DB_PASSWORD  is\nalso used to provision the local PostgreSQL owner role.  3. Build and switch     sudo   nixos-rebuild   switch   --flake   .#myhost\n  On first activation the module:   provisions the local PostgreSQL owner role and database (when\n  database.createLocally  is enabled);  starts the backend systemd service, which runs migrations and creates the\nlimited application role automatically;  serves the frontend through nginx on the configured virtual host.  Key options     Option  Default  Description     enable   false  Enable the SparkyFitness service.    frontendUrl   (required)  Public URL of the site (CORS \u002F Better Auth trusted origins).    environmentFile   (required)  Path to the systemd   EnvironmentFile  holding the secrets above.    port   3010  Backend API listen port.    stateDir   \u002Fvar\u002Flib\u002Fsparkyfitness  Persistent state (uploads, backups, temp uploads).    database.createLocally   true  Provision a local PostgreSQL instance, owner role and database.    database.package   pkgs.postgresql_16  PostgreSQL package for the local instance (must be >= 15).    nginx.enable   true  Serve the frontend and reverse-proxy the API through nginx.    nginx.virtualHost   localhost  nginx virtual host name.    extraEnvironment   {}  Additional environment variables for the backend.  To point at an external database instead, set   database.createLocally = false \nand configure   database.host ,   database.port ,   database.name ,\n  database.user  and the corresponding passwords in   environmentFile .  Local build and development     nix   build   .#sparkyfitness-server\n   nix   build   .#sparkyfitness-frontend\n   \n   nix   develop     # dev shell with node 24, pnpm and postgresql\n  The   pnpmDeps.hash  values pinned in the flake must be refreshed whenever\n  pnpm-lock.yaml  changes (a stale hash surfaces as a   hash mismatch  build\nfailure). Run the helper script to recompute them:     nix\u002Fupdate-hashes.sh\n   # or, if nix is not on PATH:\n   NIX  =  \u002Fpath\u002Fto\u002Fnix   nix\u002Fupdate-hashes.sh\n  See    nix\u002FREADME.md \nin the repository for the full layout and additional detail.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":124,"path":125,"dir":21,"title":126,"description":127,"keywords":128,"body":129},"content:1.install:11.coolify.md","\u002Finstall\u002Fcoolify","Coolify Installation Guide","This guide provides instructions for deploying SparkyFitness using Coolify, a self-hosted developer platform.",[],"  Coolify Installation Guide  This guide provides instructions for deploying SparkyFitness using   Coolify , a self-hosted developer platform.   Note: This integration is maintained by the Coolify community and is not directly managed by SparkyFitness.  For deployment instructions and configuration details, please refer to the official Coolify documentation:   Coolify SparkyFitness Service Documentation  If you encounter issues related to deploying via Coolify, please open an issue or seek support within the Coolify community.",{"id":131,"path":132,"dir":21,"title":133,"description":134,"keywords":135,"body":136},"content:1.install:12.truenas.md","\u002Finstall\u002Ftruenas","TrueNAS Scale Installation Guide","This guide provides instructions for installing SparkyFitness on TrueNAS Scale using the community app catalog.",[],"  TrueNAS Scale Installation Guide  This guide provides instructions for installing SparkyFitness on   TrueNAS Scale  using the community app catalog.   Note: This application is provided via community contribution and is not maintained directly by SparkyFitness.  For installation instructions and catalog details, please refer to the TrueNAS App Catalog:   SparkyFitness on TrueNAS App Store  If you encounter issues related to TrueNAS installation, please report them using the TrueNAS catalog issue tracking or community forums.",{"id":138,"path":139,"dir":140,"title":141,"description":142,"keywords":143,"body":144},"content:2.features:1.diary:daily-calorie-goal.md","\u002Ffeatures\u002Fdiary\u002Fdaily-calorie-goal","diary","Daily Calorie Goal","SparkyFitness allows you to set and track your daily calorie goals, providing insights into your nutritional intake. Details on how to configure and monitor your calorie goals will be added in the future.",[],"  Daily Calorie Goal  SparkyFitness allows you to set and track your daily calorie goals, providing insights into your nutritional intake. Details on how to configure and monitor your calorie goals will be added in the future.    Calorie goals can be configured under the goals section:\n ",{"id":146,"path":147,"dir":140,"title":148,"description":149,"keywords":150,"body":151},"content:2.features:1.diary:exercise.md","\u002Ffeatures\u002Fdiary\u002Fexercise","Exercise Tracking","SparkyFitness allows you to easily track your exercise routines, including details like duration, intensity, and calories burned. Comprehensive guides on logging and managing your workouts will be added in the future.",[],"  Exercise Tracking  SparkyFitness allows you to easily track your exercise routines, including details like duration, intensity, and calories burned. Comprehensive guides on logging and managing your workouts will be added in the future.",{"id":153,"path":154,"dir":140,"title":155,"description":156,"keywords":157,"body":160},"content:2.features:1.diary:meals.md","\u002Ffeatures\u002Fdiary\u002Fmeals","Meals & Meal Categories","This section provides an overview of meal-related features in SparkyFitness.",[158,159],"Suggested Meal Category Times","Custom Meals","  Meals & Meal Categories  This section provides an overview of meal-related features in SparkyFitness.   Suggested Meal Category Times  SparkyFitness dynamically suggests the appropriate meal category (e.g., Breakfast, Lunch, Dinner, Snacks, or custom categories) when you log food based on your current time of day.  How Suggested Times Work  Each meal category can have a   Default Time  assigned to it:   When you log food, the app finds the meal category whose   default_time  is the   latest time that is less than or equal to your current time  ($\\le \\text{now}$).  Each meal category's default time defines the start of its window until the next scheduled meal.  For example, if   Snacks  is set to   5:00 PM  (  17:00 ) and   Dinner  is set to   7:00 PM  (  19:00 ):\n   Logging food between   5:00 PM  and   6:59 PM  will automatically suggest   Snacks .  Logging food at or after   7:00 PM  will automatically suggest   Dinner .  Customizing Default Times  You can customize the target start time for any meal category on both Web and Mobile:    Web : Go to   Settings → Meal Categories  and edit the   Default Time  (  HH:MM ) for any category.   Mobile : Go to   Settings → Food Settings → Suggested Meal Times  and adjust the target times (  HH:MM ).   Custom Meals  Custom meals can be created and consist of previously added foods. That way, you can group foods together and don't have to add them one by one. An example of how this might look like is provided below:  Meal Management:\n   Adding a meal:\n ",{"id":162,"path":163,"dir":140,"title":164,"description":165,"keywords":166,"body":167},"content:2.features:1.diary:nutrition-summary.md","\u002Ffeatures\u002Fdiary\u002Fnutrition-summary","Nutrition Summary","SparkyFitness provides a comprehensive nutrition summary, allowing you to view your daily intake of macronutrients. Your micronutrients and an overview about Trends for the last week, month or a custom time range can be found under reports.\n",[],"  Nutrition Summary  SparkyFitness provides a comprehensive nutrition summary, allowing you to view your daily intake of macronutrients. Your micronutrients and an overview about Trends for the last week, month or a custom time range can be found under reports.\n ",{"id":169,"path":170,"dir":140,"title":171,"description":172,"keywords":173,"body":174},"content:2.features:1.diary:water-intake.md","\u002Ffeatures\u002Fdiary\u002Fwater-intake","Water Intake","SparkyFitness allows you to easily track your daily water intake, helping you stay hydrated and meet your health goals. Details on how to log and monitor your water consumption will be added in the future.",[],"  Water Intake  SparkyFitness allows you to easily track your daily water intake, helping you stay hydrated and meet your health goals. Details on how to log and monitor your water consumption will be added in the future.",{"id":176,"path":177,"dir":178,"title":179,"description":180,"keywords":181,"body":182},"content:2.features:2.check-in.md","\u002Ffeatures\u002Fcheck-in","features","Check-In","The Check-In feature in SparkyFitness allows you to quickly log your daily progress, including meals, exercises, and other key metrics. Detailed instructions on using the Check-In feature will be provided in the future.",[],"  Check-In  The Check-In feature in SparkyFitness allows you to quickly log your daily progress, including meals, exercises, and other key metrics. Detailed instructions on using the Check-In feature will be provided in the future.",{"id":184,"path":185,"dir":178,"title":186,"description":187,"keywords":188,"body":189},"content:2.features:3.reports.md","\u002Ffeatures\u002Freports","Reports","SparkyFitness provides powerful reporting tools to visualize your progress, analyze trends, and gain insights into your fitness journey.\nYour reports page might look like this:\n",[],"  Reports  SparkyFitness provides powerful reporting tools to visualize your progress, analyze trends, and gain insights into your fitness journey.\nYour reports page might look like this:\n   Metrics synced through the Android App or the ios shortcut will appear at the bottom of the reports page:\n ",{"id":191,"path":192,"dir":193,"title":194,"description":195,"keywords":196,"body":197},"content:2.features:4.food:1.food-database-manager.md","\u002Ffeatures\u002Ffood\u002Ffood-database-manager","food","Food Database Manager","This page will explain how to use the Food Database Manager in SparkyFitness.\nThe Food and exercise providers can be configured under Settings. There, you can add, modify or delete food data or exercise data providers. It might look like this for example:\n",[],"  Food Database Manager  This page will explain how to use the Food Database Manager in SparkyFitness.\nThe Food and exercise providers can be configured under Settings. There, you can add, modify or delete food data or exercise data providers. It might look like this for example:\n ",{"id":199,"path":200,"dir":193,"title":201,"description":202,"keywords":203,"body":204},"content:2.features:4.food:2.custom-food-form.md","\u002Ffeatures\u002Ffood\u002Fcustom-food-form","Custom Food Form","This page will explain how to use the Custom Food Form in SparkyFitness.\nWhen you add a food, you'll have the option to add a custom food like here:\n",[],"  Custom Food Form  This page will explain how to use the Custom Food Form in SparkyFitness.\nWhen you add a food, you'll have the option to add a custom food like here:\n   Choosing Custom Food will open a window where you can input a name, brand and both macronutrients and micronutrients\n ",{"id":206,"path":207,"dir":193,"title":208,"description":209,"keywords":210,"body":211},"content:2.features:4.food:3.food-search.md","\u002Ffeatures\u002Ffood\u002Ffood-search","Food Search","This page will explain how to search for food items in SparkyFitness.\nWhen you click on Add food, you'll have the option to search for recent foods:\n",[],"  Food Search  This page will explain how to search for food items in SparkyFitness.\nWhen you click on Add food, you'll have the option to search for recent foods:\n   You'll also have the option to search for Food online using your configured Food data providers or even scan a Barcode:\n ",{"id":213,"path":214,"dir":215,"title":216,"description":217,"keywords":218,"body":219},"content:2.features:5.exercises:exercise-database-manager.md","\u002Ffeatures\u002Fexercises\u002Fexercise-database-manager","exercises","Exercise Database Manager","This page will explain how to use the Exercise Database Manager in SparkyFitness.",[],"  Exercise Database Manager  This page will explain how to use the Exercise Database Manager in SparkyFitness.",{"id":221,"path":222,"dir":215,"title":223,"description":224,"keywords":225,"body":226},"content:2.features:5.exercises:exercise-search.md","\u002Ffeatures\u002Fexercises\u002Fexercise-search","Exercise Search","This page will explain how to search for exercises in SparkyFitness.",[],"  Exercise Search  This page will explain how to search for exercises in SparkyFitness.",{"id":228,"path":229,"dir":178,"title":230,"description":231,"keywords":232,"body":236},"content:2.features:6.goals.md","\u002Ffeatures\u002Fgoals","Goals","SparkyFitness allows you to set and track various fitness and nutrition goals, helping you stay motivated and monitor your progress.",[233,234,235],"Nutrient Goal Direction (Minimum \u002F Maximum \u002F Target)","Tracking Added Sugars","Interactions with Calculation Settings","  Goals  SparkyFitness allows you to set and track various fitness and nutrition goals, helping you stay motivated and monitor your progress.   Nutrient Goal Direction (Minimum \u002F Maximum \u002F Target)  By default, every nutrient goal in SparkyFitness is treated as a   minimum  — a target to reach, with progress filling toward 100% as you approach it. That works well for protein or fiber, but it doesn't fit every nutrient or every person: someone managing high cholesterol wants cholesterol treated as a ceiling, not something to \"fill up\"; someone maintaining their weight wants calories treated as a range to stay near, not a bar to max out.   Settings → Nutrient Goal Direction  lets you choose, per nutrient (predefined or custom), how progress should be judged:    Minimum    (default for most nutrients)  — more is better. Progress fills toward the goal; unchanged from the classic behavior.   Maximum  — less is better. The nutrient is shown as a limit to stay under: green with a checkmark while you're at or under the limit, red with an \"Xg over\" indicator once you exceed it. Cholesterol, sodium, saturated fat, trans fat, and Total Sugar default to Maximum out of the box; you can flip any nutrient back to Minimum, or set any other nutrient to Maximum, at any time.   Target range  — hit a band. You set a lower and upper bound (e.g. calories 1700–1900); the goal shows green while your total is inside the band, and amber\u002Fred outside it. Useful for calories when maintaining weight, or for precise macro tracking where being too far under is just as undesirable as being too far over.  A nutrient with no explicit choice saved simply uses its built-in default (Minimum, unless it's one of the five listed above) — nothing changes for existing goals until you visit the settings screen and pick something different.  This applies to the Diary page's Nutrition Summary card and to the Daily Energy Goal ring (for calories, when set to Target range).   Tracking Added Sugars  SparkyFitness's built-in \"Sugars\" goal reflects   total sugar  (naturally occurring plus added), because that's what most food databases report per item. If you want to track   added sugars  specifically — sugar added during processing, as distinct from sugars naturally present in fruit or milk — create a custom nutrient (Settings → Custom Nutrients) named   \"Added Sugars\"  (matching the wording used on nutrition labels), set its Goal Direction to   Maximum , and log it per food the same way you would any other custom nutrient.  Auto-calculate a recommended limit  When editing goals for a custom nutrient that looks like an added-sugar tracker (recognized name variants: \"Sugar(s)\" or \"Added Sugar(s)\", singular or plural, case-insensitive) and is set to Maximum, an   Auto-calculate  control appears next to its goal field, offering three evidence-based options:     Option  Basis  Formula     WHO Ideal  WHO's conditional recommendation for additional health benefit  5% of your daily calorie goal ÷ 4 kcal\u002Fg    WHO Maximum  WHO's strong recommendation  10% of your daily calorie goal ÷ 4 kcal\u002Fg    AHA Fixed  American Heart Association  36g\u002Fday (men), 25g\u002Fday (women) — a flat guideline, not scaled by calories  Picking an option fills in the computed gram value; you can still edit it manually afterward.   Interactions with Calculation Settings  The Nutrient Goal Direction feature only changes how progress is   displayed  against whatever goal number already exists — it doesn't compute goal values itself (except the Added Sugar auto-calculate above). Two things to be aware of when combining it with   Calculation Settings :    Calories in Target mode vs. Adaptive\u002FDynamic goals:  if your Daily Calorie Goal Adjustment is set to Adaptive, Dynamic, Percentage Earn-Back, or Device Projection, your calorie   goal value  recalculates regularly (e.g. as your Adaptive TDEE updates). A manually entered Target band for calories does   not  move with it — you'll need to revisit and adjust the band yourself if your adaptive goal shifts significantly. Target range for calories pairs best with a   Fixed  goal adjustment, where the goal value stays constant.   Two separate \"sugar\" calculations:  Calculation Settings'   Sugar Calculation Algorithm  (WHO Guidelines\u002FLow-Carb-Keto\u002FBalanced) computes a recommendation for the built-in   Total Sugar  goal. The   Auto-calculate  control described above is a distinct calculation for your   Added Sugars  custom nutrient. They share \"WHO guidelines\" terminology but target different fields with different percentages — check which one you're adjusting.",{"id":238,"path":239,"dir":240,"title":241,"description":242,"keywords":243,"body":250},"content:2.features:7.settings:calculation-settings.md","\u002Ffeatures\u002Fsettings\u002Fcalculation-settings","settings","Calculation Settings","This page explains how BMR formulas, body fat algorithms, daily energy adjustments, and calorie deficit targets are calculated in SparkyFitness.",[244,245,246,247,248,249],"1. Basal Metabolic Rate (BMR) Algorithms","2. Body Fat Algorithms","3. Daily Calorie Goal Adjustment","4. Goal Mode & Caloric Deficits","5. Metabolic Safety Floors","6. Nutrient Calculation Algorithms","  Calculation Settings  This page explains how BMR formulas, body fat algorithms, daily energy adjustments, and calorie deficit targets are calculated in   SparkyFitness .   1. Basal Metabolic Rate (BMR) Algorithms  Your Basal Metabolic Rate (BMR) represents the energy your body requires to perform basic life-sustaining functions at rest. SparkyFitness supports multiple clinical formulas to estimate BMR:     Algorithm  Required Inputs  Best For  Formula     Mifflin-St Jeor    (Default)  Age, Gender, Height, Weight  General population  $\\text{Male: } 10W + 6.25H - 5A + 5$  $\\text{Female: } 10W + 6.25H - 5A - 161$    Revised Harris-Benedict  Age, Gender, Height, Weight  Historical comparison  $\\text{Male: } 13.397W + 4.799H - 5.677A + 88.362$  $\\text{Female: } 9.247W + 3.098H - 4.33A + 447.593$    Katch-McArdle  Weight, Body Fat %  Individuals with tracked body fat  $370 + 21.6 \\times \\text{LBM}$   (LBM = Lean Body Mass)    Cunningham  Weight, Body Fat %  Highly athletic\u002Fmuscular builds  $500 + 22 \\times \\text{LBM}$    Oxford  Weight, Gender  Varied age groups & demographics  $\\text{Male: } 14.2W + 593$  $\\text{Female: } 10.9W + 677$   Note: Weight ($W$) is in kg, Height ($H$) is in cm, and Age ($A$) is in years.   2. Body Fat Algorithms  Body Fat Percentage is used directly in lean-mass BMR formulas (Katch-McArdle\u002FCunningham). SparkyFitness can estimate body fat percentage from your measurements using two algorithms:  U.S. Navy Method  Uses circumferences to estimate body fat. Measurements are converted to inches for the standard formula:    Males:  $86.01 \\times \\log_{10}(\\text{waist} - \\text{neck}) - 70.041 \\times \\log_{10}(\\text{height}) + 36.76$   Females:  $163.205 \\times \\log_{10}(\\text{waist} + \\text{hips} - \\text{neck}) - 97.684 \\times \\log_{10}(\\text{height}) - 78.387$  BMI Method  Uses height, weight, and age to estimate body fat:    Males:  $1.2 \\times \\text{BMI} + 0.23 \\times \\text{Age} - 16.2$   Females:  $1.2 \\times \\text{BMI} + 0.23 \\times \\text{Age} - 5.4$   (where $\\text{BMI} = \\text{Weight (kg)} \u002F \\text{Height (m)}^2$)   3. Daily Calorie Goal Adjustment  This setting determines   how physical activity changes your calorie budget  throughout the day:    Adaptive TDEE:  Dynamically computes your metabolic expenditure by correlating your actual weight changes with your historical calorie intake over the last 35 days.   (Best for high-precision tracking).    Expenditure (Adaptive TDEE):  On the Diary page, \"Expenditure\" represents your calculated Total Daily Energy Expenditure (TDEE). This is the baseline number from which your deficit\u002Fsurplus is subtracted.   Fallback Behavior:  If you have insufficient history (less than 14 days of weight and calorie data, or fewer than 7 days of calorie entries $\\ge 200\\text{ kcal}$), the system will use a fallback estimate based on the standard   BMR × Activity Multiplier  formula until enough data is collected.   Dynamic Goal:  Increases your budget as you burn active calories or take steps (adds exercise directly back to your budget).   Fixed Goal:  Your calorie target remains completely static, ignoring daily exercise.   Percentage Earn-Back:  Adds back a custom percentage (e.g., $50%$) of active calories burned to create a buffer against device calorie over-estimations.   Device Projection:  Projects your total full-day burn by extrapolating active steps and device data to midnight (MyFitnessPal style).    !NOTE \nIf you use   Nutrient Goal Direction 's   Target range  for calories, note that Adaptive, Dynamic, Percentage Earn-Back, and Device Projection all recalculate your calorie goal value regularly — a manually entered target band won't move with it. Target range for calories works best paired with   Fixed Goal .   4. Goal Mode & Caloric Deficits   Goal Mode  applies a body composition percentage-based deficit or maintenance target to your baseline maintenance:     Goal Mode  Deficit Percentage  Target Purpose     Maintain  $0%$  Weight maintenance    Body Recomposition  $10%$  Gain muscle while losing fat simultaneously    Cut  $15%$  Steady fat loss    High Cut  $20%$  Aggressive fat loss    Manual  Custom ($0% - 40%$)  Personalized deficit rate  Calculation Methods    Adaptive Method:  Applies the deficit to your Calculated Adaptive TDEE (falling back to BMR × activity multiplier if history is insufficient).   Manual Method:  Applies the deficit to your manually entered calorie target.   5. Metabolic Safety Floors  To protect long-term metabolic health and avoid muscle wasting, SparkyFitness checks all calorie goals against safety limits:    Resting Metabolism (RMR) Floor:  Your target should not fall below your resting metabolic rate.   Absolute Clinical Floor:  $1,200$ kcal for biological females; $1,500$ kcal for biological males.    !IMPORTANT  Enforcement Behavior:   Under the   Adaptive  method, if your calculated target falls below the safety floor, the system   automatically raises  your target to the effective floor.  Under the   Manual  method, the target is   not automatically raised , but a prominent warning banner is displayed warning you that your budget is in an unsafe range.   6. Nutrient Calculation Algorithms  These pickers choose a formula for suggesting gram targets for certain nutrient goals, based on your calorie goal, age, and sex:    Fat Breakdown Algorithm  (AHA Guidelines \u002F Keto-Adapted \u002F Mediterranean): suggests how to split total fat into saturated, polyunsaturated, monounsaturated, and trans fat.   Mineral Calculation Algorithm  (RDA Standard \u002F Athletic Performance \u002F Heart Health): suggests sodium, potassium, calcium, and iron targets.   Vitamin Calculation Algorithm  (RDA Standard \u002F Immune Support \u002F Antioxidant Focus): suggests Vitamin A and C targets.   Sugar Calculation Algorithm  (WHO Guidelines 10% max \u002F Low-Carb-Keto 5% max \u002F Balanced 15% max): suggests a target for the built-in   Total Sugar  goal, as a percentage of your daily calories.  This is different from the   Added Sugars  auto-calculate control described in   Goals → Tracking Added Sugars  — that one computes a limit for a separate, user-created \"Added Sugars\" custom nutrient using WHO\u002FAHA guidelines, not this Total Sugar percentage.",{"id":252,"path":253,"dir":240,"title":254,"description":255,"keywords":256,"body":259},"content:2.features:7.settings:external-providers.md","\u002Ffeatures\u002Fsettings\u002Fexternal-providers","External Providers","SparkyFitness supports integration with external health and fitness data providers to automatically sync your activity and measurements.",[257,258],"Supported Providers","Contributing Mock Data","  External Providers  SparkyFitness supports integration with external health and fitness data providers to automatically sync your activity and measurements.   Supported Providers  SparkyFitness supports integration with the following health and fitness data providers:   Apple Health (iOS)  Google Health Connect (Android)  Fitbit  Garmin Connect  Oura Ring  Withings  Polar Flow (partially tested)  Hevy (not tested)  OpenFoodFacts  USDA  Fatsecret  Nutritioninx  Mealie  Tandori  Strava (partially tested)   Contributing Mock Data  We are constantly working to improve these integrations. If you notice data missing or incorrect, you can help by providing anonymized mock data.  Join the   CodeWithCJ  community on   Discord  and reach out if you'd like to share your mock data to help us improve the sync logic!",{"id":261,"path":262,"dir":240,"title":263,"description":264,"keywords":265,"body":270},"content:2.features:7.settings:google-health.md","\u002Ffeatures\u002Fsettings\u002Fgoogle-health","Google Health Integration","The Google Health integration allows you to sync fitness metrics, sleep data, and health measurements from your Google Health account directly to SparkyFitness. It is the recommended replacement for Fitbit after the Fitbit Web API is deprecated in September 2026.",[25,266,267,268,269,258],"Setup Instructions","Required Scopes","Data Synchronized","Important Limitations","  Google Health Integration  The Google Health integration allows you to sync fitness metrics, sleep data, and health measurements from your Google Health account directly to SparkyFitness. It is the recommended replacement for Fitbit after the Fitbit Web API is deprecated in September 2026.   Prerequisites   A Google account with a compatible wearable (Fitbit, Wear OS, or any device that syncs to Google Health Connect)  A Google Cloud project (free tier is sufficient)   Setup Instructions  1. Create a Google Cloud project  Go to the   Google Cloud Console , create a new project (or select an existing one).  2. Enable the Google Health API  Navigate to   APIs & Services → Library , search for   Google Health API , and click   Enable .  3. Configure the OAuth consent screen  Go to   APIs & Services → OAuth consent screen :    User Type : External  Fill in the app name, support email, and developer contact   Add scopes  — click \"Add or remove scopes\" and add all six scopes listed below  Under   Test users , add your own Google account   Publish the app  (click \"Publish App\") — this is required to prevent Google from revoking refresh tokens after 7 days. It is safe to publish without Google verification for personal use; you will see an \"unverified app\" warning when connecting, which you can dismiss.  4. Create OAuth 2.0 credentials  Go to   APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID :    Application type : Web application   Authorized redirect URIs : paste the Callback URL shown in SparkyFitness (  Settings → External Data Sources → Google Health → edit icon → Callback URL )  Save and copy the   Client ID  and   Client Secret .  5. Connect in SparkyFitness   Go to   Settings → External Data Sources  and find the   Google Health  entry  Click the edit icon and paste in your   Client ID  and   Client Secret  Click   Save , then click   Connect  Complete the Google OAuth consent flow — accept the \"unverified app\" warning if prompted   Required Scopes  Add all six of these scopes to your OAuth consent screen:   https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fgooglehealth.activity_and_fitness.readonly\nhttps:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fgooglehealth.health_metrics_and_measurements.readonly\nhttps:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fgooglehealth.sleep.readonly\nhttps:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fgooglehealth.location.readonly\nhttps:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fgooglehealth.profile.readonly\nhttps:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fgooglehealth.settings.readonly\n   Data Synchronized  SparkyFitness pulls the following data from Google Health:    Activity : Steps, Active Zone Minutes (fat burn \u002F cardio \u002F peak), Activity Minutes (sedentary \u002F lightly \u002F moderately \u002F very active), Distance, Floors   Health metrics : Resting heart rate, Heart rate variability (HRV), Blood oxygen (SpO2), Respiratory rate, Skin temperature variation, Body fat percentage, VO2 Max, Daily calories, Weight   Sleep : Sleep sessions with stage breakdown (light, deep, REM, awake)   Exercise : Workouts logged in Google Health, including duration and calories   Important Limitations    !IMPORTANT  Google Health API Restrictions :    Sleep history depth : The Google Health API limits session-based data (sleep, exercises) to approximately 30 days per query. SparkyFitness automatically splits wide date ranges into 30-day chunks to work around this, so a 365-day import will succeed — it just takes a little longer.   Device-specific metrics : Some metrics (hydration, core temperature) require a device that explicitly writes them to Health Connect. Fitbit Versa 4 does not record these; a Pixel Watch or similar device is needed.   Token refresh : Access tokens expire after 1 hour and are refreshed automatically. If you encounter authentication errors after editing your credentials, use   Disconnect  then   Connect  again — editing credentials alone does not re-authorize the connection.   App publication required : If you skip publishing the OAuth app, Google will revoke your refresh token after 7 days, causing the integration to stop syncing.   Contributing Mock Data  We are constantly working to improve these integrations. If you notice data missing or incorrect, you can help by providing anonymized mock data.  Join the   CodeWithCJ  community on   Discord  and reach out if you'd like to share your Google Health mock data to help improve the sync logic!",{"id":272,"path":273,"dir":240,"title":274,"description":275,"keywords":276,"body":277},"content:2.features:7.settings:login-management.md","\u002Ffeatures\u002Fsettings\u002Flogin-management","Login Management","This page will explain how to manage login settings in SparkyFitness.",[],"  Login Management  This page will explain how to manage login settings in SparkyFitness.",{"id":279,"path":280,"dir":240,"title":281,"description":282,"keywords":283,"body":284},"content:2.features:7.settings:nutrient-display-settings.md","\u002Ffeatures\u002Fsettings\u002Fnutrient-display-settings","Nutrient Display Settings","This page will explain how to configure nutrient display settings in SparkyFitness.",[],"  Nutrient Display Settings  This page will explain how to configure nutrient display settings in SparkyFitness.",{"id":286,"path":287,"dir":240,"title":288,"description":289,"keywords":290,"body":291},"content:2.features:7.settings:polar.md","\u002Ffeatures\u002Fsettings\u002Fpolar","Polar Flow Integration","The Polar integration allows you to sync workouts, physical measurements, and daily activity metrics from your Polar account directly to SparkyFitness.",[266,268,269,258],"  Polar Flow Integration  The Polar integration allows you to sync workouts, physical measurements, and daily activity metrics from your Polar account directly to SparkyFitness.   Setup Instructions  To connect Polar Flow, follow these steps:    Register as a Developer : Visit the   Polar AccessLink Admin  portal and create a new client.   Configure Callback URL : In the Polar Admin portal, set your   Callback URL  to:\nDirectly get from External Providers page in SparkyFitness   Enter Credentials : In SparkyFitness Settings, navigate to   External Providers  and add a new \"Polar\" provider.   Enter Client ID and Client Secret : Copy these from your Polar Admin dashboard into the SparkyFitness form.   Authorize : Click \"Connect\" and you will be redirected to Polar to authorize the connection.  Data Synchronized  SparkyFitness pulls the following data from Polar:    Workouts (Exercises) : Automatically logs cardio training sessions into your Diary, including duration, calories burned, and sport type.   Physical Info : Syncs your latest   Weight  and   Height  from your Polar profile.   Daily Activity : Syncs your daily   Steps ,   Active Calories , and   Total Calories  as custom measurements.  Important Limitations    !IMPORTANT  Polar API Restrictions :    No Historical Backfill : Polar only allows access to data uploaded   after  you have authorized the SparkyFitness integration. Workouts recorded before you linked your account will not sync.   Manual Exercises : Manually added exercises in Polar Flow may have limited support or availability depending on the Polar API version.   Contributing Mock Data  We are constantly working to improve these integrations. If you notice data missing or incorrect, you can help by providing anonymized mock data.  Join the   CodeWithCJ  community on   Discord  and reach out if you'd like to share your Polar mock data to help us improve the sync logic!",{"id":293,"path":294,"dir":240,"title":295,"description":296,"keywords":297,"body":300},"content:2.features:7.settings:preferences.md","\u002Ffeatures\u002Fsettings\u002Fpreferences","Preferences","This page explains how to manage preference settings in SparkyFitness.",[298,299],"Autoscaling OpenFoodFacts","Complete Import Process","  Preferences  This page explains how to manage preference settings in   SparkyFitness .   Autoscaling OpenFoodFacts  The   Auto-scale OpenFoodFacts imports  option scales measurements and nutrition values from OpenFoodFacts to their   serving size .  This allows imports to be scaled automatically without manually entering a serving size, or when the serving size is unknown.   Comparison  Without Import Autoscaling (Default)   With Import Autoscaling    Complete Import Process  Using OpenFoodFacts Import Autoscaling  1. Add Food  Add food as normal via   “Online”  or   “Scan Barcode” .   Results are now based on the   serving size , rather than   100g    2. Edit and Add  It may still be useful to keep a   gram-based Unit Variant , especially for cases where weight-based measurements are needed.    Note:   “Auto-scale”  in the   Edit Food Details  dialog scales measurements   for that specific variant only .  \nThis is   not related  to OpenFoodFacts import scaling.  \nIt is a SparkyFitness feature that allows users to change serving sizes while automatically adjusting nutrition values.  A. Duplicate the gram measurement   B. Edit unit type and optionally set it as the default   C. Save the Food  Click   “Add Food”  or   “Update Food” .   3. Using the New Entry  A. Defaults to your Unit Variant (no more math!)   B. Referencing grams if needed  You can switch the unit back to   grams  and adjust the quantity accordingly. ",{"id":302,"path":303,"dir":178,"title":304,"description":305,"keywords":306,"body":310},"content:2.features:9.family-friends-sharing.md","\u002Ffeatures\u002Ffamily-friends-sharing","Family & Friends Sharing","Family & Friends Sharing in SparkyFitness allows you to connect with family members, friends, personal trainers, or coaches. By granting specific access permissions, you can allow others to log meals, track workouts, record check-ins, manage medications, or view progress reports on your behalf.",[307,308,309],"How to Set Up Sharing","Privilege Matrix by Permission Level","Security & Boundary Isolation","  Family & Friends Sharing  Family & Friends Sharing in SparkyFitness allows you to connect with family members, friends, personal trainers, or coaches. By granting specific access permissions, you can allow others to log meals, track workouts, record check-ins, manage medications, or view progress reports on your behalf.  The system is built with   least-privilege boundary isolation  using PostgreSQL Row-Level Security (RLS), ensuring that your private credentials and account settings are never shared.   How to Set Up Sharing  Setting up a connection is simple and can be managed directly from the application settings:    Go to Settings : Navigate to   Settings  ->   Family Access Manager  in the application sidebar.   Add a Connection :\n   Enter the email address of the family member or friend you want to connect with.  Choose the specific permissions you want to grant them (see the matrix below).   Optional:  Set an   Access End Date  if you want the permission to expire automatically.   Save Connection : Click   Add Connection . The new connection will appear under \"Rules I Created\".   Accessing Switched Profiles : The connected person will now see your profile in their   Profile Switcher  (located in the top-right corner of the dashboard). They can select your name to switch contexts and act on your behalf.   Privilege Matrix by Permission Level  SparkyFitness uses 7 granular permissions to determine exactly what a connected user can read or write in your profile:     Access Permission  Write (Create \u002F Edit \u002F Delete) Privileges  Read (View) Privileges     Manage Diary   can_manage_diary  ✍️ Food entries, exercise entries, water logs, daily goal plans, favorite (starred) foods\u002Fmeals.  📖 Food entries, exercise entries, water logs, daily goal plans, favorite (starred) foods\u002Fmeals, custom food\u002Fexercise libraries, and read-only profile\u002Flayout\u002Fwater-container settings.   ❌   Wellness logs (fasting, sleep, mood) and medication logs are completely blocked.    Manage Check-in   can_manage_checkin  ✍️ Weight, body measurements, progress photos, mood logs, fasting status, sleep logs, and custom measurement categories\u002Fvalues (e.g. GLP-1 daily check-in).  📖 Weight history, progress photos, wellness logs (mood, fasting, sleep), custom measurements, and read-only profile\u002Flayout settings.   ❌   Diary logs (food, exercise, water) and medication logs are completely blocked.    Manage Medications   can_manage_medications  ✍️ Medication schedules, pen\u002Fvial allocations, injection records, titration adjustments, and daily symptom logs.  📖 Medication lists, schedules, logs, pens, injection sites, titration steps, and symptom entries.   ❌   Diary logs (food, exercise, water) and check-in logs (weight, sleep, fasting) are completely blocked.    View Reports   can_view_reports  ❌   No write privileges  📖 All wellness, check-in, diary, and medication logs to display on charts, graphs, and the dashboard. Also includes read-only access to profile, dashboard layout, and onboarding data.    View Food Library   can_view_food_library  ❌   No write privileges  📖 User's custom food list, recipes, and custom meals — including any reusable sub-meals a meal links as ingredients — (isolated to when context is switched).   ❌   Profile, dashboard layout, and onboarding data are   not  readable — this permission alone is insufficient.    View Exercise Library   can_view_exercise_library  ❌   No write privileges  📖 User's custom exercise database and workout presets (isolated to when context is switched).   ❌   Profile, dashboard layout, and onboarding data are   not  readable — this permission alone is insufficient.    Share Integrations   share_external_providers  ❌   No write privileges  (cannot add, edit, or delete provider configurations — owner-only).  📖 Allows the family & friends to use the owner's non-private search provider configurations (e.g., FatSecret, USDA, OpenFoodFacts) to search for food and exercise items and add them to their own library.   ❌   Health integrations (Garmin, Fitbit, Withings, Google Health, Polar, Strava, Hevy) are strictly private and   never  shared — this permission does not grant access to them.   Security & Boundary Isolation  1. Tier 1: Strictly Private Data  Certain tables contain private user data that is   never  accessible to any family member or friend, regardless of the permission level. This includes:   API Keys (  api_key  table)  OIDC SSO Connections (  user_oidc_links  table)  Personal AI Assistant Chat History (  sparky_chat_history  table)  Cycle & Pregnancy hub data (  cycle_settings ,   cycle_daily_entries ,   cycles ,   user_cycle_display_preferences ,   cycle_test_entries ,   pregnancies ,   pregnancy_kick_sessions ,   pregnancy_contractions ,   pregnancy_photos ,   pregnancy_checklist_state ,   health_appointments  tables) — this reproductive-health data is   never  shared or delegated, even with   can_view_reports . It is strictly owner-only.  2. Tier 2: Read-Only Profile & Settings Data  The following data can be   read  by delegates who hold at least one of   can_manage_diary ,   can_manage_checkin ,   can_manage_medications , or   can_view_reports  — but   only the account owner can modify it :   Profile information (  profiles  table — name, date of birth, height, avatar, etc.)  General preferences (  user_preferences  table — themes, units)  Nutrient column display preferences (  user_nutrient_display_preferences )  Dashboard widget layout (  user_dashboard_layouts )  Onboarding data and completion status (  onboarding_data ,   onboarding_status )  Delegates with only library permissions   cannot  read or write any of the above.  3. Context-Switched Library Isolation  Your custom food library, recipes, custom exercises, and medication inventory are only visible to delegates when they have switched their active profile context to your profile. This prevents their personal libraries\u002Fcabinets from being cluttered with your items.  4. Automatic Token Validation & Expiry  If you set an   Access End Date  for a connection, the database automatically revokes all database read\u002Fwrite access the moment that timestamp passes. No manual action is needed.  5. Meal-to-Meal Composition  A meal's ingredient list can link another reusable meal (e.g. a sauce or side) instead of a plain food. Linking a sub-meal into a parent meal requires the same library access to the sub-meal that reading it directly would require — you cannot link a sub-meal you cannot otherwise view. This check applies independently of, and in addition to, owning the parent meal.",{"id":312,"path":313,"dir":178,"title":314,"description":315,"keywords":316,"body":317},"content:2.features:10.searching.md","\u002Ffeatures\u002Fsearching","Searching","SparkyFitness provides robust searching capabilities to help you quickly find foods, exercises, and other data within the application. Details on how to effectively use the search features will be added in the future.",[],"  Searching  SparkyFitness provides robust searching capabilities to help you quickly find foods, exercises, and other data within the application. Details on how to effectively use the search features will be added in the future.",{"id":319,"path":320,"dir":178,"title":321,"description":322,"keywords":323,"body":324},"content:2.features:11.sharing.md","\u002Ffeatures\u002Fsharing","Sharing","SparkyFitness may offer various ways to share your fitness data, including exporting data or sharing with other applications. Details on these sharing functionalities will be added in the future.",[],"  Sharing  SparkyFitness may offer various ways to share your fitness data, including exporting data or sharing with other applications. Details on these sharing functionalities will be added in the future.",{"id":326,"path":327,"dir":178,"title":328,"description":329,"keywords":330,"body":331},"content:2.features:12.user-settings.md","\u002Ffeatures\u002Fuser-settings","User Settings","SparkyFitness provides comprehensive user settings to personalize your experience, manage preferences, and configure various aspects of the application. Details on available settings will be added in the future.",[],"  User Settings  SparkyFitness provides comprehensive user settings to personalize your experience, manage preferences, and configure various aspects of the application. Details on available settings will be added in the future.",{"id":333,"path":334,"dir":178,"title":335,"description":7,"keywords":336,"body":339},"content:2.features:13.ai-assistant.md","\u002Ffeatures\u002Fai-assistant","Ai Assistant",[337,338],"Sparky Buddy (AI Assistant)","Troubleshooting AI Providers","  Sparky Buddy (AI Assistant)  Core AI Features    Food Recognition : Analyze food photos for automatic logging and nutrition extraction   Nutrition Analysis : Intelligent nutrition information extraction from text and images   Meal Suggestions : AI-powered meal recommendations and recipe generation   Question Answering : General nutrition and fitness guidance, personalized advice   Exercise Logging : Log exercises with duration, distance, and calorie estimates   Measurement Logging : Log standard and custom body measurements   Water Intake Logging : Track daily water consumption  Chat Interface    Image Upload : Send photos for food analysis   Text Input : Natural language food descriptions, questions, and commands   History : Persistent chat conversation history with session grouping   Metadata Storage : Stores structured data like food options, exercise suggestions within chat history   Settings : Direct access to AI service configuration  Food Integration    Auto-Logging : Directly add recognized foods to diary with confirmation   Nutrition Confirmation : Review and edit AI suggestions before logging   Meal Context : Understand meal timing and context for accurate logging   Brand Recognition : Identify specific food brands and products  Troubleshooting AI Providers  Most \"OpenAI Compatible \u002F OpenRouter isn't working\" reports come from provider configuration, not from SparkyFitness itself. The most common cases:  OpenRouter: \"No allowed providers are available for the selected model\" (HTTP 404)  This is an   OpenRouter account setting , not a SparkyFitness error. OpenRouter serves each model through one or more upstream providers. If your account is restricted to a subset of providers, a model whose upstream is excluded fails with this 404 — this most often hits the free (  :free ) models, which run on providers you may not have enabled.  The error body shows the mismatch directly:    available_providers  — the providers that can actually serve the model   requested_providers  — the providers your account currently allows   Fix:  In your OpenRouter account settings, review the allowed-providers \u002F data-policy preferences, then either enable the provider that serves your chosen model   or  pick a model served by a provider you already allow (e.g. an   openai\u002F ,   anthropic\u002F , or   google\u002F  model if those are your allowed upstreams).  Every request 404s (doubled URL)  If your custom URL already ends in   \u002Fchat\u002Fcompletions , SparkyFitness appends its own path and the request 404s.   Fix:  Enter only the base URL ending in   \u002Fv1  — for example   https:\u002F\u002Fopenrouter.ai\u002Fapi\u002Fv1 . For local servers such as LM Studio or Ollama, use an admin\u002Fglobal AI setting or enable    ALLOW_PRIVATE_NETWORK_AI=true  on a trusted self-hosted deployment. SparkyFitness adds   \u002Fchat\u002Fcompletions  for you.  \"Model not found\" or empty\u002Fgarbled responses  The model name must be one your endpoint actually hosts. OpenAI names like   gpt-4o-mini  will not exist on most compatible servers.   Fix:  For the   OpenAI Compatible  and   Custom  service types, enable   Use custom model  and enter your server's own model name.  Chat works, but photo analysis or label scan fails  Food-photo analysis and nutrition-label scanning request   structured JSON output ; plain chat does not. This is done to improve the quality of results. Some models and servers do not support structured output and reject those requests while chat still works.   Fix:  Choose a model that supports structured outputs \u002F JSON mode. On OpenRouter, a model's page lists whether it supports \"structured outputs\".  Local servers (LM Studio, Ollama, llama.cpp)  These usually run without an API key — leave the   API Key  field blank. Use the OpenAI-compatible base URL the server exposes, for example   http:\u002F\u002Flocalhost:1234\u002Fv1  (LM Studio) or   http:\u002F\u002Flocalhost:11434\u002Fv1  (Ollama's OpenAI-compatible endpoint).  Local\u002Fprivate AI URLs are resolved from the backend server's network, not from the browser. To prevent regular users from turning the server into a private-network proxy, private AI URLs are allowed for current admins, global admin-created AI settings, or deployments that explicitly set    ALLOW_PRIVATE_NETWORK_AI=true .  Running the chatbot on small local models (Ollama)  Small local models (roughly 3B–8B, e.g. an 8 GB Mac) can drive the chatbot's tools well, but two settings make the difference between \"works great\" and \"acts dumb\":    Raise Ollama's context window.  Ollama defaults to a 4096-token context and   silently truncates  anything longer — which chops the tool definitions and system prompt mid-way and produces wrong or malformed tool calls. Raise it before anything else:\n   Set   OLLAMA_CONTEXT_LENGTH=16384  on the Ollama server (e.g.   launchctl setenv OLLAMA_CONTEXT_LENGTH 16384  on macOS, then restart Ollama),   or  Bake   PARAMETER num_ctx 16384  into a Modelfile (  ollama create my-model -f Modelfile ) and point the service at that model.  On an 8 GB machine, start at   8192  — context uses VRAM — and only go higher if responses stay fast.   Use the   core  tool profile.  When you add an Ollama service, SparkyFitness now preselects the   core  tool profile (in the service's settings). Core exposes the everyday logging tools plus goals (~20 tools) instead of the full ~35, which small models select from far more reliably and which fits a smaller context window. Pick   full  only on a strong local machine with a raised context window.  The server logs a warning when an Ollama service runs the   full  profile, since that combination most often overflows the default context. Also prefer models trained for tool calling (e.g.   qwen2.5:7b-instruct ,   llama3.1:8b ) — plain small chat models make unreliable tool calls.",{"id":341,"path":342,"dir":178,"title":343,"description":7,"keywords":344,"body":346},"content:2.features:14.measurements.md","\u002Ffeatures\u002Fmeasurements","Measurements",[345],"Measurements Tab","  Measurements Tab  Historical Data    Trend Charts : Interactive charts showing measurement trends over time   Date Range Selection : Custom time period analysis   Multiple Metrics : Compare different measurements on same chart   Goal Overlays : Show target measurements vs actual progress  Analytics    Progress Calculation : Automatic progress percentages   Milestone Tracking : Achievement notifications   Trend Analysis : Identify patterns and plateaus   Correlation Analysis : Relationship between different metrics",{"id":348,"path":349,"dir":178,"title":350,"description":351,"keywords":352,"body":357},"content:2.features:15.mcp-server.md","\u002Ffeatures\u002Fmcp-server","AI Assistant & MCP Server","SparkyFitness includes a powerful Model Context Protocol (MCP) server. This allows you to connect advanced AI assistants (like Claude Desktop, Cursor, or custom AI clients) directly to your personal health data securely.",[353,354,355,356],"🛠 Available Tools & Capabilities","🕵️ AI Personalization (The \"Health Detective\")","🔐 Security & Privacy","🚀 Getting Started","  AI Assistant & MCP Server  SparkyFitness includes a powerful   Model Context Protocol (MCP)  server. This allows you to connect advanced AI assistants (like Claude Desktop, Cursor, or custom AI clients) directly to your personal health data securely.  When you enable the MCP Server, your AI assistant transforms into a   Personal Health Intelligence  layer that can read your health logs, track your progress, and provide hyper-personalized coaching based on your actual data.   🛠 Available Tools & Capabilities  The AI assistant can perform the following actions across different health domains. All tools automatically respect your   Unit Preferences  (e.g., converting lbs to kg or kcal to kJ).  🥗 Nutrition & Food  Track your diet, manage meals, and analyze your nutritional intake.     Feature  Tool Action  Example Prompt     Log Food   log_food  \"I just had a 250g steak and a salad.\"    Meal Templates   log_meal  \"Log my 'Standard Breakfast' for today.\"    Water Tracking   log_water  \"I drank 500ml of water.\"    Daily Diary   list_diary  \"What have I eaten today?\"    Copy Entries   copy_from_yesterday  \"Copy my breakfast from yesterday to today.\"    Nutrition Analysis   get_nutritional_summary  \"Give me a breakdown of my macros for the last 7 days.\"  🏋️ Exercise & Fitness  Manage your workouts, track strength progress, and use presets.     Feature  Tool Action  Example Prompt     Log Workout   log_exercise  \"Log 3 sets of Bench Press at 80kg for 10 reps.\"    Workout Presets   log_workout_preset  \"Start my 'Leg Day' workout.\"    Exercise Details   get_exercise_details  \"How do I perform a Bulgarian Split Squat?\"    Progress Tracking   get_exercise_progress  \"Show me my Bench Press progress over the last month.\"    Search Library   search_exercises  \"Find some advanced chest exercises using dumbbells.\"  📈 Biometrics & Check-ins  Monitor your weight, sleep, mood, and daily habits.     Feature  Tool Action  Example Prompt     Daily Wizard   sparky_daily_checkin_wizard  \"I'm ready for my daily check-in.\"    Weight & Body   log_biometrics  \"My weight is 185 lbs today.\"    Sleep & Mood   log_sleep ,   log_mood  \"I slept 7 hours and feel like an 8\u002F10.\"    Fasting Status   get_fasting_status  \"Am I still in my fasting window?\"    Weight History   get_biometrics_history  \"Show me my weight trend for the last 30 days.\"    Custom Metrics   log_custom_metric  \"My blood pressure was 120\u002F80 today.\"  📋 Goals, Habits & Reports  Set targets and get consolidated performance reviews.    Habit Tracking  (  sparky_manage_habits ): \"Did I take my vitamins today?\"   Goal Management  (  sparky_manage_goals ): \"Set a new weight goal of 175 lbs by July.\"   Weekly Reports  (  sparky_get_report ): \"Give me a weekly performance summary.\"   Profile Settings  (  sparky_manage_profile ): \"Change my energy unit to kJ.\"   🕵️ AI Personalization (The \"Health Detective\")  Because the AI has access to all these tools, it can do things a standard app cannot:    Correlation Detection : \"I noticed your sleep quality is 20% better on days you finish your last meal before 7 PM.\"   Smart Planning : \"Based on your current weight trend and yesterday's activity, I recommend increasing your protein by 20g today.\"   Inventory Logic : \"You've logged Greek Yogurt 5 times this week. Should I add it to your high-protein shopping list?\"   🔐 Security & Privacy    User Isolation (RLS) : Normal MCP tools are restricted by PostgreSQL   Row Level Security , scoped to the user authenticated by the API key. The AI can   only  see data belonging to that user.   Admin-Only Dev Tools : A small set of optional developer\u002Fdebugging tools is   off by default . They are enabled only when   DEV_TOOLS_ENABLED=true  and the request uses an admin API key. These tools intentionally run with elevated database access (the owner pool, bypassing Row Level Security), so leave them disabled unless you are actively debugging.   Local First : If you run SparkyFitness locally, your data never leaves your infrastructure until you send it to your chosen AI provider (e.g., Anthropic or OpenAI).  🚀 Getting Started  The MCP server is now served   in-process  by the main SparkyFitness server at   POST \u002Fmcp . There is no separate MCP service to run.  1. Generate an API Key  Go to   Profile → Personal API Key  in the web UI and generate a key (or call   POST \u002Fidentity\u002Fuser\u002Fgenerate-api-key ). You'll pass this as a   Bearer Token  in the   Authorization  header.  2. Find Your MCP Endpoint    Production :   https:\u002F\u002F\u003Cyour-host>\u002Fmcp  (the production nginx config proxies   \u002Fmcp  to the server).   Local dev :   http:\u002F\u002Flocalhost:8080\u002Fmcp  — the frontend Vite dev proxy forwards   \u002Fmcp  to the server. Hitting the server port directly at   http:\u002F\u002Flocalhost:3010\u002Fmcp  also works.  3. Configure Your Client   HTTP \u002F remote-capable clients  (Cursor and other clients that support streamable HTTP) point directly at   \u002Fmcp  with an   Authorization: Bearer \u003CAPI_KEY>  header:     {\n     \"mcpServers\"  : {\n       \"sparky-fitness\"  : {\n         \"url\"  :   \"https:\u002F\u002F\u003Cyour-host>\u002Fmcp\"  ,\n         \"headers\"  : {\n           \"Authorization\"  :   \"Bearer \u003CAPI_KEY>\"\n         }\n       }\n     }\n   }\n   stdio-only clients  (such as the classic Claude Desktop config) can't talk HTTP directly. Use the off-the-shelf    mcp-remote  bridge. The key goes in an   env  block, and the header uses the no-space   Authorization:${AUTH_HEADER}  form —   mcp-remote 's documented workaround for clients that mangle spaces in header arguments (e.g. Claude Desktop on Windows, Cursor):     {   \"mcpServers\"  : {   \"sparky-fitness\"  : {\n       \"command\"  :   \"npx\"  ,\n       \"args\"  : [  \"-y\"  ,   \"mcp-remote\"  ,   \"https:\u002F\u002F\u003Cyour-host>\u002Fmcp\"  ,\n                \"--header\"  ,   \"Authorization:${AUTH_HEADER}\"  ],\n       \"env\"  : {   \"AUTH_HEADER\"  :   \"Bearer \u003CAPI_KEY>\"   } } } }\n   Note: for a local-dev server over plain HTTP, add   --allow-http  to the args and use   http:\u002F\u002Flocalhost:8080\u002Fmcp  (or   http:\u002F\u002Flocalhost:3010\u002Fmcp  to hit the server directly) —   mcp-remote  refuses non-HTTPS URLs otherwise.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":359,"path":360,"dir":178,"title":361,"description":362,"keywords":363,"body":368},"content:2.features:16.cycle-hub:1.index.md","\u002Ffeatures\u002Fcycle-hub","Period & Cycle Hub","The Cycle Hub is a self-hosted, privacy-first suite designed to track, calculate, and analyze menstrual health, fertility, and pregnancy. This document outlines how to utilize the period and cycle features.",[364,365,366,367],"1. Onboarding & Settings","2. Daily Log & Cycle Features","3. Calendar & Projections","4. Notifications & Reminders","  Period & Cycle Hub  The Cycle Hub is a self-hosted, privacy-first suite designed to track, calculate, and analyze menstrual health, fertility, and pregnancy. This document outlines how to utilize the period and cycle features.  1. Onboarding & Settings  To configure your cycle preferences, navigate to   Settings -> Cycle & Pregnancy . Here you can set:    Current Mode : Select between   Standard  (Period Tracking),   TTC  (Trying to Conceive),   Pregnancy ,   Postpartum , or   Menopause .   Cycle & Period Length : Input your average cycle length (e.g. 28 days) and average period duration (e.g. 5 days) as fallbacks.   Birth Control Method : Select your contraceptive method (e.g. pill, IUD, none) to calibrate the prediction engine.   Discreet Mode : Toggle this option to replace all cycle hub headers, sidebar navigation labels, and icons with a neutral   \"Wellness\"  label and generic wellness icon.   2. Daily Log & Cycle Features  Click   \"Today's Log\"  on the dashboard to record daily metrics:    Flow Tracking (4 Levels) : Log flow intensity across four levels (Spotting, Light, Medium, Heavy) to record period start\u002Fend dates.   BBT Logging & Biphasic Detection : Record your waking temperature to the hundredths decimal place (e.g. 36.55 °C) to assist ovulation detection.   Ovulation & Fertile Window : View estimated fertile days and ovulation timing calculated from logs and historical statistics.   40+ Symptoms, Moods, Meds, Sex Log :\n    Symptoms : Log from 43 physical and emotional symptoms (Cramps, Headache, Fatigue, Insomnia, Acne, etc.).   Moods : Log emotional states (Happy, Calm, Sensitive, Irritable, Anxious, Sad).   Meds : Track daily pills or custom medications with check-in compliance logs.   Sex Log : Record intercourse sessions, with toggles for protected or unprotected status.   Sleep, Water, Weight, Energy : Track hydration, nightly sleep duration, body weight, and daily energy levels. The Daily Log panel displays a read-only glance header showing today's totals for Water (ml), Sleep (hrs), and Weight (kg).   3. Calendar & Projections  Navigate to the   Calendar  tab to view your history and projections:    Cycle Calendar & Predictions : Month-grid calendar displaying period history, predicted period dates, and fertile window\u002Fovulation days.   Paint Period Timelines : Click the   Edit Periods  (pencil icon) to tap calendar blocks and instantly log or erase period intervals in bulk.   Cycle History & Regularity : View historical cycles with horizontal track timelines, manage excluded outliers, or manually add older cycle logs.   4. Notifications & Reminders    Period & Ovulation Reminders :   Planned Roadmap  (This feature is currently deferred to the active backlog as it requires app-wide background worker and notification dispatching infrastructure).",{"id":370,"path":371,"dir":372,"title":373,"description":374,"keywords":375,"body":378},"content:2.features:16.cycle-hub:2.trying-to-conceive.md","\u002Ffeatures\u002Fcycle-hub\u002Ftrying-to-conceive","cycle-hub","Trying to Conceive (TTC)","TTC Mode provides specialized fertility tracking, ovulation overrides based on hormone testing, biphasic temperature shift calculations, and countdown counters for the luteal phase (the Two-Week Wait).",[376,377],"1. Fertility Tracking & Predictions","2. Alerts, Tests & Content","  Trying to Conceive (TTC)  TTC Mode provides specialized fertility tracking, ovulation overrides based on hormone testing, biphasic temperature shift calculations, and countdown counters for the luteal phase (the Two-Week Wait).  1. Fertility Tracking & Predictions    Daily Conception Probability : When TTC Mode is active, standard cycle indicators are replaced with fertility predictions. Conception probability ranges from   Low  (pre-fertile window) to   High\u002FPeak  (the 5 days before ovulation and the day of ovulation itself).   OPK \u002F LH Test Logging : Log results from Ovulation Predictor Kits (Negative, Low, High, Peak). If a   Peak  OPK is recorded, the prediction engine shifts your estimated ovulation date to the following day, adjusting subsequent period predictions accordingly.   Cervical Mucus & Position :\n    Cervical Mucus : Track consistency (Dry, Sticky, Creamy, Watery, Eggwhite). Eggwhite mucus is associated with peak fertility.   Cervical Position : Log physical characteristics (Height: Low\u002FMed\u002FHigh; Firmness: Firm\u002FSoft; Openness: Closed\u002FOpen).   BBT Chart with Coverline : Ovulation is confirmed using the clinical 3-over-6 rule (3 consecutive daily temperatures at least   0.11 °C  above a coverline calculated from the previous 6 days). The chart highlights this ovulation day and renders the coverline.   Intercourse Tracking : Log intercourse sessions, with toggles for protected or unprotected status.   2. Alerts, Tests & Content    Two-Week Wait & Pregnancy Test :\n    Two-Week Wait (2WW) : Displays a dashboard widget tracking Days Past Ovulation (DPO) and the implantation window (6–12 DPO).   Pregnancy Test : Log Home Pregnancy Test (HPT) results (Negative, Faint, Positive). Positive logs display a congratulations banner with a mode switcher link to   Pregnancy Mode .   TTC Coaching Articles : Care Hub displays articles filtered specifically for conceiving users (e.g. tracking advice, nutritional tips).   Fertile Window Alerts :   Planned Roadmap  (Fertility calendar push notifications are deferred to the active backlog pending app-wide notification system integration).",{"id":380,"path":381,"dir":372,"title":382,"description":383,"keywords":384,"body":388},"content:2.features:16.cycle-hub:3.pregnancy.md","\u002Ffeatures\u002Fcycle-hub\u002Fpregnancy","Pregnancy Mode","Pregnancy Mode shifts the application focus from fertility prediction to pregnancy milestone tracking, kick counting, contraction timing, maternal vitals, and checklists.",[385,386,387],"1. Gestational Milestones & Info","2. Daily Tracking Tools (Quick Tiles)","3. Physical Wellness Roadmap","  Pregnancy Mode  Pregnancy Mode shifts the application focus from fertility prediction to pregnancy milestone tracking, kick counting, contraction timing, maternal vitals, and checklists.  1. Gestational Milestones & Info    Week-by-Week Baby Size & Tips : Scroll through weeks 4 to 40+ on the baby growth scrubber to view custom womb illustrations showing fetal size comparisons, average length (cm), average weight (g), and daily developmental tips.   Birth Plan, Hospital Bag, Checklists :\n    Birth Plan : Configure preferences for delivery settings, pain relief options, and newborn care to export and share with your medical team.   Hospital Bag : Customize checklist tasks for Mother, Partner, and Baby.   Weekly Checklists : Weekly task lists (e.g. glucose tests, pediatrician research) populated automatically based on gestational week.   2. Daily Tracking Tools (Quick Tiles)  Manage your daily pregnancy workflows via six dashboard tiles:    Kick Counter with Sessions : Start a timing session to record baby movements. The app logs each kick, storing full historical session lists to track trends.   Contraction Timer + 5-1-1 Alert : Record contraction durations and intervals. If the pattern matches the clinical   5-1-1 Alert  (contractions \u003C= 5 mins apart, lasting >= 1 min, sustained for >= 1 hour), the app flags a warning banner advising you to contact your healthcare provider.   Bump Photo Journal : Upload, browse, and delete weekly photos of your bump to visually document physical progression.   Weight & BP Tracking :\n    Weight Tracking : Logs weight against pre-pregnancy targets (Singleton\u002FTwins) based on IOM guidelines.   BP (Blood Pressure) Tracking : Records systolic\u002Fdiastolic blood pressure logs to help monitor cardiovascular health.   Prenatal Vitamin Toggle : Quick-log buttons on the vitals card to record daily prenatal vitamin and iron compliance.   Appointments & Scans : Log upcoming doctor checkups, lab scans, or ultrasound appointments.   Food & Medication Safety : Safety categories (Safe, Caution, Avoid) with risk breakdowns (e.g. soft cheeses, herbal teas, ibuprofen).   3. Physical Wellness Roadmap    Prenatal Workouts & Pelvic Floor :   Planned Roadmap  (Surfacing specialized core\u002Fpelvic workouts is deferred to the future fitness program backlog).",{"id":390,"path":391,"dir":372,"title":392,"description":393,"keywords":394,"body":398},"content:2.features:16.cycle-hub:4.insights.md","\u002Ffeatures\u002Fcycle-hub\u002Finsights","Cycle Insights, Care & Privacy","This section outlines advanced trend analysis, the clinical care hub, and privacy configurations.",[395,396,397],"1. Insights & Content","2. Care Hub prep tools","3. Privacy & Data Portability","  Cycle Insights, Care & Privacy  This section outlines advanced trend analysis, the clinical care hub, and privacy configurations.  1. Insights & Content  The Insights tab maps logging trends across your cycles and phases:    Cycle Regularity Chart : Plots cycle lengths across your history, displaying your average length line to visualize regularity.   BBT Trend & Fertile Score : Graphs daily Basal Body Temperature curves, highlights confirmed ovulation days, and maps fertile windows alongside ovulation predictor results.   Symptom Heatmap & Correlations : Displays a heat map representing the frequency and severity of your logged symptoms, helping correlate symptoms with specific cycle phases.   Weight & Sleep Trends : Renders average sleep duration, hydration levels, and weight fluctuations across your menstrual cycle phases, using min-sample gating to ensure statistical relevance.   Curated Health Library : Search and read educational articles filtered by your active mode (Standard, TTC, or Pregnancy).   PMS \u002F PCOS \u002F Endometriosis Flags : The cycle analysis engine highlights clinical warning flags (such as irregular cycles, short cycles, or heavy bleeding patterns) and links directly to relevant health library articles.   2. Care Hub prep tools    Birth-Plan Builder : In Pregnancy Mode, prepare preferences for delivery environments, pain relief, and newborn procedures to export and share with your medical provider.   Hospital-Bag Checklist : Pre-populated lists (for Mother, Partner, and Baby) with customization support.   Doctor Report : Compile a comprehensive PDF summary of your cycle lengths, symptoms, BBT charts, or pregnancy vitals (kicks, weight gain, blood pressure) to hand to your physician during visits.   3. Privacy & Data Portability  As a self-hosted platform, your data never leaves your instance:    Discreet Mode : Enable this in Settings to change the sidebar label to   \"Wellness\"  and replace cycle icons with generic health graphics.   Data Export : Download a full backup of your entire cycle history, settings, and logs as a single JSON file.   Zero Telemetry : The app does not track, collect, or upload your health records.",{"id":400,"path":401,"dir":372,"title":402,"description":403,"keywords":404,"body":407},"content:2.features:16.cycle-hub:5.modes-comparison.md","\u002Ffeatures\u002Fcycle-hub\u002Fmodes-comparison","Cycle Tracking Modes Comparison","The Period & Cycle Hub supports 5 distinct tracking modes to align with different physiological phases. Below is a detailed feature comparison, active features, and the roadmap for upcoming modes.",[405,406],"Feature Matrix","Tracking Modes Detail","  Cycle Tracking Modes Comparison  The Period & Cycle Hub supports 5 distinct tracking modes to align with different physiological phases. Below is a detailed feature comparison, active features, and the roadmap for upcoming modes.  Feature Matrix     Feature \u002F Capability  Standard Mode  TTC Mode  Pregnancy Mode  Postpartum Mode (Roadmap)  Menopause Mode (Roadmap)     Menstrual Flow Logging  Yes  Yes  No  Lochia Only  No (or highly irregular)    Cycle Length Predictions  Yes (Next 3)  Yes (Next 3)  No  No (Suspended)  No (Irregularity focus)    Fertile Window \u002F Ovulation  Yes (Stats-based)  Yes (Advanced)  No  No  No    BBT & Biphasic Detection  Yes  Yes (Enhanced)  No  No  No    Symptom Phase Matrix  Yes  Yes  No (Trimester-based)  Yes (Recovery-based)  Yes (Hot flash focus)    Fetal Milestones & Kick Counter  No  No  Yes  No  No    Contraction Timer  No  No  Yes  No  No    HRT (Hormone Replacement) Log  No  No  No  No  Yes    Breastfeeding \u002F Kegels Log  No  No  No  Yes  No   Tracking Modes Detail  1. Standard Cycle Tracking (  standard )    Status :   Fully Active  (Included in Onboarding)   Goal : Track menstruation history, forecast upcoming periods, and log standard physical\u002Femotional symptoms.   Key Features :\n   Predicts next 3 cycles.  Estimates ovulation and standard fertile windows.  Standard symptom-to-cycle-phase correlation matrix.  2. Trying to Conceive (  ttc )    Status :   Fully Active  (Included in Onboarding)   Goal : Maximize the probability of conception by tracking fertility biomarkers.   Key Features :\n    Cervical Mucus & Position Picker : Logs fluid quality (creamy, eggwhite, etc.) and cervical changes.   Intercourse Logger : Logs session timing with protected\u002Funprotected tags.   Enhanced Ovulation Detection : Integrates Basal Body Temperature (BBT) biphasic spikes and Luteinizing Hormone (LH) test strips to pinpoint ovulation.  3. Pregnancy Tracking (  pregnant )    Status :   Fully Active  (Included in Onboarding)   Goal : Track gestational progress, fetal development, and pregnancy-specific milestones.   Key Features :\n    Pregnancy Today Dashboard : Replaces cycle predictions with gestational weeks\u002Fdays, estimated due date (EDD) countdown, and fetus size comparisons (e.g. size of a fruit).   Contraction Timer : Logs contraction durations and frequencies to detect active labor.   Kick Counter : Records fetal movement sessions.  4. Postpartum & Recovery (  postpartum )    Status :   Roadmap \u002F Database Placeholder  (Excluded from Onboarding)   Goal : Track maternal recovery after childbirth, hormonal resetting, and newborn care integration.   Planned Features :\n    Lochia Tracker : Specialized log for postpartum discharge stages (rubra, serosa, alba).   Breastfeeding & Pump Logger : Logs feeding intervals, breast sides, and milk volumes.   Pelvic Floor (Kegels) Reminders : Tracks daily pelvic floor rehabilitation.   Sleep Deficit Heatmap : Correlates night wakings with maternal fatigue and recovery levels.  5. Menopause Transition (  menopause )    Status :   Roadmap \u002F Database Placeholder  (Excluded from Onboarding)   Goal : Track the perimenopause and menopause transition, focusing on hot flashes, irregular cycles, and hormone therapy.   Planned Features :\n    Hot Flash Intensity Tracker : Instant log button to record severity and frequency of hot flashes or night sweats.   Anovulatory Cycle Tracking : Mode to identify non-ovulatory or highly irregular cycles without triggering standard period predictions.   HRT Compliance logs : Tracks hormone replacement therapy usage and symptom mitigation.   Bone Density & Estrogen Projections : Educational charts tracing age-related hormonal shifts.",{"id":409,"path":410,"dir":7,"title":411,"description":412,"keywords":413,"body":414},"content:2.features:index.md","\u002Ffeatures","Features Overview","This section provides an overview of the key features available in SparkyFitness.",[],"  Features Overview  This section provides an overview of the key features available in SparkyFitness.",{"id":416,"path":417,"dir":418,"title":419,"description":420,"keywords":421,"body":424},"content:3.administration:1.oauth-authentication.md","\u002Fadministration\u002Foauth-authentication","administration","OAuth Authentication (OpenID Connect)","SparkyFitness supports OpenID Connect (OIDC) for user authentication, allowing integration with various identity providers. This guide outlines how to configure OIDC within your SparkyFitness instance.",[8,422,423,110],"Configuration Steps","OIDC Flow","  OAuth Authentication (OpenID Connect)  SparkyFitness supports OpenID Connect (OIDC) for user authentication, allowing integration with various identity providers. This guide outlines how to configure OIDC within your SparkyFitness instance.  Overview  SparkyFitness leverages the   openid-client  library to facilitate secure OIDC authentication. OIDC settings are stored in the database and can be managed via the application's administrative interface. You can configure multiple OIDC providers, allowing users to choose their preferred login method.  Configuration Steps  To set up OIDC authentication, you will need to configure the following settings, typically found in the administration section of your SparkyFitness application:    Issuer URL : The URL of your OIDC Identity Provider (IdP). This is where SparkyFitness will discover the IdP's configuration (e.g.,   https:\u002F\u002Faccounts.google.com ).   Client ID : The unique identifier for your SparkyFitness application registered with the OIDC IdP.   Client Secret : The secret key provided by your OIDC IdP for your SparkyFitness application. This should be kept confidential.   Scope : Set this to   openid profile email . While customization might be possible, it has not been tested to work properly.   Redirect URI : The URL where the OIDC IdP will redirect the user after authentication. You should take this URI directly from the administration interface in the app. It is highly recommended to use the default redirect URI suggested by the frontend. While customization might be possible, it has not been tested to work properly.   Auto-Register Users : (Optional) If enabled, new users who successfully authenticate via OIDC but do not have an existing SparkyFitness account will be automatically registered.   Enable Email\u002FPassword Login : (Optional) If OIDC is enabled, this setting determines whether traditional email\u002Fpassword login is still permitted.  Advanced Settings (Optional)  The application is tested with the default values for these settings. Customization is not tested and may not work properly.    Token Endpoint Auth Method : The method used to authenticate the SparkyFitness application with the OIDC token endpoint.   ID Token Signed Response Algorithm : The algorithm used to sign the ID Token (e.g.,   RS256 ,   ES256 ).   Userinfo Signed Response Algorithm : The algorithm used to sign the UserInfo response.   Request Timeout : The timeout in milliseconds for OIDC requests. The default is 3500ms. If you are on a slow network or your OIDC provider is slow to respond, you may need to increase this value.  OIDC Flow  When a user attempts to log in via OIDC:   SparkyFitness redirects the user to the configured OIDC Identity Provider.  The user authenticates with the IdP.  Upon successful authentication, the IdP redirects the user back to the SparkyFitness   oidc-callback  endpoint with an authorization code.  SparkyFitness exchanges the authorization code for an ID Token and Access Token with the IdP.  User information is extracted from the ID Token and\u002For UserInfo endpoint.  If auto-registration is enabled and the user is new, a new SparkyFitness account is created. Otherwise, the existing account is linked or the user is logged in.  Troubleshooting    Invalid Redirect URI : Ensure the Redirect URI configured in SparkyFitness exactly matches the one registered with your OIDC Identity Provider.   Incorrect Client ID\u002FSecret : Double-check that the Client ID and Client Secret are correct and match the values from your IdP.   Issuer URL Issues : Verify that the Issuer URL is correct and accessible from your SparkyFitness server.   Algorithm Mismatches : If you see errors related to \"invalid signature\" or \"algorithm mismatch,\" verify that the \"ID Token Signed Response Algorithm\" and \"Userinfo Signed Response Algorithm\" settings in SparkyFitness match the requirements of your OIDC provider.",{"id":426,"path":427,"dir":418,"title":428,"description":429,"keywords":430,"body":432},"content:3.administration:2.reverse-proxy.md","\u002Fadministration\u002Freverse-proxy","Reverse Proxy","This page will provide details on configuring a reverse proxy for SparkyFitness.",[431],"Running behind Cloudflare Tunnel + Cloudflare Access","  Reverse Proxy  This page will provide details on configuring a reverse proxy for SparkyFitness.  If using a proxy like Nginx Proxy Manager, ensure the following headers are configured:     proxy_set_header Host $host;\n   proxy_set_header X-Real-IP $remote_addr;\n   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n   proxy_set_header X-Forwarded-Proto $scheme;\n   add_header X-Content-Type-Options \"nosniff\";\n   proxy_set_header X-Forwarded-Ssl on;\n  This sample can be found under   sample  If you want to rely on docker networking instead, choose the scheme   http , enter the container name   sparkyfitness-frontend \nand port   80 .Note: In order for docker networking to work, the Nginx Proxy Manager network has to be connected to the   sparkyfitness-frontend  container. You can find the name of your networks using   docker network ls , find the container name using   docker container ls  and connect them using   docker network connect network container .  Running behind Cloudflare Tunnel + Cloudflare Access  SparkyFitness has its own login, so Cloudflare Access simply adds an extra authentication layer in front of the app. A few settings keep the two working together smoothly:    Set a generous Access session duration.  In your Cloudflare Access application settings, increase \"Session Duration\" (e.g. to 1 week or 1 month). In a browser, Access always uses its interactive login redirect the first time and after this duration expires — that's expected and can't be skipped for browser traffic. A longer duration just makes it infrequent.   For the mobile app or any other non-browser client  (scripts, monitoring, backend integrations) that calls the API directly without a browser to complete Access's login redirect, create a Cloudflare Access   service token  and have the client send   CF-Access-Client-Id  and   CF-Access-Client-Secret  headers with the token's values on every request. This does not apply to Chrome or other browsers — service tokens are for clients that can attach fixed headers, which an interactive browser session cannot do.   If your frontend and backend are on different hostnames  (a split-origin setup, not the default single-container deployment), set   SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS  on the server to the public frontend hostname so the backend's CORS check accepts it — see   Environment Variables . The frontend's nginx also sends   Access-Control-Allow-Origin  for   manifest.json  and   \u002Flocales\u002F*  based on   SPARKY_FITNESS_FRONTEND_URL .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":434,"path":435,"dir":418,"title":436,"description":437,"keywords":438,"body":441},"content:3.administration:3.manual_backup_restore.md","\u002Fadministration\u002Fmanual_backup_restore","Manual Backup and Restore for SparkyFitness","This document provides instructions for performing manual backup and restore operations for SparkyFitness, primarily for disaster recovery scenarios where the in-app restore might not be feasible.",[439,440],"1. Manual Backup","2. Manual Restore (Disaster Recovery)","  Manual Backup and Restore for SparkyFitness  This document provides instructions for performing manual backup and restore operations for SparkyFitness, primarily for disaster recovery scenarios where the in-app restore might not be feasible.  1. Manual Backup  While the application provides scheduled backups, you can manually trigger a backup if needed. The in-app backup process creates a combined archive containing the PostgreSQL database dump and the   uploads  directory.   Important Note:  This backup functionality is new and should be used with caution. While it creates a backup, it's highly recommended to create additional backups independently of this application. Always follow the 3-2-1 backup strategy (3 copies of your data, on 2 different media, with 1 copy offsite) to ensure data safety. The functionality of restore may not work properly in all scenarios, so do not rely solely on this in-app backup.   Location of Backups: \nAll backup files are stored in a Docker volume mounted to the   SparkyFitnessServer  service. The default path within the container is   \u002Fapp\u002FSparkyFitnessServer\u002Fbackup . You will need to access this volume from your Docker host.  2. Manual Restore (Disaster Recovery)  This process is for situations where the SparkyFitness application or its Docker containers are not functioning correctly, or if you need to restore to a completely new environment.   WARNING:  This process will   permanently delete all existing data  in your PostgreSQL database and   uploads  directory before restoring from the backup. Ensure you have chosen the correct backup file.  Prerequisites:   Access to your Docker host machine.  The   docker-compose.yml  file used to deploy SparkyFitness.  The full backup archive (  sparkyfitness_full_backup_YYYYMMDD_HHMMSS.tar.gz ) you wish to restore.   docker  and   docker-compose  (or   docker compose ) installed on your host.   psql  and   tar  utilities available on your host or within a temporary container.  Steps:    Stop SparkyFitness Services: \nNavigate to the directory containing your   docker-compose.yml  file and stop the SparkyFitness services.     docker   compose   down\n   Identify and Access the Backup Volume: \nFind the Docker volume associated with the   SparkyFitnessServer 's backup directory. You can inspect your   docker-compose.yml  for volume definitions or use   docker volume ls  and   docker volume inspect \u003Cvolume_name> .\nThe volume will likely be mounted to a path like   \u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002F\u003Cvolume_name>\u002F_data  on Linux hosts.  Let's assume your backup volume is named   sparkyfitness_server_backup_data  and it's mounted to   \u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002Fsparkyfitness_server_backup_data\u002F_data .   Prepare the Backup File: \nCopy your chosen   sparkyfitness_full_backup_YYYYMMDD_HHMMSS.tar.gz  file into the backup volume's data directory on your host.     cp   \u002Fpath\u002Fto\u002Fyour\u002Fbackup\u002Fsparkyfitness_full_backup_YYYYMMDD_HHMMSS.tar.gz   \u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002Fsparkyfitness_server_backup_data\u002F_data\u002F\n  Replace   \u002Fpath\u002Fto\u002Fyour\u002Fbackup\u002F  with the actual path to your backup file.   Extract the Backup Archive: \nYou'll need to extract the combined archive to get the database dump and uploads archive. You can do this directly on the host if   tar  is available, or use a temporary Docker container.   Option A: Using host   tar  (if available):     cd   \u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002Fsparkyfitness_server_backup_data\u002F_data\u002F\n   tar   -xzf   sparkyfitness_full_backup_YYYYMMDD_HHMMSS.tar.gz\n   Option B: Using a temporary Docker container:     docker   run   --rm   -v   sparkyfitness_server_backup_data:\u002Fbackup_volume   ubuntu:latest   tar   -xzf   \u002Fbackup_volume\u002Fsparkyfitness_full_backup_YYYYMMDD_HHMMSS.tar.gz   -C   \u002Fbackup_volume\n  This will extract   sparkyfitness_db_backup_YYYYMMDD_HHMMSS.sql.gz  and   sparkyfitness_uploads_backup_YYYYMMDD_HHMMSS.tar.gz  into the backup volume.   Clear Existing Database and Uploads Data:  This step is destructive.  Ensure you have stopped the services and are confident in your backup.    Clear   uploads  directory: \nIdentify the Docker volume for your   SparkyFitnessServer 's   uploads  directory (e.g.,   sparkyfitness_server_uploads_data ).     # Example: Assuming uploads volume is sparkyfitness_server_uploads_data\n   docker   run   --rm   -v   sparkyfitness_server_uploads_data:\u002Fuploads_volume   ubuntu:latest   rm   -rf   \u002Fuploads_volume\u002F  *\n   Clear PostgreSQL Database: \nYou need to drop and recreate the database. You can use a temporary PostgreSQL client container.\nFirst, get the database connection details from your   docker-compose.yml  or   .env  file (DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME).     # Example: Replace with your actual DB details\n   DB_HOST  =  \"sparkyfitness-db\"   # Or localhost if connecting directly to host DB\n   DB_PORT  =  \"5432\"\n   DB_USER  =  \"sparkyfitness\"\n   DB_PASSWORD  =  \"your_db_password\"\n   DB_NAME  =  \"sparkyfitness\"\n   \n   # Drop database\n   docker   run   --rm   -e   PGPASSWORD=  ${DB_PASSWORD}   postgres:latest   dropdb   -h   ${DB_HOST}   -p   ${DB_PORT}   -U   ${DB_USER} ${DB_NAME}\n   \n   # Create database\n   docker   run   --rm   -e   PGPASSWORD=  ${DB_PASSWORD}   postgres:latest   createdb   -h   ${DB_HOST}   -p   ${DB_PORT}   -U   ${DB_USER} ${DB_NAME}\n   Note: If your   sparkyfitness-db  container is not running, you might need to start it temporarily or adjust   DB_HOST  to   localhost  if PostgreSQL is directly accessible on the host.   Restore Database from Dump: \nUse the   psql  command to restore the database from the extracted   .sql.gz  file.     # Example: Replace with your actual DB details and backup file name\n   DB_HOST  =  \"sparkyfitness-db\"\n   DB_PORT  =  \"5432\"\n   DB_USER  =  \"sparkyfitness\"\n   DB_PASSWORD  =  \"your_db_password\"\n   DB_NAME  =  \"sparkyfitness\"\n   DB_DUMP_FILE  =  \"\u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002Fsparkyfitness_server_backup_data\u002F_data\u002Fsparkyfitness_db_backup_YYYYMMDD_HHMMSS.sql.gz\"\n   \n   gunzip   -c   ${DB_DUMP_FILE}   |   docker   run   --rm   -i   -e   PGPASSWORD=  ${DB_PASSWORD}   postgres:latest   psql   -h   ${DB_HOST}   -p   ${DB_PORT}   -U   ${DB_USER}   -d   ${DB_NAME}\n   Restore Uploads Directory: \nExtract the   uploads  tar archive into the   SparkyFitnessServer 's   uploads  volume.     # Example: Assuming uploads volume is sparkyfitness_server_uploads_data\n   UPLOADS_TAR_FILE  =  \"\u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002Fsparkyfitness_server_backup_data\u002F_data\u002Fsparkyfitness_uploads_backup_YYYYMMDD_HHMMSS.tar.gz\"\n   \n   docker   run   --rm   -v   sparkyfitness_server_uploads_data:\u002Fuploads_volume   ubuntu:latest   tar   -xzf   ${UPLOADS_TAR_FILE}   -C   \u002Fuploads_volume\n   Clean Up Temporary Files: \nRemove the extracted database dump and uploads tar files from your backup volume.     cd   \u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002Fsparkyfitness_server_backup_data\u002F_data\u002F\n   rm   sparkyfitness_db_backup_YYYYMMDD_HHMMSS.sql.gz\n   rm   sparkyfitness_uploads_backup_YYYYMMDD_HHMMSS.tar.gz\n   rm   sparkyfitness_full_backup_YYYYMMDD_HHMMSS.tar.gz\n   Start SparkyFitness Services:     docker   compose   up   -d\n  Your SparkyFitness instance should now be restored to the state of your chosen backup.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":443,"path":444,"dir":418,"title":445,"description":446,"keywords":447,"body":448},"content:3.administration:4.homepage-widget.md","\u002Fadministration\u002Fhomepage-widget","Homepage Dashboard Widget","This guide provides instructions for adding the SparkyFitness service widget to your Homepage dashboard.",[],"  Homepage Dashboard Widget  This guide provides instructions for adding the SparkyFitness service widget to your   Homepage  dashboard.   Note: This widget is maintained by the Homepage developer community.  The SparkyFitness widget displays a summary of your health stats (e.g., active goals, calorie intake) directly on your personal dashboard.  For detailed configuration instructions, API key requirements, and widget options, please refer to the official Homepage documentation:   Homepage SparkyFitness Widget Documentation",{"id":450,"path":451,"dir":452,"title":453,"description":454,"keywords":455,"body":459},"content:4.mobile-app:1.mobile-app.md","\u002Fmobile-app\u002Fmobile-app","mobile-app","Mobile App","The Mobile App is available for both iOS and Android devices. It allows you to sync your data from Apple Health or Android Health Connect. It also provides a convenient way to access Sparky Fitness on the go.",[456,457,458],"iOS","Android","Screenshot (iOS)","  Mobile App  The Mobile App is available for both iOS and Android devices. It allows you to sync your data from Apple Health or Android Health Connect. It also provides a convenient way to access Sparky Fitness on the go.   Mobile App requires HTTPS , though support for self-signed certificates has been added. Since the app handles health data, HTTPS is required for the app to be allowed to be published on the Google Play Store. See the   Google Play Policy Center  for more information.  iOS  The iOS version of the Sparky Fitness app is available on the App Store.   Get it here  Testflight  Join the Testflight beta program to get early access to new features and updates:   Join Testflight  Android  Install APK  You can download the latest APK from our   GitHub releases page . Look for the latest release and download the   SparkyFitnessMobile.apk  file. Then transfer it to your android device for installation.  Google Play Beta  The Android version is available as a google play store beta. You can join the beta program to get early access to new features and updates:   First, join the   Google Play beta group  Then you will have access to closed testing and can   download the beta here  Screenshot (iOS)  ",{"id":461,"path":462,"dir":452,"title":463,"description":464,"keywords":465,"body":467},"content:4.mobile-app:2.proxy-setup.md","\u002Fmobile-app\u002Fproxy-setup","Proxy Tunnel Setup","If you use a proxy tunnel such as Cloudflare or Pangolin, you will need to configure the app to send a special header.",[466],"Pangolin","  Proxy Tunnel Setup  If you use a proxy tunnel such as Cloudflare or Pangolin, you will need to configure the app to send a special header.  Pangolin   Open your Pangolin dashboard click \"Links\" in the sidebar  Click Create Share Link  Choose your resource, enter a title, and an expiration date. Click Create Link  Underneath the QR code, click \"Usage Examples\" to see how your token will be sent as a header. Copy this down.     In the Sparky Fitness app, navigate to the settings screen  Click on your server to edit it or add a new server.  Enter in the header information that you copied from the Pangolin dashboard. You may need to click the + button to add another field.  ",{"id":469,"path":470,"dir":452,"title":110,"description":7,"keywords":471,"body":473},"content:4.mobile-app:3.troubleshooting.md","\u002Fmobile-app\u002Ftroubleshooting",[472],"Getting a Diagnostic Report","  Troubleshooting  Getting a Diagnostic Report  If you encounter issues with SparkyFitness, you can generate a diagnostic report to help identify the problem. This report includes logs, configuration details, and system information. No personal data is included, that includes all health, food and exercise related data.  You can find the Diagnostic Report tool on the settings screen by scrolling all the way to the bottom. You will be able to save the report or you can share it directly with the developers on Discord or in a GitHub issue.  ",{"id":475,"path":476,"dir":7,"title":477,"description":478,"keywords":479,"body":481},"content:5.community-guides.md","\u002Fcommunity-guides","Community Guides","This section highlights community-contributed guides and resources for SparkyFitness. These guides are created by users like you to share knowledge, tips, and best practices.",[480],"How to Contribute or Find Guides","  Community Guides  This section highlights community-contributed guides and resources for SparkyFitness. These guides are created by users like you to share knowledge, tips, and best practices.  How to Contribute or Find Guides  If you have a guide you'd like to share, or if you're looking for specific community-driven content, here's how you can engage:    Share your knowledge : Write a guide and share it with the community. You can submit it as a pull request to the documentation repository.   Join our Discord : Engage with other community members, ask questions, and find answers in our Discord server. Many community guides and tips are shared there informally.   GitHub Discussions : Check the GitHub Discussions for ongoing conversations, shared solutions, and requests for new guides.   Contribute to the documentation : If you see a gap in the documentation or have a guide that would benefit others, consider contributing directly to this documentation site.",{"id":483,"path":484,"dir":7,"title":485,"description":486,"keywords":487,"body":492},"content:6.faq.md","\u002Ffaq","Frequently Asked Questions (FAQ)","This section provides answers to common questions about SparkyFitness.",[488,489,453,490,110,491,15],"General & Project Questions","Setup & Deployment","Features & Customization","Cloud & Hosting","  Frequently Asked Questions (FAQ)  This section provides answers to common questions about SparkyFitness.  General & Project Questions    What is SparkyFitness? \nSparkyFitness is a comprehensive fitness tracking and management application designed to help users monitor their nutrition, exercise, and body measurements. It provides tools for daily progress tracking, goal setting, and insightful reports to support a healthy lifestyle.   Is SparkyFitness free? Why a custom license? \nSparkyFitness uses a custom license to retain commercial rights. Building and maintaining the project requires significant resources (hardware, developer accounts, infrastructure, AI tools, etc.). If companies commercially host the project, it is reasonable to ask them to obtain permission or contribute back.  Recently, several hosting providers began offering SparkyFitness. While some reached out to discuss partnerships and revenue sharing, others did not. This reinforced the decision to keep commercial hosting under a separate license rather than adopting a standard open-source license that would relinquish that control.  The intention is not to prevent individuals from using or self-hosting the project, but to ensure that if SparkyFitness becomes commercially valuable, the project itself can remain sustainable. The licensing model may be revisited as the project grows, but this currently represents the fairest balance.   Will SparkyFitness be free forever? \nThere are no plans to charge self-hosted users. However, maintaining the project involves ongoing expenses such as development infrastructure, developer license fees, and AI services. If you find SparkyFitness valuable, consider sponsoring the project to help keep it sustainable and free for everyone.   Is my data private? \nYes. SparkyFitness does not collect or transmit any of your personal data; everything is stored locally on your server. However, third-party services you configure (such as OpenAI or Google Gemini AI APIs, external data providers) may process and store data according to their respective policies.   What is the goal of SparkyFitness? \nThe goal is to build SparkyFitness into a comprehensive, \"one-stop\" health and wellness solution. Rather than switching between multiple apps, we want SparkyFitness to cover calorie tracking, exercise and workout logging, wellness metrics, medications, and mental health in a single unified platform.   What features can I expect next, and how are updates prioritized? \nWe prioritize bug fixes above all else to ensure the application remains stable, which is why bugs are addressed and closed as quickly as possible. For new features and enhancements, we prioritize based on impact (features requested by many users), followed by the oldest pending requests.   My GitHub request was closed as completed, but I don't see the changes in my app. Why? \nWhen an issue or enhancement request is closed as completed, the code has been successfully merged into our main branch. These changes will become available in the next official release. You can verify this by checking if a Pull Request (PR) is attached to the closed item.   Setup & Deployment    How do I install SparkyFitness? \nPlease refer to the   Installation Guide  for detailed instructions on how to install SparkyFitness using various methods.   What are the system requirements? \nIf you deploy using Docker, the container package includes everything you need to run the application. However, if you are installing directly from source or utilizing other deployment methods, please refer to their respective installation guides for specific system and package dependencies.   Can I use my own external PostgreSQL database? \nYes, you can run SparkyFitness with an external database. Please refer to our   External Database Guide  for detailed configuration instructions.   Why is the installation so complex? \nWe are actively working on improving the installation experience. If you have suggestions or ideas to simplify the setup, please feel free to raise a Pull Request or open a discussion\u002Fissue on our GitHub repository.   What should I set for   SPARKY_FITNESS_FRONTEND_URL  in my   .env ? \nSet   SPARKY_FITNESS_FRONTEND_URL  to the exact URL you use to access the SparkyFitness frontend in your web browser (e.g.,   https:\u002F\u002F192.168.1.100:3004  or   https:\u002F\u002Ffitness.yourdomain.com ).   Does the mobile app support HTTP? \nNo. While the web interface can work over HTTP, the mobile app requires HTTPS to function (for camera access, barcodes, and other native features required by Apple and Google app store publishing guidelines). Because health data is highly sensitive, we do not support or recommend running your public-facing instance over HTTP.\n  https:\u002F\u002Fdeveloper.android.com\u002Fhealth-and-fitness\u002Fhealth-connect\u002Favailability  https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fhealthkit\u002Fprotecting-user-privacy   Can I migrate my data from Flo, MyFitnessPal, or other apps? \nWhile direct API integration with some platforms (like Hevy) is supported, many commercial apps (like Flo or MyFitnessPal) require enterprise credentials and restrict API access for self-hosted apps. However, SparkyFitness provides robust CSV import tools for Food, Exercises, and Check-ins. Support for importing Period, Pregnancy, and Medication history is planned for future updates.   Mobile App    Do you have a mobile app? \nYes! Please refer to our   Android Mobile App Guide  and   Apple Health Integration Guide  for detailed setup instructions.    Android : APKs are available on the   GitHub Releases page . You can also join our Google Play Store Closed Testing group via the link provided on the GitHub Wiki.   iOS : The app is live on the Apple App Store, and beta builds are accessible via Apple TestFlight.   Why are the Google closed testing or App Store builds outdated? \nThe Android APK on GitHub is updated automatically with every release. We try to keep Google Closed Testing and Apple TestFlight builds updated alongside it, though they usually take 1–2 days to be approved by Google\u002FApple. Production App Store releases, on the other hand, are pushed on a slower cycle (typically every couple of months).   How do I integrate with Gadgetbridge? \nYou can sync your wearable data from Gadgetbridge to Android's   Health Connect  first, and then use the SparkyFitness mobile app to sync those metrics into SparkyFitness. For detailed instructions, refer to the   Gadgetbridge Health Connect Integration Guide .   Do you have a smartwatch companion app (Apple Watch or Wear OS)? \nA dedicated smartwatch companion app is on our development roadmap\u002FTo-Do list.   Features & Customization    How do I sync with Garmin? \nFirst, ensure you enable the Garmin integration service in your   docker-compose.yml  file. Once enabled, log in to the SparkyFitness Web UI, navigate to the   External Data Providers  settings section, and link your Garmin Connect account.   How do I enable the Chatbot or Model Context Protocol (MCP)? \nYou can enable the AI chatbot by configuring your LLM provider credentials in the Web UI under your account settings tab. The MCP API is exposed globally and can be reached at the   \u002Fmcp  backend endpoint.   What external food and exercise\u002Fhealth data providers are supported? \nSparkyFitness integrates with several popular health, fitness, and recipe APIs:    Food & Recipes : OpenFoodFacts, USDA, FatSecret, Yazio, Swiss Food Database, Mealie, Tandoor, Nourish, and Nutritionix.   Wearables & Fitness Services : Garmin Connect, Polar, Withings, Hevy, Wger, Apple Health (via the iOS app), Google Health API and Google Health Connect (via the Android app, which allows bridging data from Google Fit, Samsung Health, Gadgetbridge, and others).   Where do I configure external data\u002FAPI providers? \nExternal lookup providers (like OpenFoodFacts, FatSecret, or Nutritionix) can be configured within the   Food & Exercise Providers  section under your admin settings tab.   Can I add custom nutrition \u002F nutrients? \nYes! You can add custom nutrients via the settings tab. Once configured, you can map these custom nutrients to your provider fields when importing new foods.   Does SparkyFitness have its own food database? \nNo, it does not package a standalone food database. Some default sources are configured out of the box, but for advanced lookups requiring API keys (like FatSecret or Nutritionix), the instance administrator must configure them in the settings.   Troubleshooting    \"Invalid key length\" error during setup \nThis error typically indicates that your   SPARKY_FITNESS_API_ENCRYPTION_KEY  in your   .env  file is not correctly configured. Ensure it is a 64-character hexadecimal string. You can generate a valid key using:     openssl   rand   -hex   32\n  Alternatively, using Node:     node   -e   \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n   Locked out due to MFA\u002F2FA issues or invalid recovery codes \nIf you are locked out of your account, you can disable MFA directly via your database. Connect to your database container (  psql ) and run:     -- 1. Disable MFA flags on users\n   UPDATE \"user\" \n   SET \n       two_factor_enabled = false,\n       mfa_totp_enabled = false,\n       mfa_email_enabled = false,\n       mfa_enforced = false,\n       email_mfa_code = NULL,\n       email_mfa_expires_at = NULL;\n   \n   -- 2. Clear configured TOTP secrets and backup codes\n   TRUNCATE TABLE \"two_factor\";\n   \n   -- 3. Disable the global mandatory MFA setting\n   UPDATE \"global_settings\" SET mfa_mandatory = false WHERE id = 1;\n  Additionally, ensure   BETTER_AUTH_SECRET  is set in your   .env  to prevent legacy payload decryption issues after a server restart.   OIDC setup fails with \"Error fetching OIDC discovery document\" or connection timeouts \nIf your OIDC provider (e.g., Authentik, Authelia) is running locally on the same host or local network, the SparkyFitness server container may fail to resolve or connect to the provider's local domain name. To resolve this, map the OIDC domain to your host's local IP address by adding an   extra_hosts  configuration to the   sparkyfitness-server  service in your   docker-compose.yml :     services  :\n     sparkyfitness-server  :\n       # ...\n       extra_hosts  :\n         -   \"auth.yourdomain.com:192.168.1.100\"   # Replace with your OIDC domain and local host IP\n   Why is my OpenFoodFacts search or lookup erroring out? \nThis is typically caused by rate-limiting on OpenFoodFacts' public API endpoints. OpenFoodFacts searches perform much more reliably if you supply your own credentials. You can register for an account and add your OpenFoodFacts credentials under the   External Data Providers  settings section in the Web UI.   Why is my Android health data not syncing properly to SparkyFitness? \nSparkyFitness uses Android's   Health Connect  to sync fitness metrics. For data to flow successfully, the source health apps must first sync their data into Health Connect. For example, many Samsung devices require a third-party application (such as   Health Sync ) to bridge data from Samsung Health into Health Connect before SparkyFitness can retrieve it.   My self-hosted LLM\u002Fchatbot is slow or failing inside SparkyFitness, but works fast outside of it? \nBy default, Ollama initializes with a context window of 4KB. The SparkyFitness chatbot and MCP integrations utilize over 35 tools and process complex schema payloads. If your VRAM is limited, the context processing will slow down significantly.\nEnsure you increase your runner's context window limit and allocate enough GPU VRAM to handle the larger payloads.  Cloud & Hosting    Is there a hosted version available? \nNo, we officially support and maintain only the self-hosted version. However, you can use third-party cloud providers (such as Pikapod or Zenith Hosting) to host your instance. Please perform your own due diligence before selecting a third-party cloud host.   Getting Help  If you can't find the answer to your question here, please consider:    Joining our Discord community : A great place to ask questions and get help from other users and developers.   Checking GitHub Discussions : Look for existing discussions or start a new one to get support.   Reporting an issue : If you believe you've found a bug, please report it on our   GitHub Issues page .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":494,"path":495,"dir":7,"title":496,"description":497,"keywords":498,"body":502},"content:7.help-me.md","\u002Fhelp-me","Help Me!","This page provides resources and guidance for getting help with SparkyFitness.",[499,500,501],"Community Support","Reporting Issues","Documentation","  Help Me!  This page provides resources and guidance for getting help with SparkyFitness.  Community Support    Discord Community : Join our vibrant Discord community to connect with other users and developers. It's a great place to ask questions, share tips, and get real-time support.    Join our Discord server   GitHub Discussions : For more in-depth questions, feature requests, or to share your ideas, visit our GitHub Discussions forum.    Go to GitHub Discussions  Reporting Issues  If you encounter a bug, unexpected behavior, or have a technical problem, please report it on our GitHub Issues page. Providing detailed information helps us resolve issues faster.    Report a Bug or Issue  Documentation    Search the Documentation : Use the search bar at the top of this documentation site to find answers to your questions.   Browse Sections : Explore the various sections of this documentation for detailed guides and overviews.  Your contributions and feedback are highly valued and help improve SparkyFitness for everyone.",{"id":504,"path":505,"dir":506,"title":507,"description":508,"keywords":509,"body":519},"content:8.developer:1.getting-started.md","\u002Fdeveloper\u002Fgetting-started","developer","Getting Started","SparkyFitness is a comprehensive fitness tracking application built with React 18 + TypeScript + Vite frontend and Node.js\u002FExpress backend, using PostgreSQL with Row Level Security.",[25,510,511,512,513,79,514,515,516,517,518],"Quick Start (Docker Recommended)","Docker Helper Script","Environment Setup","Local Development (without Docker)","Manual Docker Compose","Configuration Files","Code Quality","Next Steps","Common Issues","  Getting Started  SparkyFitness is a comprehensive fitness tracking application built with React 18 + TypeScript + Vite frontend and Node.js\u002FExpress backend, using PostgreSQL with Row Level Security.  Prerequisites  Before you begin, ensure you have the following installed:  For Docker Deployment (Recommended)    Docker & Docker Compose : Essential for running SparkyFitness in containerized environments.   Git : For cloning the SparkyFitness repository.  For Local Development (without Docker)    Node.js 18+  and   npm : The JavaScript runtime and package manager.   PostgreSQL 15+ : The database server.   Git : For version control.  Quick Start (Docker Recommended)  The fastest way to get SparkyFitness running is using our Docker helper script:     # Clone the repository\n   git   clone   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness.git\n   cd   SparkyFitness\n   \n   # Copy environment template\n   cp   docker\u002F.env.example   .env\n   \n   # The SPARKY_FITNESS_API_ENCRYPTION_KEY environment variable needs to be set to a valid value\n   # You can generate a secure key with the following command:\n   # openssl rand -hex 32\n   # or\n   # node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n   # or\n   # generate and set it without manually editing the .env file\n   sed   \"s\u002FSPARKY_FITNESS_API_ENCRYPTION_KEY=changeme_replace_with_a_64_character_hex_string\u002FSPARKY_FITNESS_API_ENCRYPTION_KEY=$(  openssl   rand   -hex   32  )\u002F\"   .env   >   .env.tmp   &&   mv   .env.tmp   .env\n   \n   # Edit any other environment variables as needed\n   # If you are running Docker on another machine, you will need to update the\n   # SPARKY_FITNESS_FRONTEND_URL variable\n   \n   # Start development environment (with live reloading)\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n   \n   # Access the application at http:\u002F\u002Flocalhost:8080 or the URL you set earlier\n  Docker Helper Script  The Docker helper script provides an easy interface for managing your development and production environments:     # Show all available commands and help\n   .\u002Fdocker\u002Fdocker-helper.sh   help\n   \n   # Start development environment\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n   \n   # Start production environment  \n   .\u002Fdocker\u002Fdocker-helper.sh   prod   up\n   \n   # View logs\n   .\u002Fdocker\u002Fdocker-helper.sh   logs\n   \n   # Stop services\n   .\u002Fdocker\u002Fdocker-helper.sh   down\n   \n   # Clean up everything\n   .\u002Fdocker\u002Fdocker-helper.sh   clean\n  Available Commands    dev up  - Start development environment with live reloading   prod up  - Start production environment with optimized builds   down  - Stop all services   logs [service]  - View logs for all services or specific service   clean  - Remove all containers, networks, and volumes   build  - Rebuild all images   restart [service]  - Restart all services or specific service  Environment Setup  Development Environment  Perfect for active development with live reloading:     # Start development stack\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n   \n   # Services available:\n   # - Frontend: http:\u002F\u002Flocalhost:8080 (live reload)\n   # - Backend: http:\u002F\u002Flocalhost:3010 (direct access)\n   # - Database: localhost:5432 (direct access)\n  Development Features    Live Reloading : Both frontend and backend automatically reload on file changes   Volume Mounts : Your local code is mounted into containers for instant updates   Direct Database Access : Connect directly to PostgreSQL for debugging   Development Dependencies : All dev tools and debugging capabilities enabled  Production Environment  Optimized builds for deployment testing:     # Start production stack\n   .\u002Fdocker\u002Fdocker-helper.sh   prod   up\n   \n   # Service available:\n   # - Application: http:\u002F\u002Flocalhost:3004 (nginx proxy)\n  Production Features    Optimized Builds : Minified frontend and production-ready backend   Nginx Proxy : Single entry point with load balancing and static file serving   Environment Isolation : Separate network and security configurations   DockerHub Images : Uses pre-built images for faster deployment  Local Development (without Docker)  If you prefer to run the application locally without Docker:  Database Setup    Install PostgreSQL 15+   Create database :\n     CREATE DATABASE sparkyfitness;\n   CREATE USER sparky WITH PASSWORD 'your_password';\n   GRANT ALL PRIVILEGES ON DATABASE sparkyfitness TO sparky;\n  Backend Setup     # Navigate to server directory\n   cd   SparkyFitnessServer\n   \n   # Install dependencies\n   npm   install\n   \n   # Copy and configure environment\n   cp   .env.example   .env\n   # Edit .env with your database credentials\n   \n   # Run database migrations\n   npm   run   migrate\n   \n   # Start development server\n   npm   run   dev\n  Frontend Setup     # Navigate to project root\n   cd   ..\n   \n   # Install dependencies\n   npm   install\n   \n   # Start development server\n   npm   run   dev\n  Environment Variables  Copy the environment template and configure according to your setup:     cp   docker\u002F.env.example   .env\n  Key variables to configure:  Database Configuration    DATABASE_URL  - PostgreSQL connection string   DB_HOST ,   DB_PORT ,   DB_NAME ,   DB_USER ,   DB_PASSWORD  - Individual database settings  Application Settings    PORT  - Backend server port (default: 3010)   NODE_ENV  - Environment mode (development\u002Fproduction)   JWT_SECRET  - Secret key for JWT token signing  Frontend Configuration    SPARKY_FITNESS_SERVER_HOST  - Backend service connection   SPARKY_FITNESS_SERVER_PORT  - Backend service port  AI Integration    OPENAI_API_KEY  - OpenAI API key for AI features   GOOGLE_AI_API_KEY  - Google Gemini API key   ANTHROPIC_API_KEY  - Anthropic Claude API key  Manual Docker Compose  If you prefer to use Docker Compose directly:     # Production deployment\n   docker-compose   -f   docker\u002Fdocker-compose.prod.yml   up   -d\n   \n   # Development with live reloading\n   docker-compose   -f   docker\u002Fdocker-compose.dev.yml   up\n   \n   # Stop services\n   docker-compose   down\n   \n   # View logs\n   docker-compose   logs   -f   [service_name]\n  Configuration Files  The Docker setup includes several configuration files:  Dockerfiles    Dockerfile.frontend  - Multi-stage frontend build   Dockerfile.backend  - Backend Node.js application   docker\u002Fnginx.conf.template  - Nginx configuration template  Compose Files    docker-compose.dev.yml  - Development environment   docker-compose.prod.yml  - Production environment  Configuration    docker\u002F.env.example  - Environment variables template   docker\u002Fdocker-entrypoint.sh  - Environment variable substitution script   docker\u002Fdocker-helper.sh  - Management script with validation  Code Quality  To maintain code consistency and prevent errors, it's crucial to adhere to the project's code quality standards. Before committing any changes, ensure that your code passes the linting and formatting checks for the frontend.    Linting : Run   npm run lint  in the   SparkyFitnessFrontend  directory to check for potential errors and enforce coding style.   Formatting : Run   npx prettier . --check  in the   SparkyFitnessFrontend  directory to verify consistent code formatting. If you need to fix formatting issues, use   npm run format .  Next Steps  Once you have the application running:    Explore the Application : Visit   http:\u002F\u002Flocalhost:8080  (dev) or   http:\u002F\u002Flocalhost:3004  (prod)   Create an Account : Register a new user account   Check the API : Backend API is available at   http:\u002F\u002Flocalhost:3010\u002Fapi  (dev only)   Review the Architecture : See our   Architecture Guide   Start Contributing : Check out our   Contributing Guide  Common Issues  Port Conflicts  If you encounter port conflicts, check what's using the required ports:     # Check port usage\n   lsof   -i   :8080    # Frontend\n   lsof   -i   :3010    # Backend  \n   lsof   -i   :5432    # Database\n  Database Connection Issues  Ensure PostgreSQL is running and credentials are correct in your   .env  file.  Permission Issues  Make sure Docker has proper permissions and your user is in the   docker  group:     sudo   usermod   -aG   docker   $USER\n   # Log out and back in\n  For more detailed troubleshooting, see our   Troubleshooting Guide .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":521,"path":522,"dir":506,"title":13,"description":523,"keywords":524,"body":534},"content:8.developer:2.architecture.md","\u002Fdeveloper\u002Farchitecture","SparkyFitness is built with a modern, full-stack architecture designed for scalability, maintainability, and performance.",[525,526,527,528,529,530,531,532,533],"High-Level Overview","Technology Stack","Directory Structure","Key Directories Explained","Core Application Features","Security Architecture","Performance Considerations","Deployment Architecture","Integration Points","  Architecture  SparkyFitness is built with a modern, full-stack architecture designed for scalability, maintainability, and performance.  High-Level Overview  The application follows a client-server model, with a clear separation of concerns between the frontend, backend, and database.   ┌─────────────────────────────────────────────────────────────────┐\n│                     SparkyFitness Architecture                  │\n└─────────────────────────────────────────────────────────────────┘\n\n                              User\n                               │\n                               ▼\n                    ┌─────────────────────┐\n                    │   React Frontend    │\n                    │  (Vite + TypeScript)│\n                    └──────────┬──────────┘\n                               │ HTTP\u002FAPI\n                               ▼\n                    ┌─────────────────────┐\n                    │ Node.js\u002FExpress API │\n                    │     (Backend)       │\n                    └──────────┬──────────┘\n                               │\n              ┌────────────────┼────────────────┐\n              │                │                │\n              ▼                ▼                ▼\n    ┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐\n    │  PostgreSQL     │ │ AI Services │ │  External APIs  │\n    │   Database      │ │             │ │                 │\n    │   (with RLS)    │ │ • OpenAI    │ │ • Nutritionix   │\n    └─────────────────┘ │ • Google    │ │ • OpenFoodFacts │\n                        │ • Anthropic │ │ • FatSecret     │\n                        └─────────────┘ │ • Wger          │\n                                        └─────────────────┘\n  Technology Stack  Frontend (src\u002F)    Framework : React 18 with TypeScript   Build Tool : Vite for fast development and optimized builds   UI Components : shadcn\u002Fui built on Tailwind CSS   State Management & Data Fetching : React Context for global state, and TanStack Query for server state management (with hooks in   src\u002Fhooks\u002F  and API functions\u002Fkeys in   src\u002Fapi\u002F ).   Routing : React Router v6   HTTP Client : Fetch API (utilized by TanStack Query)  Backend (SparkyFitnessServer\u002F)    Runtime : Node.js with Express.js framework   Database : PostgreSQL with Row Level Security (RLS)   Authentication : JWT-based authentication   Architecture Pattern : Repository pattern for data access   AI Integration : Multi-provider support (OpenAI, Anthropic, Google, etc.)   External Integrations : Food providers, Exercise data, Health data  Database    Primary Database : PostgreSQL 15+   Security : Row Level Security (RLS) for data isolation   Schema Management : Migration-based schema updates   Connection : Connection pooling with transaction management  Directory Structure  Root Directory (  SparkyFitness\u002F )   SparkyFitness\u002F\n├── src\u002F                          # Frontend React application\n│   ├── components\u002F               # Reusable UI components\n│   ├── contexts\u002F                 # React Context providers\n│   ├── hooks\u002F                    # Custom React hooks\n│   ├── pages\u002F                    # Page-level components\n│   ├── services\u002F                 # API service layer\n│   └── utils\u002F                    # Shared utilities\n├── SparkyFitnessServer\u002F          # Backend Node.js application\n│   ├── models\u002F                   # Repository pattern (database layer)\n│   ├── routes\u002F                   # Express route handlers\n│   ├── integrations\u002F             # External API integrations\n│   ├── ai\u002F                       # AI provider configurations\n│   ├── middleware\u002F               # Express middleware\n│   └── utils\u002F                    # Backend utilities\n├── docker\u002F                       # Docker configuration files\n└── docs\u002F                         # Documentation site (Nuxt Content)\n  Key Directories Explained   src\u002F  (Frontend)  The frontend follows a component-based architecture with clear separation of concerns:     components\u002F : Reusable UI components built with shadcn\u002Fui    contexts\u002F : React Context providers for global state (user preferences, auth, etc.)    hooks\u002F : Custom hooks for data fetching, local storage, and business logic    layouts\u002F : Reusable page structures and layout components    pages\u002F : Top-level page components that compose smaller components    services\u002F : API integration layer with type-safe interfaces    utils\u002F : Shared utility functions and constants   SparkyFitnessServer\u002F  (Backend)  The backend implements a layered architecture with repository pattern:     models\u002F : Repository pattern implementations for data access    routes\u002F : Express route handlers organized by feature    integrations\u002F : External service integrations (food providers, AI services)    middleware\u002F : Express middleware for authentication, logging, error handling    ai\u002F : AI provider configurations and routing logic    utils\u002F : Backend utilities including database migrations   docker\u002F  Contains all Docker-related configuration:    Docker Compose files : Separate configurations for development and production   Dockerfiles : Multi-stage builds for frontend and backend   Configuration templates : Nginx configuration with environment variable substitution   Helper scripts : Management scripts for easy Docker operations   docs\u002F  Documentation site built with Nuxt Content and Docus theme:    Content-driven : All documentation in Markdown with frontmatter   Auto-generated navigation : Based on file structure and numbering   Live editing : Supports Nuxt Studio for visual editing  Frontend Data Management with TanStack Query  For new developers, understanding data fetching and state management in the frontend is crucial. SparkyFitness leverages   TanStack Query  (formerly React Query) for managing server state, which can be a new concept if you're used to simpler global state management solutions.   What is TanStack Query? \nTanStack Query is a powerful library for managing, caching, and synchronizing server state in your React applications. It handles the complexities of data fetching, including caching, background updates, stale-while-revalidate logic, retries, and error handling, allowing you to focus on your UI.   Why do we use it?    Simplified Data Fetching : Reduces boilerplate for data fetching logic.   Performance : Aggressive caching and background refetching make the UI feel faster and more responsive.   Robustness : Built-in retry mechanisms, error handling, and data synchronization ensure a stable user experience.   Developer Experience : Provides powerful hooks (  useQuery ,   useMutation ) that integrate seamlessly with React components, abstracting away complex asynchronous logic.   Core Concepts:    Queries (  useQuery ) : Used for fetching data (GET requests). They are associated with unique   Query Keys  (e.g.,   ['todos', todoId] ) which TanStack Query uses for caching and invalidation.   Mutations (  useMutation ) : Used for creating, updating, or deleting data on the server (POST, PUT, DELETE requests). Mutations often invalidate relevant queries to ensure the UI reflects the latest server data.   Query Keys : Arrays used to uniquely identify queries. They are fundamental for TanStack Query's caching and data synchronization mechanisms.   Integration in SparkyFitness:    API Functions : Located in   src\u002Fapi\u002F . These functions define how data is fetched or mutated from the backend. They typically return promises.   Query Keys : Also defined in   src\u002Fapi\u002F  alongside their respective API functions, ensuring consistency.   Custom Hooks : You'll find   useQuery  and   useMutation  implementations wrapped in custom hooks within   src\u002Fhooks\u002F . These custom hooks abstract the TanStack Query logic, providing a clean interface for components to consume data or trigger server-side changes.   Example (Conceptual): \nInstead of:     \u002F\u002F Component.tsx\n   useEffect  (()   =>   {\n     const   fetchData   =   async   ()   =>   {\n       const   response   =   await   fetch  (  '\u002Fapi\u002Fusers'  );\n       const   data   =   await   response.  json  ();\n       \u002F\u002F ... set state\n     };\n     fetchData  ();\n   }, []);\n  You'll typically use:     \u002F\u002F src\u002Fapi\u002FuserApi.ts\n   import   { api }   from   '@\u002Fservices\u002Fapi'  ;\n   \n   const   userKeys   =   {\n     all: [  'users'  ]   as   const  ,\n     details  : (  id  :   string  )   =>   [  ...  userKeys.all, id]   as   const  ,\n   };\n   \n   const   getUsers   =   ()   =>   {\n     return   api.  get  (  '\u002Fusers'  );\n   };\n   \n   \u002F\u002F src\u002Fhooks\u002FuseUsers.ts\n   import   { useQuery }   from   '@tanstack\u002Freact-query'  ;\n   import   { userKeys, getUsers }   from   '@\u002Fapi\u002FuserApi'  ;\n   \n   export   const   useUsers   =   ()   =>   {\n     return   useQuery  ({\n       queryKey: userKeys.all,\n       queryFn: getUsers,\n     });\n   };\n   \n   \u002F\u002F Component.tsx\n   import   { useUsers }   from   '@\u002Fhooks\u002FuseUsers'  ;\n   \n   const   UserList   =   ()   =>   {\n     const   {   data  :   users  ,   isLoading  ,   isError   }   =   useUsers  ();\n   \n     if   (isLoading)   return   \u003C  div  >Loading users  ...\u003C\u002F  div  >  ;\n     if   (isError)   return   \u003C  div  >Error fetching users  \u003C\u002F  div  >  ;\n   \n     return   (\n       \u002F\u002F ... render users\n     );\n   };\n  This structured approach helps manage data flow efficiently and predictably throughout the application.  Core Application Features  User Authentication & Access Control    Individual Users : Full access to their own data   Family Sharing : Granular permission system for family members   Row Level Security : Database-enforced data isolation   JWT Authentication : Secure token-based authentication  Data Management Architecture    Repository Pattern : All database operations use repository pattern   Transaction Management : Multi-table operations wrapped in transactions   External Provider Integration : Modular system for food, exercise, and health data   Audit Fields :   created_at ,   updated_at  on all tables  AI Integration Architecture  Multi-provider AI system supporting various use cases:                              AI Integration Flow\n         \nUser ──► Chat Interface ──► AI Router ──┬──► OpenAI GPT\n                                        ├──► Google Gemini  \n                                        └──► Anthropic Claude\n                                              │\n                                              ▼\n                                          Database\n                                              │\n                                    ┌─────────┼─────────┐\n                                    ▼         ▼         ▼\n                              Food Diary  Measurements  Goals &\n                                                       Progress\n  AI Capabilities:    Food Logging : Natural language food entry and nutrition analysis   Image Analysis : Photo-based food recognition and logging   Progress Tracking : Intelligent progress analysis and recommendations   Goal Management : AI-assisted goal setting and tracking   Measurement Logging : Conversational body measurement entry  External Integrations  Food Providers    OpenFoodFacts : Open food database with extensive product information   Nutritionix : Commercial nutrition database with restaurant chains   FatSecret : Food database with recipe and meal planning features  Exercise Data    Wger : Open exercise database with detailed exercise information   Custom Exercise Library : User-created and community exercises  Health Data    Apple Health : Integration for importing health and fitness data   Manual Entry : Direct input for measurements and health metrics  Security Architecture  Database Security    Row Level Security (RLS) : PostgreSQL RLS policies ensure users only access their data   Encrypted Connections : All database connections use SSL\u002FTLS   API Key Encryption : All external API keys encrypted at rest  Application Security    JWT Tokens : Secure authentication with configurable expiration   Input Validation : Comprehensive input validation and sanitization   Rate Limiting : API rate limiting to prevent abuse   CORS Configuration : Properly configured CORS for frontend access  Performance Considerations  Frontend Optimization    Code Splitting : Route-based code splitting with React.lazy   State Optimization : TanStack Query for server state caching   Component Optimization : Memoization and efficient re-rendering   Bundle Optimization : Vite's optimized production builds  Backend Optimization    Connection Pooling : PostgreSQL connection pooling   Query Optimization : Efficient database queries with proper indexing   Caching Strategy : Response caching for external API calls   Error Handling : Comprehensive error handling and logging  Database Optimization    Indexing Strategy : Proper indexing on frequently queried columns   Query Performance : Optimized queries with explain plans   Transaction Efficiency : Minimal transaction scope and duration  Deployment Architecture  Docker-based Deployment    Multi-stage Builds : Optimized Docker images with minimal size   Environment Separation : Clear separation between development and production   Service Orchestration : Docker Compose for service coordination   Health Checks : Container health monitoring and automatic restarts  Production Considerations    Reverse Proxy : Nginx for load balancing and static file serving   SSL Termination : SSL\u002FTLS termination at the proxy level   Environment Variables : Secure configuration management   Logging Strategy : Centralized logging with structured log formats  Integration Points  Frontend-Backend Communication    RESTful API : Clean REST API design with consistent response formats   Type Safety : Shared TypeScript types between frontend and backend   Error Handling : Standardized error response format   Authentication : JWT token-based authentication with automatic refresh  Database Integration    Migration System : Automated database migrations on startup   Connection Management : Pool-based connection management   Transaction Patterns : Consistent transaction handling across operations   Data Validation : Both application-level and database-level validation  This architecture provides a solid foundation for the SparkyFitness application, ensuring scalability, maintainability, and a great user experience.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":536,"path":537,"dir":506,"title":538,"description":539,"keywords":540,"body":547},"content:8.developer:3.contributing.md","\u002Fdeveloper\u002Fcontributing","Contributing to SparkyFitness","We welcome contributions of all kinds! Whether you're fixing bugs, adding features, improving documentation, or helping other users, your contributions make SparkyFitness better for everyone.",[541,542,543,544,545,15,546],"Quick Start","Development Workflow","Coding Standards","Pull Request Process","Types of Contributions","Recognition","  Contributing to SparkyFitness  We welcome contributions of all kinds! Whether you're fixing bugs, adding features, improving documentation, or helping other users, your contributions make SparkyFitness better for everyone.  Quick Start     # Fork and clone the repository\n   git   clone   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness.git\n   cd   SparkyFitness\n   \n   # Copy environment template\n   cp   docker\u002F.env.example   .env\n   \n   # The SPARKY_FITNESS_API_ENCRYPTION_KEY environment variable needs to be set to a valid value\n   # You can generate a secure key with the following command:\n   # openssl rand -hex 32\n   # or\n   # node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n   # or\n   # generate and set it without manually editing the .env file\n   sed   \"s\u002FSPARKY_FITNESS_API_ENCRYPTION_KEY=changeme_replace_with_a_64_character_hex_string\u002FSPARKY_FITNESS_API_ENCRYPTION_KEY=$(  openssl   rand   -hex   32  )\u002F\"   .env   >   .env.tmp   &&   mv   .env.tmp   .env\n   \n   # Edit any other environment variables as needed\n   # If you are running Docker on another machine, you will need to update the\n   # SPARKY_FITNESS_FRONTEND_URL variable\n   \n   # Start development environment\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n   \n   # Access the application at http:\u002F\u002Flocalhost:8080 or the URL you set earlier\n  Development Workflow  Setting Up Your Development Environment    Fork the repository  on GitHub   Clone your fork  locally:\n     git   clone   https:\u002F\u002Fgithub.com\u002FYOUR_USERNAME\u002FSparkyFitness.git\n   cd   SparkyFitness\n   Add the upstream remote :\n     git   remote   add   upstream   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness.git\n   Set up your development environment  using our   Getting Started Guide  Development Process  Branch Management    Main Branch : The   main  branch contains the latest stable code   Feature Branches : Create feature branches from   main  for new work   Naming Convention : Use descriptive branch names like   feature\u002Fadd-exercise-tracking  or   fix\u002Flogin-validation  Making Changes    Create a feature branch  from   main :     git   checkout   main\n   git   pull   upstream   main\n   git   checkout   -b   feature\u002Fyour-feature-name\n   Make your changes  following our coding standards:   Follow existing code patterns and conventions  Write clear, self-documenting code  Add comments for complex logic  Ensure your changes don't break existing functionality   Test your changes thoroughly :   Test in the development environment  Verify both frontend and backend functionality  Test edge cases and error scenarios  Ensure mobile responsiveness for UI changes   Commit your changes :     git   add   .\n   git   commit   -m   \"feat: add exercise tracking functionality\"\n  Coding Standards  General Principles    Clean Code : Write self-documenting, readable code   DRY (Don't Repeat Yourself) : Avoid code duplication   SOLID Principles : Follow object-oriented design principles   Separation of Concerns : Keep different aspects of the application separate  Frontend Standards (React\u002FTypeScript)  Component Structure     \u002F\u002F Use functional components with hooks\n   const   ExampleComponent  :   React  .  FC  \u003C  ExampleProps  >   =   ({   prop1  ,   prop2   })   =>   {\n     \u002F\u002F Hooks at the top\n     const   [  state  ,   setState  ]   =   useState  \u003C  StateType  >(  ''  );\n     const   {   data  ,   isLoading   }   =   useQuery  ([  'key'  ], fetchFn);\n     \n     \u002F\u002F Event handlers\n     const   handleSubmit   =   useCallback  ((  e  :   React  .  FormEvent  )   =>   {\n       e.  preventDefault  ();\n       \u002F\u002F Handle submission\n     }, [dependencies]);\n     \n     \u002F\u002F Early returns for loading\u002Ferror states\n     if   (isLoading)   return   \u003C  LoadingSpinner   \u002F>;\n     \n     return   (\n       \u003C  div className  =  \"component-container\"  >\n         {  \u002F* Component JSX *\u002F  }\n       \u003C\u002F  div  >\n     );\n   };\n  TypeScript Guidelines    Strict typing : Use TypeScript strictly, avoid   any  type   Interface definitions : Define clear interfaces for props and data   Type exports : Export types that are used across components   Generic components : Use generics for reusable components  Styling Conventions    Tailwind CSS : Use Tailwind utility classes for styling   shadcn\u002Fui : Prefer shadcn\u002Fui components over custom components   Responsive Design : Use responsive classes (  sm: ,   md: ,   lg: )   Dark Mode : Support both light and dark themes  Backend Standards (Node.js\u002FExpress)  TypeScript First    New Files : All new backend files must be written in TypeScript   Strict Mode : Enable strict TypeScript checking   Type Safety : Avoid   any  type, use proper types and interfaces   Existing JavaScript : You may maintain existing JavaScript files as JavaScript. New files must be TypeScript, and conversion is encouraged when adding significant functionality.  Zod Schema Validation    Required for New Endpoints : All new API endpoints must define Zod schemas for validation   Request Validation : Validate request body, params, and query parameters   Response Schemas : Define expected response shapes   Error Handling : Use Zod's error formatting for client-friendly validation errors  Example:     import   { z }   from   'zod'  ;\n   \n   \u002F\u002F Define schemas\n   const   createUserSchema   =   z.  object  ({\n     email: z.  string  ().  email  (),\n     name: z.  string  ().  min  (  1  ),\n     password: z.  string  ().  min  (  8  )\n   });\n   \n   \u002F\u002F Use in route\n   app.  post  (  '\u002Fapi\u002Fusers'  ,   async   (  req  ,   res  )   =>   {\n     const   validated   =   createUserSchema.  parse  (req.body);\n     \u002F\u002F ... rest of handler\n   });\n  Testing Requirements    New Endpoints Must Have Tests : All new API endpoints require automated tests   Test Coverage : Include happy path, error cases, and edge cases   Integration Tests : Test database interactions and external dependencies   Run Before PR : Execute   pnpm run typecheck && pnpm run lint && pnpm run test  and ensure all checks pass  Repository Pattern     \u002F\u002F All database operations use repository pattern\n   const   userRepository   =   {\n     async   createUser  (  userData  ) {\n       const   client   =   await   pool.  connect  ();\n       try   {\n         await   client.  query  (  'BEGIN'  );\n         \u002F\u002F Database operations\n         await   client.  query  (  'COMMIT'  );\n         return   result;\n       }   catch   (error) {\n         await   client.  query  (  'ROLLBACK'  );\n         throw   error;\n       }   finally   {\n         client.  release  ();\n       }\n     }\n   };\n  API Design    RESTful endpoints : Follow REST conventions   Consistent responses : Use standard response format   Error handling : Implement comprehensive error handling   Input validation : Validate all inputs with Zod schemas  Security Practices    SQL injection prevention : Use parameterized queries   Authentication : Verify JWT tokens on protected routes   Input sanitization : Sanitize all user inputs   Error messages : Don't expose sensitive information  Database Standards  Migration Guidelines    Version control : All schema changes through migrations   Backwards compatibility : Ensure migrations don't break existing data   Transaction wrapping : Wrap migrations in transactions   Rollback scripts : Provide rollback capabilities  Naming Conventions    Tables : Snake case, plural (e.g.,   food_diary_entries )   Columns : Snake case (e.g.,   created_at ,   user_id )   Indexes : Descriptive names (e.g.,   idx_food_diary_user_date )  Pull Request Process  Before Submitting    Update your branch  with the latest changes:     git   checkout   main\n   git   pull   upstream   main\n   git   checkout   your-feature-branch\n   git   merge   main\n   Run the full test suite :     # Test the application thoroughly\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n   # Test your changes manually\n   # Run any automated tests\n   Review your changes :     git   diff   main...your-feature-branch\n  Pull Request Checklist       Branch is up to date  with the latest   main  branch      Changes have been tested  thoroughly in development environment      Code follows project conventions  and standards      No console errors or warnings  introduced      Mobile responsiveness  verified for UI changes      Database migrations  included if schema changes      Documentation updated  if new features or API changes      Environment variables  documented if new ones added      Backend Code Standards  (if applicable):\n     New backend files are written in TypeScript    New endpoints include Zod schemas for validation    New endpoints include automated tests      Quality Checks Passed :\n     Frontend:   pnpm run validate  in   SparkyFitnessFrontend\u002F    Backend:   pnpm run typecheck && pnpm run lint && pnpm run test  in   SparkyFitnessServer\u002F    Mobile:   pnpm run lint && pnpm run test:run -- --watchman=false --runInBand  in   SparkyFitnessMobile\u002F  Submitting Your PR    Push your changes :     git   push   origin   your-feature-branch\n   Create a Pull Request  on GitHub with:    Clear title : Concise description of the change   Detailed description : What problem does this solve and how?   Screenshots : For UI changes, include before\u002Fafter screenshots   Testing notes : How to test the changes   Breaking changes : Note any breaking changes   Related issues : Reference any related issues (e.g.,   Fixes #123 )  PR Template     ## Description\n   Brief description of changes and the problem they solve.\n   \n   ## Type of Change\n   -   [ ] Bug fix (non-breaking change which fixes an issue)\n   -   [ ] New feature (non-breaking change which adds functionality)\n   -   [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n   -   [ ] Documentation update\n   \n   ## Testing\n   -   [ ] Changes have been tested locally\n   -   [ ] No console errors or warnings\n   -   [ ] Mobile responsiveness verified (for UI changes)\n   \n   ## Screenshots (if applicable)\n   Include screenshots for UI changes.\n   \n   ## Additional Notes\n   Any additional information or context about the changes.\n  Review Process    Automated Validation : PR validation workflow checks that required checkboxes are checked\n   Detects Frontend, Backend, Mobile, and UI changes automatically  Validates mandatory checkboxes based on change type  Posts validation results as a comment on your PR   Important : Do not remove checkboxes from the PR template - the validation will fail   Automated Tests : CI tests run for changed components (Frontend, Backend, Mobile)   Code Review : Address feedback from reviewers promptly   Testing : Reviewers will test your changes   Approval : Get approval from maintainers   Merge : Maintainers will merge your PR  Automated PR Validation  Our PR validation workflow automatically checks your submission:   What it validates:   ✅ Integrity & License checkbox (MANDATORY for all PRs)  ✅ Alignment checkbox (MANDATORY for new features)  ✅ Frontend Quality checkbox (MANDATORY for Frontend changes)  ✅ Backend Code Quality checkbox (MANDATORY for Backend changes)  ✅ Screenshots checkbox (MANDATORY for UI changes)  ⚠️ PR type selection (Issue\u002FFeature\u002FDocumentation)  ⚠️ Linked issue reference  ⚠️ Description completeness   How it works:   The workflow runs when you open or edit a PR  It detects which parts of the codebase you changed  It validates that appropriate checkboxes are checked  It posts a comment with validation results and guidance  The PR check will fail if required checkboxes are missing   Common issues:    Don't remove checkboxes : Keep all checkboxes in the PR template   Check the right boxes : Make sure to check boxes that apply to your changes   Backend changes : Must confirm TypeScript, Zod schemas, and tests for new code   UI changes : Must include before\u002Fafter screenshots  After Your PR is Merged    Delete your feature branch :     git   checkout   main\n   git   pull   upstream   main\n   git   branch   -d   your-feature-branch\n   git   push   origin   --delete   your-feature-branch\n   Update your local main :     git   pull   upstream   main\n  Types of Contributions  Bug Fixes    Report issues : Use GitHub issues to report bugs   Provide details : Include steps to reproduce, expected vs actual behavior   Include environment : OS, browser, version information   Screenshots : Visual bugs should include screenshots  New Features    Discuss first : Open an issue to discuss new features before implementing   Small increments : Break large features into smaller, reviewable chunks   Documentation : Include documentation for new features   Tests : Ensure new features are properly tested  Documentation    Keep it current : Update documentation when code changes   Clear examples : Provide clear examples and use cases   User-focused : Write from the user's perspective   Technical accuracy : Ensure technical information is accurate  Code Quality    Refactoring : Improve code structure and readability   Performance : Optimize slow operations   Security : Address security vulnerabilities   Dependencies : Keep dependencies up to date  Getting Help  Community Support    GitHub Issues : Ask questions using GitHub issues   Discussions : Use GitHub Discussions for general questions   Documentation : Check the documentation first  Maintainer Support    Complex Issues : Tag maintainers for complex technical issues   Feature Requests : Discuss significant feature requests with maintainers   Architecture Questions : Get guidance on architectural decisions  Recognition  Contributors are recognized in several ways:    Contributors list : All contributors are listed in the project   Release notes : Significant contributions are mentioned in release notes   Community recognition : Active contributors may be invited to join the core team  Thank you for contributing to SparkyFitness! Your efforts help make fitness tracking better for everyone.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":549,"path":550,"dir":506,"title":551,"description":552,"keywords":553,"body":560},"content:8.developer:4.database.md","\u002Fdeveloper\u002Fdatabase","Database Schema & Migrations","Last updated: 2026-07-08",[554,555,556,557,558,559],"Database Overview","Schema Design Principles","Row Level Security (RLS)","Table Index","Database Migrations","Database Maintenance","  Database Schema & Migrations   Last updated: 2026-07-08  This document covers the database structure, schema design, and migration process for SparkyFitness.   Note:   For   authoritative table definitions , see   db_schema_backup.sql  (SQL source) or   shared\u002Fsrc\u002Fschemas\u002Fdatabase\u002F  (TypeScript Zod schemas).  For   security tier classifications and permission mappings , see    11.database-security-tiers.md .   Database Overview  SparkyFitness uses PostgreSQL 15+ with Row Level Security (RLS) to ensure data isolation between users. The database follows a normalized design with clear relationships between entities.   Schema Design Principles  Naming Conventions    Tables : Snake case, plural (e.g.,   food_entries ,   user_preferences )   Columns : Snake case (e.g.,   created_at ,   user_id ,   total_calories )   Foreign Keys :   {table_name}_id  format (e.g.,   user_id ,   food_item_id )   Indexes : Descriptive names (e.g.,   idx_food_entries_user_date ,   idx_measurements_user_type )  Standard Fields  All tables include these audit fields:    id  - UUID primary key using   gen_random_uuid()   created_at  - Timestamp with timezone, defaults to   NOW()   updated_at  - Timestamp with timezone, updated via triggers   Row Level Security (RLS)  Every user-specific table has RLS policies to enforce data isolation. PostgreSQL context functions (initialized via   public.set_app_context(userId, authenticatedUserId)  on every connection) control access:     -- Example: diary logs are readable by delegates with diary read access and\n   -- writable by delegates with can_manage_diary. rls_policies.sql usually applies\n   -- this via the create_diary_policy('food_entries') generator, which emits:\n   ALTER TABLE food_entries ENABLE ROW LEVEL SECURITY;\n   CREATE POLICY select_policy ON public.food_entries FOR SELECT TO PUBLIC\n     USING (has_diary_read_access(user_id));\n   CREATE POLICY modify_policy ON public.food_entries FOR ALL TO PUBLIC\n     USING (has_diary_access(user_id))\n     WITH CHECK (has_diary_access(user_id));\n   Key functions:    current_user_id()  — active profile context (may differ during family delegation; from   app.user_id )   authenticated_user_id()  — the true logged-in actor (never changes; from   app.authenticated_user_id )   can_access_user_data(target_user_id, permission_type, authenticated_user_id())  — resolves a logical permission (  diary ,   checkin ,   medications ,   reports , plus   *_read  variants) against the   family_access  grant. Domain shortcuts wrap it:   has_diary_read_access ,   has_diary_access ,   has_checkin_read_access ,   has_medication_access ,   has_family_access .  Cycle and pregnancy tables are owner-only (no delegation). See   SparkyFitnessServer\u002Fdb\u002Frls_policies.sql  for the complete policy set and the   create_*_policy  generators.   Table Index  Quick reference of all tables by domain and purpose. For detailed security tier, permission type, and access rules, see    11.database-security-tiers.md .  Authentication & Identity (Tier 1: Owner-Only)     Table  Purpose     user  Account identity, password hash, email    session  Active authentication sessions    api_key  User-generated API keys for external access    passkey  Passwordless login credentials    two_factor  2FA recovery codes and secrets    verification  Email verification tokens    account  Auth credentials and email accounts  Food & Nutrition (Tier 2\u002F3: Owner-Write, Delegate-Read\u002FWrite)     Table  Purpose     foods  Custom food items created by user    food_variants  Serving size options for foods    food_entries  Logged meals\u002Fcalories for the day    food_entry_meals  Meal details associated with logged entries    meals  Custom meal templates    meal_foods  Ingredients assigned to meals    meal_types  Custom meal type definitions (breakfast, lunch, etc.)    meal_plans  Weekly meal planning schedules    meal_plan_templates  Reusable meal plan templates    meal_plan_template_assignments  Scheduled meal templates to calendar    meal_plan_assignment_sets  Sets within assigned meal plans  Exercise & Workouts (Tier 2\u002F3: Owner-Write, Delegate-Read\u002FWrite)     Table  Purpose     exercises  Custom exercises created by user    exercise_entries  Logged exercises for the day    exercise_preset_entries  Logged workout presets for the day    exercise_entry_sets  Reps, weights, and sets completed    exercise_entry_activity_details  Heart rate, distance, activity data    workout_presets  Custom workout\u002Fpreset templates    workout_preset_exercises  Exercises assigned to presets    workout_preset_exercise_sets  Reps\u002Fsets configured in presets    workout_plan_templates  Templates for weekly workout schedules    workout_plan_template_assignments  Scheduled workout templates to calendar    workout_plan_assignment_sets  Sets within assigned workout plans  Measurements & Health (Tier 1\u002F3: Owner-Only or Delegate-Write)     Table  Purpose     check_in_measurements  Weight, neck, waist, hips measurements    check_in_photos  Progress photos    custom_measurements  User-defined custom measurement types    custom_categories  User-defined measurement categories    water_intake  Total water logged for the day    water_intake_entries  Individual logged water cups    water_containers  Configured container sizes    sleep_entries  Sleep logs (bedtime, wake time)    sleep_entry_stages  Sleep stage breakdowns (REM, Deep, Light)    sleep_need_calculations  AI sleep need calculations    daily_sleep_need  Sleep goals calculated for the day  Fasting, Mood, Medications, & Symptoms (Tier 1\u002F3: Owner-Only or Delegate-Write)     Table  Purpose     fasting_logs  Fasting timeline logs (start\u002Fend fast)    mood_entries  Logged mood and energy levels    user_custom_moods  User-defined mood tags (icon\u002Fcolor)    medications  Custom medication inventory lists    medication_schedules  Reminders and schedules for medications    medication_entries  Logs of medications taken    medication_pens  Trackers for medication delivery pens    medication_titration_steps  Automated titration dosage plans    injection_entries  Injection logs (site, time, etc.)    user_custom_symptoms  Custom tracked health symptoms    symptom_entries  Logs of daily tracked symptom severity  Cycle & Pregnancy (Tier 1: Owner-Only)     Table  Purpose     cycles  Menstrual cycle history records    cycle_settings  Cycle hub settings (mode, parameters)    cycle_daily_entries  Per-day cycle logs (flow, BBT, mood, etc.)    cycle_test_entries  Ovulation and pregnancy test logs    pregnancies  Pregnancy records (due date, status)    pregnancy_kick_sessions  Fetal kick-counter sessions    pregnancy_contractions  Contraction timer logs    pregnancy_photos  Bump photo journal    pregnancy_checklist_state  Weekly pregnancy checklist completion    health_appointments  Prenatal and other health appointments  User Preferences & Settings (Tier 2: Owner-Only Write, Delegate-Read)     Table  Purpose     profiles  User full name, height, display metrics    user_preferences  Unit display preferences (Metric vs Imperial)    user_nutrient_display_preferences  Nutrient column display preferences    user_meal_visibilities  Visibility settings for meals    user_goals  Active daily calorie\u002Fmacro goals    user_custom_nutrients  Custom nutrient definitions    user_nutrient_goal_preferences  Per-user minimum\u002Fmaximum\u002Ftarget goal direction override per nutrient (predefined or custom)    user_water_containers  Configured container sizes    user_dashboard_layouts  Rearranged dashboard widget positions    user_medication_display_preferences  GLP-1\u002FMedication display preferences    user_mood_display_preferences  Mood picker visibility settings    user_cycle_display_preferences  Cycle dashboard tile visibility    user_allergen_preferences  Allergen preferences    user_ignored_updates  Records of skipped release updates  AI & Chat (Tier 1: Owner-Only)     Table  Purpose     sparky_chat_history  AI Assistant chat messages and history    ai_service_settings  User-defined custom assistant configurations  Admin & System (Tier 1: Admin-Only or Public)     Table  Purpose     global_settings  Application feature flags and config    sso_provider  Active Single Sign-On providers    oidc_providers  OpenID Connect integration settings    external_provider_types  Search provider configurations (FatSecret, USDA)    external_data_providers  Configured API integrations    medication_types  Medication categories lookup    medication_route_types  Medication administration routes lookup    medication_schedule_types  Medication scheduling frequencies lookup    admin_activity_logs  Admin action audits    day_classification_cache  Daily summary caching logs  Internal & Shared (Tier 2: Owner-Only or System)     Table  Purpose     onboarding_data  Initial user onboarding metrics    onboarding_status  User onboarding status    family_access  Sharing rules and delegation credentials    backup_settings  Automated database backup settings   Database Migrations  SparkyFitness uses a custom migration system that runs automatically on server startup.  Migration Process  The migration system:    Checks current database version  on startup   Applies pending migrations  in order   Tracks applied migrations  in the   migrations  table   Logs migration results  for debugging  Migration Structure  Migrations are stored in   SparkyFitnessServer\u002Fdb\u002Fmigrations\u002F  with the naming pattern:   YYYYMMDDHHMMSS_description.sql\n  Example:   20240315103000_add_exercise_tracking.sql  Creating a New Migration    Create the migration file  in the migrations directory:     cd   SparkyFitnessServer\u002Fdb\u002Fmigrations\u002F\n   touch   20240315142000_add_meal_planning.sql\n   Write the migration SQL  — see the migration checklist in the repo's agent-docs folder (for developers and AI tools)   Update   db_schema_backup.sql  with the new schema state   Apply RLS policies  (these are reapplied automatically on startup from   db\u002Frls_policies.sql )  Migration Best Practices  Backwards Compatibility    Add columns  with default values to avoid breaking existing code   Create new tables  rather than modifying existing ones when possible   Use transactions  to ensure atomic migrations   Test migrations  on development data first  Transaction Management     BEGIN;\n   -- All migration statements here\n   -- If any statement fails, entire migration rolls back\n   COMMIT;\n  Index Creation     -- Create indexes concurrently to avoid blocking\n   CREATE INDEX CONCURRENTLY idx_food_entries_user_date \n   ON food_entries(user_id, created_at);\n  Data Migration     BEGIN;\n   -- Create new table\n   CREATE TABLE new_table (id UUID PRIMARY KEY, ...);\n   \n   -- Migrate existing data\n   INSERT INTO new_table (...)\n   SELECT ... FROM old_table;\n   \n   -- Drop old table (after verifying migration)\n   -- DROP TABLE old_table;\n   \n   COMMIT;\n  Rollback Strategy  While not automated, rollback migrations can be created:    Document rollback steps  in migration comments   Create rollback scripts  for complex migrations   Test rollback procedures  in development   Backup database  before applying production migrations  Troubleshooting Migrations  Migration Fails    Check migration logs  in application startup   Verify database connection  and permissions   Check for syntax errors  in migration SQL   Ensure migration dependencies  are met  Migration Tracking Issues     -- Check applied migrations\n   SELECT * FROM migrations ORDER BY applied_at;\n   \n   -- Manually mark migration as applied (if needed)\n   INSERT INTO migrations (version, applied_at) \n   VALUES ('20240315142000', NOW());\n  Database State Issues     -- Check table structure\n   \\d table_name\n   \n   -- Check RLS policies\n   SELECT * FROM pg_policies WHERE tablename = 'table_name';\n   \n   -- Check indexes\n   SELECT indexname, indexdef FROM pg_indexes \n   WHERE tablename = 'table_name';\n   Database Maintenance  Performance Monitoring    Query performance : Use   EXPLAIN ANALYZE  for slow queries   Index usage : Monitor index usage with   pg_stat_user_indexes   Connection monitoring : Track connection pool usage  Regular Maintenance    VACUUM : Regular vacuuming for performance   ANALYZE : Update table statistics   Index maintenance : Rebuild indexes if needed   Log rotation : Rotate and archive database logs  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":562,"path":563,"dir":506,"title":564,"description":565,"keywords":566,"body":572},"content:8.developer:5.api-reference.md","\u002Fdeveloper\u002Fapi-reference","API Reference","This document provides comprehensive information about the SparkyFitness API, including OpenAPI specification, endpoints, and integration guidelines.",[567,568,569,570,571],"OpenAPI Specification","Purpose in SparkyFitness","Key Elements of SparkyFitness's API (as described by OpenAPI)","Accessing the API Documentation","Detailed API Endpoints","  API Reference  This document provides comprehensive information about the SparkyFitness API, including OpenAPI specification, endpoints, and integration guidelines.  OpenAPI Specification  The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs. It allows both humans and computers to discover and understand the capabilities of a service without access to source code, documentation, or network traffic inspection.  Purpose in SparkyFitness  For SparkyFitness, an OpenAPI specification would serve several key purposes:    API Documentation : Provides clear and interactive documentation for all backend API endpoints, including request parameters, response structures, and authentication methods.   Client Code Generation : Enables automatic generation of client SDKs (Software Development Kits) in various programming languages, simplifying integration for third-party applications or mobile clients.   API Testing : Facilitates automated testing of API endpoints, ensuring consistency and correctness.   Design and Collaboration : Serves as a single source of truth for API design, improving collaboration between frontend and backend developers.  Key Elements of SparkyFitness's API (as described by OpenAPI)  An OpenAPI specification for SparkyFitness would detail:    Endpoints : All available API routes (e.g.,   \u002Fapi\u002Ffood ,   \u002Fapi\u002Fusers ,   \u002Fapi\u002Fexercises ).   Operations : HTTP methods supported for each endpoint (GET, POST, PUT, DELETE).   Parameters : Input parameters for each operation, including their types, formats, and whether they are required.   Responses : The structure of successful and error responses, including status codes and data models.   Authentication : How clients authenticate with the API (e.g., JWT tokens).   Data Models (Schemas) : Definitions of the data structures used in requests and responses (e.g.,   FoodItem ,   UserProfile ,   ExerciseEntry ).  Accessing the API Documentation  While a live, interactive OpenAPI documentation (like Swagger UI) might be available in development environments, the core API is consumed by the SparkyFitness frontend and can be explored by examining the backend routes in   SparkyFitnessServer\u002Froutes\u002F  and the service definitions in   SparkyFitnessServer\u002Fservices\u002F .   Detailed API Endpoints  Authentication    API Key : Used for specific endpoints like   \u002Fapi\u002Fhealth-data . The API Key should be sent in the   Authorization  header as   Bearer \u003CAPI_KEY>  or in the   X-API-Key  header. The API Key must have the necessary permissions (e.g.,   health_data_write ).   JWT Token : Used for most authenticated endpoints. The JWT token should be sent in the   Authorization  header as   Bearer \u003CJWT_TOKEN> .  Error Handling  General error responses follow a consistent structure:    400 Bad Request : Indicates invalid input or missing required fields.   401 Unauthorized : Occurs when authentication credentials are missing or invalid.   403 Forbidden : Occurs when the authenticated user does not have the necessary permissions.   404 Not Found : The requested resource could not be found.   500 Internal Server Error : An unexpected error occurred on the server.  Example Error Response:     {\n     \"error\"  :   \"Error message describing the issue.\"\n   }\n  Endpoints  1.   \u002Fapi\u002Fhealth-data    Path :   \u002Fapi\u002Fhealth-data   Method :   POST   Description : Submits various health data points (e.g., weight, steps, active calories, custom measurements) to the system. This endpoint is crucial for integrating SparkyFitness with external health tracking services like iOS Shortcuts and Android mobile apps, allowing seamless data submission.   Authentication : API Key (sent via   Authorization  header as   Bearer \u003CAPI_KEY>  or   X-API-Key  header). The API Key must have   health_data_write  permission.   Request Body : An array of health data objects, or a single health data object.\n    Structure :\n     [\n     {\n       \"value\"  :   \u003Cnumber>  ,\n       \"type\"  :   \"\u003Cstring>\"  ,\n       \"date\"  :   \"\u003CYYYY-MM-DD>\"  ,\n       \"timestamp\"  :   \"\u003CISO 8601 string, optional>\"\n     },\n     ...\n   ]\n   Fields :\n    value  (required, number): The measurement value.   type  (required, string): The type of health data. This field is case-sensitive. Supported types include:\n    weight : Records body weight.   step : Records the number of steps taken.   water : Records water intake in milliliters.   Active Calories : Records calories burned through physical activity.  Any other string: Will be treated as a custom measurement category. If a category with this name does not exist, it will be automatically created.   date  (required, string): The date of the measurement in   YYYY-MM-DD  format (e.g., \"2025-08-19\").   timestamp  (optional, string): The exact timestamp of the measurement in ISO 8601 format (e.g., \"2025-08-19T08:30:00Z\"). If provided, the   entryHour  will be extracted for more granular tracking.   Examples :\n    Weight :\n     [\n     {\n       \"value\"  :   70.5  ,\n       \"type\"  :   \"weight\"  ,\n       \"date\"  :   \"2025-08-19\"\n     }\n   ]\n   Steps :\n     [\n     {\n       \"value\"  :   10000  ,\n       \"type\"  :   \"step\"  ,\n       \"date\"  :   \"2025-08-19\"\n     }\n   ]\n   Water Intake :\n     [\n     {\n       \"value\"  :   500  ,\n       \"type\"  :   \"water\"  ,\n       \"date\"  :   \"2025-08-19\"\n     }\n   ]\n   Active Calories :\n     [\n     {\n       \"value\"  :   500  ,\n       \"type\"  :   \"Active Calories\"  ,\n       \"date\"  :   \"2025-08-19\"\n     }\n   ]\n   Custom Measurement (e.g., \"Blood Pressure Systolic\") :\n     [\n     {\n       \"value\"  :   120  ,\n       \"type\"  :   \"Blood Pressure Systolic\"  ,\n       \"date\"  :   \"2025-08-19\"  ,\n       \"timestamp\"  :   \"2025-08-19T08:30:00Z\"\n     }\n   ]\n   Responses :\n    200 OK : returned whenever the request body itself is well-formed, even if some individual records could not be processed. Per-record outcomes are reported in the body:   processed  lists successful records,   errors  lists rejected records with their reasons, and   skipped  lists records that were intentionally not written (e.g. Nutrition records without a   source_id , which cannot be deduplicated).   errors  and   skipped  are always present, possibly empty. A 200 with a non-empty   errors  array means the remaining records were still saved.\n     {\n     \"message\"  :   \"All health data successfully processed.\"  ,\n     \"processed\"  : [\n       {\n         \"type\"  :   \"weight\"  ,\n         \"status\"  :   \"success\"  ,\n         \"data\"  : {   \"id\"  :   \"uuid\"  ,   \"user_id\"  :   \"uuid\"  ,   \"entry_date\"  :   \"2025-08-19\"  ,   \"weight\"  :   70.5   }\n       }\n     ],\n     \"errors\"  : [],\n     \"skipped\"  : []\n   }\n \nPartial failure example (still   200 OK ):\n     {\n     \"message\"  :   \"Some health data entries could not be processed.\"  ,\n     \"processed\"  : [\n       {\n         \"type\"  :   \"weight\"  ,\n         \"status\"  :   \"success\"  ,\n         \"data\"  : {   \"id\"  :   \"uuid\"  ,   \"user_id\"  :   \"uuid\"  ,   \"entry_date\"  :   \"2025-08-19\"  ,   \"weight\"  :   70.5   }\n       }\n     ],\n     \"errors\"  : [\n       {\n         \"error\"  :   \"Missing required fields: value (for scalar types), type, or date\u002Ftimestamp in one of the entries\"  ,\n         \"entry\"  : {   \"value\"  :   null  ,   \"type\"  :   \"step\"  ,   \"date\"  :   \"2025-08-19\"   }\n       }\n     ],\n     \"skipped\"  : []\n   }\n    Breaking change note (v0.18+) : earlier server versions returned   400 Bad Request  with the   { \"message\", \"processed\", \"errors\" }  body when   any  record in the batch failed. Automations that keyed on the 400 status to detect partial failures should instead inspect the   errors  array of the 200 response.   400 Bad Request : returned only for malformed request bodies (invalid JSON, or an array containing entries that are not non-null objects).\n     {\n     \"error\"  :   \"Invalid JSON array format.\"\n   }\n \nor\n     {\n     \"error\"  :   \"Invalid health data format. All entries must be non-null objects.\"\n   }\n   401 Unauthorized :\n     {\n     \"error\"  :   \"Unauthorized: Missing API Key\"\n   }\n \nor\n     {\n     \"error\"  :   \"Unauthorized: Invalid or inactive API Key\"\n   }\n   403 Forbidden :\n     {\n     \"error\"  :   \"Forbidden: API Key does not have health_data_write permission\"\n   }\n  2.   \u002Fapi\u002Fmeasurements\u002Fcheck-in    Path :   \u002Fapi\u002Fmeasurements\u002Fcheck-in   Method :   POST   Description : Upserts (inserts or updates) daily check-in measurements for the authenticated user. Only one check-in entry is allowed per day.   Authentication : JWT Token (sent via   Authorization  header as   Bearer \u003CJWT_TOKEN> ).   Request Body :    Structure :\n     {\n     \"entry_date\"  :   \"\u003CYYYY-MM-DD>\"  ,\n     \"weight\"  :   \u003Cnumber  ,   optional>,\n     \"body_fat\"  :   \u003Cnumber  ,   optional>,\n     \"bmi\"  :   \u003Cnumber  ,   optional>,\n     \"neck\"  :   \u003Cnumber  ,   optional>,\n     \"chest\"  :   \u003Cnumber  ,   optional>,\n     \"waist\"  :   \u003Cnumber  ,   optional>,\n     \"hips\"  :   \u003Cnumber  ,   optional>,\n     \"thigh\"  :   \u003Cnumber  ,   optional>,\n     \"calf\"  :   \u003Cnumber  ,   optional>,\n     \"bicep\"  :   \u003Cnumber  ,   optional>,\n     \"forearm\"  :   \u003Cnumber  ,   optional>,\n     \"steps\"  :   \u003Cnumber  ,   optional>\n   }\n   Fields :\n    entry_date  (required, string): The date of the check-in in   YYYY-MM-DD  format.  Other fields (optional, number): Various measurement values.   Responses :    200 OK :\n     {\n     \"message\"  :   \"Check-in measurements upserted successfully.\"  ,\n     \"data\"  : {   \"id\"  :   \"uuid\"  ,   \"user_id\"  :   \"uuid\"  ,   \"entry_date\"  :   \"2025-08-19\"  ,   \"weight\"  :   70.5   }\n   }\n   400 Bad Request :\n     {\n     \"error\"  :   \"Entry date is required.\"\n   }\n   401 Unauthorized : (If JWT is missing or invalid)   403 Forbidden : (If user is not authorized)   Path :   \u002Fapi\u002Fmeasurements\u002Fcheck-in\u002F:date   Method :   GET   Description : Retrieves daily check-in measurements for a specific date for the authenticated user.   Authentication : JWT Token.   Path Parameters :    date  (required, string): The date of the check-in in   YYYY-MM-DD  format.   Responses :    200 OK :\n     {\n     \"id\"  :   \"uuid\"  ,\n     \"user_id\"  :   \"uuid\"  ,\n     \"entry_date\"  :   \"2025-08-19\"  ,\n     \"weight\"  :   70.5  ,\n     \"body_fat\"  :   15.2\n   }\n \nor   {}  if no entry found for the date.   400 Bad Request :\n     {\n     \"error\"  :   \"Date is required.\"\n   }\n   401 Unauthorized :   403 Forbidden :   Path :   \u002Fapi\u002Fmeasurements\u002Fcheck-in\u002F:entry_date   Method :   PUT   Description : Updates an existing daily check-in measurement entry for a specific date.   Authentication : JWT Token.   Path Parameters :    entry_date  (required, string): The date of the check-in in   YYYY-MM-DD  format.   Request Body :    Structure : Same as POST request for   \u002Fapi\u002Fmeasurements\u002Fcheck-in , but   entry_date  is provided in the path.   Fields : Any of the optional measurement fields (e.g.,   weight ,   body_fat ,   neck , etc.) to update.   Responses :    200 OK :\n     {\n     \"id\"  :   \"uuid\"  ,\n     \"user_id\"  :   \"uuid\"  ,\n     \"entry_date\"  :   \"2025-08-19\"  ,\n     \"weight\"  :   71.0  ,\n     \"body_fat\"  :   15.2\n   }\n   400 Bad Request :\n     {\n     \"error\"  :   \"Entry date is required.\"\n   }\n   401 Unauthorized : (If JWT is missing or invalid)   403 Forbidden : (If user is not authorized)   404 Not Found :\n     {\n     \"error\"  :   \"Check-in measurement not found or not authorized to update.\"\n   }\n   Path :   \u002Fapi\u002Fmeasurements\u002Fcheck-in\u002F:id   Method :   DELETE   Description : Deletes a daily check-in measurement entry.   Authentication : JWT Token.   Path Parameters :    id  (required, string): The ID of the check-in entry to delete.   Responses :    200 OK :\n     {\n     \"message\"  :   \"Check-in measurement deleted successfully.\"\n   }\n   400 Bad Request :\n     {\n     \"error\"  :   \"Check-in Measurement ID is required.\"\n   }\n   401 Unauthorized :   403 Forbidden :   404 Not Found :\n     {\n     \"error\"  :   \"Check-in measurement not found or not authorized to delete.\"\n   }\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":574,"path":575,"dir":506,"title":576,"description":577,"keywords":578,"body":583},"content:8.developer:6.troubleshooting.md","\u002Fdeveloper\u002Ftroubleshooting","Troubleshooting & Debugging","This comprehensive guide provides solutions to common issues and debugging techniques for SparkyFitness developers.",[579,580,581,582,15],"Common Issues and Solutions","Debugging Techniques","Development Environment Issues","Advanced Debugging","  Troubleshooting & Debugging  This comprehensive guide provides solutions to common issues and debugging techniques for SparkyFitness developers.  Common Issues and Solutions  Port Conflicts  If you encounter errors indicating that a port is already in use, another application is likely using one of the ports required by SparkyFitness (e.g., 8080 for frontend, 3010 for backend, 5432 for PostgreSQL).   Solution:    Identify the conflicting process :\n   On Linux\u002FmacOS:   lsof -i :\u003Cport_number>  (e.g.,   lsof -i :8080 )  On Windows:   netstat -ano | findstr :\u003Cport_number>  followed by   taskkill \u002FPID \u003CPID> \u002FF   Stop the conflicting service  or   change the port  in your   .env  file.  Database Connection Issues  Problems connecting to the PostgreSQL database can arise from incorrect credentials, the database not running, or network issues.   Solution:    Check database logs :\n     .\u002Fdocker\u002Fdocker-helper.sh   dev   logs   sparkyfitness-db\n   Verify   .env  settings : Ensure   SPARKY_FITNESS_DB_NAME ,   SPARKY_FITNESS_DB_USER , and   SPARKY_FITNESS_DB_PASSWORD  are correct.   Reset database (Development only!) : If data integrity is not critical, you can perform a destructive reset.\n     .\u002Fdocker\u002Fdocker-helper.sh   dev   down\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   clean\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n  Build Failures  Issues during the build process (e.g.,   npm install  or Docker image builds) can be caused by corrupted caches or dependency problems.   Solution:    Clean rebuild :\n     .\u002Fdocker\u002Fdocker-helper.sh   dev   build   --no-cache\n   Full reset :\n     .\u002Fdocker\u002Fdocker-helper.sh   dev   clean\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up\n  Permission Issues (Linux\u002FWSL)  On Linux or Windows Subsystem for Linux (WSL), you might encounter permission errors related to Docker volumes, especially for the PostgreSQL data directory.   Solution:    Fix volume permissions :\n     sudo   chown   -R   $USER  :  $USER   .\u002Fpostgresql\n  \"Invalid key length\" error  This error typically indicates that your   SPARKY_FITNESS_API_ENCRYPTION_KEY  in your   .env  file is not correctly configured. Ensure it is a 64-character hexadecimal string.   Solution: \nGenerate a valid key using:     openssl   rand   -hex   32\n   # or\n   node   -e   \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n  Rate Limiting Issues  SparkyFitness implements rate limiting at the Nginx reverse proxy layer to prevent brute-force attacks and DoS attempts.   Common Rate Limiting Errors:    429 Too Many Requests  on login\u002Fsignup endpoints  Connection refused during high traffic   Solution:    Check rate limit configuration  in   docker\u002Fnginx.conf.template :\n     limit_req_zone $binary_remote_addr zone=login_signup_zone:10m rate=5r\u002Fs;\n   Temporary bypass for development :\n     # Edit nginx.conf.template and increase rate limits\n   # Then restart containers\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   restart\n   Production tuning : Adjust rate limits based on actual usage patterns  Authentication & JWT Issues   Common symptoms:    401 Unauthorized  errors  Token expired messages  Login session not persisting   Solution:    Check JWT secret configuration :\n     # Ensure JWT_SECRET is properly set in .env\n   grep   JWT_SECRET   .env\n   Clear browser storage :\n     \u002F\u002F In browser console\n   localStorage.  clear  ();\n   sessionStorage.  clear  ();\n   Verify token expiration settings  in backend configuration  Debugging Techniques  Application Logs   View all service logs:     .\u002Fdocker\u002Fdocker-helper.sh   dev   logs\n   Follow specific service logs:     .\u002Fdocker\u002Fdocker-helper.sh   dev   logs   -f   sparkyfitness-frontend\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   logs   -f   sparkyfitness-server\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   logs   -f   sparkyfitness-db\n   Backend debugging logs:     # Enable debug logging in .env\n   LOG_LEVEL  =  debug\n   \n   # View structured logs\n   docker   exec   -it   sparkyfitness-server-1   tail   -f   \u002Fapp\u002Flogs\u002Fapp.log\n  Container Inspection   List running containers:     .\u002Fdocker\u002Fdocker-helper.sh   dev   ps\n   Execute commands in containers:     # Frontend container\n   docker   exec   -it   sparkyfitness-frontend-1   sh\n   \n   # Backend container\n   docker   exec   -it   sparkyfitness-server-1   sh\n   \n   # Database container\n   docker   exec   -it   sparkyfitness-db-1   psql   -U   sparky   -d   sparkyfitness_db\n   Inspect container resources:     # Check resource usage\n   docker   stats\n   \n   # Inspect container configuration\n   docker   inspect   sparkyfitness-server-1\n  Database Debugging   Connect to PostgreSQL:     docker   exec   -it   sparkyfitness-db-1   psql   -U   sparky   -d   sparkyfitness_db\n   Common database queries:     -- Check table structure\n   \\dt\n   \n   -- View recent logs\n   SELECT * FROM logs ORDER BY created_at DESC LIMIT 10;\n   \n   -- Check user data\n   SELECT id, email, created_at FROM users LIMIT 5;\n   \n   -- Monitor active connections\n   SELECT * FROM pg_stat_activity;\n   Database migration issues:     # Check migration status\n   docker   exec   -it   sparkyfitness-server-1   npm   run   migrate:status\n   \n   # Force migration reset (DANGEROUS)\n   docker   exec   -it   sparkyfitness-server-1   npm   run   migrate:reset\n  Network Debugging   Check container networking:     # List Docker networks\n   docker   network   ls\n   \n   # Inspect network configuration\n   docker   network   inspect   \u003C  network_nam  e  >\n   \n   # Test connectivity between containers\n   docker   exec   -it   sparkyfitness-frontend-1   ping   sparkyfitness-server\n   API endpoint testing:     # Test backend health endpoint\n   curl   http:\u002F\u002Flocalhost:3010\u002Fapi\u002Fhealth\n   \n   # Test with authentication\n   curl   -H   \"Authorization: Bearer \u003Ctoken>\"   http:\u002F\u002Flocalhost:3010\u002Fapi\u002Fusers\u002Fprofile\n  Performance Debugging   Monitor resource usage:     # Real-time resource monitoring\n   docker   stats   --format   \"table {{.Container}}\\t{{.CPUPerc}}\\t{{.MemUsage}}\"\n   \n   # System resource usage\n   htop    # or top on basic systems\n   Database performance:     -- Check slow queries\n   SELECT query, calls, total_time, mean_time \n   FROM pg_stat_statements \n   ORDER BY mean_time DESC \n   LIMIT 10;\n   \n   -- Check locks\n   SELECT * FROM pg_locks WHERE NOT GRANTED;\n  Development Environment Issues  Hot Reload Not Working   Frontend hot reload issues:     # Check Vite configuration\n   cat   vite.config.ts\n   \n   # Restart with clean cache\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   down\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   up   --build\n  Environment Variable Issues   Debug environment variables:     # Check .env file is loaded\n   docker   exec   -it   sparkyfitness-server-1   env   |   grep   SPARKY\n   \n   # Verify frontend environment variables\n   docker   exec   -it   sparkyfitness-frontend-1   env   |   grep   VITE\n  TypeScript Compilation Issues   Common TypeScript errors:     # Check TypeScript configuration\n   cat   tsconfig.json\n   \n   # Run type checking manually\n   docker   exec   -it   sparkyfitness-frontend-1   npm   run   type-check\n   \n   # Clear TypeScript cache\n   rm   -rf   node_modules\u002F.cache\n  Advanced Debugging  Memory Leaks   Identify memory leaks:     # Monitor memory usage over time\n   watch   -n   1   'docker stats --no-stream'\n   \n   # Use Node.js heap dumps\n   docker   exec   -it   sparkyfitness-server-1   node   --inspect=0.0.0.0:9229   server.js\n  Performance Profiling   Backend profiling:     \u002F\u002F Add to backend code for profiling\n   const   profiler   =   require  (  'v8-profiler-next'  );\n   \n   \u002F\u002F Start profiling\n   profiler.  startProfiling  (  'API_PROFILE'  );\n   \n   \u002F\u002F End profiling and save\n   const   profile   =   profiler.  stopProfiling  (  'API_PROFILE'  );\n   profile.  export  ().  pipe  (fs.  createWriteStream  (  'profile.cpuprofile'  ));\n  Security Debugging   Check for security vulnerabilities:     # NPM audit\n   npm   audit\n   \n   # Docker security scanning\n   docker   scan   sparkyfitness-server:latest\n  Getting Help  When troubleshooting fails, reach out to the community:    Discord Community :   https:\u002F\u002Fdiscord.gg\u002FvcnMT5cPEA   GitHub Discussions : Post detailed questions with logs   Documentation : Search this comprehensive documentation site   Issue Templates : Use provided GitHub issue templates for bug reports  Creating Effective Bug Reports  Include the following information:    Environment details : OS, Docker version, Node.js version   Steps to reproduce : Clear, numbered steps   Expected vs. actual behavior : What should happen vs. what happens   Logs : Relevant log excerpts (use code blocks)   Configuration : Relevant parts of .env or config files (sanitized)   Screenshots : For UI issues   Log collection command:     # Collect all relevant logs\n   .\u002Fdocker\u002Fdocker-helper.sh   dev   logs   >   debug-logs-  $(  date   +%Y%m%d-%H%M%S  )  .txt\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":585,"path":586,"dir":506,"title":587,"description":7,"keywords":588,"body":594},"content:8.developer:7.testing.md","\u002Fdeveloper\u002Ftesting","Testing",[8,589,590,591,592,593],"Running Tests Locally","CI Workflow","Test File Locations","Writing Frontend Tests","Coverage Reports","  Testing  Overview  SparkyFitness uses   Jest  for JavaScript\u002FTypeScript testing across the frontend, backend, and mobile projects, and   pytest  for the Garmin microservice.  Running Tests Locally  Each component has its own test scripts:     # Frontend (Vite + React)\n   cd   SparkyFitnessFrontend\n   pnpm   test            # Run tests in watch mode\n   pnpm   test:ci         # Run tests once with coverage (CI mode)\n   \n   # Backend (Node.js + Express)\n   cd   SparkyFitnessServer\n   pnpm   test            # Run tests in watch mode\n   pnpm   test:ci         # Run tests once with coverage (CI mode)\n   \n   # Mobile (React Native + Expo)\n   cd   SparkyFitnessMobile\n   npm   run   test:run     # Run tests once\n   npm   run   test:ci      # Run tests once with coverage (CI mode)\n   \n   # Garmin Microservice (Python)\n   cd   SparkyFitnessGarmin\n   pytest   --cov=.   --cov-report=html\n  CI Workflow  The CI pipeline (  .github\u002Fworkflows\u002Fci-tests.yml ) runs on pull requests and pushes to   main . It uses   path-based change detection  via   dorny\u002Fpaths-filter  so that only the affected component's tests run.     Component  Trigger Path  Package Manager  Test Command    Frontend   SparkyFitnessFrontend\u002F**  pnpm   pnpm run test:ci   Mobile   SparkyFitnessMobile\u002F**  npm   npm run test:ci   Server   SparkyFitnessServer\u002F**  pnpm   pnpm run test:ci   Garmin   SparkyFitnessGarmin\u002F**  pip   pytest  Test File Locations   SparkyFitnessFrontend\u002F\n  src\u002Ftests\u002F\n    setupTests.ts              # Global test setup (jest-dom, polyfills)\n    components\u002F                # Component tests\n      MealBuilder.test.tsx\n      MealManagement.test.tsx\n      MealPlanCalendar.test.tsx\n\nSparkyFitnessServer\u002F\n  __tests__\u002F                   # Backend unit and integration tests\n\nSparkyFitnessMobile\u002F\n  __tests__\u002F                   # Mobile app tests\n  Writing Frontend Tests  Mock Pattern  All frontend component tests follow a consistent mocking strategy:     \u002F\u002F 1. Mock i18n — return fallback string or key\n   jest.  mock  (  'react-i18next'  , ()   =>   ({\n     useTranslation  : ()   =>   ({\n       t  : (  key  :   string  ,   defaultValueOrOpts  ?:   string   |   Record  \u003C  string  ,   unknown  >)   =>   {\n         if   (  typeof   defaultValueOrOpts   ===   'string'  )   return   defaultValueOrOpts;\n         if   (defaultValueOrOpts   &&   typeof   defaultValueOrOpts   ===   'object'   &&   'defaultValue'   in   defaultValueOrOpts) {\n           return   defaultValueOrOpts.defaultValue   as   string  ;\n         }\n         return   key;\n       },\n     }),\n   }));\n   \n   \u002F\u002F 2. Mock contexts\n   jest.  mock  (  '@\u002Fcontexts\u002FActiveUserContext'  , ()   =>   ({\n     useActiveUser  : ()   =>   ({ activeUserId:   'test-user-id'   }),\n   }));\n   jest.  mock  (  '@\u002Fcontexts\u002FPreferencesContext'  , ()   =>   ({\n     usePreferences  : ()   =>   ({ loggingLevel:   'debug'  , foodDisplayLimit:   100   }),\n   }));\n   \n   \u002F\u002F 3. Mock toast\n   jest.  mock  (  '@\u002Fhooks\u002Fuse-toast'  , ()   =>   ({ toast: jest.  fn  () }));\n   \n   \u002F\u002F 4. Mock logging\n   jest.  mock  (  '@\u002Futils\u002Flogging'  , ()   =>   ({\n     debug: jest.  fn  (), info: jest.  fn  (), warn: jest.  fn  (), error: jest.  fn  (),\n   }));\n   \n   \u002F\u002F 5. Mock services with trackable fns\n   const   mockGetMeals   =   jest.  fn  ();\n   jest.  mock  (  '@\u002Fservices\u002FmealService'  , ()   =>   ({\n     getMeals  : (  ...  args  :   unknown  [])   =>   mockGetMeals  (  ...  args),\n   }));\n  Conventions   Test files live alongside their component domain in   src\u002Ftests\u002Fcomponents\u002F  Use   @testing-library\u002Freact  for rendering and assertions  Mock complex child components as simple stubs to isolate the component under test  Use   waitFor  for async operations (API calls, state updates)  Use   initialFoods  or similar props to inject data without needing interactive sub-components  Coverage Reports  Coverage reports are generated in the   coverage\u002F  directory of each component when running   test:ci . In CI, they are uploaded as build artifacts and retained for 7 days.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":596,"path":597,"dir":598,"title":599,"description":7,"keywords":600,"body":606},"content:8.developer:8.advanced:1.ai-command-patterns.md","\u002Fdeveloper\u002Fadvanced\u002Fai-command-patterns","advanced","AI Command Patterns & Context Guide",[601,602,603,604,605,533],"Common User Interaction Patterns","Database Context for AI Operations","AI Response Templates","Error Handling Patterns","Context Optimization","  AI Command Patterns & Context Guide  Common User Interaction Patterns  Food Logging Commands   User Intent : Log food intake\n  Common Phrases :   \"I ate 2 slices of pizza\"  \"Add 1 cup of rice to lunch\"  \"Log breakfast: 2 eggs and toast\"  \"I had dominos chicken pizza\"   Expected AI Response :   Extract food items with quantities  Determine meal type (breakfast\u002Flunch\u002Fdinner\u002Fsnacks)  Get nutrition data from database or AI knowledge  Present confirmation dialog with nutrition summary  Add to food diary upon confirmation   Context Date Extraction :   \"today\" → current date  \"yesterday\" → previous date  \"last Sunday\" → specific past date  No date mentioned → assume today  Measurement Logging Commands   User Intent : Record body measurements\n  Common Phrases :   \"My weight is 70kg today\"  \"Waist measurement: 32 inches\"  \"I weighed 154 pounds this morning\"   Expected AI Response :   Extract measurement type and value  Convert units if necessary  Save to appropriate measurement table  Provide confirmation with trend information  Goal Setting Commands   User Intent : Update nutrition or fitness goals\n  Common Phrases :   \"Set my calorie goal to 1800\"  \"I want to consume 120g protein daily\"  \"Change my water goal to 10 glasses\"   Expected AI Response :   Identify goal type and target value  Update user_goals table  Apply to future dates using goal timeline function  Confirm changes with previous vs new goals  Progress Inquiry Commands   User Intent : Get progress information\n  Common Phrases :   \"How am I doing today?\"  \"Show my calorie progress\"  \"What's my weight trend this week?\"   Expected AI Response :   Query relevant data based on request type  Calculate progress percentages  Provide trend analysis  Suggest improvements if applicable  Database Context for AI Operations  Food Operations   Tables : foods, food_entries, food_variants\n  Key Operations :   Search foods by name\u002Fbrand  Create custom foods when not found  Calculate nutrition based on quantity  Handle different serving units   Nutrition Calculation :   final_nutrition = (food_nutrition \u002F food_serving_size) * user_quantity\n  Measurement Operations   Tables : check_in_measurements, custom_measurements, custom_categories\n  Key Operations :   Record standard measurements (weight, waist, etc.)  Handle custom measurement categories  Convert between units (kg\u002Flbs, cm\u002Finches)  Track trends over time  Goal Operations   Tables : user_goals\n  Key Operations :   Retrieve current goals for date  Update goals with timeline management  Handle historical vs future goal changes  Calculate progress percentages  Family Access Context   Tables : family_access\n  Permission Checks :   Always check   can_access_user_data()  before operations  Respect permission levels (read vs write)  Handle permission inheritance rules  AI Response Templates  Food Logging Success   \"Great! I've analyzed your [meal_type] and found:\n\n**[quantity] [food_name]:**\n• [calories] calories\n• [protein]g protein, [carbs]g carbs, [fat]g fat\n• [fiber]g fiber, [sodium]mg sodium\n\nWould you like me to add this to your [meal_type] for [date]?\"\n  Progress Summary   \"Here's your progress for today:\n\n**Calories:** [consumed]\u002F[goal] ([percentage]%)\n**Protein:** [consumed]g\u002F[goal]g ([percentage]%)\n**Carbs:** [consumed]g\u002F[goal]g ([percentage]%)\n**Fat:** [consumed]g\u002F[goal]g ([percentage]%)\n\n[motivational message based on progress]\"\n  Measurement Confirmation   \"Recorded your [measurement_type]: [value] [unit]\n\n[Trend information if available]\n[Encouragement or suggestions]\"\n  Error Handling Patterns  Food Not Found   Search for similar foods in database  Offer to create custom food  Ask for more specific information (brand, preparation)  Provide nutrition estimation if possible  Invalid Measurements   Check for reasonable ranges  Confirm unusual values with user  Suggest unit conversion if needed  Provide context about normal ranges  Permission Denied   Explain family access limitations  Suggest contacting data owner  Offer alternative accessible features  Maintain privacy without revealing restricted data  Context Optimization  Essential Context (Always Load)   User's current goals  Today's food entries  Active family access permissions  Basic app navigation structure  On-Demand Context (Load Based on Query)    Food queries : Food database, nutrition facts, meal history   Measurement queries : Historical measurements, trends, goals   Report queries : Analytics data, progress calculations   Settings queries : User preferences, AI configuration  Performance Considerations   Cache frequently accessed nutrition data  Limit historical data queries to reasonable ranges  Use database functions for complex calculations  Batch related operations when possible  Integration Points  Direct Database Operations   Food entries creation\u002Fmodification  Measurement logging  Goal updates  Custom food creation  UI Refresh Triggers   Dispatch 'foodDiaryRefresh' event after food logging  Update measurement charts after new entries  Refresh progress bars after goal changes  Update family access status after permission changes  Notification Patterns   Success toasts for completed operations  Error alerts for failed operations  Confirmation dialogs for destructive actions  Progress notifications for long operations",{"id":608,"path":609,"dir":598,"title":610,"description":611,"keywords":612,"body":616},"content:8.developer:8.advanced:2.chatbot-workflow.md","\u002Fdeveloper\u002Fadvanced\u002Fchatbot-workflow","Sparky Chatbot Workflow (Refined)","This document outlines the refined workflow for how the Sparky chatbot processes user messages, identifies intent, extracts data, interacts with the database, and provides responses, incorporating improvements for robustness, multi-item handling, context, and error management.",[613,614,615],"Overall Process","Detailed Workflow by Intent","Chatbot Tool Profiles & Dynamic Category Classification","  Sparky Chatbot Workflow (Refined)  This document outlines the refined workflow for how the Sparky chatbot processes user messages, identifies intent, extracts data, interacts with the database, and provides responses, incorporating improvements for robustness, multi-item handling, context, and error management.  Overall Process    User Input:  The user sends a message to the chatbot in natural language, potentially including text and\u002For an image.   AI Intent Recognition & Data Extraction:  The chatbot sends the user's message to the AI model along with recent conversation history (e.g., the last 5 messages) and a detailed system prompt. The system prompt will instruct the AI to:\n    Prioritize the current user message  when determining intent and extracting data.  Use the conversation history primarily for   context  (e.g., understanding follow-ups like \"add another one\", clarifying ambiguous terms, or referencing previous items).   Avoid re-processing requests  that appear to have been completed in the recent history.   Application Logic (SparkyNutritionCoach):  Based on the   intent  provided by the AI, the application logic routes the request to the appropriate handler function.   Database Interaction:  The handler function interacts with the Supabase database to log data (food entries, exercise entries, measurements) or retrieve information.   Response Generation:  Based on the success or failure of the database operation, or if the intent was conversational, a user-friendly response message is generated.   User Output:  The generated response message is displayed to the user in the chat interface.  Detailed Workflow by Intent  The AI is designed to identify one of the following intents:    Log Food (  log_food )    AI Data:    food_name  (string),   quantity  (number, inferred or default 1),   unit  (string, inferred or default \"g\"),   meal_type  (string, inferred or default \"snack\"),   date  (string, ISO format, inferred or null).   Application Logic:    Validation:  Check if   food_name  is present and is a string.  Search for the extracted   food_name  in the   foods  table (user's custom first, then public).   If Food Found:  Log a new entry in the   food_entries  table using the found   food_id , extracted   quantity ,   unit ,   meal_type , and the extracted   date  (defaulting to today if null). Validate the date to prevent logging future entries.   If Food Not Found:  Send a secondary request to the AI specifically asking it to generate 3 realistic food options similar to the requested   food_name , including estimated nutritional details and serving information. Include context like the original input and potentially user preferences (e.g., dietary restrictions) in the prompt.   AI Options Response:  AI returns JSON with   food_options  array.   Application Logic (Options):  Display the generated food options to the user in a numbered list. Guide the user to reply with a number to select an option OR provide manual nutrition details (e.g., \"If none fit, reply with 'manual: 100 cal, 5g protein...'\"). Store the options data (including original request details) in the chat message's metadata for handling the user's subsequent selection or manual entry.   Log Exercise (  log_exercise )    AI Data:    exercise_name  (string),   duration_minutes  (number, inferred or null),   distance  (number, inferred or null),   distance_unit  (string, inferred or null),   date  (string, ISO format, inferred or null).   Application Logic:    Validation:  Check if   exercise_name  is present and is a string.  Search the   exercises  table for the extracted   exercise_name .   If Exercise Found:  Log a new entry in the   exercise_entries  table with extracted details (  exercise_id ,   duration_minutes  - using AI value or default from DB,   calories_burned  - calculated,   distance ,   distance_unit , extracted   date ). Validate the date.   If Exercise Not Found:  Send a secondary request to the AI specifically asking it to generate 3 exercise options similar to the requested exercise, including estimated   calories_per_hour .   AI Options Response:  AI returns JSON with   exercise_options  array.   Application Logic (Options):  Display the generated exercise options to the user in a numbered list. Guide the user on how to provide manual details if needed. Store options data in metadata.   Log Body Measurements (  log_measurement  - standard types)    AI Data:    measurements  (array of objects), each with   type  (\"weight\", \"neck\", \"waist\", \"hips\", \"steps\"),   value  (number),   unit  (string, inferred or null, except for steps which defaults to \"steps\"),   date  (string, ISO format, inferred or null).   Application Logic:    Validation:  Check if   measurements  is an array and each object has   type  and   value .  For each measurement in the   measurements  array:\n   If   type  is standard: Upsert into the   check_in_measurements  table for the user and the extracted   date  (defaulting to today). Validate the date.  Generate a confirmation message listing the measurements that were successfully logged.   Log Custom Measurements (  log_measurement  - custom type)    AI Data:    measurements  (array of objects), each with   type  (\"custom\"),   name  (string),   value  (number),   unit  (string, inferred or null),   date  (string, ISO format, inferred or null).   Application Logic:    Validation:  Check if   measurements  is an array and each custom object has   type ,   name , and   value .  For each custom measurement in the   measurements  array:\n   Search for a category with the extracted   name  in the   custom_categories  for the user.   If Category Found:  Use the found   category_id .   If Category Not Found:  Create a new entry in   custom_categories  with the extracted   name , defaulting   frequency  to 'daily' and   measurement_type  to 'numeric'. Use the new   category_id .  Insert a new entry in the   custom_measurements  with user ID,   category_id , extracted   value , and extracted   date \u002Ftimestamp (defaulting to now). Validate the date.  Generate a confirmation message listing the custom measurements that were successfully logged.   Log Water Intake (  log_water )    AI Data:    glasses_consumed  (number, inferred or default 1),   date  (string, ISO format, inferred or null).   Application Logic:    Validation:  Check if   glasses_consumed  is a number or null.  Get the current water intake for the user for the extracted   date  (defaulting to today).  Calculate the new total by adding the extracted   glasses_consumed  (or default 1) to the current total.  Upsert the new total into the   water_intake  table for the user and the extracted   date . Validate the date.  Generate a confirmation message showing the added glasses and the new total for the day.   Ask Question (  ask_question ) \u002F General Chat (  chat )    AI Data:  Empty   data  object,   response  (string containing the AI's conversational reply).   Application Logic:   Display the   response  provided directly by the AI.  3. Post-Logging Actions & User Interaction    After successful logging (any type):   Trigger a refresh of relevant data displays (e.g., food diary, measurements charts).   Refined Progress Updates:  Batch progress updates for multi-item inputs (display one summary after all items are processed). For single item logs, update immediately. The update message should include a summary of today's relevant data (nutrition, exercise, measurements) and a coaching tip. Tailor the summary slightly based on the type of item just logged.   Handling Option Selection:   If the user's next message is a number and the previous bot message contained options metadata:\n    Validation:  Check if the number is a valid index for the options stored in the metadata and if the metadata is still valid\u002Fpresent.   If Valid Selection:  Process the selected option using the stored data (e.g., call   addFoodOption  or   addExerciseOption ).   If Invalid Selection:  Return a   CoachResponse  with   action: 'none'  and a message guiding the user (e.g., \"Please select a valid option number or tell me what you'd like to do.\").  If the user's next message is not a number but matches the format for manual data entry (e.g., \"manual: ...\"), process the manual entry.  If the user's next message is unrelated, process it as a new input using the standard AI workflow.  Relevant Database Tables  Here are the schemas for the relevant database tables for context:     -- check_in_measurements table\n   create table public.check_in_measurements (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     entry_date date not null default CURRENT_DATE,\n     weight numeric null,\n     neck numeric null,\n     waist numeric null,\n     hips numeric null,\n     steps integer null,\n     created_at timestamp with time zone not null default now(),\n     updated_at timestamp with time zone not null default now(),\n     constraint check_in_measurements_pkey primary key (id),\n     constraint check_in_measurements_user_date_unique unique (user_id, entry_date)\n   ) TABLESPACE pg_default;\n     -- custom_categories table\n   create table public.custom_categories (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     name character varying(50) not null,\n     measurement_type character varying(50) not null, -- e.g., 'numeric', 'text'\n     frequency text not null, -- e.g., 'Daily', 'Weekly', 'Monthly', 'All'\n     created_at timestamp with time zone not null default now(),\n     updated_at timestamp with time zone not null default now(),\n     constraint custom_categories_pkey primary key (id),\n     constraint custom_categories_user_id_fkey foreign KEY (user_id) references auth.users (id),\n     constraint custom_categories_frequency_check check (\n       (\n         frequency = any (array['All'::text, 'Daily'::text, 'Hourly'::text, 'Weekly'::text, 'Monthly'::text]) -- Added Weekly, Monthly based on common use cases\n       )\n     )\n   ) TABLESPACE pg_default;\n     -- custom_measurements table\n   create table public.custom_measurements (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     category_id uuid not null,\n     value numeric not null,\n     entry_date date not null,\n     entry_hour integer null, -- For hourly frequency\n     entry_timestamp timestamp with time zone not null default now(),\n     created_at timestamp with time zone not null default now(),\n     constraint custom_measurements_pkey primary key (id),\n     constraint custom_measurements_unique_entry unique (user_id, category_id, entry_date, entry_hour), -- Ensure uniqueness based on frequency\n     constraint custom_measurements_category_id_fkey foreign KEY (category_id) references custom_categories (id) on delete CASCADE,\n     constraint custom_measurements_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- food_entries table\n   create table public.food_entries (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     food_id uuid not null,\n     meal_type character varying(50) not null, -- e.g., 'breakfast', 'lunch', 'dinner', 'snack'\n     quantity numeric not null,\n     unit character varying(50) null, -- e.g., 'g', 'oz', 'piece'\n     entry_date date not null,\n     created_at timestamp with time zone not null default now(),\n     variant_id uuid null, -- Link to food_variants if applicable\n     constraint food_entries_pkey primary key (id),\n     constraint food_entries_food_id_fkey foreign KEY (food_id) references foods (id),\n     constraint food_entries_user_id_fkey foreign KEY (user_id) references auth.users (id),\n     constraint food_entries_variant_id_fkey foreign KEY (variant_id) references food_variants (id)\n   ) TABLESPACE pg_default;\n     -- foods table\n   create table public.foods (\n     id uuid not null default gen_random_uuid (),\n     name character varying(255) not null,\n     calories numeric null,\n     protein numeric null,\n     carbs numeric null,\n     fat numeric null,\n     serving_size numeric null, -- Default serving size in grams or standard unit\n     serving_unit character varying(50) null, -- e.g., 'g', 'ml', 'piece'\n     is_custom boolean null default false, -- True if created by a user\n     user_id uuid null, -- Creator user_id if is_custom is true\n     created_at timestamp with time zone null default now(),\n     updated_at timestamp with time zone null default now(),\n     barcode character varying(255) null, -- For scanning\n     openfoodfacts_id character varying(255) null, -- Link to external databases\n     shared_with_public boolean null default false,\n     saturated_fat numeric null, -- Added for comprehensive nutrition\n     polyunsaturated_fat numeric null,\n     monounsaturated_unsaturated numeric null,\n     trans_fat numeric null,\n     cholesterol numeric null,\n     sodium numeric null,\n     potassium numeric null,\n     dietary_fiber numeric null,\n     sugars numeric null,\n     vitamin_a numeric null,\n     vitamin_c numeric null,\n     calcium numeric null,\n     iron numeric null,\n     constraint foods_pkey primary key (id),\n     constraint foods_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- exercise_entries table\n   create table public.exercise_entries (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     exercise_id uuid not null,\n     duration_minutes integer not null,\n     calories_burned integer not null,\n     entry_date date null,\n     notes text null,\n     created_at timestamp with time zone null default now(),\n     constraint exercise_entries_pkey primary key (id),\n     constraint exercise_entries_exercise_id_fkey foreign KEY (exercise_id) references exercises (id),\n     constraint exercise_entries_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- exercises table\n   create table public.exercises (\n     id uuid not null default gen_random_uuid (),\n     name character varying(255) not null,\n     category character varying(50) null, -- e.g., 'cardio', 'strength'\n     calories_per_hour integer null, -- Estimated calories burned per hour\n     description text null,\n     is_custom boolean null default false,\n     user_id uuid null, -- Creator user_id if is_custom is true\n     created_at timestamp with time zone null default now(),\n     updated_at timestamp with time zone null default now(),\n     shared_with_public boolean null default false,\n     constraint exercises_pkey primary key (id),\n     constraint exercises_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- water_intake table\n   create table public.water_intake (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     entry_date date not null,\n     glasses_consumed integer not null,\n     created_at timestamp with time zone not null default now(),\n     updated_at timestamp with time zone not null default now(),\n     constraint water_intake_pkey primary key (id),\n     constraint water_intake_user_date_unique unique (user_id, entry_date),\n     constraint water_intake_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- ai_service_settings table\n   create table public.ai_service_settings (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     service_name character varying(255) not null, -- e.g., 'OpenAI', 'Google Gemini'\n     service_type character varying(50) not null, -- e.g., 'openai', 'google'\n     api_key text not null,\n     is_active boolean not null default true,\n     model_name character varying(255) null, -- Specific model used\n     system_prompt text null, -- Custom system prompt for the AI\n     custom_url text null, -- For custom or compatible services\n     created_at timestamp with time zone not null default now(),\n     updated_at timestamp with time zone not null default now(),\n     constraint ai_service_settings_pkey primary key (id),\n     constraint ai_service_settings_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- sparky_chat_history table\n   create table public.sparky_chat_history (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     session_id uuid not null default gen_random_uuid (), -- To group messages by session\n     message_type character varying(50) not null, -- 'user' or 'assistant'\n     content text not null, -- The message content\n     created_at timestamp with time zone not null default now(),\n     metadata jsonb null, -- To store additional data like food options, image URLs, etc.\n     -- Deprecated fields, kept for history but not actively used in new workflow:\n     message text null,\n     response text null,\n     image_url text null,\n     constraint sparky_chat_history_pkey primary key (id),\n     constraint sparky_chat_history_user_id_fkey foreign KEY (user_id) references auth.users (id)\n   ) TABLESPACE pg_default;\n     -- user_preferences table\n   create table public.user_preferences (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     date_format character varying(50) not null default 'yyyy-MM-dd',\n     default_weight_unit character varying(50) not null default 'kg',\n     default_measurement_unit character varying(50) not null default 'cm',\n     auto_clear_history text null default 'never', -- 'never', 'session', '7days', '30days'\n     system_prompt text null, -- User-specific override for AI system prompt\n     created_at timestamp with time zone not null default now(),\n     updated_at timestamp with time zone not null default now(),\n     constraint user_preferences_pkey primary key (id),\n     constraint user_preferences_user_id_fkey foreign KEY (user_id) references auth.users (id) on delete CASCADE,\n     constraint user_preferences_auto_clear_history_check check (\n       (\n         auto_clear_history = any (array['never'::text, 'session'::text, '7days'::text, '30days'::text])\n       )\n     )\n   ) TABLESPACE pg_default;\n     -- user_goals table\n   create table public.user_goals (\n     id uuid not null default gen_random_uuid (),\n     user_id uuid not null,\n     goal_date date null, -- Null for default goal\n     calories numeric null,\n     protein numeric null,\n     carbs numeric null,\n     fat numeric null,\n     water_goal integer null,\n     created_at timestamp with time zone null default now(),\n     updated_at timestamp with time zone null default now(),\n     saturated_fat numeric null, -- Added for comprehensive nutrition goals\n     polyunsaturated_fat numeric null,\n     monounsaturated_fat numeric null,\n     trans_fat numeric null,\n     cholesterol numeric null,\n     sodium numeric null,\n     potassium numeric null,\n     dietary_fiber numeric null,\n     sugars numeric null,\n     vitamin_a numeric null,\n     vitamin_c numeric null,\n     calcium numeric null,\n     iron numeric null,\n     constraint user_goals_pkey primary key (id),\n     constraint user_goals_user_id_fkey foreign KEY (user_id) references auth.users (id),\n     constraint user_goals_unique_user_date unique (user_id, goal_date) -- Ensure only one goal per user per date\n   ) TABLESPACE pg_default;\n  Chatbot Tool Profiles & Dynamic Category Classification  To support smaller local models (e.g. Ollama running Gemma or Llama models) that have limited context windows and struggle with high tool counts, the chatbot does not send every available tool to the provider on every turn. Instead, it utilizes   Dynamic Tool Selection ,   Auto Intent Classification , and a   self-healing escalation tool  that lets the model recover from a classification miss mid-conversation.  1. Tool Profiles: Full vs. Core  The system defines two main tool configuration profiles matching the user's active AI Service Settings:     full  Profile (35 domain tools):  Contains all developer, coaching, and granular utility tools.    core  Profile (19 domain tools):  Contains only the essential logging and tracking tools for food, exercise, checkins, and goals.  2. Two Modes: Manual Selection vs. Auto Classification  How the category set is chosen determines whether the tool set is a   strict ceiling  or a   self-healing floor :    Manual selection (strict ceiling):  If the user explicitly picks categories in the chat tool selector, the server composes exactly that narrow set via   buildChatbotTools  (the last tool carries the Anthropic cache breakpoint) and offers   no  escalation tool. The system prompt lists the dormant domains and instructs the model to tell the user to enable that category in the tool selector — it must never attempt or fake a capability it wasn't given. This respects the user's deliberate limit (and their token budget on small models).   Auto classification (self-healing floor):  If the user does not pick categories, the server classifies intent (pipeline below) and serves tools from a single in-memory full surface per   (userId, tz)  (  buildChatToolSurface  in   ai\u002Ftools\u002Findex.ts ) that always composes every domain plus one extra tool,   sparky_enable_tools . The classified categories narrow what is actually   sent  to the provider that turn via the AI SDK's   activeTools , while the always-present escalation tool lets a capable model widen the set mid-turn (section 4). The Anthropic cache breakpoint sits on   sparky_enable_tools , which is always in   activeTools , so caching stays stable.  The MCP tool surface (  buildChatbotTools ) is unaffected by any of this — it always publishes the full or core set directly and has no escalation tool.    Note on small local models:  the escalation tool (section 4) only helps if the model is capable enough to notice a missing tool and call   sparky_enable_tools  for it. Very small models (e.g. a 2B Gemma\u002FLlama) often will not — they may just hallucinate success. For those, getting the classification right up front (or a well-chosen manual selection) matters far more than escalation.  3. Auto Intent Classification Pipeline  When the user has not manually selected categories, the backend dynamically calculates the minimum required tool categories for each message via an automatic classification pipeline:     graph TD\n       A[Incoming User Message] --> AA{Image attached?}\n       AA -- Yes --> AB[Add vision + food]\n       AA -- No --> B[Phase 1: Keyword Regex Matching]\n       AB --> B\n       B -- Match Found --> C[Load Matched Category Tools, e.g. food + reports]\n       B -- No Match --> D[Phase 2: LLM Intent Classifier]\n       D -- Success --> E[Load Classified Category Tools]\n       D -- 'none' --> EN[Load coaching only]\n       D -- Error --> F[Phase 3: Profile Default]\n       F --> G[\"Load full or core default set\"]\n       C --> H{Model calls sparky_enable_tools mid-turn?}\n       E --> H\n       EN --> H\n       G --> H\n       H -- Yes --> I[Widen activeTools for the next agent step]\n       H -- No --> J[Respond with the turn's tool set]\n  Deterministic Vision Routing  An attached image always adds   vision  (and   food , the dominant meal-photo case) to the matched categories before keyword or LLM classification runs — this is unambiguous, so it never goes through the fuzzier keyword\u002FLLM paths.  Phase 1: Fast Keyword Regex Matching (0ms Overhead)  Before making any model calls, the server matches the user's message against a set of predefined regex keywords for each domain (e.g.   \"calories\" ,   \"eat\" , or stems like   \"summar(y|ize|ise)\"  for   food \u002F  reports ;   \"walked\" ,   \"lifted\" , or   \"swim\" \u002F  \"yoga\"  for   exercise ). All rules run against the full message — a message can and often does match multiple domains at once (e.g.   \"summarize what I ate and did yesterday\"  matches both   food  and   reports ), and every match is kept: loading an extra category costs a little payload, but missing one blocks the request outright, so keyword matching always favors recall over precision.    Outcome:  If any rule matches, the server bypasses the LLM classifier completely. This results in   0ms overhead  and   0 token cost .   By design, this list is intentionally not exhaustive and is English-only.  User phrasing is unbounded across paraphrases, typos, and languages; growing the regex list indefinitely trades recall for false positives (e.g. an overly broad \"run\" rule would fire on \"I ran out of milk\"). Phase 1 matching is English-only; non-English queries will simply fall back to Phase 2 (the LLM Intent Classifier), which naturally handles multilingual intent. Gaps here are expected to be caught by Phase 2, or recovered from via the escalation tool (below) if even Phase 2 misses.  Phase 2: LLM Classifier Fallback (Low-Latency)  If no keyword rule matched, it triggers a low-latency LLM intent classification request.    Context:  It sends the last   2 messages of context  (the assistant's previous reply + the user's latest query) to ensure short answers like   \"today\"  or   \"yes\"  are correctly understood in context.   Outcome:  The model is instructed to output only a comma-separated list of active categories (e.g.   \"food, exercise\" ). The server parses this string and registers only those specific toolsets.    \"none\"  response:  A confident \"no domain applies\" (general chit-chat) loads just the   coaching  category rather than falling back to a wider default — the escalation tool recovers if that guess is wrong.  Phase 3: Profile Default Fallback  If the LLM classifier call itself fails (network\u002Fservice error — as opposed to a confident   \"none\" ):    Outcome:  The server no longer forces a fixed category subset. Instead it defers to the tool profile's own default: the   full  profile's default is every category, and the   core  profile's default is   ['food', 'exercise', 'checkin', 'goals'] . This keeps the same \"never send more than a small local model can handle\" guarantee that the   core  profile exists for, while cloud\u002Ffull-profile users still get everything by default when classification is unavailable.  4. Escalation:   sparky_enable_tools  (auto mode only)  Because no classifier tier is perfect, the   auto-classification  tool surface always includes one extra tool,   sparky_enable_tools . If the model realizes mid-conversation that it needs a tool category that wasn't loaded (e.g. it was classified to   food  but the user also wants exercise logged), it calls   sparky_enable_tools  with the missing category slugs. A   prepareStep  callback (  buildEscalationPrepareStep  in   services\u002FchatService.ts ) inspects the prior agent step for that call and widens   activeTools  for the next step accordingly — no re-classification or tool-map recomposition needed. The system prompt lists any dormant categories and instructs the model to call this tool before telling the user something isn't possible, so a classification miss becomes one extra agent step instead of a wrong answer.  This escalation path is deliberately   disabled for manual selections  (section 2): a manual pick is a limit the user set on purpose, so instead of self-widening, the model points the user back to the tool selector.  5. Modular Prompt Composition  To save context window tokens, the chatbot system prompts are split into modular markdown templates:    Base Prompts (  chatbot-full.md  &   chatbot-core.md ):  Contain overall behavior, tone, and formatting instructions.   Category Sub-prompts (e.g.   chatbot-full-food.md ,   chatbot-full-vision.md ):  Contain specialized instructions. These sub-prompts are dynamically appended   only  when their corresponding category tools are loaded. This saves up to 500-700 tokens on simple conversational or logging queries.  6. Resilient Tool Validation Fallbacks  To further support smaller local models that occasionally fail to extract required parameters:    Exercise Logging Fallback:  If   log_exercise  is called without   exercise_id  or   exercise_name , the handler automatically defaults the name to   \"General Exercise\"  and logs it successfully instead of throwing a validation error.   Food Schema Enforcement:  The   food_name  description in the schema explicitly marks the parameter as required for   log_external_food  to ensure LLMs correctly populate it.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":618,"path":619,"dir":598,"title":620,"description":621,"keywords":622,"body":630},"content:8.developer:8.advanced:3.rate-limiting.md","\u002Fdeveloper\u002Fadvanced\u002Frate-limiting","Rate Limiting Implementation","This document outlines the rate limiting strategy implemented for the SparkyFitness application, focusing on protecting sensitive authentication endpoints.",[623,624,625,626,627,628,629],"Purpose","Implementation Layer","Nginx Configuration","Endpoints Protected","Configuration","API Key Rate Limiting","Testing the Rate Limiting","  Rate Limiting Implementation  This document outlines the rate limiting strategy implemented for the SparkyFitness application, focusing on protecting sensitive authentication endpoints.  Purpose  Rate limiting is crucial for:    Preventing Brute-Force Attacks : Limiting the number of login attempts from a single IP address within a given time frame.   Mitigating Denial-of-Service (DoS) Attacks : Restricting the rate of requests to prevent server overload.   Preventing Account Creation Spam : Limiting the rate of new user registrations.   Protecting Password Reset Flows : Preventing abuse of email-based recovery mechanisms.   Securing MFA Endpoints : Limiting attempts to bypass multi-factor authentication.  Implementation Layer  Rate limiting is implemented at the   Nginx reverse proxy layer . This is the most efficient approach as it blocks malicious requests before they reach the backend Node.js application, conserving server resources.  Nginx Configuration  The rate limiting is configured in the   nginx.conf  file.  1. Client IP Detection  To correctly identify clients behind proxies or CDNs like Cloudflare, the configuration uses a chain of IP detection mechanisms:     # Trust docker gateway and Cloudflare IPs for real IP detection\n   set_real_ip_from 172.16.0.0\u002F12;  # Docker networks\n   set_real_ip_from 10.0.0.0\u002F8;      # Private networks\n   real_ip_header CF-Connecting-IP;\n   real_ip_recursive on;\n   \n   map $http_cf_connecting_ip $client_ip_from_cf {\n       \"\"      $binary_remote_addr;\n       default $http_cf_connecting_ip;\n   }\n   \n   map $http_x_real_ip $rate_limit_key {\n       \"\"      $client_ip_from_cf;\n       default $http_x_real_ip;\n   }\n  The detection priority is:    CF-Connecting-IP  header (Cloudflare)   X-Real-IP  header (other proxies)  Direct connection IP (  $binary_remote_addr )  2. Defining a Rate Limiting Zone  A shared memory zone named   auth_zone  is defined to track request rates based on client IP addresses:     limit_req_zone $rate_limit_key zone=auth_zone:10m rate=${NGINX_RATE_LIMIT};\n   limit_req_status 429;\n    $rate_limit_key : Uses the detected client IP address for tracking.   zone=auth_zone:10m : Defines a 10-megabyte shared memory zone.   rate=${NGINX_RATE_LIMIT} : Configurable rate limit (default:   5r\u002Fs ). Set to   10000r\u002Fs  to effectively disable rate limiting.   limit_req_status 429 : Explicitly returns HTTP 429 (Too Many Requests) when rate limited.  3. Applying the Rate Limit to Endpoints  The   limit_req  directive is applied to specific authentication endpoints within the   server  block.   Exact match endpoints:     # Apply rate limit to login endpoint\n   location = \u002Fapi\u002Fauth\u002Flogin {\n       limit_req zone=auth_zone burst=5 nodelay;\n       proxy_pass http:\u002F\u002F${SPARKY_FITNESS_SERVER_HOST}:${SPARKY_FITNESS_SERVER_PORT}\u002Fauth\u002Flogin;\n       # ... other proxy settings ...\n   }\n   \n   # Apply rate limit to register endpoint\n   location = \u002Fapi\u002Fauth\u002Fregister {\n       limit_req zone=auth_zone burst=5 nodelay;\n       proxy_pass http:\u002F\u002F${SPARKY_FITNESS_SERVER_HOST}:${SPARKY_FITNESS_SERVER_PORT}\u002Fauth\u002Fregister;\n       # ... other proxy settings ...\n   }\n   Regex match for MFA endpoints:     # Apply rate limit to all MFA endpoints\n   location ~ ^\u002Fapi\u002Fauth\u002Fmfa(\u002F.*)?$ {\n       limit_req zone=auth_zone burst=5 nodelay;\n       rewrite ^\u002Fapi\u002F(.*)$ \u002F$1 break;\n       proxy_pass http:\u002F\u002F${SPARKY_FITNESS_SERVER_HOST}:${SPARKY_FITNESS_SERVER_PORT};\n       # ... other proxy settings ...\n   }\n  Configuration parameters:    limit_req zone=auth_zone : Refers to the defined rate limiting zone.   burst=5 : Allows a burst of up to 5 requests beyond the defined rate.   nodelay : Requests exceeding the burst limit are immediately rejected with a   429 Too Many Requests  error, rather than being delayed.  Endpoints Protected  The following authentication endpoints are protected by Nginx rate limiting:     Endpoint  Purpose     \u002Fapi\u002Fauth\u002Flogin  User login    \u002Fapi\u002Fauth\u002Fregister  New user registration    \u002Fapi\u002Fauth\u002Fforgot-password  Password reset request    \u002Fapi\u002Fauth\u002Freset-password  Password reset completion    \u002Fapi\u002Fauth\u002Frequest-magic-link  Magic link request    \u002Fapi\u002Fauth\u002Fmagic-link-login  Magic link authentication    \u002Fapi\u002Fauth\u002Fmfa\u002F*  All MFA-related endpoints  Configuration  The rate limit can be configured via the   NGINX_RATE_LIMIT  environment variable in your Docker Compose configuration:     environment  :\n     -   NGINX_RATE_LIMIT=5r\u002Fs    # Default: 5 requests per second\n  To effectively disable rate limiting (e.g., for testing), set a very high value:     environment  :\n     -   NGINX_RATE_LIMIT=10000r\u002Fs\n  API Key Rate Limiting  In addition to Nginx rate limiting on auth endpoints,   API key authentication  has its own per-key rate limit enforced at the application layer by Better Auth.  Defaults     Setting  Value    Time window  60,000 ms (1 minute)   Max requests  100 per window  These defaults apply to all newly created API keys.  Configuration  The limits can be overridden via environment variables:     Variable  Description  Default     SPARKY_FITNESS_API_KEY_RATELIMIT_WINDOW_MS  Time window in milliseconds   60000    SPARKY_FITNESS_API_KEY_RATELIMIT_MAX_REQUESTS  Max requests per window   100  Behavior  When the rate limit is exceeded, the server returns:    HTTP 429  with   {\"error\": \"Rate limit exceeded.\"}  A   Retry-After  header indicating seconds until the window resets (at most 60s with default settings)  This rate limit is per API key, not per IP. Cookie-based browser sessions are not affected.  Testing the Rate Limiting  To test the rate limiting, ensure your Docker Compose environment is running with the updated   nginx.conf . Then, use   curl  to send a high volume of requests to the protected endpoints.  Example   curl  command (replace with your domain and adjust payload):     for   i   in   $(  seq   1   15  );   do   curl   -k   -s   -o   \u002Fdev\u002Fnull   -w   \"%{http_code}\\n\"   -X   POST   -H   \"Content-Type: application\u002Fjson\"   -d   '{\"email\":\"test@example.com\", \"password\":\"password\"}'   https:\u002F\u002Fyour-domain.com\u002Fapi\u002Fauth\u002Flogin   &   done\n  You should observe   429 Too Many Requests  HTTP status codes for requests exceeding the defined rate and burst limits.  Note on 503 Errors During Testing  During initial testing,   503 Service Unavailable  errors might be observed instead of   429 s. This indicates that Nginx is indeed applying the rate limit (as confirmed by Nginx error logs showing   limiting requests ), but it's also encountering issues connecting to or receiving timely responses from the backend server. While the rate limiting itself is functional, consistent   503 s suggest an underlying issue with the backend's stability or readiness under load, which is outside the scope of the rate limiting implementation itself.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":632,"path":633,"dir":598,"title":634,"description":635,"keywords":636,"body":637},"content:8.developer:8.advanced:4.translations.md","\u002Fdeveloper\u002Fadvanced\u002Ftranslations","Translations","This section will provide details on translations within SparkyFitness. This feature is planned for future development.",[],"  Translations  This section will provide details on translations within SparkyFitness. This feature is planned for future development.",{"id":639,"path":640,"dir":598,"title":641,"description":7,"keywords":642,"body":651},"content:8.developer:8.advanced:5.wger-integration-plan.md","\u002Fdeveloper\u002Fadvanced\u002Fwger-integration-plan","Wger Exercise Database Integration Plan",[643,644,645,646,647,648,649,650],"1. Introduction","2. Chosen Approach: Direct Wger API Integration","3. Architecture","4. Data Flow and Logic","5. Security Considerations","6. Refactoring Existing Data Providers","7. UI\u002FUX Considerations","8. Implementation Steps (High-Level)","  Wger Exercise Database Integration Plan  1. Introduction  This document outlines the plan for integrating the   wger  exercise database into the SparkyFitness application. The goal is to provide users with the ability to search for exercises from a comprehensive external database and add them to their personal exercise catalog, similar to how food data providers are integrated.  2. Chosen Approach: Direct Wger API Integration  After evaluating several options, direct integration with the   wger  REST API is the chosen approach due to its API-driven nature, potential for calorie information, rich data, and maintainability. This avoids the complexities of importing static data files and managing local copies of a large external database.  3. Architecture  The integration will involve modifications to the backend services, API routes, and frontend components.     graph TD\n       A[User Interface] --> B(Exercise Search Component)\n       B --> C{SparkyFitness Backend API}\n       C --> D[Existing Exercise Service]\n       C --> E[New Wger Exercise Service]\n       D --> F[SparkyFitness DB: User Exercises]\n       E --> G(Wger REST API)\n       E -- Cache Wger Responses --> H[Server-Side Cache]\n       B -- Add Selected Exercise --> D\n   Explanation of Components:    User Interface : The user interacts with an enhanced Exercise Search Component.   Exercise Search Component : This component will query the SparkyFitness Backend API for exercise search results.   SparkyFitness Backend API : This acts as a central point, routing requests to the appropriate services. It will handle authentication and authorization.   Existing Exercise Service : Handles operations related to exercises already in the user's personal database (  public.exercises  table).   New Wger Exercise Service : This service will be responsible for:\n   Making API calls to the   wger  REST API.  Handling search queries and fetching detailed exercise information.  Implementing server-side caching for   wger  API responses to improve performance and reduce redundant external calls.  Mapping   wger  data to SparkyFitness's   public.exercises  schema.   Wger REST API : The external source of exercise data (  https:\u002F\u002Fwger.de\u002Fapi\u002Fv2\u002F ).   Server-Side Cache : A mechanism (e.g., Redis, in-memory cache) to store   wger  API responses temporarily.   SparkyFitness DB: User Exercises : The existing   public.exercises  table, which will store user-specific exercises, including those imported from   wger .  4. Data Flow and Logic  4.1. Exercise Search   User types a search query in the frontend Exercise Search Component.  The frontend sends the query to a new backend API endpoint (e.g.,   \u002Fapi\u002Fexercises\u002Fsearch-external ).  The backend endpoint calls the   New Wger Exercise Service .  The   New Wger Exercise Service  queries the   wger  API (checking cache first).   wger  API returns exercise search results.  The   New Wger Exercise Service  processes the results, potentially filtering or reformatting them.  The backend API combines results from   wger  and potentially existing user exercises.  Results are returned to the frontend for display.  4.2. Adding a Wger Exercise to User's Catalog   User selects a   wger  exercise from the search results and clicks \"Add\".  The frontend sends a request to an existing or new backend API endpoint (e.g.,   \u002Fapi\u002Fexercises\u002Fadd-external ).  The backend endpoint calls the   Existing Exercise Service  (or a dedicated function within it).  The   Existing Exercise Service  retrieves the full details of the selected   wger  exercise from the   New Wger Exercise Service  (which may involve another   wger  API call or cache lookup).  The   Existing Exercise Service  maps the   wger  exercise data to the   public.exercises  table schema.    name : Mapped directly from   wger.name .   category : Mapped from   wger.category  (or a suitable default\u002Fderived category).   description : Mapped from   wger.description  or a summary of   wger.instructions .   is_custom : Set to   TRUE .   user_id : Extracted from the authenticated JWT.   source_external_id : A new column in   public.exercises  will store the   wger  exercise's unique ID. This will be a   TEXT  field.   calories_per_hour : Calculated using   wger 's MET value.  4.3. Calories Per Hour Calculation  The   wger  API provides a   met  (Metabolic Equivalent of Task) value for exercises. The   calories_per_hour  will be calculated using the following formula:   Calories Burned per Minute = (METs * 3.5 * Body Weight in kg) \u002F 200  Calories Burned per Hour = Calories Burned per Minute * 60   Body Weight Source Priority:    User's Latest Check-in Weight : The system will attempt to retrieve the user's most recent weight from the   public.check_in_measurements  table.   Standard Average Body Weight : If the user has no recorded check-in weight, a standard average body weight (e.g., 70 kg or 154 lbs) will be used as a fallback.  5. Security Considerations    Authentication : All new backend API endpoints will be protected by JWT authentication. The   user_id  will always be extracted from the authenticated token and will   not  be passed directly as a parameter in requests.   Authorization : Ensure that only authenticated users can add exercises to their catalog.  6. Refactoring Existing Data Providers  To generalize the concept of external data sources, the existing   food_data_providers  will be refactored.    Renaming : The   food_data_providers  table, related files, and code references will be renamed to a more generic term, such as   external_data_providers  or   api_integrations .   Scope : This refactoring will encompass both backend and frontend codebases to ensure consistency.   Impact : This change will allow the system to manage various types of external data providers (food, exercise, etc.) under a unified structure.  7. UI\u002FUX Considerations   The frontend exercise search component will be enhanced to display results from both existing user exercises and   wger  exercises.  The UI will follow existing patterns, particularly those established by the food search and add components (e.g.,   EnhancedFoodSearch.tsx ), to ensure a consistent and intuitive user experience.  8. Implementation Steps (High-Level)   Create   docs\u002Fwger-integration-plan.md  (this document).  Analyze existing food provider architecture for generalization.  Plan refactoring of   food_data_providers  to a generic name.  Execute refactoring of data providers (rename tables, files, update code).  Add   source_external_id  column to   public.exercises  table.  Implement new backend service to interact with the   wger  API (search, fetch details, caching).  Create new API endpoint for   wger  exercise search (ensuring JWT for user_id).  Enhance frontend exercise search component (to query both existing and   wger  exercises).  Implement logic to add   wger  exercise to user's   public.exercises  table (mapping fields including calories, using user's latest weight or average if not available).  Test end-to-end functionality.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":653,"path":654,"dir":506,"title":655,"description":656,"keywords":657,"body":666},"content:8.developer:9.translations.md","\u002Fdeveloper\u002Ftranslations","Internationalization (i18n) Setup in SparkyFitnessFrontend","This document outlines the setup for internationalization (i18n) in the SparkyFitnessFrontend application using i18next and react-i18next.",[658,659,660,661,662,663,664,665],"1. Core Libraries","2. Translation File Structure","3. i18next Configuration (src\u002Fi18n.ts)","4. Integration into React Application (src\u002Fmain.tsx)","5. Language Handling Component (src\u002Fcomponents\u002FLanguageHandler.tsx)","6. Using Translations in Components","7. Language Switcher in Settings (src\u002Fcomponents\u002FSettings.tsx)","8. Adding New Languages","  Internationalization (i18n) Setup in SparkyFitnessFrontend  This document outlines the setup for internationalization (i18n) in the SparkyFitnessFrontend application using   i18next  and   react-i18next .  1. Core Libraries  The following npm packages are used for i18n:    i18next : The core i18n library.   react-i18next : Integration for React applications.   i18next-browser-languagedetector : Detects the user's language from the browser.   i18next-http-backend : Loads translation files over HTTP.  These dependencies are installed in the   SparkyFitnessFrontend  directory.  2. Translation File Structure  Translation files are stored in the   public\u002Flocales  directory, following the format   public\u002Flocales\u002F{{languageCode}}\u002Ftranslation.json .    public\u002Flocales\u002Fen\u002Ftranslation.json : Contains English translations.   public\u002Flocales\u002Fta\u002Ftranslation.json : Contains Tamil translations.  Each   translation.json  file is a simple JSON object where keys represent translation identifiers and values are the translated strings. Nested objects can be used to organize translations (e.g.,   \"nav.diary\" ).  Example (  translation.json ):     {\n     \"nav\"  : {\n       \"diary\"  :   \"Diary\"  ,\n       \"checkin\"  :   \"Check-In\"\n     },\n     \"settings\"  : {\n       \"profileInformation\"  : {\n         \"title\"  :   \"Profile Information\"\n       }\n     }\n   }\n  3. i18next Configuration (  src\u002Fi18n.ts )  The   i18next  instance is configured in    SparkyFitnessFrontend\u002Fsrc\u002Fi18n.ts .     import   i18n   from   'i18next'  ;\n   import   { initReactI18next }   from   'react-i18next'  ;\n   import   LanguageDetector   from   'i18next-browser-languagedetector'  ;\n   import   HttpApi   from   'i18next-http-backend'  ;\n   \n   i18n\n     .  use  (HttpApi)\n     .  use  (LanguageDetector)\n     .  use  (initReactI18next)\n     .  init  ({\n       supportedLngs: [  'en'  ,   'ta'  ],   \u002F\u002F List of supported languages\n       fallbackLng:   'en'  ,   \u002F\u002F Fallback language if a translation is missing\n       detection: {\n         order: [  'localStorage'  ,   'querystring'  ,   'cookie'  ,   'sessionStorage'  ,   'navigator'  ,   'htmlTag'  ],\n         caches: [  'localStorage'  ,   'cookie'  ],\n       },\n       backend: {\n         loadPath:   '\u002Flocales\u002F{{lng}}\u002F{{ns}}.json'  ,   \u002F\u002F Path to load translation files\n       },\n       react: {\n         useSuspense:   false  ,   \u002F\u002F Set to true if you want to use React.Suspense for loading translations\n       },\n     });\n   \n   export   default   i18n;\n   Key Configuration Details:    supportedLngs : An array of language codes that your application supports.   fallbackLng : The language to use if a translation for the current language is missing.   detection.order : Specifies the order in which   i18next  tries to detect the user's language.   localStorage  is prioritized to use the user's saved preference.   backend.loadPath : The URL pattern to fetch translation files.   {{lng}}  is replaced by the current language code, and   {{ns}}  by the namespace (defaulting to   translation ).   react.useSuspense : Set to   false  to avoid using React's Suspense feature for translations, simplifying initial setup.  4. Integration into React Application (  src\u002Fmain.tsx )  The   i18next  instance is initialized and provided to the React application in    SparkyFitnessFrontend\u002Fsrc\u002Fmain.tsx .     import   { createRoot }   from   'react-dom\u002Fclient'\n   import   App   from   '.\u002FApp.tsx'\n   import   '.\u002Findex.css'\n   import   { BrowserRouter }   from   'react-router-dom'  ;\n   import   { AuthProvider }   from   '.\u002Fhooks\u002FuseAuth.tsx'  ;\n   import   '.\u002Fi18n'  ;   \u002F\u002F Import the i18n configuration\n   import   { Suspense }   from   'react'  ;\n   \n   createRoot  (document.  getElementById  (  \"root\"  )  !  ).  render  (\n     \u003C  Suspense fallback  =  \"loading\"  >\n       \u003C  BrowserRouter  >\n         \u003C  AuthProvider  >\n           \u003C  App   \u002F>\n         \u003C\u002F  AuthProvider  >\n       \u003C\u002F  BrowserRouter  >\n     \u003C\u002F  Suspense  >\n   );\n  The   Suspense  component is used to display a fallback (e.g., \"loading\") while translations are being loaded.  5. Language Handling Component (  src\u002Fcomponents\u002FLanguageHandler.tsx )  A dedicated component,    SparkyFitnessFrontend\u002Fsrc\u002Fcomponents\u002FLanguageHandler.tsx , is used to synchronize the   i18next  language with the user's preference stored in the   PreferencesContext .     import   { useEffect }   from   'react'  ;\n   import   { useTranslation }   from   'react-i18next'  ;\n   import   { usePreferences }   from   '@\u002Fcontexts\u002FPreferencesContext'  ;\n   \n   const   LanguageHandler   =   ()   =>   {\n     const   {   i18n   }   =   useTranslation  ();\n     const   {   language   }   =   usePreferences  ();\n   \n     useEffect  (()   =>   {\n       if   (language) {\n         i18n.  changeLanguage  (language);\n       }\n     }, [language, i18n]);\n   \n     return   null  ;   \u002F\u002F This component doesn't render anything\n   };\n   \n   export   default   LanguageHandler;\n  This component ensures that when the   language  preference changes (e.g., via the language switcher in settings),   i18next  updates its active language.  6. Using Translations in Components  To use translations in any React component, import the   useTranslation  hook from   react-i18next .     import   { useTranslation }   from   'react-i18next'  ;\n   \n   const   MyComponent   =   ()   =>   {\n     const   {   t   }   =   useTranslation  ();\n   \n     return   (\n       \u003C  div  >\n         \u003C  h1  >{  t  (  'nav.diary'  )}  \u003C\u002F  h1  >\n         \u003C  p  >{  t  (  'settings.profileInformation.description'  )}  \u003C\u002F  p  >\n       \u003C\u002F  div  >\n     );\n   };\n  The   t  function takes a translation key (e.g.,   \"nav.diary\" ) and returns the corresponding translated string for the currently active language.  7. Language Switcher in Settings (  src\u002Fcomponents\u002FSettings.tsx )  The language switcher is integrated into the   Preferences  section of the   Settings  component. It uses the   language  state and   setLanguage  function from   PreferencesContext  to update the user's preferred language.     \u002F\u002F Inside Settings.tsx\n   import   { useTranslation }   from   \"react-i18next\"  ;\n   import   { usePreferences }   from   \"@\u002Fcontexts\u002FPreferencesContext\"  ;\n   \u002F\u002F ... other imports\n   \n   const   Settings  :   React  .  FC  \u003C  SettingsProps  >   =   ({   onShowAboutDialog   })   =>   {\n     const   {   t   }   =   useTranslation  ();\n     const   {   language  ,   setLanguage   }   =   usePreferences  ();\n     \u002F\u002F ... other state and functions\n   \n     \u002F\u002F Inside the Preferences AccordionContent\n     \u003C  div  >\n       \u003C  Label htmlFor  =  \"language\"  >  {  t  (  'settings.preferences.language'  )}  \u003C\u002F  Label  >\n       \u003C  Select\n         value  =  {language}\n         onValueChange  =  {setLanguage}\n       >\n         \u003C  SelectTrigger  >\n           \u003C  SelectValue   \u002F>\n         \u003C\u002F  SelectTrigger  >\n         \u003C  SelectContent  >\n           \u003C  SelectItem value  =  \"en\"  >  English  \u003C\u002F  SelectItem  >\n           \u003C  SelectItem value  =  \"ta\"  >  தமிழ்  \u003C\u002F  SelectItem  >\n         \u003C\u002F  SelectContent  >\n       \u003C\u002F  Select  >\n     \u003C\u002F  div  >\n     \u002F\u002F ...\n   };\n  8. Adding New Languages  To add a new language (e.g., Spanish -   es ):    Create Translation File:  Create a new JSON file:   public\u002Flocales\u002Fes\u002Ftranslation.json .   Add Translations:  Populate   translation.json  with Spanish translations for all keys used in the application.   Update   i18n.ts :  Add   'es'  to the   supportedLngs  array in    SparkyFitnessFrontend\u002Fsrc\u002Fi18n.ts .   Update Language Switcher:  Add a new   SelectItem  for Spanish in the language switcher within    SparkyFitnessFrontend\u002Fsrc\u002Fcomponents\u002FSettings.tsx .   Backend Update (if applicable):  If you want to store the language preference in the backend, ensure the   user_preferences  table and associated API endpoints can handle the new language code.  By following these steps, you can easily extend the application to support additional languages.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":668,"path":669,"dir":670,"title":671,"description":672,"keywords":673,"body":675},"content:8.developer:10.mcp:0.dev.md","\u002Fdeveloper\u002Fmcp\u002Fdev","mcp","Development and Debugging Tools","Utility tools for developers to inspect the database, check server status, and run internal tests.",[674],"Tools within Development","  Development and Debugging Tools (  devTools )  The   devTools  are a collection of utility functions designed to aid developers in inspecting the system, debugging issues, and performing internal tasks. These tools provide access to database schema, user information, and server stats.   Tool Name:    devTools  (Note: This is a collection of tools, not a single one)   These tools are   off by default . The in-process   \u002Fmcp  server only exposes them when   DEV_TOOLS_ENABLED=true    and  the request authenticates with an   admin  API key. They run with elevated database access (the owner pool, bypassing Row Level Security), so keep them disabled outside of active debugging.  Tools within Development   sparky_inspect_schema    Description:  Inspect the database schema to understand available tables and columns.   Parameters:    table  (string): Name of the table to inspect (e.g.,   foods ,   exercise_entries ).   sparky_get_user_info    Description:  Get information about the current user authenticated by the MCP API key.   Parameters:  None.   sparky_get_db_stats    Description:  Get current database connection pool statistics (total, idle, and waiting connection counts).   Parameters:  None.",{"id":677,"path":678,"dir":670,"title":679,"description":680,"keywords":681,"body":683},"content:8.developer:10.mcp:1.food.md","\u002Fdeveloper\u002Fmcp\u002Ffood","Food Management Tool","Comprehensive tool for tracking and managing dietary intake.",[682],"Actions","  Food Management Tool (  manage_food )  The   manage_food  tool is the primary interface for all nutrition tracking and management within SparkyFitness. It allows users and AI agents to search for food, log meals, create custom food items, and manage their daily food diary.   Tool Name:    manage_food   Description:  Primary tool for nutrition tracking. Use this to search for food, log meals, create custom food items, and manage your daily diary. Supports multi-turn conversations where you provide details one by one.  Actions  The   manage_food  tool supports the following actions:   search_food    Description:  Search for existing food items in the database.   Parameters:    food_name  (string): The name of the food item to search for.   search_type  (enum: \"exact\", \"broad\"): The type of search to perform.   log_food    Description:  Logs a food item to your daily diary. Handles both existing and new food items.   Parameters:    food_name  (string): The name of the food item.   food_id  (string, optional): UUID of the food item (if known).   variant_id  (string, optional): UUID of the food variant (if known).   quantity  (number): The amount consumed.   unit  (string): The unit of measurement (e.g., 'g', 'piece', 'serving').   meal_type  (string): The meal timeframe (e.g., 'breakfast', 'lunch', 'dinner', 'snacks').   entry_date  (string, YYYY-MM-DD): The date of the record.   Special Handling for Unknown Foods:  If   food_name  is not found, the AI will be instructed to infer nutritional details and create the food via   create_food  before re-attempting to log.   create_food    Description:  Creates a new custom food item in the database with its nutritional information.   Parameters:    food_name  (string): The name of the new food item.   brand  (string, optional): The brand name of the food.   macros  (object): Nutritional information for the food.\n    calories  (number)   protein  (number)   carbs  (number)   fat  (number)   saturated_fat  (number)   polyunsaturated_fat  (number)   monounsaturated_fat  (number)   trans_fat  (number)   cholesterol  (number)   sodium  (number)   potassium  (number)   fiber  (number)   sugar  (number)   vitamin_a  (number)   vitamin_c  (number)   calcium  (number)   iron  (number)   gi  (string, enum: \"None\", \"Very Low\", \"Low\", \"Medium\", \"High\", \"Very High\")   quantity  (number, optional): The default serving size value.   unit  (string, optional): The default serving size unit.   search_meal    Description:  Search for existing meal templates.   Parameters:    meal_name  (string): The name of the meal template to search for.   log_meal    Description:  Logs a predefined meal template to your daily diary.   Parameters:    meal_id  (string, optional): UUID of the meal template (if known).   meal_name  (string, optional): Name of the meal template (alternative to ID).   meal_type  (string): The meal timeframe.   entry_date  (string, YYYY-MM-DD): The date of the record.   quantity  (number, optional): Multiplier for the meal template.   unit  (string, optional): Unit for the meal template multiplier.   list_diary    Description:  Retrieves all logged food and meal entries for a specific date.   Parameters:    entry_date  (string, YYYY-MM-DD, optional): The date to retrieve the diary for. Defaults to today.   delete_entry    Description:  Deletes a specific food or meal entry from the diary.   Parameters:    entry_id  (string): UUID of the entry to delete.   entry_type  (enum: \"food_entry\", \"food_entry_meal\"): The type of entry.   update_entry    Description:  Updates the quantity or unit of an existing food or meal entry.   Parameters:    entry_id  (string): UUID of the entry to update.   entry_type  (enum: \"food_entry\", \"food_entry_meal\"): The type of entry.   quantity  (number): The new amount.   unit  (string): The new unit of measurement.   copy_from_yesterday    Description:  Copies all food entries from a source date (defaults to yesterday) to a target date (defaults to today) for a specific meal type.   Parameters:    target_date  (string, YYYY-MM-DD, optional): The date to copy entries to.   source_date  (string, YYYY-MM-DD, optional): The date to copy entries from.   meal_type  (string, optional): The specific meal type to copy (e.g., 'breakfast').   save_as_meal_template    Description:  Saves a set of food entries from a specific date and meal type as a new reusable meal template.   Parameters:    entry_date  (string, YYYY-MM-DD): The date from which to save entries.   meal_type  (string): The meal type to save (e.g., 'lunch').   meal_name  (string): The name for the new meal template.   description  (string, optional): A description for the meal template.",{"id":685,"path":686,"dir":670,"title":687,"description":688,"keywords":689,"body":690},"content:8.developer:10.mcp:2.exercise.md","\u002Fdeveloper\u002Fmcp\u002Fexercise","Exercise Management Tool","Tool for tracking fitness activities and managing workouts.",[682],"  Exercise Management Tool (  manage_exercise )  The   manage_exercise  tool is designed for comprehensive fitness tracking. It allows users and AI agents to search for exercises, log workouts (with multi-set support), manage routines, and view exercise history. If an exercise is not found, it can be automatically created.   Tool Name:    manage_exercise   Description:  Primary tool for fitness tracking. Use this to search for exercises, log workouts (multi-set support), manage routines, and view your exercise history. If an exercise is missing, it will be automatically created. Supports providing details across multiple turns.  Actions  The   manage_exercise  tool supports the following actions:   search_exercises    Description:  Searches for existing exercise definitions.   Parameters:    searchTerm  (string): Name or part of exercise name.   muscleGroup  (string, optional): Muscle group to filter by (e.g., \"Chest\", \"Biceps\").   equipment  (string, optional): Equipment to filter by (e.g., \"Dumbbell\", \"None\").   create_exercise    Description:  Creates a new exercise definition.   Parameters:    name  (string): Full name for a new exercise.   category  (string, optional): Category (e.g., \"Strength\", \"Cardio\").   calories_per_hour  (number, optional): Estimated calories burned per hour.   description  (string, optional): Description of the exercise.   log_exercise    Description:  Logs an exercise performed by the user, including sets and reps if applicable.   Parameters:    exercise_id  (string, optional): UUID of the exercise.   exercise_name  (string, optional): Name of the exercise to log (alternative to ID).   entry_date  (string, YYYY-MM-DD): The date the exercise was performed.   duration_minutes  (number, optional): Duration of the exercise in minutes.   calories_burned  (number, optional): Calories burned during the exercise.   notes  (string, optional): Any additional notes for the exercise.   sets  (array of objects, optional): Details for multiple sets (e.g., for strength training).\n   Each set object includes:   reps  (number),   weight  (number, kg),   duration  (number, seconds),   rest_time  (number, seconds),   set_type  (enum: \"Working Set\", \"Warmup\", \"Drop Set\", \"Failure\").   list_exercise_diary    Description:  Retrieves all logged exercise entries for a specific date, representing the user's exercise history.   Parameters:    entry_date  (string, YYYY-MM-DD): The date to retrieve the exercise diary for.   get_workout_presets    Description:  Retrieves a list of available workout presets\u002Froutines.   Parameters:  None.   log_workout_preset    Description:  Logs a predefined workout preset to the user's exercise diary.   Parameters:    preset_id  (string, optional): UUID of the workout preset.   preset_name  (string, optional): Name of the preset to log (alternative to ID).   entry_date  (string, YYYY-MM-DD): The date the preset was performed.   delete_exercise_entry    Description:  Deletes a specific exercise entry from the user's diary.   Parameters:    entry_id  (string): UUID of the exercise entry to delete.",{"id":692,"path":693,"dir":670,"title":694,"description":695,"keywords":696,"body":697},"content:8.developer:10.mcp:3.checkin.md","\u002Fdeveloper\u002Fmcp\u002Fcheckin","Health Check-in Management Tool","Tool for logging and tracking various health metrics including biometrics, mood, sleep, and fasting.",[682],"  Health Check-in Management Tool (  manage_checkin )  The   manage_checkin  tool is a primary interface for logging and tracking various health metrics. It allows users and AI agents to record biometrics (weight, steps, measurements), custom health metrics, mood, sleep, and fasting windows.   Tool Name:    manage_checkin   Description:  Primary tool for health tracking. Use this to log your WEIGHT, daily step count, height, body measurements (waist, neck, hips), mood, sleep duration\u002Fquality, and fasting windows. Supports providing health details across multiple turns.  Actions  The   manage_checkin  tool supports the following actions:   log_biometrics    Description:  Logs or updates various biometric measurements for a given date.   Parameters:    entry_date  (string, YYYY-MM-DD): The date of the record.   weight  (number, optional): Weight value.   weight_unit  (enum: \"kg\", \"lbs\", \"lb\", \"g\", optional): Unit for weight (defaults to kg).   steps  (number, optional): Daily step count.   height  (number, optional): Height value.   height_unit  (enum: \"cm\", \"in\", \"inch\", \"ft\", optional): Unit for height.   neck  (number, optional): Neck measurement.   waist  (number, optional): Waist measurement.   hips  (number, optional): Hips measurement.   measurements_unit  (enum: \"cm\", \"in\", \"inch\", optional): Unit for body measurements.   body_fat  (number, optional): Body fat percentage.   log_custom_metric    Description:  Logs a value for a user-defined custom health category.   Parameters:    category_name  (string): Name of the custom category (e.g., \"Blood Pressure\").   value  (string or number): The value to record.   unit  (string, optional): Unit for the recorded value.   notes  (string, optional): Optional notes for the entry.   entry_date  (string, YYYY-MM-DD): The date of the record.   list_categories    Description:  Lists all user-defined custom health categories.   Parameters:  None.   create_category    Description:  Creates a new custom health category for logging.   Parameters:    category_name  (string): Name of the custom category.   unit  (string, optional): Unit for the new category.   log_mood    Description:  Logs the user's mood for a specific date.   Parameters:    mood_value  (number): Mood score (typically 1-10).   notes  (string, optional): Optional notes about the mood.   entry_date  (string, YYYY-MM-DD): The date of the record.   log_fasting    Description:  Logs a fasting window.   Parameters:    start_time  (string, ISO 8601): Start timestamp of the fasting window.   end_time  (string, ISO 8601, optional): End timestamp of the fasting window.   fasting_status  (enum: \"ACTIVE\", \"COMPLETED\", \"CANCELLED\", optional): Current status of the fast.   fasting_type  (string, optional): Type of fasting (e.g., \"Intermittent\").   log_sleep    Description:  Logs sleep details for a given date.   Parameters:    entry_date  (string, YYYY-MM-DD): The date of the sleep entry.   duration_seconds  (number, optional): Total sleep duration in seconds.   sleep_score  (number, optional): Sleep quality score (0-100).   bedtime  (string, ISO 8601, optional): Bedtime timestamp.   wake_time  (string, ISO 8601, optional): Wake up timestamp.   source  (string, optional): Source of data (e.g., \"manual\", \"Garmin\", \"Fitbit\").   list_checkin_diary    Description:  Retrieves all logged health check-in entries (biometrics, mood, sleep, custom metrics) for a specific date.   Parameters:    entry_date  (string, YYYY-MM-DD, optional): The date to retrieve the diary for. Defaults to today.",{"id":699,"path":700,"dir":670,"title":701,"description":702,"keywords":703,"body":705},"content:8.developer:10.mcp:4.coach.md","\u002Fdeveloper\u002Fmcp\u002Fcoach","Coaching and Trends Tool","Provides health summaries and analyzes long-term trends for coaching insights.",[704],"Tools within Coach","  Coaching and Trends Tool (  coachTools )  The   coachTools  are designed to provide high-level insights into a user's health status and long-term trends. It aggregates data from various sources (food, exercise, check-ins) to offer summaries and identify patterns relevant for health coaching.   Tool Name:    coachTools  (Note: This is a collection of tools, not a single one)  Tools within Coach   get_health_summary    Description:  Get a summary of the user's health status (Nutrition, Fitness, Vitals) for a specific date range.   Parameters:    start_date  (string, YYYY-MM-DD): Start date for the summary.   end_date  (string, YYYY-MM-DD, optional): End date for the summary. Defaults to   start_date  if not provided.   analyze_trends    Description:  Analyze weight trends vs. calorie intake to identify plateaus or progress. (Feature coming in full Phase 3 implementation!)   Parameters:    days  (number, optional): Number of days to analyze. Defaults to 7.   get_30_day_trends    Description:  Get comprehensive trends for the last 30 days including food, exercise, mood, sleep, and biometrics. This tool gathers aggregated data across these domains to provide a holistic view of the user's progress and patterns.   Parameters:    end_date  (string, YYYY-MM-DD, optional): End date for the 30-day period. Defaults to today.",{"id":707,"path":708,"dir":670,"title":709,"description":710,"keywords":711,"body":713},"content:8.developer:10.mcp:5.engagement.md","\u002Fdeveloper\u002Fmcp\u002Fengagement","Engagement and Nudge Tool","Tools for proactive user engagement, streak tracking, and contextual nudges.",[712],"Tools within Engagement","  Engagement and Nudge Tool (  proactiveTools )  The   proactiveTools  are designed to enhance user engagement through automated triggers, streak tracking, and context-aware nudges. These tools help to motivate users and provide timely, relevant feedback.   Tool Name:    proactiveTools  (Note: This is a collection of tools, not a single one)  Tools within Engagement   check_engagement_triggers    Description:  Scans the user's data for moments that require a proactive nudge (e.g., missed workout, plateau, achievement).   Parameters:    user_id  (string): The ID of the user to check. Defaults to   MOCK_USER_ID .   get_logging_streak    Description:  Retrieves the user's current consecutive logging streak for any health or fitness data.   Parameters:  None. (Note: Logic for streak calculation is a feature coming soon!)   get_contextual_nudge    Description:  Generates a context-aware nudge based on recent user activity or inactivity.   Parameters:  None. (Note: Logic for contextual nudge generation is a feature coming soon!)",{"id":715,"path":716,"dir":670,"title":717,"description":718,"keywords":719,"body":721},"content:8.developer:10.mcp:6.vision.md","\u002Fdeveloper\u002Fmcp\u002Fvision","Vision Integration Tools","Tools for analyzing images, such as food photos and nutrition labels.",[720],"Tools within Vision","  Vision Integration Tools (  visionTools )  The   visionTools  are designed to integrate computer vision capabilities into the SparkyFitness platform. These tools will enable the analysis of images, such as food photos for nutritional estimation and nutrition labels for data extraction.   Tool Name:    visionTools  (Note: This is a collection of tools, not a single one)  Tools within Vision   analyze_food_image    Description:  Analyzes an image of food to estimate its nutritional content. This tool will connect with advanced vision models (e.g., Gemini\u002FGPT-4o Vision) to provide macro and calorie estimations from visual data.   Parameters:    image_url  (string): Base64 encoded image data or a URL of the food image to be analyzed.   scan_label    Description:  Scans a nutrition label from an image to extract detailed nutritional information. This tool will utilize OCR and structured data extraction techniques to parse data from food packaging labels.   Parameters:    image_url  (string): Base64 encoded image data or a URL of the nutrition label image to be scanned.",{"id":723,"path":724,"dir":506,"title":725,"description":552,"keywords":726,"body":730},"content:8.developer:11.database-security-tiers.md","\u002Fdeveloper\u002Fdatabase-security-tiers","Database Security & RLS Tiers",[727,728,729],"Identity & Context Functions","The Three Security Tiers","System & Global Reference Tables (Public Read, Admin Write)","  Database Security & RLS Tiers   Last updated: 2026-07-08  SparkyFitness uses PostgreSQL Row-Level Security (RLS) to enforce strict data isolation between accounts, caregivers, family members, and third-party integrations (API keys). This document covers the security design, context switching mechanism, and the three-tier database table classifications.   Identity & Context Functions  PostgreSQL session variables are initialized at the start of every pool client transaction (via the   public.set_app_context(userId, authenticatedUserId)  helper). RLS policies evaluate access using these functions:     current_user_id() : Returns the ID of the   active profile context  being viewed (which changes during family delegation context switching; read from   app.user_id ).    authenticated_user_id() : Returns the ID of the   true authenticated logged-in actor  (which never changes during context switching; read from   app.authenticated_user_id ).    can_access_user_data(targetUserId, permissionType, authenticatedUserId) : Checks whether the authenticated user holds the given logical permission over the target user's data (  diary ,   checkin ,   medications ,   reports , and read-only   *_read  variants). Domain helpers such as   has_diary_read_access ,   has_checkin_read_access , and   has_medication_access  wrap it. Cycle and pregnancy are owner-only and are   not  delegatable.   The Three Security Tiers  All tables in the SparkyFitness database are classified into one of three security tiers to isolate data access according to the least-privilege principle:  Tier 1: Strictly Private (Owner-Only Read & Write)  These tables contain highly sensitive credentials, API keys, SSO tokens, 2FA recovery data, or private log histories.   Only the owner (  authenticated_user_id() ) can view or modify these records.  Family delegates and context-switched API keys have absolutely zero access.     Table Name  Description  Write (insert\u002Fupdate\u002Fdelete)  Read (select)     user  Account identity, password hash, role, email status  Owner-Only (  authenticated_user_id() )  Owner-Only    two_factor  Two-factor authentication (2FA) recovery codes and secrets  Owner-Only  Owner-Only    verification  Email verification tokens  Owner-Only  Owner-Only    api_key  User-generated API keys for external access  Owner-Only  Owner-Only    user_oidc_links  OpenID Connect SSO credentials links  Owner-Only  Owner-Only    passkey  Passkey credentials for passwordless login  Owner-Only  Owner-Only    session  Active user authentication sessions  Owner-Only  Owner-Only    passkey_registration_tickets  Short-lived (~60s), single-use tickets bridging the mobile→browser passkey registration handoff (transient session material)  System-Only (RLS on, no policies;   getSystemClient  only)  System-Only    account  Auth credentials and email accounts  Owner-Only  Owner-Only    sparky_chat_history  AI Assistant chat messages and history  Owner-Only  Owner-Only    user_ignored_updates  Records of skipped release updates  Owner-Only  Owner-Only    admin_activity_logs  Admin action audits  Admin-Only  Admin-Only    ai_service_settings  User-defined custom assistant configurations  Owner-Only  Owner-Only (Public configs readable by all)    cycle_settings  Cycle & pregnancy hub settings (mode, cycle parameters, birth control, conditions)  Owner-Only  Owner-Only    cycle_daily_entries  Per-day cycle logs (flow, period products, BBT, cervical mucus, moods, libido, notes)  Owner-Only  Owner-Only    cycles  Derived\u002Fmanually-corrected period & cycle history records  Owner-Only  Owner-Only    user_cycle_display_preferences  Private preference on cycle dashboard tile\u002Fcard visibility  Owner-Only  Owner-Only    user_mood_display_preferences  Personal show\u002Fhide config for the mood picker  Owner-Only  Owner-Only    cycle_test_entries  Ovulation (OPK) and pregnancy test logs  Owner-Only  Owner-Only    pregnancies  Pregnancy records (due date, status, linked prenatal medication)  Owner-Only  Owner-Only    pregnancy_kick_sessions  Fetal kick-counter sessions  Owner-Only  Owner-Only    pregnancy_contractions  Contraction timer logs  Owner-Only  Owner-Only    pregnancy_photos  Bump photo journal  Owner-Only  Owner-Only    pregnancy_checklist_state  Weekly pregnancy checklist completion\u002Fcustom items  Owner-Only  Owner-Only    health_appointments  Prenatal & other health appointments  Owner-Only  Owner-Only   Tier 2: View-Only Shared (Owner-Only Write, Delegate-Read)  These tables contain user profiles, layouts, display settings, and custom databases (like the foods\u002Fexercises database libraries). Switched delegates can view this data to render the dashboard, but only the account owner is allowed to create or edit them.     Table Name  Description  Write (insert\u002Fupdate\u002Fdelete)  Read (select)     profiles  User full name, height, and display metrics   Owner-Only  (  authenticated_user_id() )  Switched Delegate (  current_user_id() )    user_preferences  Unit display preferences (Metric vs Imperial)   Owner-Only  (  authenticated_user_id() )  Switched Delegate    user_nutrient_display_preferences  Rearranged nutrient column preferences   Owner-Only  Switched Delegate    user_medication_display_preferences  Private preference on GLP-1\u002FMedication display   Owner-Only  Delegate with   can_manage_medications  or   can_view_reports    user_dashboard_layouts  Rearranged dashboard widget positions   Owner-Only  Switched Delegate    onboarding_data  Initial user onboarding metrics   Owner-Only  Switched Delegate    onboarding_status  User onboarding status   Owner-Only  Switched Delegate    meal_types  Custom breakfast, lunch, dinner, snack layouts   Owner-Only  Switched Delegate with   can_manage_diary  or   can_view_reports    foods  Custom food items created by the user   Owner-Only  Delegate with   can_view_food_library ,   can_manage_diary , or   can_view_reports    food_variants  Serving options \u002F sizes for custom foods   Owner-Only  Delegate with   can_view_food_library ,   can_manage_diary , or   can_view_reports    meals  Custom meals created by the user   Owner-Only  Delegate with   can_view_food_library ,   can_manage_diary , or   can_view_reports    meal_foods  Ingredients assigned inside a custom meal — either a food (  food_id ) or a linked reusable sub-meal (  child_meal_id ,   item_type='meal' ). Writing a linked-meal row requires the caller to also have library access to the referenced sub-meal, in addition to owning the parent meal.   Owner-Only  (and the referenced food\u002Fsub-meal must be accessible to the owner)  Delegate with   can_view_food_library ,   can_manage_diary , or   can_view_reports    exercises  Custom exercises created by the user   Owner-Only  Delegate with   can_view_exercise_library ,   can_manage_diary , or   can_view_reports    workout_presets  Custom workouts\u002Fpresets created by the user   Owner-Only  Delegate with   can_view_exercise_library ,   can_manage_diary , or   can_view_reports    workout_preset_exercises  Exercises assigned inside a workout preset   Owner-Only  Delegate with   can_view_exercise_library ,   can_manage_diary , or   can_view_reports    workout_preset_exercise_sets  Reps\u002Fsets configured inside a preset exercise   Owner-Only  Delegate with   can_view_exercise_library ,   can_manage_diary , or   can_view_reports    workout_plan_templates  Templates for weekly workout schedules   Owner-Only  Delegate with   can_view_exercise_library ,   can_manage_diary , or   can_view_reports    external_data_providers  Configured API integrations (FatSecret, USDA)   Owner-Only  Delegate with   share_external_providers    family_access  Sharing rules & delegation credentials   Owner-Only  Owner or Switched Delegate    user_goals  Active daily calorie\u002Fmacro goals   Owner-Only  Delegate with   can_manage_diary  or   can_view_reports    user_nutrient_goal_preferences  Per-user minimum\u002Fmaximum\u002Ftarget goal direction override per nutrient   Owner-Only  Delegate with   can_manage_diary  or   can_view_reports    weekly_goal_plans  Scheduled goal plan adjustments   Owner-Only  Delegate with   can_manage_diary  or   can_view_reports    user_water_containers  Configured container sizes (e.g. 500ml bottle)   Owner-Only  Delegate with   can_manage_diary  or   can_view_reports   Tier 3: Delegate-Writable (Daily Logs & Schedules)  These tables contain daily diaries, logging entries, and scheduler items.   Caregivers\u002Fdelegates with active delegation permissions are granted full read and write access to log or modify data on behalf of the owner.  A. Diary Logs (Writable by delegates with   can_manage_diary  \u002F Readable by   can_view_reports  or   can_manage_diary )     Table Name  Description  Write (insert\u002Fupdate\u002Fdelete)  Read (select)     food_entries  Logged meals\u002Fcalories consumed for the day  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    food_entry_meals  Meal details associated with logged food entries  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    food_favorites  Starred (favorite) foods\u002Fmeals for quick re-logging  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    exercise_entries  Logged exercises\u002Fsets completed for the day  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    exercise_preset_entries  Logged workout presets for the day  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    exercise_entry_sets  Reps, weights, and sets completed for the logged exercises  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    exercise_entry_activity_details  Heart rate, distance, and activity details for workout logs  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    water_intake  Total water logged for the day  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    water_intake_entries  Individual logged water cups\u002Fcontainers for the day  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    meal_plan_template_assignments  Active meal templates scheduled to the calendar  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    workout_plan_template_assignments  Active workout templates scheduled to the calendar  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports    workout_plan_assignment_sets  Active sets scheduled in workout plans  Delegate with   can_manage_diary  Delegate with   can_manage_diary  or   can_view_reports  B. Medication & Symptom Logs (Writable by delegates with   can_manage_medications  \u002F Readable by   can_view_reports  or   can_manage_medications )     Table Name  Description  Write (insert\u002Fupdate\u002Fdelete)  Read (select)     medications  Custom medication inventory lists (e.g. insulin)  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    medication_schedules  Reminders\u002Fschedules to take medications  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    medication_entries  Logs of medications taken  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    medication_pens  Trackers for medication delivery pens  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    injection_entries  Injection logs (e.g., site of injection)  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    medication_titration_steps  Automated titration dosage plans  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    user_custom_symptoms  Custom tracked health symptoms  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    symptom_entries  Logs of daily tracked symptom severity  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports    user_custom_symptom_locations  Custom locations where symptoms occur  Delegate with   can_manage_medications  Delegate with   can_manage_medications  or   can_view_reports  C. Check-In & Wellness Logs (Writable by delegates with   can_manage_checkin  \u002F Readable by   can_view_reports  or   can_manage_checkin )     Table Name  Description  Write (insert\u002Fupdate\u002Fdelete)  Read (select)     check_in_measurements  Weight, neck, waist, hips measurements  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    check_in_photos  Progress photos  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    sleep_entries  Sleep logs (bedtime, wake time)  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    sleep_entry_stages  Sleep stage breakdowns (REM, Deep, Light)  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    sleep_need_calculations  AI sleep need calculations  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    daily_sleep_need  Sleep goals calculated for the day  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    fasting_logs  Logs of fasting timelines (start\u002Fend fast)  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    mood_entries  Logged mood and energy levels  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    day_classification_cache  Daily summary caching logs  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    custom_categories  User-defined custom measurement categories (e.g. GLP-1 daily check-in metrics)  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    custom_measurements  Logged values for custom measurement categories  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports    user_custom_moods  User-defined mood tags (icon\u002Fcolor) for the mood picker  Delegate with   can_manage_checkin  Delegate with   can_manage_checkin  or   can_view_reports   System & Global Reference Tables (Public Read, Admin Write)  These tables store global configuration settings, lookup values, and reference metadata. They do not contain user-specific data and do not have Row-Level Security enabled. All authenticated users can read them, but only administrators can update them.     Table Name  Description  Write (insert\u002Fupdate\u002Fdelete)  Read (select)     global_settings  Application global feature flags and system configurations  Admin-Only  Authenticated Users    backup_settings  Automated database backup timing and storage credentials  Admin-Only  Admin-Only    sso_provider  Active Single Sign-On providers (Google, Apple, etc.)  Admin-Only  Public (Login page)    oidc_providers  OpenID Connect integration settings and metadata  Admin-Only  Public    external_provider_types  Search provider configurations lookup (FATSecret, USDA)  Admin-Only  Authenticated Users    medication_types  Medication categories lookup (GLP-1, Insulin, ADHD, etc.)  Admin-Only  Authenticated Users    medication_route_types  Medication administration route lookup (Subcutaneous, Oral)  Admin-Only  Authenticated Users    medication_schedule_types  Medication scheduling frequencies lookup (Daily, Weekly)  Admin-Only  Authenticated Users",{"id":732,"path":733,"dir":7,"title":734,"description":735,"keywords":736,"body":737},"content:8.support-the-project.md","\u002Fsupport-the-project","Support The Project","You can support the SparkyFitness project by actively engaging with it. This includes:",[],"  Support The Project  You can support the SparkyFitness project by actively engaging with it. This includes:    Raising Enhancement Requests : Share your ideas for new features or improvements to existing ones. Your suggestions help us evolve the product.   Reporting Issues : If you encounter any bugs or unexpected behavior, please report them. Detailed issue reports are crucial for identifying and fixing problems, ensuring a better experience for everyone.  You can submit both enhancement requests and bug reports on our GitHub Issues page:   https:\u002F\u002Fgithub.com\u002FCodeWithCJ\u002FSparkyFitness\u002Fissues  Your feedback is invaluable in helping us improve SparkyFitness for the entire community.",{"id":739,"path":740,"dir":7,"title":741,"description":742,"keywords":743,"body":753},"content:9.privacy_policy.md","\u002Fprivacy_policy","Privacy Policy","SparkyFitness is committed to protecting your privacy. This Privacy Policy explains how information is handled when you use the SparkyFitness mobile application.",[8,744,745,746,747,748,749,750,751,752],"Data Collection and Handling","How Your Information Is Used","Data Storage and Security","Data Retention and Deletion","Third-Party Services","Children’s Privacy","Limitation of Liability","Changes to This Privacy Policy","Contact Us","  Privacy Policy  SparkyFitness is committed to protecting your privacy. This Privacy Policy explains how information is handled when you use the SparkyFitness mobile application.  Overview  SparkyFitness is designed with a privacy-first architecture. The app does not collect, store, or process personal or health data on SparkyFitness-operated servers. All data remains under your control on your device and, if configured by you, on your own self-hosted SparkyFitness server.  Data Collection and Handling  Information You Provide and Control    Self-Hosted Server Connection Information:  If you choose to enable synchronization with a self-hosted SparkyFitness server, the app stores your server URL and authentication token   locally on your device . This information is used only to connect to your server and is never transmitted to SparkyFitness or any third party.   Health Data:  With your explicit permission, the app may access health data provided by platform services such as Apple Health or Google Health Connect. This data is:   Accessed only for app functionality  Stored locally on your device  Synced only to your self-hosted SparkyFitness server, if configured  SparkyFitness does not receive, store, or process this data.   Camera:  Sparky accesses your device's camera for two purposes: (1) scanning barcodes on food packaging, which is decoded entirely on your device — no image is transmitted, and (2) capturing nutrition label photos, which are transmitted to your Sparky server only when you have enabled this optional feature.   AI-Powered Nutrition Label Scanning:  This feature is disabled by default. When you enable it, nutrition label images are sent from your device to your Sparky server, which then forwards them to a cloud AI provider you have configured on the server (e.g., OpenAI, Google, Anthropic). Your AI provider credentials are never stored on your mobile device. The mobile app has no knowledge of which AI provider is configured.   Your Server is Yours:  Because Sparky is self-hosted, your server's data handling, retention, and AI provider choices are governed by your own configuration and the privacy policies of any AI provider you choose to integrate. We do not have access to your server or its data.  Information We Do Not Collect    Personal identifiers  (name, email, address, etc.)   Health or fitness data  on SparkyFitness servers   Usage analytics  or tracking data   Advertising identifiers   Device or network identifiers  How Your Information Is Used  All data handled by the app is used solely to provide core functionality, including displaying fitness information and synchronizing with your self-hosted server. We do not sell, rent, share, or monetize user data in any way.  Data Storage and Security   Data is stored   locally on your device  using platform-provided security mechanisms.  If enabled, data is transmitted directly to your   self-hosted server .  SparkyFitness does not operate or have access to these servers.  Data Retention and Deletion  SparkyFitness does not retain user data on developer-operated servers.  On-device data   Health data and configuration data are stored locally on the user’s device.  This data is retained only for as long as the app remains installed or until the user deletes it.  Deleting data   Users can delete all locally stored data at any time by clearing the app’s data or uninstalling the SparkyFitness app from their device.  Once the app is uninstalled, all locally stored data is permanently removed from the device.  User Self-hosted server data   If the user enables synchronization, health data is stored on the user’s own self-hosted SparkyFitness server.  Data retention and deletion on the self-hosted server are fully controlled by the user.  Users can delete their server-side data at any time by removing it from their self-hosted SparkyFitness server.  SparkyFitness does not have access to, cannot delete, and does not retain any user data stored on user-managed servers.  Third-Party Services  SparkyFitness does not use third-party analytics, advertising, or tracking services. Any data stored on your self-hosted server is governed by your own server configuration and security practices.  Children’s Privacy  SparkyFitness is not intended for children under the age of 13. We do not knowingly collect personal information from children.  Limitation of Liability  The SparkyFitness mobile application is provided \"as is,\" without warranty of any kind, express or implied. The developer of SparkyFitness shall not be liable for any damages, direct or indirect, arising from the use or inability to use the application, including but not limited to data loss, system errors, or any other issues that may arise.  Users are solely responsible for the security and integrity of their self-hosted SparkyFitness server and any data stored thereon. The developer is not responsible for any breaches, data loss, or other security incidents that may occur on a user's self-hosted server.  Changes to This Privacy Policy  Developer reserves the right to change or modify this Privacy Policy at any time, and any changes will be effective upon being posted unless otherwise indicated. You are encouraged to periodically review this policy for the latest information on privacy practices. If you do not accept the terms of this Privacy Policy, you are asked to discontinue using SparkyFitness.  Contact Us  If you have any questions about this Privacy Policy, please contact us at:   codewithcj001@gmail.com",1784905756880]