github Cawlumm/lyftr v0.1.0-beta.7

pre-release4 hours ago

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/refresh can 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 — answers 401 instead of minting a new
    pair. Handle 401 by signing in again. Tokens issued before this release survive the
    upgrade itself.
  • GET /api/v1/exercises filters and values are slugs (#116)
    ?equipment=body only now matches nothing; send body-only. Also e-z-curl-bar,
    medicine-ball, exercise-ball, foam-roll, olympic-weightlifting, lower-back,
    middle-back, and none for what used to be an empty equipment. 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-status lost in_progress (there is no background seed to be inside any more);
    sync-exercises answers {"refreshed":N} and refreshes the cache rather than
    importing; reset-exercises answers {"cleared":N} and clears only unreferenced rows
    rather than wiping and re-seeding. A caller polling in_progress will loop forever.
  • POST /api/v1/food/saved answers 200 for a repeat star (#136)
    Starring an already-starred food returns 200 with the row that exists, not 201 with
    the row you described — so the request's macros are discarded. Treat 200 and 201
    alike. A boot migration deletes duplicate rows, keeping the lowest id per food, so an id
    that lost that dedupe now 404s on delete.
  • name and brand are trimmed before validation on the food write paths (#139, #142)
    POST /api/v1/food, PUT /api/v1/food/:id and POST /api/v1/food/saved. A
    whitespace-only name is refused with 422 instead of stored; a padded name round-trips
    trimmed, so exact-string matching against your own records can mismatch.
  • servings is capped at 100 (#186)
    Above that is a 422. 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/weight accepts a calendar day only. from and to must be
    YYYY-MM-DD; a timestamp is rejected with 400, 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_MODE no longer defaults on in development. A bare go run . no longer seeds
    the demo account; opt in with DEMO_MODE=true. Compose and fly.toml are unchanged.
  • serving_size on 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

Full Changelog: v0.1.0-beta.6...v0.1.0-beta.7

Don't miss a new lyftr release

NewReleases is sending notifications on new releases.