Skip to content

Commit 05c944a

Browse files
authored
Merge pull request #2 from StuMason/feature/htmx-admin-panel
feat: Complete V3 API Integration with HTMX Admin Panel
2 parents ac3818a + 8841209 commit 05c944a

39 files changed

+2815
-158
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ logs/
6969
# Documentation
7070
site/
7171
.mkdocs_cache/
72+
docs/local/
7273

7374
# Environment
7475
.env.local

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
77
WORKDIR /app
88

99
# Copy project files
10-
COPY pyproject.toml .
10+
COPY pyproject.toml uv.lock README.md ./
1111
COPY src/ src/
1212

1313
# Install dependencies

README.md

Lines changed: 77 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -8,153 +8,127 @@ Polar devices collect health data: sleep, HRV, activity, exercises. The Polar AP
88

99
This server:
1010

11-
1. Syncs data from Polar API automatically
11+
1. Syncs all 9 Polar API endpoints automatically
1212
2. 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
1515
5. 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

4238
1. Go to [admin.polaraccesslink.com](https://admin.polaraccesslink.com)
4339
2. 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`
4541
4. 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
6246
git clone https://github.com/StuMason/polar-flow-server.git
6347
cd polar-flow-server
64-
65-
# Start PostgreSQL + API server
6648
docker-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

12687
Environment variables (see `.env.example`):
12788

12889
```bash
129-
# Database (PostgreSQL required)
90+
# Database
13091
DATABASE_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
13697
SYNC_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
151125
uv sync --all-extras
152126

153127
# Start PostgreSQL
154128
docker-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
160134
uv run pytest
@@ -163,56 +137,28 @@ uv run pytest
163137
uv 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

docker-compose.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,18 @@ services:
2020
depends_on:
2121
postgres:
2222
condition: service_healthy
23+
env_file:
24+
- .env
2325
environment:
2426
DATABASE_URL: postgresql+asyncpg://polar:polar@postgres:5432/polar
2527
DEPLOYMENT_MODE: self_hosted
26-
SYNC_ON_STARTUP: "true"
28+
SYNC_ON_STARTUP: "false"
2729
SYNC_INTERVAL_HOURS: 1
28-
LOG_LEVEL: INFO
30+
LOG_LEVEL: DEBUG
2931
volumes:
3032
- ~/.polar-flow:/root/.polar-flow
33+
- ./src:/app/src # Mount source for hot reload
34+
command: uv run uvicorn polar_flow_server.app:app --host 0.0.0.0 --port 8000 --reload
3135
ports:
3236
- "8000:8000"
3337
restart: unless-stopped

0 commit comments

Comments
 (0)