When you start an exercise, the Mini App now fetches the most
recent time you logged it and shows a hint line in the sets card
("Last time: 8×60, 6×60, 5×60 · 3 days ago"), plus pre-fills the
weight input with the last set's weight.
- db.get_last_exercise(user_id, name): most recent non-deleted
entry, case-insensitive name match, sets_detail parsed.
- GET /api/exercises/last?name=<name>.
- webapp: loadLastSession() on startExercise + draft restore;
hint cleared on editExercise (the set rows are the reference
there). Pre-fill only when the weight field is empty and no
sets logged yet, so it never clobbers user input.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
iOS numeric keypad has no minus key, so users couldn't enter
negative weights for assisted bodyweight exercises (e.g. -20 kg
assisted pull-ups).
Added a small +/- button next to the weight input that flips the
sign of whatever's there (or seeds a lone "-" when the field is
empty so the user can type digits after it). Active state lights
up the button so you can see at a glance that the value is
negative. Parses and stores as a negative REAL in SQLite; existing
display code (fmtWeight) already handles negative numbers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Settings infrastructure + one working preference:
- New user_settings table (JSON blob per user, so adding
future keys needs no migration).
- db.get_settings / update_settings helpers (merge semantics).
- GET/PUT /api/settings endpoints.
- New Settings tab in the Mini App with a rest-timer on/off
toggle. Setting is loaded on init and written through on
change; the rest-timer display now respects it.
Units (kg/lb) and language are intentionally left unwired for
now — each needs end-to-end display/input changes and deserve
focused passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously only the bot's /delete command could remove a workout —
the Mini App history view had an edit pencil but no delete button.
Added a trash-icon button next to the pencil with a native
Telegram confirm dialog before deleting.
Also added the per-user workout number to each history card header
(e.g. "#3 · Sun 19 Apr 2026, 14:30") so users can correlate with
the number shown in save toasts and /history.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Shows mm:ss since the last set was added for the current exercise.
Purely client-side — no round trip to the server. Resets on new
exercise, clears when no current exercise or 0 sets, and survives
draft restore.
The settings-toggle gate is still TBD (Profile/settings feature
isn't built yet); the timer is small and muted enough to keep
always-on in the meantime.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The two concerns sharing one gray block felt crowded. Giving the
next-exercise input its own card creates clear visual separation
and a natural "what comes next" feel.
Drop the now-redundant top-border/padding on .sets-section since
it's its own card now.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The empty "Exercise name" field above the current exercise's sets
felt counter-intuitive. Putting it below the sets reads naturally:
current exercise on top, prompt to start the next one at the bottom.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Compute `git describe --tags --always --dirty` at server startup
and expose via unauthenticated /api/version. Render as small muted
text at the bottom of the Mini App so the running version can be
confirmed at a glance.
Once tags exist, the badge will show e.g. v0.1.0 or v0.1.0-3-gSHA.
Until then it shows the short SHA.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rebuilt Log view: exercise name input with autocomplete, per-set
entry (reps x weight), exercise cards with edit/remove. Comma and
dot both work as decimal separators. Notes field. Collapsible raw
text input as fallback.
Edit saved workouts from History (pencil icon). Loads exercises
into editor, Save becomes Update, Cancel returns to History.
localStorage draft persistence: auto-saves on every state change,
restores on reopen (24h expiry), clears on save.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- server.py: aiohttp API serving webapp/ and REST endpoints using existing db.py
- start.py: orchestrator that loads token, starts server + localtunnel + bot
- webapp/: Mini App frontend (Log, History, Stats) with Telegram-native theming
- bot.py: added Mini App menu button and inline button on /start
- flake.nix: added aiohttp + localtunnel, nix run now uses start.py