Shared browser-based calorie and weight tracker with an Express API, SQLite persistence, Docker packaging, and an included assistant skill for assistant logging.
Synthetic demo screenshots are included below; they do not contain real user data.
- Shared SQLite-backed meal and weight history
- REST API for meals, weights, edits, deletes, and assistant-friendly logging
- Dashboard and journal pages served from the same container
- Optional
API_TOKENwrite protection viax-api-token - Docker image build workflow for GitHub Actions / GHCR
- Bundled skill at
skills/calorie-tracker-api/
.
├─ .github/workflows/container.yml # CI: check, smoke test, build/publish image
├─ Dockerfile # Production container image
├─ docker-compose.yml # Local/self-hosted deployment example
├─ package.json
├─ package-lock.json
├─ server.js # Express + SQLite API + static hosting
├─ public/ # Browser UI
├─ scripts/smoke-test.mjs # API smoke test used by CI
└─ skills/calorie-tracker-api/ # assistant skill for agent/API usage
A synthetic demo export is available at examples/demo-export.json. It is safe to use for screenshots, local testing, and import/restore demos; it contains no real user data.
Dry-run import into a local server:
npm run import -- examples/demo-export.json http://localhost:8080Apply it to a disposable local database:
npm run import -- examples/demo-export.json http://localhost:8080 --applyRequires Node.js 22.x because the backend uses node:sqlite.
npm ci
npm run check
npm run smoke
npm startOpen: http://localhost:8080
By default the database is created at ./data/tracker.db. Override with DATA_DIR or DB_PATH if needed.
For self-hosting, reverse proxy, backup, restore, and update procedures, see DEPLOYMENT.md.
Future improvement ideas and project scope boundaries are tracked in ROADMAP.md.
docker build -t calorie-tracker:local .
docker run --rm -p 8092:8080 -v calorie_tracker_data:/app/data calorie-tracker:localOpen: http://localhost:8092
Or use Compose:
docker compose up -d --buildThe included workflow in .github/workflows/container.yml does this on pull requests and pushes:
- Install dependencies with
npm ci - Run
npm run check - Run
npm run smoke - Build the Docker image with Buildx
- Publish to GHCR on non-PR pushes
Published image tags include:
mainfor default-branch builds- branch tags for branch pushes
- version tags for
v*.*.*tags sha-<commit>tags for traceability
The manual Release workflow publishes latest. In other words, latest means latest stable release, while main means current main-branch build.
Expected image path once the repository is on GitHub:
ghcr.io/<owner>/<repo>:latest
If the repository name contains uppercase letters, rename it or adjust the workflow image name to lowercase before first publish; GHCR image names must be lowercase.
The important state is the SQLite database in the Docker volume mounted at /app/data. For home deployments, back this volume up before upgrades and on a regular schedule.
Simple export check:
curl http://localhost:8092/api/export > calorie-tracker-export.jsonOr use the bundled helper, which writes to backups/ by default:
npm run export -- http://localhost:8092Override the destination path:
CALORIE_TRACKER_EXPORT_PATH=/safe/backups/calorie-tracker.json npm run exportFor a full database backup, stop the container or use SQLite-aware backup tooling, then copy tracker.db from the data volume.
Imports are safe by default: the helper performs a dry-run unless --apply is provided. The default mode is merge/upsert.
Dry-run an export restore:
npm run import -- backups/calorie-tracker-export.json http://localhost:8092Apply a merge/upsert restore:
npm run import -- backups/calorie-tracker-export.json http://localhost:8092 --applyReplace all existing rows before importing:
npm run import -- backups/calorie-tracker-export.json http://localhost:8092 --apply --replaceIf API_TOKEN is set on the server, pass it with --token or CALORIE_TRACKER_API_TOKEN.
Set API_TOKEN to require x-api-token on write endpoints:
environment:
- API_TOKEN=change-meProtected routes:
POST /api/meals,PUT /api/meals/:id,DELETE /api/meals/:idPOST /api/weights,PUT /api/weights/:id,DELETE /api/weights/:idPOST /api/log
Security note: API_TOKEN is lightweight API write protection, not a complete user login system. For internet-facing or multi-user deployments, add reverse-proxy auth, VPN access, or another trusted access layer in front of the app.
GET /api/healthGET /api/exportPOST /api/importGET /api/meals?limit=2000POST /api/mealsPUT /api/meals/:idDELETE /api/meals/:idGET /api/weights?limit=2000POST /api/weightsPUT /api/weights/:idDELETE /api/weights/:idPOST /api/logwith{ "kind": "meal|weight", "payload": { ... } }
The repo includes skills/calorie-tracker-api/SKILL.md. After cloning/installing the repo where assistant can read it, copy or symlink that skill folder into the assistant skills directory if it is not automatically mounted by your deployment.
For the existing your-tracker.example.com deployment, keep the container reachable by reverse proxy. If reverse proxy proxies by Docker DNS name, attach the container to the same proxy network used by reverse proxy, for example:
docker network connect infra_proxy calorie-tracker 2>/dev/null || trueUse the Release workflow to create a version tag from the current main branch:
- Open Actions → Release → Run workflow.
- Enter a semver version like
2.0.1. - The workflow creates and pushes tag
v2.0.1. - The Release workflow creates the tag, publishes versioned GHCR tags directly, and creates a GitHub Release with image references.
The Release workflow publishes these image tags:
latestvX.Y.ZX.Y.ZX.Ysha-<commit>
Recommended deployment tags:
ghcr.io/<owner>/<repo>:latestfor automatic latest stable release updatesghcr.io/<owner>/<repo>:vX.Y.Zfor pinned stable home deploymentsghcr.io/<owner>/<repo>:sha-<commit>for exact rollback/debuggingghcr.io/<owner>/<repo>:mainonly when you intentionally want newest main-branch build
GPL-3.0, matching the repository license.