Skip to content

Architecture

Technical architecture of polar-flow-server.

System Overview

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Polar API     │────▶│  Sync Service   │────▶│    Database     │
│  (AccessLink)   │     │  (polar-flow)   │     │ (PostgreSQL/    │
└─────────────────┘     └─────────────────┘     │    DuckDB)      │
                                                 └────────┬────────┘
                                                          │
                        ┌─────────────────┐               │
                        │   REST API      │◀──────────────┘
                        │   (Litestar)    │
                        └────────┬────────┘
                                 │
              ┌──────────────────┼──────────────────┐
              │                  │                  │
              ▼                  ▼                  ▼
        ┌──────────┐      ┌──────────┐      ┌──────────┐
        │Dashboard │      │  Mobile  │      │   MCP    │
        │  (Web)   │      │   App    │      │ (Claude) │
        └──────────┘      └──────────┘      └──────────┘

Components

Sync Service

Fetches data from Polar AccessLink API using the polar-flow SDK.

Responsibilities: - Authenticate with Polar API using OAuth2 tokens - Fetch all data types (sleep, activity, exercises, etc.) - Transform SDK models to database schemas - Upsert records (insert or update on conflict)

Data flow: 1. SDK fetches JSON from Polar API 2. Pydantic models validate and parse response 3. Transformers convert SDK models to database dicts 4. SQLAlchemy upserts records by unique key

Transformers

Bridge between SDK models and database schemas. Located in src/polar_flow_server/transformers/.

Each transformer: - Accepts SDK model + user_id - Returns dict ready for database insertion - Handles field name mapping (SDK → DB) - Performs type conversions (timestamps, JSON serialization)

Example:

from polar_flow_server.transformers import SleepTransformer

# SDK model from polar-flow
sdk_sleep = await client.sleep.list()

# Transform to database dict
db_dict = SleepTransformer.transform(sdk_sleep[0], user_id="12345")

Database Models

SQLAlchemy 2.0 async models in src/polar_flow_server/models/.

Core tables: - sleep - Nightly sleep data with stages, HRV, vitals - nightly_recharge - ANS charge, recovery status - activity - Daily steps, calories, active time - exercise - Workouts with duration, distance, HR

Analytics tables: - cardio_load - Training strain and tolerance - sleepwise_alertness - Hourly alertness predictions - sleepwise_bedtime - Optimal sleep timing - continuous_hr - Daily heart rate summaries - activity_samples - Minute-by-minute activity

Biosensing tables: - spo2 - Blood oxygen measurements - ecg - ECG recordings with waveforms - body_temperature - Continuous body temp - skin_temperature - Nightly skin temp

All tables include: - id (auto-increment primary key) - user_id (string, for multi-tenancy) - created_at, updated_at (timestamps)

REST API

Litestar async web framework serving JSON endpoints.

Structure: - /api/v1/users/{user_id}/... - User-scoped data endpoints - /api/v1/users/{user_id}/sync/trigger - Manual sync trigger - /health - Health check - /admin/... - Admin dashboard (if enabled)

Database sessions: - Injected via Litestar dependency injection - Async SQLAlchemy sessions - Connection pooling via asyncpg (PostgreSQL) or aiosqlite (DuckDB)

Multi-Tenancy

Every database query is scoped by user_id:

stmt = (
    select(Sleep)
    .where(Sleep.user_id == user_id)
    .where(Sleep.date >= since_date)
)

Self-hosted mode: - Single user - user_id = Polar API user ID - DuckDB for simple deployment

SaaS mode: - Multiple users - user_id = Your application's user ID (e.g., Laravel UUID) - PostgreSQL for production

Configuration

Environment variables via Pydantic Settings:

Variable Description Default
DATABASE_URL Database connection string sqlite+aiosqlite:///./data.db
SYNC_DAYS_LOOKBACK Days to sync by default 28
POLAR_TOKEN_PATH Path to token file ~/.polar-flow/token
LOG_LEVEL Logging level INFO
ADMIN_ENABLED Enable admin dashboard false

Tech Stack

  • Framework: Litestar (async, high-performance)
  • ORM: SQLAlchemy 2.0 (async)
  • Database: PostgreSQL (prod) / DuckDB (self-hosted)
  • SDK: polar-flow (Polar API client)
  • Validation: Pydantic 2
  • Logging: structlog (structured JSON logs)
  • Type checking: mypy strict mode