@@ -8,153 +8,127 @@ Polar devices collect health data: sleep, HRV, activity, exercises. The Polar AP
88
99This server:
1010
11- 1 . Syncs data from Polar API automatically
11+ 1 . Syncs all 9 Polar API endpoints automatically
12122 . Stores everything in PostgreSQL (your data, your server)
13- 3 . Runs analytics (HRV baselines, recovery scores, sleep debt)
14- 4 . Exposes REST API for dashboards and integrations
13+ 3 . Provides an HTMX-powered admin dashboard
14+ 4 . Exposes REST API for custom integrations
15155 . Multi-user ready (same codebase for self-hosted and SaaS)
1616
1717## Architecture
1818
1919```
20- Polar API → polar-flow SDK → Sync Service → PostgreSQL → Analytics → REST API
21- ↓
22- Laravel/Dashboard
20+ Polar API → polar-flow SDK → Sync Service → PostgreSQL
21+ ↓
22+ Admin Dashboard (HTMX)
23+ ↓
24+ REST API
2325```
2426
25- ** Python data analytics engine :**
27+ ** Stack :**
2628- Litestar (async web framework)
2729- SQLAlchemy 2.0 (async ORM)
28- - PostgreSQL (self-hosted or shared with Laravel)
29- - Polars (data processing)
30- - Strict type checking with mypy
31-
32- ** Multi-tenancy:**
33- - Every table includes ` user_id ` column
34- - All API endpoints scoped by ` user_id `
35- - Self-hosted: one user, SaaS: many users
36- - Same codebase for both modes
30+ - PostgreSQL
31+ - HTMX + Tailwind (admin UI)
32+ - polar-flow SDK v1.3.0
3733
3834## Quick Start
3935
4036### 1. Get Polar API Credentials
4137
42381 . Go to [ admin.polaraccesslink.com] ( https://admin.polaraccesslink.com )
43392 . Create a new client
44- 3 . Set redirect URI to ` http://localhost:8888 /callback `
40+ 3 . Set redirect URI to ` http://localhost:8000/admin/oauth /callback `
45414 . Note your ` CLIENT_ID ` and ` CLIENT_SECRET `
4642
47- ### 2. Authenticate with Polar
48-
49- ``` bash
50- # Authenticate to get your token
51- docker run -it --rm \
52- -e CLIENT_ID=your_client_id \
53- -e CLIENT_SECRET=your_client_secret \
54- -v ~ /.polar-flow:/root/.polar-flow \
55- ghcr.io/stumason/polar-flow-server:latest \
56- polar-flow auth
57- ```
58-
59- ### 3. Start with Docker Compose
43+ ### 2. Start with Docker Compose
6044
6145``` bash
6246git clone https://github.com/StuMason/polar-flow-server.git
6347cd polar-flow-server
64-
65- # Start PostgreSQL + API server
6648docker-compose up -d
67-
68- # Check health
69- curl http://localhost:8000/health
70-
71- # View logs
72- docker-compose logs -f
7349```
7450
75- The server starts syncing data every hour automatically.
76-
77- ## API Usage
51+ ### 3. Connect Your Polar Account
7852
79- All endpoints are scoped by ` user_id ` :
53+ 1 . Open http://localhost:8000/admin
54+ 2 . Enter your Polar OAuth credentials
55+ 3 . Click "Connect with Polar" to authorize
56+ 4 . Hit "Sync Now" to pull your data
8057
81- ``` bash
82- # Get your Polar user ID (stored during auth)
83- export USER_ID=$( cat ~ /.polar-flow/user_id)
84- export TOKEN=$( cat ~ /.polar-flow/token)
85-
86- # Get sleep data
87- curl " http://localhost:8000/api/v1/users/$USER_ID /sleep?days=30"
88-
89- # Get sleep for specific date
90- curl " http://localhost:8000/api/v1/users/$USER_ID /sleep/2026-01-09"
91-
92- # Trigger manual sync
93- curl -X POST \
94- -H " X-Polar-Token: $TOKEN " \
95- " http://localhost:8000/api/v1/users/$USER_ID /sync/trigger"
96- ```
58+ The server syncs data every hour automatically.
9759
98- Visit ` http://localhost:8000/docs ` for interactive API documentation.
60+ ## Dashboard
9961
100- ## Data Stored
62+ The admin panel at ` /admin/dashboard ` shows:
10163
102- ** Sleep:**
103- - Sleep score, stages (light/deep/REM)
104- - HRV average and samples
105- - Heart rate (avg/min/max)
106- - Breathing rate, skin temperature
64+ - ** Key Metrics** - HRV, Heart Rate, Training Strain, Alertness, Sleep Score
65+ - ** Record Counts** - All 9 data types with totals
66+ - ** Recent Sleep** - Last 7 days with scores
67+ - ** Nightly Recharge** - HRV, ANS charge, recovery status
68+ - ** Training Load** - Strain, tolerance, load ratio
69+ - ** Continuous HR** - Daily min/avg/max heart rate
10770
108- ** Nightly Recharge:**
109- - ANS charge (autonomic nervous system)
110- - Sleep charge and status
111- - HRV, heart rate, breathing rate status
71+ ## Data Synced (9 Endpoints)
11272
113- ** Daily Activity:**
114- - Steps, distance, calories
115- - Active time, inactivity alerts
116- - Activity score
117-
118- ** Exercises:**
119- - Sport type, duration, distance
120- - Heart rate zones and averages
121- - Pace, cadence, power
122- - Training load
73+ | Endpoint | Data |
74+ | ----------| ------|
75+ | ** Sleep** | Score, stages (light/deep/REM), duration |
76+ | ** Nightly Recharge** | HRV, ANS charge, recovery status |
77+ | ** Daily Activity** | Steps, distance, calories, active time |
78+ | ** Exercises** | Sport, duration, HR zones, training load |
79+ | ** Cardio Load** | Strain, tolerance, load ratio, status |
80+ | ** SleepWise Alertness** | Hourly alertness predictions |
81+ | ** SleepWise Bedtime** | Optimal sleep timing recommendations |
82+ | ** Activity Samples** | Minute-by-minute step data |
83+ | ** Continuous HR** | All-day heart rate (5-min intervals) |
12384
12485## Configuration
12586
12687Environment variables (see ` .env.example ` ):
12788
12889``` bash
129- # Database (PostgreSQL required)
90+ # Database
13091DATABASE_URL=postgresql+asyncpg://polar:polar@postgres:5432/polar
13192
13293# Deployment mode
133- DEPLOYMENT_MODE=self_hosted # or 'saas' for Laravel integration
94+ DEPLOYMENT_MODE=self_hosted
13495
13596# Sync settings
13697SYNC_INTERVAL_HOURS=1
137- SYNC_ON_STARTUP=true
138- SYNC_DAYS_LOOKBACK=30
98+ SYNC_ON_STARTUP=false
99+ SYNC_DAYS_LOOKBACK=28
139100
140- # API
141- API_HOST=0.0.0.0
142- API_PORT=8000
101+ # Optional: Set explicit encryption key (auto-generated otherwise)
102+ # ENCRYPTION_KEY=your-32-byte-fernet-key
103+ ```
104+
105+ ## API Endpoints
106+
107+ ``` bash
108+ # Health check
109+ curl http://localhost:8000/health
110+
111+ # Get sleep data (last 7 days)
112+ curl " http://localhost:8000/api/users/{user_id}/sleep?days=7"
113+
114+ # Get sleep for specific date
115+ curl " http://localhost:8000/api/users/{user_id}/sleep/2026-01-10"
116+
117+ # Trigger manual sync (via admin panel recommended)
118+ curl -X POST http://localhost:8000/admin/sync
143119```
144120
145121## Development
146122
147123``` bash
148- # Clone and install
149- git clone https://github.com/StuMason/polar-flow-server.git
150- cd polar-flow-server
124+ # Install dependencies
151125uv sync --all-extras
152126
153127# Start PostgreSQL
154128docker-compose up -d postgres
155129
156130# Run server with hot reload
157- uv run polar-flow-server serve --reload
131+ uv run uvicorn polar_flow_server.app:app --reload
158132
159133# Run tests
160134uv run pytest
@@ -163,56 +137,28 @@ uv run pytest
163137uv run mypy src/polar_flow_server
164138
165139# Lint
166- uv run ruff check src/ tests/
140+ uv run ruff check src/
167141```
168142
169- ## SaaS Integration (Laravel)
170-
171- For managed hosting with Laravel:
172-
173- 1 . Share PostgreSQL database between Laravel and Python service
174- 2 . Laravel manages users, billing, auth
175- 3 . Python service handles data sync and analytics
176- 4 . Laravel calls Python API for data retrieval
177-
178- ``` php
179- // Laravel example
180- $response = Http::get("http://python-service:8000/api/v1/users/{$user->id}/sleep");
181- $sleepData = $response->json();
182- ```
143+ ## Multi-Tenancy
183144
184- ## Analytics (Coming Soon)
145+ The server supports multiple users out of the box:
185146
186- - HRV baselines (7/30/60-day rolling medians)
187- - Recovery score calculation
188- - Sleep debt tracking
189- - Training load analysis
190- - Injury risk prediction
191- - ML-powered insights
192-
193- ## Documentation
194-
195- Full documentation: [ stumason.github.io/polar-flow-server] ( https://stumason.github.io/polar-flow-server/ )
196-
197- - [ Quick Start] ( https://stumason.github.io/polar-flow-server/quickstart/ )
198- - [ API Reference] ( https://stumason.github.io/polar-flow-server/api/overview/ )
199- - [ Architecture] ( https://stumason.github.io/polar-flow-server/architecture/ )
200- - [ Deployment] ( https://stumason.github.io/polar-flow-server/deployment/self-hosted/ )
201-
202- ## License
147+ - Every table includes ` user_id ` column
148+ - All queries scoped by ` user_id `
149+ - Self-hosted: typically one user
150+ - SaaS: many users, same codebase
203151
204- MIT
152+ For SaaS deployment, set ` DEPLOYMENT_MODE=saas ` and provide ` ENCRYPTION_KEY ` .
205153
206154## Built With
207155
208- - [ polar-flow] ( https://github.com/StuMason/polar-flow ) - Modern Python SDK for Polar AccessLink API
156+ - [ polar-flow] ( https://github.com/StuMason/polar-flow ) - Python SDK for Polar AccessLink API
209157- [ Litestar] ( https://litestar.dev/ ) - Async web framework
210158- [ SQLAlchemy] ( https://www.sqlalchemy.org/ ) - Async ORM
211- - [ PostgreSQL] ( https://www.postgresql.org/ ) - Database
212- - [ Polars] ( https://pola.rs/ ) - Data processing
213-
214- ## Managed Service
159+ - [ HTMX] ( https://htmx.org/ ) - Admin UI interactions
160+ - [ Tailwind CSS] ( https://tailwindcss.com/ ) - Styling
215161
216- Want dashboards, mobile apps, and support without self-hosting?
162+ ## License
217163
218- Check out [ stumason.dev ] ( https://stumason.dev ) - managed service built with this engine + Laravel.
164+ MIT
0 commit comments