dexafix

command module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

README

DexaFix logo

DexaFix

Corrects smart-scale results using DEXA scan results.

CI codecov Latest release License Sponsor on Open Collective Go version Container image

Quick start  ·  Features  ·  Documentation  ·  Configuration  ·  Security  ·  Contributing  ·  Sponsor


DexaFix is a Go web app that stores per-user DEXA scans and scale readings, and shows one estimated value per day. Each user has an account and sees only their own data. Users sign in with a password or with an external provider.

[!WARNING] Read Limitations and security before you expose DexaFix to the internet.

✨ Features

Area Feature
📊 Measurements and estimates Per-user DEXA scans and scale readings, entered in the browser or by JSON API.
Each reading records its measurement method (smart scale, caliper, BodPod, hydrostatic, tape, visual AI) and whether athlete mode was on.
One estimate per day for weight, body fat, fat mass, fat-free mass, lean mass, hydration, bone mass, visceral fat index, BMI, fat mass index (FMI), lean mass index (LMI) and the android/gynoid (A/G) fat ratio.
🔐 Accounts and security Password sign-in, plus OpenID Connect, Sign in with Apple and OAuth 2.0 providers. See Accounts and sign-in.
Passkeys (WebAuthn) for signing in without a password, with a device's fingerprint, face or PIN. See Passkeys.
Password reset by one-time link, made by an administrator or requested by e-mail. See Password reset.
Optional two-step verification for password sign-in, with an authenticator app and recovery codes, and an administrator policy for who must use it. Administrators confirm a code again before each Admin page.
New accounts are closed by default, and security-relevant events go to an audit log.
📥 Imports Optional Withings import, so scale readings do not need typing in. See Withings import.
Strength Level sync, per day, with multi-day sync for users an administrator allows.
🗂️ Data Export of settings and personal details, and of all scans and readings, as JSON (GDPR articles 15 and 20). See Your data.
Deleting a user removes their measurements and settings.
🛠️ Operations SQLite (default) or Postgres. Schema changes are versioned migrations, applied on startup. See Database.
Server settings (base URL, trusted proxies, PROXY protocol, audit retention, e-mail) are edited on the Admin page and take effect at once, without a restart.
Optional HTTPS on its own port, with HTTP/2 and HTTP/3 (QUIC), using an uploaded or a self-signed certificate. See Running behind a reverse proxy.
Container image on a scratch base, for amd64 and arm64, built by ContainerForge as ghcr.io/trueforge-org/dexafix.
Signed images and checksums (cosign), published by the release workflow.

🚀 Quick start

Requires the Go version in go.mod.

go run . serve

Open http://localhost:8080 and create an account. The first account becomes the administrator.

[!IMPORTANT] Unless DEXAFIX_ENCRYPTION_KEY is set, the first run creates the encryption key file dexafix.key. Back it up: the server does not start without it.

Or run the container image. The key file is then inside the data volume, at /config/dexafix.key:

docker run -p 8080:8080 -v dexafix-data:/config ghcr.io/trueforge-org/dexafix:latest

Continue with Getting started.

🧩 Running as two processes

dexafix serve web runs the pages and the public listeners, and dexafix serve api runs the database and the security decisions. Each can be deployed separately. See Split deployment.

📚 Documentation

The full documentation starts at docs/index.md.

