A no-BS, self-hosted weight and calorie tracker built with FastAPI + Jinja templates and offline-first frontend behavior.
- Backend:
main.pyserves full templates and HTMX partials. - Frontend bootstrap:
static/js/bootstrap.mjs(exportswindow.MaxModeAPI compatibility layer). - Frontend modules:
static/js/modules/storage.mjs: localStorage-backed state snapshot (loadState) and mutations.static/js/modules/data-utils.mjs: pure weight/chart/date utilities.static/js/modules/charts.mjs: dashboard/weights SVG chart rendering.static/js/views/dashboard-ui.mjs: dashboard metric rendering.static/js/views/weights-ui.mjs: weights list/chart/modal/delete UI.static/js/views/profile-ui.mjs: profile + avatar rendering.
- HTMX compatibility layer:
static/vendor/htmx.min.js(self-hosted). - PWA worker:
service-worker.jswith safe caching rules and update handling.
uv run uvicorn main:app --reloadOpen: http://127.0.0.1:8000
- The calorie tracker uses
LiteLLMfor provider-agnostic meal estimation. - Current dev/test default: set
OPENAI_API_KEYin.env. - Optional provider override: set
MEAL_AI_MODEL(for exampleanthropic/...,openai/..., orvertex_ai/...).
Backend route/rendering tests:
uv run python -m unittest discover -s tests -vFrontend pure utility tests:
node --test tests_frontend/*.test.mjs- Load
/,/weights,/profileonline. - Add/edit/delete weight entries and verify chart + dashboard + profile updates.
- Switch chart ranges (
7D,30D,90D,All) and verify chart redraw. - Refresh with service worker active and confirm app still loads offline.
- Verify
HX-Requestpartial swaps update only#main-content.