The release where a failed request says so. Every screen that could hang, blank out or
invent a number now tells you what happened instead — plus food by weight, a name of your
own, and exercises served live rather than shipped as a copy.
Breaking changes
Only self-hosters driving the HTTP API directly are affected; the web and mobile apps are
updated in step. Full detail for each is in docs/API_CHANGES.md at this tag.
POST /api/v1/auth/refreshcan now refuse a structurally valid token (#114)
Refresh is checked against the account's token version, so a token issued before a
password change — or for a deleted account — answers401instead of minting a new
pair. Handle401by signing in again. Tokens issued before this release survive the
upgrade itself.GET /api/v1/exercisesfilters and values are slugs (#116)
?equipment=body onlynow matches nothing; sendbody-only. Alsoe-z-curl-bar,
medicine-ball,exercise-ball,foam-roll,olympic-weightlifting,lower-back,
middle-back, andnonefor what used to be an emptyequipment. A boot migration
rewrites stored values to match, so a value out of a response goes straight back into a
filter.- The exercise catalog is served live from open-exercise-db (#116)
The seeded 800-row copy of free-exercise-db is gone. Different ids, names, descriptions
and image URLs; a fresh install starts empty and fills as searches run; upstream results
are no longer alphabetically ordered. Nothing deletes a row that workout or program data
references. - The three
admin/*exercise endpoints changed shape and behaviour (#116)
seed-statuslostin_progress(there is no background seed to be inside any more);
sync-exercisesanswers{"refreshed":N}and refreshes the cache rather than
importing;reset-exercisesanswers{"cleared":N}and clears only unreferenced rows
rather than wiping and re-seeding. A caller pollingin_progresswill loop forever. POST /api/v1/food/savedanswers200for a repeat star (#136)
Starring an already-starred food returns200with the row that exists, not201with
the row you described — so the request's macros are discarded. Treat200and201
alike. A boot migration deletes duplicate rows, keeping the lowest id per food, so an id
that lost that dedupe now404s on delete.nameandbrandare trimmed before validation on the food write paths (#139, #142)
POST /api/v1/food,PUT /api/v1/food/:idandPOST /api/v1/food/saved. A
whitespace-only name is refused with422instead of stored; a padded name round-trips
trimmed, so exact-string matching against your own records can mismatch.servingsis capped at 100 (#186)
Above that is a422. Bulk importers writing large multipliers should split the entry
or scale the per-serving macros instead.
Late correction, shipped in v0.1.0-beta.6 and never announced:
GET /api/v1/weightaccepts a calendar day only.fromandtomust be
YYYY-MM-DD; a timestamp is rejected with400, where a malformed bound used to be
ignored and quietly return the whole history.
Also worth knowing
Not breaking, but you may notice them:
DEMO_MODEno longer defaults on in development. A barego run .no longer seeds
the demo account; opt in withDEMO_MODE=true. Compose andfly.tomlare unchanged.serving_sizeon food search and barcode results reads"100 g"or"100 ml"
instead of"per 100g". A display label; the macro figures behind it are unchanged.- Every API error message is now a sentence. No status code, route or field changed;
a caller matching on the wording will need updating.
What's new
A failed request says so, everywhere (#145, #153, #154, #155, #157, #158, #163, #177,
#180, #181)
A request that got no answer no longer hangs the thing that was waiting on it. The token
refresh ran on an unbounded client, so one dead network moment left a saving spinner, a
disabled button or a half-drawn screen stuck until the app was force-quit — #145 was
filmed as a workout timer ticking beside five taps on a dead button. Every request now
settles, and only the server can end a session: a timeout, a dropped connection or a 502
from a restarting backend keeps you signed in and offers a retry, where it used to look
like a sign-out. Nine mobile confirm sheets that swallowed their errors now show the reason
under the same finger that tapped. The API answers in sentences rather than validator
jargon, and a screen that failed to load says what failed instead of drawing a chart of
nothing.
Log food by weight, and read the pack's own serving (#186)
Enter 150 g rather than working out what fraction of a serving that is. Where a barcode
carries its own serving size, that is what the figures are scaled by, instead of assuming
100 g. This is also what #41 asked for. The amount field stops at what one entry holds
(100 servings) as you type, and says why a key did not land, rather than showing a figure
the Log button then refuses (#191).
A name of your own (#187)
Set a display name in Settings and the dashboard greets you by it, with a different
weightlifting line under it each day. Without one it still falls back to your email, as
before.
Change your password in the app, and reset it from the CLI when it's lost (#114)
Settings has a password form on both platforms. For a self-hoster locked out of their own
instance there is a reset-password command that does not need the old password. Changing
a password now ends sessions holding older tokens.
Say when a barcode lookup is running, and why it failed (#183)
A scan used to sit silent for as long as the lookup took. It now shows that it is working,
and distinguishes "no such product" from "the lookup could not be reached".
Exercises come from open-exercise-db (#116)
The catalog is queried live and cached as it is read, rather than seeding 800 rows into
every install. Smaller images, upstream corrections arrive without a release, and one
shared taxonomy of slugs across the filter and the payload.
One food is one favourite (#115, #136, #137, #139, #142, #190)
The star is a single control, tappable anywhere on the row, and present in the diary as
well as search. It answers the tap at once, and if the server refuses it flips back and
says why, under your finger, instead of a banner at the top of a scrolled list. Starring the same food twice no longer creates a second favourite, names
and brands are normalised on read and on write, and rows already stored are repaired on
boot. Deleting from My Foods works.
Decimal numbers can be typed on any keyboard (#141, #147)
Android's number pad draws the locale's separator, and for half of Europe that is a comma
with no full stop available — which made a decimal weight unenterable. Every numeric field
now accepts the separator the keyboard actually emits, with one shared sanitiser behind
them.
Accessible names, and gym mode is a dialog (#156, #178)
Controls that were icon-only now have names a screen reader can read, gym mode announces
itself as a dialog and traps focus, and mobile's semantic colours are the theme's decision,
held to AA contrast on both grounds.
Fixes and improvements
- Fix the app shell: metadata, fonts, demo sign-in and a transparent header (#152)
- Stop the dev loop crashing — let Expo configure Metro for the monorepo (#143)
- Mobile pickers share one server list, one scanner and one inline confirm (#179)
- Weight figures each answer for the read they came from, rather than one shared spinner
(#181) - Stop two food-history tests and the weight figures test from rotting with the calendar
(#176, #182) - Build the tester APK on Node 22, which eas-cli now requires (#149)
- Fix the release badge and every APK download link (#112)
- Refresh every screenshot against the current UI (#113)
- Add the sponsorship and support links across the repo (#111)
Security and supply chain
- Add CodeQL, dependency review and Dependabot config (#121), and drop Dependabot's
version-update PRs in favour of the advisory ones (#133) - Bump dependencies to clear every fixable advisory (#120)
- Every PR is reviewed automatically, with the defect classes worth hunting in this repo
spelled out, a size cap so the reviewer never reads a diff nobody would, and a check
branch protection can require (#159, #160, #161, #162, #175)
Known issues
- Gym Mode rep and weight inputs can overwrite what you typed on consecutive keypresses
(#151) — not yet reproduced outside the reporter's device; a fix is held until it is. - Typed weights are not held to the app's own 0.1 precision (#148).
Contributors
@dhananjaypesu (#139)
@pdschneider (#115, #164, #170, #171)
@Cabiny6 (#141, #145)
@valterschutz (#41)
@Cawlumm
Android (side-load)
Download lyftr-v0.1.0-beta.7.apk below. On your phone, open it and
allow "install from unknown sources" if prompted.
iOS is distributed via TestFlight / the App Store (Apple doesn't allow
side-loading), so it isn't attached here.
What's Changed
- Add the sponsorship and support links across the repo by @Cawlumm in #111
- Fix the release badge and every APK download link by @Cawlumm in #112
- Refresh every screenshot against the current UI by @Cawlumm in #113
- Change your password in-app, and reset it from the CLI when it's lost by @Cawlumm in #114
- Query open-exercise-db for exercises instead of shipping a copy by @Cawlumm in #116
- Add CodeQL, dependency review, and Dependabot config by @Cawlumm in #121
- Drop Dependabot version updates by @Cawlumm in #133
- Bump dependencies to clear every fixable advisory by @Cawlumm in #120
- Favorites: one star, tappable anywhere by @Cawlumm in #136
- Trim saved food names and brands so one food is one favourite by @dhananjaypesu in #139
- Close out #137: normalise on read, on write, and for rows already stored by @Cawlumm in #142
- Build the tester APK on Node 22, which eas-cli now requires by @Cawlumm in #149
- Accept the separator the keyboard actually emits (#141) by @Cawlumm in #147
- Stop the dev loop crashing: let Expo configure Metro for the monorepo by @Cawlumm in #143
- Fix the app shell: metadata, fonts, demo sign-in, and a transparent header by @Cawlumm in #152
- Bound the token refresh, and stop treating silence as a verdict (#145) by @Cawlumm in #153
- The API answers in sentences by @Cawlumm in #154
- No blank screens, no invented dates by @Cawlumm in #155
- Accessible names, and gym mode is a dialog by @Cawlumm in #156
- The error state itself: one mark, one component, both apps by @Cawlumm in #157
- Oversight: review every PR, and give branch protection a check to require by @Cawlumm in #159
- Make the review workflow skip cleanly when unconfigured by @Cawlumm in #160
- Tell the reviewer what matters in this repo by @Cawlumm in #161
- Cap PR size, and stop the reviewer reading a diff nobody would by @Cawlumm in #162
- The plumbing every failing request goes through by @Cawlumm in #158
- Give the review defect classes to hunt, not just severities by @Cawlumm in #175
- Say when something failed, instead of drawing the wreckage by @Cawlumm in #163
- Stop two food-history tests from rotting with the calendar by @Cawlumm in #176
- Mobile: a failed save or delete says so, where the tap was by @Cawlumm in #177
- Mobile: semantic colour is the theme's decision, held to AA by @Cawlumm in #178
- Mobile: pickers on useServerList, one scanner, one inline confirm by @Cawlumm in #179
- Mobile: a failed load says it failed, scoped to what failed by @Cawlumm in #180
- Web: each weight figure answers for the read it came from by @Cawlumm in #181
- Stop the weight figures test clicking a button that isn't there yet by @Cawlumm in #182
- Show a barcode lookup is running, and say why it failed by @Cawlumm in #183
- Star a food from the diary too by @Cawlumm in #185
- Log food by weight, and read the pack's own serving by @Cawlumm in #186
- The dashboard greeting: a name of your own, and a line under it by @Cawlumm in #187
- Record the nine API breaks beta.7 is carrying, and format main by @Cawlumm in #188
- A failed star flips back and toasts why, instead of a banner above the list by @Cawlumm in #190
- Stop the Log Food amount field taking a value no entry can hold by @Cawlumm in #191
New Contributors
- @dhananjaypesu made their first contribution in #139
Full Changelog: v0.1.0-beta.6...v0.1.0-beta.7