Page What you find there
01 · Getting started Build, run and create the first account.
02 · Configuration Flags, environment variables and secrets.
03 · Running behind a reverse proxy Trusted proxies, base URL, PROXY protocol, and HTTPS with HTTP/2 and HTTP/3.
04 · Database SQLite and Postgres, migrations and moving between them.
05 · Commands The db commands for migrations, copies and rekeying, and recovery commands.
06 · Using the app The pages of the web interface.
07 · Accounts and sign-in Providers, passkeys, password reset, two-step verification, audit log and your data.
08 · Encryption What is encrypted, the key and rotating it.
09 · Estimates How the daily estimates are calculated.
10 · Withings import Linking Withings and importing readings.
11 · JSON API Routes, authentication and the import endpoint.
12 · CI and releases What CI checks and how releases are made.
13 · Development Tests, project layout and schema changes.
14 · Limitations and security Read before you expose the app.
15 · Split deployment Running the frontend and the backend as two processes, with Compose and troubleshooting.
16 · Workers The processes that talk to Withings and Strength Level, and the Workers admin page.
17 · Body service The readings, scans and estimates as a process of their own, with a database, key and secret of their own.
Key rotation Design note on the key check and why rotation stays manual.
CI details The README badges, the secrets to configure and how to cut a release.

🔐 Security

  • Encrypted at rest: e-mail addresses, Withings tokens, the Strength Level login, provider secrets, two-step verification secrets and every server setting (including the SMTP password and an uploaded HTTPS key) are encrypted with AES-256-GCM.
  • Hashed secrets: passwords are hashed with bcrypt, and session and access tokens and recovery codes are stored only as hashes.
  • Optional second step: two-step verification (authenticator app and recovery codes) protects password sign-in. Administrators can require it.
  • Audit log: sign-ins, account and token changes, imports, exports and every administrator action are recorded.
Read more

To report a vulnerability or a bug, open an issue at github.com/trueforge-org/dexafix/issues.

🤝 Contributing and development

Tests, the project layout and how to make schema changes are in Development. CI checks and release builds are described in CI and releases.

Ideas and questions are welcome as GitHub issues.

♥ Support DexaFix

DexaFix is free and open source and is built in spare time. If it helps you, please consider sponsoring it on Open Collective. The app has the same links in its footer.

📄 License

DexaFix is licensed under the GNU Affero General Public License, version 3. See LICENSE.

Documentation

Overview

Command dexafix is the entry point of the binary. It sets up logging and runs the command line implemented in package cmd.

Directories

