working
This commit is contained in:
199
SPECIFICATION.md
Normal file
199
SPECIFICATION.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# Project Specification: Fitbit-Garmin Local Sync
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
### 1.1. Project Purpose
|
||||
|
||||
The Fitbit-Garmin Local Sync is a standalone Python application designed to synchronize health and fitness data between the Fitbit and Garmin Connect platforms. Its primary functions are to transfer weight data from Fitbit to Garmin, archive activity files from Garmin to a local directory, and download a wide range of Garmin health metrics for local storage and analysis.
|
||||
|
||||
The application runs as a self-contained web server with a simple, browser-based user interface. It is designed for simple, private deployment and operates without external cloud services, using a PostgreSQL database for all configuration, credential storage, and state management.
|
||||
|
||||
### 1.2. Key Goals
|
||||
|
||||
* **Simplicity:** Easy to deploy and use via a simple web UI.
|
||||
* **Privacy:** All sensitive data (credentials, tokens, health stats) is stored locally.
|
||||
* **Control:** All operations are triggered by the user through buttons in the web interface.
|
||||
* **Resilience:** Robust error handling and state tracking to prevent duplicate data and manage API failures.
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Features
|
||||
|
||||
### 2.1. Weight Data Synchronization (Fitbit to Garmin)
|
||||
* Fetches weight history from the Fitbit API.
|
||||
* Securely uploads new weight entries to the Garmin Connect API.
|
||||
* Maintains a persistent record of synced entries in the PostgreSQL database to prevent duplicate uploads.
|
||||
|
||||
### 2.2. Activity Data Archiving (Garmin to Local)
|
||||
* Fetches a list of historical activities from the Garmin Connect API.
|
||||
* Downloads the original, high-fidelity activity file (e.g., `.fit`, `.gpx`, `.tcx`).
|
||||
* Saves the activity files to a structured local directory.
|
||||
* Maintains a persistent record of downloaded activities to prevent duplicate downloads.
|
||||
|
||||
### 2.3. Garmin Health Metrics Download
|
||||
* Downloads a comprehensive range of available health metrics from Garmin Connect. This includes, but is not limited to:
|
||||
* Daily summaries (steps, calories, distance, intensity minutes)
|
||||
* Heart rate data (resting, max, daily averages)
|
||||
* Sleep data (stages, duration, scores)
|
||||
* Body composition (weight, BMI, body fat - if available from Garmin itself)
|
||||
* Stress levels
|
||||
* Body Battery
|
||||
* Respiration rate
|
||||
* SpO2
|
||||
* Training readiness and load
|
||||
* Recovery advisor
|
||||
* All available activity data and metrics
|
||||
* Stores these metrics in the PostgreSQL database for historical tracking and analysis.
|
||||
|
||||
### 2.4. Enhanced Garmin Client Capabilities
|
||||
* Extends the `GarminClient` to support downloading all available metrics from Garmin Connect, including but not limited to:
|
||||
* Detailed activity data with all associated metrics
|
||||
* Historical health metrics across all available categories
|
||||
* Extended sleep analysis data
|
||||
* Advanced training and fitness metrics
|
||||
* Comprehensive wellness data
|
||||
* Includes robust error handling and retry mechanisms for reliable data retrieval.
|
||||
|
||||
### 2.5. Extended API Interface for Querying
|
||||
* Enhances the backend API to support querying and listing of metrics and activities:
|
||||
* `GET /api/metrics/list`: Returns a list of available metric types and date ranges
|
||||
* `GET /api/metrics/query`: Allows filtering and retrieval of specific metrics by date range, type, or other criteria
|
||||
* `GET /api/activities/list`: Returns metadata for all downloaded/available activities
|
||||
* `GET /api/activities/query`: Allows advanced filtering of activities by type, date, duration, etc.
|
||||
* `GET /api/health-data/summary`: Provides aggregated health statistics
|
||||
* Provides JSON responses optimized for both UI display and external integration.
|
||||
|
||||
### 2.6. Local Data Persistence
|
||||
* Utilizes PostgreSQL database to maintain all application state and configuration.
|
||||
* Configuration data includes Fitbit/Garmin API credentials, OAuth tokens, and sync settings.
|
||||
* Weight records are stored with unique IDs to prevent duplicate processing and sync tracking.
|
||||
* Sync logs and status information are maintained for monitoring and troubleshooting.
|
||||
* All health metrics and activity metadata are stored in structured database tables.
|
||||
* Supports ACID transactions for data consistency and integrity.
|
||||
|
||||
---
|
||||
|
||||
## 3. Application Architecture
|
||||
|
||||
### 3.1. Core Components
|
||||
|
||||
The application will be built in Python 3 using the FastAPI framework to serve both a web interface and a backend API.
|
||||
|
||||
1. **`main.py`**: The entry point of the application. It will define the FastAPI app, create the UI and API routes, and run the Uvicorn server.
|
||||
2. **`templates/`**: A directory containing Jinja2 HTML templates for the web interface.
|
||||
3. **`static/`**: A directory containing CSS and client-side JavaScript files.
|
||||
4. **`PostgreSQLManager`**: The data access layer for the PostgreSQL database.
|
||||
5. **`FitbitClient`**: The service layer for the Fitbit API.
|
||||
6. **`GarminClient`**: The enhanced service layer for the Garmin Connect API. This will include methods for fetching all available health metrics (e.g., `get_daily_summary`, `get_sleep_data`, `get_heart_rates`, `get_all_metrics`, `get_training_readiness`, etc.) and advanced activity data.
|
||||
7. **`SyncApp`**: The main application controller. It will be instantiated by API routes to perform sync tasks. This will include new methods for orchestrating the download and storage of Garmin health metrics (e.g., `sync_garmin_metrics()`) and enhanced querying capabilities.
|
||||
|
||||
### 3.2. Authentication Flows
|
||||
|
||||
#### 3.2.1. Fitbit API Authentication
|
||||
The application implements OAuth 2.0 flow with the following steps:
|
||||
1. Checks for existing Fitbit credentials (Client ID, Client Secret, Access Token, Refresh Token) in the PostgreSQL database.
|
||||
2. If credentials are missing, prompts the user to enter Client ID and Client Secret via the UI.
|
||||
3. Generates an authorization URL using the Fitbit API and redirects the user to grant permissions.
|
||||
4. Captures the authorization callback URL containing the code.
|
||||
5. Exchanges the authorization code for access and refresh tokens.
|
||||
6. Stores the tokens securely in the PostgreSQL database.
|
||||
7. Uses the refresh token callback mechanism to automatically refresh tokens when they expire.
|
||||
|
||||
#### 3.2.2. Garmin Connect Authentication
|
||||
The application implements authentication using the garth library with the following steps:
|
||||
1. Checks for existing Garmin credentials (username, password) in the PostgreSQL database.
|
||||
2. Checks for existing OAuth1/OAuth2 tokens stored from previous sessions in the database.
|
||||
3. If no tokens exist, performs a fresh login using username/password with garth.
|
||||
4. Creates a GarminConnect client instance using the garth authentication tokens.
|
||||
5. Saves the OAuth tokens to the PostgreSQL database for reuse in subsequent sessions.
|
||||
6. Implements automatic re-authentication if API returns 401 unauthorized errors.
|
||||
7. Supports both global (garmin.com) and China (garmin.cn) domains.
|
||||
|
||||
### 3.3. Data Flow Example: Weight Sync
|
||||
|
||||
1. User clicks the "Sync Weight" button on the web interface.
|
||||
2. Client-side JavaScript sends a request to the `POST /api/sync/weight` endpoint.
|
||||
3. The API handler in `main.py` triggers the `SyncApp.sync_weight()` method as a background task.
|
||||
4. The backend logic proceeds as previously defined (fetch from Fitbit, save to DB, get unsynced, upload to Garmin, mark as synced).
|
||||
5. The web UI receives a confirmation and can periodically poll a status endpoint to show progress or completion.
|
||||
|
||||
---
|
||||
|
||||
## 4. PostgreSQL Database Schema
|
||||
|
||||
The PostgreSQL database will use the following tables for storing application data:
|
||||
* `config`: Contains all application configuration (API credentials, tokens, sync settings)
|
||||
* `weight_records`: Individual weight records with unique IDs, timestamps, and sync status
|
||||
* `activities`: Activity metadata including download status and file paths
|
||||
* `health_metrics`: Stores all Garmin health metrics with timestamps and metric types
|
||||
* `sync_logs`: Sync operation logs with timestamps, status, and results
|
||||
* `api_tokens`: OAuth tokens for Fitbit and Garmin with expiration tracking
|
||||
|
||||
---
|
||||
|
||||
## 5. Web Interface and User Flow
|
||||
|
||||
The user interacts with the application through a simple, multi-page web interface.
|
||||
|
||||
### 5.1. Page: Status (Home)
|
||||
|
||||
* **URL**: `/`
|
||||
* **Content**:
|
||||
* A dashboard showing the current sync status (total records, synced vs. unsynced counts for weight and activities).
|
||||
* A table displaying recent sync log entries.
|
||||
* A "Sync Weight" button.
|
||||
* A "Sync Activities" button with an input for the number of days to look back.
|
||||
* A navigation link to the Setup page.
|
||||
|
||||
### 5.2. Page: Setup
|
||||
|
||||
* **URL**: `/setup`
|
||||
* **Content**:
|
||||
* A form to enter and save Garmin Connect `username` and `password`.
|
||||
* A form to enter and save Fitbit `Client ID` and `Client Secret`.
|
||||
* A display of the current Fitbit authorization status and a link to the Fitbit authorization URL.
|
||||
* An input field for the user to paste the full callback URL from their browser after authorizing the Fitbit app, with a button to submit it and complete the OAuth flow.
|
||||
|
||||
### 5.3. Backend API for UI
|
||||
|
||||
The web interface will be powered by a set of internal API endpoints.
|
||||
|
||||
* `GET /api/status`: Provides JSON data for the status dashboard.
|
||||
* `GET /api/logs`: Provides JSON data for the sync logs table.
|
||||
* `POST /api/sync/weight`: Triggers the weight sync.
|
||||
* `POST /api/sync/activities`: Triggers the activity sync.
|
||||
* `POST /api/setup/garmin`: Saves Garmin credentials from the setup form.
|
||||
* `POST /api/setup/fitbit`: Saves Fitbit credentials and returns the auth URL.
|
||||
* `POST /api/setup/fitbit/callback`: Completes the Fitbit OAuth flow.
|
||||
* `GET /api/metrics/list`: Returns a list of available metric types and date ranges.
|
||||
* `GET /api/metrics/query`: Allows filtering and retrieval of specific metrics by date range, type, or other criteria.
|
||||
* `GET /api/activities/list`: Returns metadata for all downloaded/available activities.
|
||||
* `GET /api/activities/query`: Allows advanced filtering of activities by type, date, duration, etc.
|
||||
* `GET /api/health-data/summary`: Provides aggregated health statistics.
|
||||
|
||||
---
|
||||
|
||||
## 6. Project Dependencies
|
||||
|
||||
* **`fastapi`**: The web framework for building the API and serving the UI.
|
||||
* **`uvicorn`**: The ASGI server to run the application.
|
||||
* **`Jinja2`**: For rendering HTML templates.
|
||||
* **`fitbit`**: Python client for the Fitbit API.
|
||||
* **`garminconnect`**: Python client for the Garmin Connect API.
|
||||
* **`garth`**: Handles authentication for `garminconnect`.
|
||||
* **`psycopg2`** or **`asyncpg`**: PostgreSQL database adapter.
|
||||
* **`SQLAlchemy`**: Database toolkit and ORM for Python.
|
||||
|
||||
---
|
||||
|
||||
## 7. Deployment
|
||||
|
||||
A `Dockerfile` will be provided to build a container image for easy deployment.
|
||||
|
||||
* The container will be based on a slim Python 3 image.
|
||||
* It will copy the application code and install dependencies from `requirements.txt`.
|
||||
* Requires access to a PostgreSQL database for configuration and state storage.
|
||||
* Connection parameters can be provided via environment variables or configuration UI.
|
||||
* A volume must be mounted at `/app/data` to ensure persistence of all downloaded activity files.
|
||||
* The server will run on port 8000, which must be exposed.
|
||||
* The command for the container will be: `uvicorn main:app --host 0.0.0.0 --port 8000`.
|
||||
Reference in New Issue
Block a user