mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Add the optional FITBIT_REDIRECT_URI to .env.production.example (BYO-key shape, derives from NEXT_PUBLIC_APP_URL) so check-env documents it. Rename the settings-card copy from "Google Health" to "Fitbit" across all six locales now that the transport is the classic Fitbit Web API.
231 lines
12 KiB
Bash
231 lines
12 KiB
Bash
# =============================================================================
|
|
# HealthLog -- production .env example
|
|
# =============================================================================
|
|
# Mirrors `scripts/env-manifest.json`. The `pnpm check-env --file
|
|
# .env.production.example` CI step (see `.github/workflows/env-check.yml`)
|
|
# enforces every variable declared `required: true` in the manifest has a
|
|
# non-empty placeholder here, so a contributor who introduces a new
|
|
# required var without updating this file fails the workflow.
|
|
#
|
|
# Placeholders are syntactic only -- replace with real secrets before
|
|
# deploying. The check-env presence rule treats any non-empty,
|
|
# non-whitespace string as "set", so the `<placeholder>` style below
|
|
# satisfies the manifest without leaking a usable credential.
|
|
#
|
|
# Generate the two crypto secrets locally with:
|
|
# $ openssl rand -hex 32
|
|
# =============================================================================
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Core -- required for boot
|
|
# -----------------------------------------------------------------------------
|
|
DATABASE_URL="postgresql://healthlog:<password>@db:5432/healthlog?schema=public"
|
|
POSTGRES_PASSWORD="<openssl rand -hex 32>"
|
|
NEXT_PUBLIC_APP_URL="https://healthlog.example.com"
|
|
APP_URL="https://healthlog.example.com"
|
|
ENCRYPTION_KEY="<openssl rand -hex 32>"
|
|
API_TOKEN_HMAC_KEY="<openssl rand -hex 32>"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Withings OAuth -- optional integration
|
|
# -----------------------------------------------------------------------------
|
|
# WITHINGS_CLIENT_ID=""
|
|
# WITHINGS_CLIENT_SECRET=""
|
|
# WITHINGS_WEBHOOK_SECRET=""
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# WHOOP -- optional integration
|
|
# -----------------------------------------------------------------------------
|
|
# The WHOOP app client id/secret are per-user BYO-keys: each user registers
|
|
# their own WHOOP developer app and pastes the client id/secret into Settings
|
|
# (stored encrypted in the DB). There is therefore no WHOOP_CLIENT_ID/SECRET.
|
|
#
|
|
# WHOOP_WEBHOOK_SECRET is the instance-level secret carried as the trailing
|
|
# path segment of the webhook URL AND used to verify the WHOOP HMAC body
|
|
# signature. WHOOP_REDIRECT_URI overrides the derived
|
|
# `${NEXT_PUBLIC_APP_URL}/api/whoop/callback` when the public URL differs.
|
|
# WHOOP_WEBHOOK_SECRET="<openssl rand -hex 32>"
|
|
# WHOOP_REDIRECT_URI=""
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Fitbit -- optional integration (classic Web API, per-user BYO-keys)
|
|
# -----------------------------------------------------------------------------
|
|
# Each user registers their own app at https://dev.fitbit.com (self-serve, no
|
|
# brand verification) and pastes the OAuth Client ID + Client Secret into
|
|
# Settings (stored encrypted in the DB). There is therefore no
|
|
# FITBIT_CLIENT_ID/SECRET here. The OAuth flow uses Authorization Code + PKCE.
|
|
#
|
|
# FITBIT_REDIRECT_URI overrides the derived
|
|
# `${NEXT_PUBLIC_APP_URL}/api/fitbit/callback` when the public URL differs; it
|
|
# must exactly match the Callback URL registered in the dev.fitbit.com app.
|
|
# FITBIT_REDIRECT_URI=""
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Polar AccessLink -- optional integration (full OAuth, shared app from env)
|
|
# -----------------------------------------------------------------------------
|
|
# Register an app at https://admin.polaraccesslink.com and set its redirect URI
|
|
# to `${NEXT_PUBLIC_APP_URL}/api/polar/callback`. Both vars together enable the
|
|
# Polar connect button; set neither to leave the integration disabled. Polar
|
|
# access tokens do not expire and carry no refresh token. POLAR_REDIRECT_URI
|
|
# overrides the derived callback when the public URL differs.
|
|
# POLAR_CLIENT_ID=""
|
|
# POLAR_CLIENT_SECRET=""
|
|
# POLAR_REDIRECT_URI=""
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Oura Cloud v2 -- optional integration (full OAuth, shared app from env)
|
|
# -----------------------------------------------------------------------------
|
|
# Register an app at https://cloud.ouraring.com/oauth/applications and set its
|
|
# redirect URI to `${NEXT_PUBLIC_APP_URL}/api/oura/callback`. Both vars together
|
|
# enable the Oura connect button. Oura uses refresh tokens; the sync refreshes
|
|
# reactively on a 401. OURA_REDIRECT_URI overrides the derived callback.
|
|
# OURA_CLIENT_ID=""
|
|
# OURA_CLIENT_SECRET=""
|
|
# OURA_REDIRECT_URI=""
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Web Push -- VAPID keys (optional; the admin panel is the easier path)
|
|
# -----------------------------------------------------------------------------
|
|
# Web Push needs NO Apple account and no paid service -- just a VAPID keypair.
|
|
# The EASIEST path is the admin panel: /admin -> Web Push VAPID -> "Generate
|
|
# keys" mints and stores the pair for you (private key encrypted at rest). Use
|
|
# these env vars only if you prefer env-config over the DB. The loader reads
|
|
# DB first, then env (src/lib/notifications/vapid-config.ts). NOTE: these are
|
|
# NOT in docker-compose.yml's `environment:` whitelist -- if you go the env
|
|
# route under compose, add them there too or the values never reach the
|
|
# container (see docs/self-hosting/getting-started.md Troubleshooting).
|
|
# VAPID_PUBLIC_KEY=""
|
|
# VAPID_PRIVATE_KEY=""
|
|
# VAPID_SUBJECT="mailto:you@example.com"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# APNs -- iOS push (optional, all-or-none)
|
|
# -----------------------------------------------------------------------------
|
|
# Only the native iOS app uses APNs, and it needs a paid Apple Developer
|
|
# Program membership. Web Push (above) needs NO Apple account -- it covers
|
|
# every browser and the installed PWA on iPhone. Leave this whole block unset
|
|
# unless you ship the native app. Key-source precedence when more than one is
|
|
# set: APNS_KEY_B64 > APNS_KEY > APNS_KEY_FILE.
|
|
# APNS_KEY_ID=""
|
|
# APNS_TEAM_ID=""
|
|
# APNS_BUNDLE_ID=""
|
|
# APNS_KEY_B64="" # PEM body base64-encoded -- recommended (escapes newlines)
|
|
# APNS_KEY="" # OR APNS_KEY (raw PEM) OR APNS_KEY_FILE -- one satisfies the manifest
|
|
# APNS_KEY_FILE=""
|
|
# APNS_CRITICAL_ENTITLEMENT="" # "true" only if your build has Apple's Critical Alerts entitlement; else urgent = time-sensitive
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# SMTP -- email notification channel (optional, all-or-none)
|
|
# -----------------------------------------------------------------------------
|
|
# Operator SMTP transport for the email channel. SMTP_HOST + SMTP_PORT +
|
|
# SMTP_FROM together enable it; SMTP_USER/SMTP_PASS are optional (omit for an
|
|
# unauthenticated relay). SMTP_SECURE=true uses implicit TLS (port 465);
|
|
# unset/false uses STARTTLS (port 587). Per-user recipient address is set in
|
|
# Settings -> Notifications, not here. Missing the core trio disables the
|
|
# channel silently. Listed in docker-compose.yml's environment whitelist so
|
|
# these reach the container.
|
|
# SMTP_HOST=""
|
|
# SMTP_PORT="587"
|
|
# SMTP_FROM="HealthLog <noreply@example.com>"
|
|
# SMTP_USER=""
|
|
# SMTP_PASS=""
|
|
# SMTP_SECURE="false"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Deploy webhook -- Coolify -> HealthLog auto-deploy feedback
|
|
# -----------------------------------------------------------------------------
|
|
# DEPLOY_WEBHOOK_SECRET=""
|
|
# Optional: deployment-dashboard URL (e.g. the Coolify UI) linked in
|
|
# deploy-failure notifications. When unset the notification omits the link.
|
|
# DEPLOY_LOGS_URL=""
|
|
# Optional replay hardening: require a fresh X-Deploy-Webhook-Timestamp
|
|
# header (unix seconds / ms or ISO-8601, +/- 5 minutes) on every webhook
|
|
# call. Leave unset for Coolify's stock sender (it attaches no
|
|
# timestamp); see docs/ops/deploy.md.
|
|
# DEPLOY_WEBHOOK_REQUIRE_TIMESTAMP="false"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# TLS leaf pin monitor -- alarm when the pinned leaf certificate rotates
|
|
# -----------------------------------------------------------------------------
|
|
# The native client SPKI-pins the served TLS leaf. Set this to the
|
|
# known-good leaf pin(s) so the monitor can alarm on a rotation. The value
|
|
# is base64(sha256(DER subjectPublicKeyInfo)); comma-separate to hold both
|
|
# the current and the next pin during a dual-pin renewal window. See
|
|
# docs/ops/tls-cert-pin.md for extraction + the re-pin runbook.
|
|
# TLS_LEAF_SPKI_PINS=""
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Off-host backups -- all-or-none
|
|
# -----------------------------------------------------------------------------
|
|
# BACKUP_S3_ENDPOINT=""
|
|
# BACKUP_S3_BUCKET=""
|
|
# BACKUP_S3_ACCESS_KEY=""
|
|
# BACKUP_S3_SECRET_KEY=""
|
|
# BACKUP_ENCRYPTION_KEY=""
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# FHIR health-record export -- optional
|
|
# -----------------------------------------------------------------------------
|
|
# Per-export ceiling on the number of MedicationAdministration rows in the
|
|
# FHIR Bundle. The report window already scopes the set; this is a coarse
|
|
# safety ceiling on the serialised Bundle size. Bounded 1..50000; any unset
|
|
# or out-of-range value falls back to the default of 5000. Raise it only for
|
|
# an unusual multi-year, many-medication workload.
|
|
# FHIR_MAX_MEDICATION_ADMINISTRATIONS="5000"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Dashboard snapshot -- BUILD-TIME toggle (default ON)
|
|
# -----------------------------------------------------------------------------
|
|
# The dashboard hydrates every above-the-fold tile from the single
|
|
# `GET /api/dashboard/snapshot` cell so the whole strip shares one
|
|
# completion moment. This is the default and the desired behaviour.
|
|
#
|
|
# `NEXT_PUBLIC_*` vars are inlined into the client bundle at BUILD time,
|
|
# not read at runtime -- so this has NO effect on the prebuilt GHCR
|
|
# image and is intentionally absent from the `docker-compose.yml`
|
|
# runtime `environment:` whitelist. To fall back to the legacy
|
|
# four-cell path you must rebuild the image with the var set to "false":
|
|
#
|
|
# $ NEXT_PUBLIC_DASHBOARD_SNAPSHOT=false pnpm build # or a Dockerfile ARG
|
|
#
|
|
# NEXT_PUBLIC_DASHBOARD_SNAPSHOT="false"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Client-IP resolution -- optional (required behind Cloudflare)
|
|
# -----------------------------------------------------------------------------
|
|
# When the stack sits behind Cloudflare, the real visitor IP arrives in the
|
|
# `cf-connecting-ip` header; the X-Forwarded-For chain otherwise yields the
|
|
# Cloudflare edge IP, so the audit-log overview stores the CF datacentre
|
|
# address and the geo lookup resolves the wrong location. Set this to "1"
|
|
# ONLY when Cloudflare is in front -- a direct-exposed self-host must leave
|
|
# it unset, or an attacker could forge the header. Off by default.
|
|
# TRUST_CF_CONNECTING_IP="1"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# IP geolocation lookup -- optional
|
|
# -----------------------------------------------------------------------------
|
|
# The admin login/audit overview enriches auth events with a coarse
|
|
# "City, CC" location + carrier. The default online provider is ip-api.com.
|
|
# Override the base URL to point at a different provider; the response must
|
|
# match either the ipwho.is shape (`success` + `country_code`) or the
|
|
# ip-api.com shape (`status` + `countryCode`). HTTPS only -- a non-HTTPS URL
|
|
# is refused (audit-event IPs must never egress over plaintext HTTP). The
|
|
# `/<ip>` segment is appended automatically.
|
|
# IP_GEO_LOOKUP_URL="https://ip-api.com/json"
|
|
#
|
|
# Set to "1" to disable all third-party IP egress (GDPR Art. 44). With egress
|
|
# off the resolver uses only the offline GeoLite2 MMDB tier, if present.
|
|
# IP_GEO_LOOKUP_DISABLED="1"
|