Path Synopsis
Package cmd implements the DexaFix command line: `serve` runs the web app, `db` migrates and copies the database, and `info` prints information about the binary.
Package cmd implements the DexaFix command line: `serve` runs the web app, `db` migrates and copies the database, and `info` prints information about the binary.
pkg
app
Package app runs the application as one process: a frontend and a backend that talk to each other through the internal API over an in-process transport, exactly as two processes would over the network.
Package app runs the application as one process: a frontend and a backend that talk to each other through the internal API over an in-process transport, exactly as two processes would over the network.
backend/body
Package bodybackend is the body service: a user's scale readings and DEXA scans, the estimates computed from them and the rules for importing readings from a source such as Withings.
Package bodybackend is the body service: a user's scale readings and DEXA scans, the estimates computed from them and the rules for importing readings from a source such as Withings.
backend/main
Package mainbackend is the main backend, the process behind `dexafix serve api`.
Package mainbackend is the main backend, the process behind `dexafix serve api`.
estimate
Package estimate builds one estimated result per day from DEXA scans and scale/body-composition readings.
Package estimate builds one estimated result per day from DEXA scans and scale/body-composition readings.
frontend
Package frontend serves the HTML pages (Go templates + htmx).
Package frontend serves the HTML pages (Go templates + htmx).
mailer
Package mailer sends plain-text e-mail through an SMTP server.
Package mailer sends plain-text e-mail through an SMTP server.
models
Package models holds the domain types shared by the store, estimator and web layers.
Package models holds the domain types shared by the store, estimator and web layers.
shared
Package shared is the parent of the packages that the frontend and the backend have in common.
Package shared is the parent of the packages that the frontend and the backend have in common.
shared/apiclient
Package apiclient is how the frontend process talks to the backend process.
Package apiclient is how the frontend process talks to the backend process.
shared/bodyapi
Package bodyapi is the contract between the main backend and the body service, the part that holds a user's scale readings and DEXA scans and computes their estimates.
Package bodyapi is the contract between the main backend and the body service, the part that holds a user's scale readings and DEXA scans and computes their estimates.
shared/edge
Package edge holds the HTTP edge code shared by the frontend and the backend process: working out who the visitor is behind a reverse proxy, the PROXY protocol, and request limiting.
Package edge holds the HTTP edge code shared by the frontend and the backend process: working out who the visitor is behind a reverse proxy, the PROXY protocol, and request limiting.
shared/inproc
Package inproc is an http.RoundTripper that runs a request against an http.Handler in the same process.
Package inproc is an http.RoundTripper that runs a request against an http.Handler in the same process.
shared/jobs
Package jobs tracks the background jobs of one half of the application.
Package jobs tracks the background jobs of one half of the application.
shared/mtls
Package mtls secures the link between the web (frontend) and api (backend) processes with mutual TLS: the backend only talks to a client that presents a certificate from the configured CA, and the frontend only talks to a backend that presents one.
Package mtls secures the link between the web (frontend) and api (backend) processes with mutual TLS: the backend only talks to a client that presents a certificate from the configured CA, and the frontend only talks to a backend that presents one.
shared/must
Package must turns an error that cannot happen into a panic, so that a caller does not carry a branch no test can reach.
Package must turns an error that cannot happen into a panic, so that a caller does not carry a branch no test can reach.
shared/timezones
Package timezones lists the common IANA time zones and validates a name.
Package timezones lists the common IANA time zones and validates a name.
shared/tlsutil
Package tlsutil checks PEM certificates; the frontend serves them and the backend stores them.
Package tlsutil checks PEM certificates; the frontend serves them and the backend stores them.
shared/workerapi
Package workerapi is the contract between the backend and the workers: processes that talk to outside services (Withings, Strength Level, ...) for the backend and have no database.
Package workerapi is the contract between the backend and the workers: processes that talk to outside services (Withings, Strength Level, ...) for the backend and have no database.
store
Package store defines the persistence interface used by the application.
Package store defines the persistence interface used by the application.
store/sqlstore
Package sqlstore implements store.Store on top of bun, for SQLite and PostgreSQL.
Package sqlstore implements store.Store on top of bun, for SQLite and PostgreSQL.
store/valkeystate
Package valkeystate keeps the state that must agree across backend processes and is touched on every sign-in in Valkey (or any Redis-compatible server) instead of the database: the failed attempt counters and the single-use nonces.
Package valkeystate keeps the state that must agree across backend processes and is touched on every sign-in in Valkey (or any Redis-compatible server) instead of the database: the failed attempt counters and the single-use nonces.
workers
Package workers is the parent folder of the worker processes' code: one package per provider (pkg/workers/withings, pkg/workers/strengthlevel, ...) next to the generic loop in pkg/workers/runner.
Package workers is the parent folder of the worker processes' code: one package per provider (pkg/workers/withings, pkg/workers/strengthlevel, ...) next to the generic loop in pkg/workers/runner.
workers/builtin
Package builtin lists the workers that ship with the program, so the processes that run them (dexafix serve worker, and the single-process mode) choose providers by name without knowing any of them.
Package builtin lists the workers that ship with the program, so the processes that run them (dexafix serve worker, and the single-process mode) choose providers by name without knowing any of them.
workers/runner
Package runner is the loop every worker runs: register with the backend, lease jobs, run the handler of the job's kind while renewing the lease, and report how it ended.
Package runner is the loop every worker runs: register with the backend, lease jobs, run the handler of the job's kind while renewing the lease, and report how it ended.
workers/strengthlevel
Package strengthlevel is the worker for Strength Level.
Package strengthlevel is the worker for Strength Level.
workers/withings
Package withings is the worker for Withings: it talks to the Withings API for the backend.
Package withings is the worker for Withings: it talks to the Withings API for the backend.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL