github umutkeltek/healthsave-observatory v1.2.0
HealthSave Observatory v1.2.0

5 hours ago

A new install is locked down from the first start: it gets an API key, a
dashboard password and a QR code to pair the app. Releases now ship as
pre-built images, and healthsave update, backup and restore handle
upgrades and backups. Observatory Care, an optional licence, adds encrypted
off-site backups, restore drills and update rollback. Everything that was free
stays free.

Upgrade

git fetch --tags
git checkout v1.2.0
docker compose up -d
  • From this release on, docker compose up -d pulls pre-built images for
    linux/amd64 and linux/arm64 instead of building them on your machine.
    To keep building from source, add the build override:
    docker compose -f docker-compose.yml -f docker-compose.build.override.yml up -d --build.
  • Two additive migrations run on the first docker compose up -d: 028_lab_results
    (blood test results) and 029_api_keys (participant keys). They add tables and
    change nothing you already have; the migrate service applies them before the
    API starts, as always.
  • Your .env is not changed. An install without an API key, dashboard
    password or broker login keeps working as before, and healthsave doctor
    says what is open. healthsave pair --new-key adds a key; then pair the
    phone again.
  • For later releases, healthsave update does all of this for you, and takes
    a backup first.

Security

  • healthsave setup basic now generates an API key. A fresh install no longer
    accepts unauthenticated reads and writes from everyone on your network.
    Existing installs keep their .env untouched.
  • New healthsave pair shows the server URL, the API key and, when qrencode
    is installed, a QR code for the HealthSave app. healthsave pair --new-key
    rotates the key and restarts the API and web.
  • The Observatory web dashboard asks for a password when WEB_PASSWORD is set.
    Setup generates one for new installs, and healthsave pair shows it. Without
    a session, pages redirect to /login and every data route (including the
    /api/* pass-through to the API) returns 401. An older .env without
    WEB_PASSWORD behaves as before, and healthsave doctor warns when such a
    dashboard listens on anything but loopback, or when the dashboard has a
    password but the API has no key. Session cookies are also keyed with a
    generated WEB_SESSION_SECRET; server actions check the session themselves;
    ten wrong passwords in a minute pause sign-in; sign-in and sign-out refuse
    cross-site posts.
  • healthsave doctor warns when no API key is set.
  • Advanced setup suggests a generated key instead of open access.
  • SECURITY.md says how to report a vulnerability privately.
  • The reverse-proxy example no longer carries the maintainer's hostnames and
    LAN address: server_name _, and generate-self-signed.sh takes
    CERT_HOSTNAMES / CERT_IPS.

Added

  • Pre-built images for linux/amd64 and linux/arm64, signed with cosign:
    ghcr.io/umutkeltek/healthsave-observatory (API, migrations, worker, agents
    and the Home Assistant bridge) and ghcr.io/umutkeltek/healthsave-observatory-web.
    docker-compose.yml pulls the images of the release you checked out;
    docker-compose.build.override.yml builds them from source instead.
  • Lab results. healthsave labs import FILE.csv loads blood test results with
    LOINC ids; GET /api/v2/labs and GET /api/v2/labs/{loinc} return each marker
    against the lab's own printed range and your own history. Results from two labs
    stay separate rows and are never averaged. A Labs page shows the trend per
    marker and one cross-match card (ferritin against resting heart rate) with its
    coverage and limits. (migration 028_lab_results)
  • Participants. One Observatory can hold several people. healthsave participants add NAME prints a pairing code for the free app; the data lands under that
    person's own key. The .env API key stays the admin key and sees everyone;
    GET /api/v2/owners lists people, nine /api/v2/* reads take ?owner=, and the
    web dashboard gets a participant switcher. healthsave participants revoke
    refuses a key everywhere. The phone routes are unchanged. (migration
    029_api_keys)
  • Home Assistant pack under integrations/home-assistant/pack/: three blueprints
    (wind-down from sleep length, a recovery-aware morning in plain words, a
    low-data warning) and a plain-cards Body dashboard, built on the bridge's own
    sensor.healthsave_observatory_* entities.
  • The Home Assistant / MQTT bridge publishes one person only. It reads the
    default owner (the person behind the .env API key) unless
    HEALTHSAVE_BRIDGE_OWNER names another participant's id; a second person's
    rows never reach a published payload.
  • Observatory Care, an optional licence for people who want their install
    looked after (docs):
    healthsave backup --encrypt, --offsite REMOTE (through rclone, to storage
    you own) and --schedule daily|weekly; healthsave restore --drill FILE,
    which restores a backup into a throwaway database and compares every table's
    row count; and healthsave update --rollback. healthsave license installs
    and shows the licence file, which is checked on your machine against a
    built-in public key and never phones home. Encrypted backups still restore
    without a licence.
  • Remote access without opening ports: an optional tailscale Compose profile
    serves the web app and the API on your tailnet over HTTPS, with no router
    port opened and Funnel off. See
    Remote access.
  • Settings -> Web sign-in sets, changes or turns off the dashboard password
    (changes need the current password; this browser stays signed in, others are
    signed out). It is stored as a salted scrypt hash in the new web_data
    volume and takes over from WEB_PASSWORD. healthsave web-password reset
    removes it when the password is lost.
  • healthsave update [--to TAG] moves a git install to the newest release:
    backup first, then checkout of the tag, then a restart of exactly the
    services that were running, on the new release's images. It refuses local
    edits to tracked files and prints the way back if the new release does not
    start.
  • healthsave backup writes the database (pg_dump), .env and
    config.yaml to one owner-only .tar file. healthsave restore FILE
    saves the current database first, then restores with TimescaleDB's
    pre/post-restore steps, checks the migration count, and restarts the
    services it stopped. It refuses a backup from a different TimescaleDB version.

Changed

  • The bundled Mosquitto broker requires a login when MOSQUITTO_USERNAME and
    MOSQUITTO_PASSWORD are set. Setup generates both for new installs, and
    healthsave up --home-assistant prints them for Home Assistant's MQTT
    integration. The bridge falls back to this login when HA_MQTT_USERNAME and
    HA_MQTT_PASSWORD are empty. An older .env keeps the broker anonymous,
    with a warning in its logs.
  • Setup turns on the four analysis jobs that need no AI model (anomalies,
    trends, correlations, recovery) when it writes a new config.yaml, so
    Findings fill in without any AI setup. Advanced setup now keeps them on when
    you skip Ollama. Existing config.yaml files and config.yaml.example are
    unchanged.
  • The AI narrator no longer downloads LiteLLM's model price list from GitHub
    each time LiteLLM loads (it uses the bundled copy), and LiteLLM telemetry is
    off. Bundled Grafana no longer sends usage reports or checks for updates.
    Neither request carried health data, but neither went through the egress
    gate.
  • The web app runs on Node.js 22. Node.js 20 no longer gets security fixes.
  • Today shows compact readings, links each reading and finding to its
    evidence, and has larger touch targets on phones.

Fixed

  • A fresh install no longer starts with every analysis job off. Compose passes
    an empty ANALYSIS_*_ENABLED value when .env does not set one, and an
    empty value counted as "off", overriding config.yaml. Empty now means "not
    set". The same applies to LLM_REDACT_CLOUD_PROMPTS, so an empty value
    keeps cloud-prompt redaction on.
  • The installers install the newest published release instead of main.
    npx healthsave defaulted to a v0.1.5 tag that never existed, so a fresh
    npx install failed. "Newest published" means the GitHub Release, which
    exists only once that release's images are published; without it, the
    newest vX.Y.Z tag. Set HEALTHSAVE_OBSERVATORY_REF (or --ref) to pick a
    tag, branch or commit. The npm bootstrapper is now 0.2.0.
  • Activity summaries keep every field when a batch arrives, stand hours
    included.
  • Replaying an old batch no longer makes sync readiness report a metric as
    behind when newer data is already stored.
  • Testing the AI connection from Settings accepts the same local model hosts
    the server already trusts.

Compatibility

  • The routes the App Store app depends on are unchanged: POST /api/apple/batch,
    GET /api/apple/status and GET /api/health. The OpenAPI lock changed only
    in its version number.
  • The remote VM deploy (deploy/remote-vm/deploy.sh) still builds from the
    deployed commit, with the same ports and image names as before.

Known limits

  • The bundled Grafana dashboards still read across every person on an
    Observatory that holds participants; filter them per panel or keep Grafana
    off such an install. Findings and the weekly Body Brief are produced for the
    primary person only.

Don't miss a new healthsave-observatory release

NewReleases is sending notifications on new releases.