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 -dpulls pre-built images for
linux/amd64andlinux/arm64instead 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) and029_api_keys(participant keys). They add tables and
change nothing you already have; themigrateservice applies them before the
API starts, as always. - Your
.envis not changed. An install without an API key, dashboard
password or broker login keeps working as before, andhealthsave doctor
says what is open.healthsave pair --new-keyadds a key; then pair the
phone again. - For later releases,
healthsave updatedoes all of this for you, and takes
a backup first.
Security
healthsave setup basicnow generates an API key. A fresh install no longer
accepts unauthenticated reads and writes from everyone on your network.
Existing installs keep their.envuntouched.- New
healthsave pairshows the server URL, the API key and, whenqrencode
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_PASSWORDis set.
Setup generates one for new installs, andhealthsave pairshows it. Without
a session, pages redirect to/loginand every data route (including the
/api/*pass-through to the API) returns401. An older.envwithout
WEB_PASSWORDbehaves as before, andhealthsave doctorwarns 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
generatedWEB_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 doctorwarns when no API key is set.- Advanced setup suggests a generated key instead of open access.
SECURITY.mdsays how to report a vulnerability privately.- The reverse-proxy example no longer carries the maintainer's hostnames and
LAN address:server_name _, andgenerate-self-signed.shtakes
CERT_HOSTNAMES/CERT_IPS.
Added
- Pre-built images for
linux/amd64andlinux/arm64, signed with cosign:
ghcr.io/umutkeltek/healthsave-observatory(API, migrations, worker, agents
and the Home Assistant bridge) andghcr.io/umutkeltek/healthsave-observatory-web.
docker-compose.ymlpulls the images of the release you checked out;
docker-compose.build.override.ymlbuilds them from source instead. - Lab results.
healthsave labs import FILE.csvloads blood test results with
LOINC ids;GET /api/v2/labsandGET /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. (migration028_lab_results) - Participants. One Observatory can hold several people.
healthsave participants add NAMEprints a pairing code for the free app; the data lands under that
person's own key. The.envAPI key stays the admin key and sees everyone;
GET /api/v2/ownerslists 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.envAPI key) unless
HEALTHSAVE_BRIDGE_OWNERnames 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; andhealthsave update --rollback.healthsave licenseinstalls
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
tailscaleCompose 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 newweb_data
volume and takes over fromWEB_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 backupwrites the database (pg_dump),.envand
config.yamlto one owner-only.tarfile.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_USERNAMEand
MOSQUITTO_PASSWORDare set. Setup generates both for new installs, and
healthsave up --home-assistantprints them for Home Assistant's MQTT
integration. The bridge falls back to this login whenHA_MQTT_USERNAMEand
HA_MQTT_PASSWORDare empty. An older.envkeeps 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 newconfig.yaml, so
Findings fill in without any AI setup. Advanced setup now keeps them on when
you skip Ollama. Existingconfig.yamlfiles andconfig.yaml.exampleare
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 emptyANALYSIS_*_ENABLEDvalue when.envdoes not set one, and an
empty value counted as "off", overridingconfig.yaml. Empty now means "not
set". The same applies toLLM_REDACT_CLOUD_PROMPTS, so an empty value
keeps cloud-prompt redaction on. - The installers install the newest published release instead of
main.
npx healthsavedefaulted to av0.1.5tag that never existed, so a fresh
npxinstall failed. "Newest published" means the GitHub Release, which
exists only once that release's images are published; without it, the
newestvX.Y.Ztag. SetHEALTHSAVE_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/statusandGET /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.