Your health data belongs to you. Track it on your own terms.
A self-hosted, privacy-first health tracking PWA.
Weight, blood pressure, mood, medications, AI insights -- all under your control.
Website · Live Demo · Documentation
Most health apps lock your data behind proprietary clouds, push subscriptions, and sell your metrics to advertisers. HealthLog takes a different approach: your data stays on your server, encrypted at rest, accessible only to you.
Health Metrics -- Track weight, blood pressure, pulse, body fat, sleep, and steps with interactive trend charts, moving averages, and traffic-light ranges based on ESC/ESH 2018 guidelines.
Mood Logging -- 5-point scale with tags, notes, and trend analytics. Syncs automatically from moodLog.app via webhook.
Medication Compliance -- Flexible scheduling with time windows, recurrence patterns, intake logging (take/skip/snooze), and compliance heatmaps. External API for iOS Shortcuts integration.
Withings Integration -- OAuth2 device sync for scales, blood pressure monitors, and activity trackers with automatic deduplication.
AI-Powered Insights -- Bring your own OpenAI API key. Personalized analysis across blood pressure, weight, pulse, mood, BMI, and medication adherence. Cached daily to minimize API usage.
Doctor Report PDF Export -- Generate professional medical reports client-side. European format with vital sign summaries, BP/BMI classification, compliance rates, and optional AI analysis.
PWA with Offline Support -- Installable on iOS and Android. Service worker with intelligent caching strategies for reliable offline access.
Multi-Channel Notifications -- Telegram (with inline action buttons), ntfy (self-hostable), and Web Push. Medication reminders with late/missed escalation.
Gamification -- 30+ persistent achievements across intake streaks, compliance milestones, and healthy metric streaks.
Internationalization -- Full German and English UI with 1000+ translation keys. Browser-based locale detection with per-user override.
git clone https://github.com/MBombeck/HealthLog.git
cd HealthLog
cp .env.example .envGenerate the required secrets:
openssl rand -hex 32 # SESSION_SECRET
openssl rand -hex 32 # ENCRYPTION_KEY
openssl rand -hex 32 # API_TOKEN_HMAC_KEYAdd them to .env, then:
docker compose up -dOpen http://localhost:3000. The first registered user becomes admin.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, React Server Components) |
| Language | TypeScript (strict mode) |
| Database | PostgreSQL 16 + Prisma 7 (22 models) |
| Job Queue | pg-boss 12 (reminders, insights, backups) |
| UI | shadcn/ui, Tailwind CSS 4, Radix UI, Lucide Icons |
| Charts | Recharts 3 |
| Data Fetching | TanStack Query 5 |
| Forms | React Hook Form 7 + Zod 4 |
| Auth | SimpleWebAuthn 13, Argon2id |
| Notifications | Telegram Bot API, ntfy, Web Push (VAPID) |
| jsPDF (client-side generation) | |
| Testing | Vitest 4 |
| Deployment | Docker (multi-stage Alpine) |
HealthLog is designed for people who take data ownership seriously.
- Self-hosted -- Your data never leaves your server. No telemetry, no third-party tracking.
- AES-256-GCM encryption -- All stored secrets (OAuth tokens, API keys, VAPID keys) are encrypted at rest.
- Passkey authentication -- WebAuthn as primary auth with password fallback (Argon2id + zxcvbn strength validation).
- Server-side sessions -- PostgreSQL-backed with 30-day sliding expiry, HttpOnly/SameSite=Strict cookies.
- Security headers -- CSP with nonces, HSTS, X-Frame-Options DENY, Permissions-Policy, Referrer-Policy.
- Rate limiting -- Sliding window on auth and API endpoints.
- HMAC-SHA256 API tokens -- Bearer tokens are hashed before storage.
- Audit logging -- All sensitive operations tracked with IP addresses.
| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
SESSION_SECRET |
64-char hex string for session signing |
ENCRYPTION_KEY |
64-char hex string for AES-256-GCM |
API_TOKEN_HMAC_KEY |
64-char hex string for API token hashing |
| Variable | Description |
|---|---|
NEXT_PUBLIC_APP_URL |
Public-facing URL (default: http://localhost:3000) |
WITHINGS_CLIENT_ID |
Withings OAuth2 client ID |
WITHINGS_CLIENT_SECRET |
Withings OAuth2 client secret |
WITHINGS_REDIRECT_URI |
OAuth callback URL |
WITHINGS_WEBHOOK_SECRET |
Webhook URL hardening secret |
TELEGRAM_WEBHOOK_SECRET |
Telegram bot webhook secret |
Telegram bot token, ntfy settings, Web Push VAPID keys, Umami, and GlitchTip URLs are configured in the Admin Panel and stored encrypted in the database.
src/
├── app/ # Next.js App Router pages & API routes
│ ├── api/ # REST API endpoints (~60 route files)
│ ├── admin/ # Admin panel
│ ├── medications/ # Medication management
│ ├── measurements/ # Health metric entry
│ ├── insights/ # AI-powered analytics
│ ├── achievements/ # Gamification page
│ ├── onboarding/ # 4-step guided setup
│ └── settings/ # User preferences
├── components/
│ ├── ui/ # shadcn/ui primitives
│ ├── layout/ # Shell (sidebar, topbar, bottom nav)
│ ├── medications/ # Medication cards, forms, timeline
│ ├── measurements/ # Measurement form, list
│ ├── mood/ # Mood form, mood list
│ └── charts/ # Recharts wrappers
├── lib/
│ ├── auth/ # Session, audit, passkey logic
│ ├── notifications/ # Dispatcher + channel senders
│ ├── jobs/ # pg-boss worker
│ ├── analytics/ # Trend calculations, compliance
│ ├── withings/ # OAuth client, sync service
│ ├── i18n/ # Translations context & config
│ ├── validations/ # Shared Zod schemas
│ ├── crypto.ts # AES-256-GCM encrypt/decrypt
│ ├── db.ts # Prisma singleton
│ └── doctor-report-pdf.ts # Client-side PDF generation
├── hooks/ # React hooks
└── generated/prisma/ # Generated Prisma client
- RSC by default --
"use client"only for interactive components - API envelope -- All responses follow
{ data, error, meta }shape - Encrypted secrets -- Withings tokens, API keys, VAPID keys, notification credentials
- Timezone-aware --
Europe/Berlinfor display, UTC in database - Route protection --
proxy.tschecks session cookie, redirects unauthenticated requests - Client-side PDF -- Doctor reports generated in browser via jsPDF
All mutations require authentication via session cookie. External ingest uses Bearer tokens.
Health Data
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/measurements |
List measurements (paginated, filterable) |
POST |
/api/measurements |
Create measurement |
DELETE |
/api/measurements/:id |
Delete measurement |
GET |
/api/analytics |
Trend summaries (7d/30d) |
GET |
/api/export |
Export as CSV or JSON |
POST |
/api/import |
Import from JSON |
POST |
/api/doctor-report |
Aggregated data for PDF |
Mood
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/mood-entries |
List mood entries |
POST |
/api/mood-entries |
Create mood entry |
DELETE |
/api/mood-entries/:id |
Delete mood entry |
GET |
/api/mood/analytics |
Mood trend analytics |
POST |
/api/integrations/moodlog/webhook |
moodLog.app webhook |
Medications
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/medications |
List all medications |
POST |
/api/medications |
Create medication |
PUT |
/api/medications/:id |
Update medication |
DELETE |
/api/medications/:id |
Delete medication |
POST |
/api/medications/:id/intake |
Log intake event |
GET |
/api/medications/:id/compliance |
Compliance stats |
POST |
/api/ingest/medication |
External intake (Bearer) |
Auth and Integrations
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/auth/register |
Create account |
POST |
/api/auth/login |
Password login |
POST |
/api/auth/logout |
Destroy session |
GET |
/api/auth/me |
Current user profile |
POST |
/api/auth/passkey/* |
WebAuthn flows |
GET |
/api/withings/connect |
Initiate Withings OAuth |
POST |
/api/insights/generate |
Regenerate AI insights |
GET |
/api/gamification/achievements |
Achievement progress |
GET |
/api/health |
Docker health check |
| Integration | Setup | Purpose |
|---|---|---|
| Withings | Env vars | Auto-sync weight, BP, and activity |
| Telegram | Admin Panel | Medication reminders with inline buttons |
| ntfy | User Settings | Self-hosted push notifications |
| Web Push | Admin Panel | Browser-native VAPID notifications |
| OpenAI | User Settings | AI health insights (BYOK) |
| moodLog.app | User Settings | Mood tracking sync |
| Umami | Admin Panel | Privacy-friendly analytics |
| GlitchTip | Admin Panel | Sentry-compatible error tracking |
# Prerequisites: Node.js 20+, pnpm, PostgreSQL
cp .env.example .env
pnpm install
pnpm db:generate
pnpm db:migrate
pnpm devpnpm dev # Development server
pnpm build # Production build
pnpm lint # ESLint
pnpm typecheck # TypeScript strict check
pnpm test # Vitest
pnpm format # Prettier
pnpm db:generate # Generate Prisma client
pnpm db:migrate # Create & apply migration
pnpm db:migrate:deploy # Apply migrations (production)
pnpm db:studio # Prisma Studio GUIThe included docker-compose.yml runs the app and PostgreSQL. The entrypoint automatically waits for the database, runs pending migrations, and starts the server.
The app listens on port 3000. Place it behind Nginx, Caddy, or Traefik for TLS termination. Works out of the box with Coolify.
Contributions are welcome. See CONTRIBUTING.md for guidelines.
- Code style:
pnpm format && pnpm lint - Type safety:
pnpm typecheckmust pass - Tests:
pnpm test - UI language: German. Code, comments, and commits: English.
HealthLog is licensed under the GNU Affero General Public License v3.0.