Commit graph

12 commits

Author SHA1 Message Date
Danny
9f146d60fa feat: last-session recall when starting an exercise
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>
2026-05-22 12:52:37 +02:00
Danny
6d1de53b2e feat: profile/settings (rest timer toggle)
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>
2026-04-19 15:36:06 +02:00
Danny
52277e99de feat: interaction / event logging
New `events` table with (user_id, kind, created_at, data JSON).
Instruments:

Bot:
- cmd.start, cmd.history, cmd.stats, cmd.delete, cmd.export, cmd.feedback
- workout.save (source=text), workout.delete (source=bot)

Server:
- workout.save (source=webapp), workout.update, workout.delete (source=webapp)
- POST /api/events for Mini App client-side events

Mini App:
- miniapp.open on init()
- set.add on addSet(), with exercise name / reps / weight
  (per-set timestamps unlock the rest-timer feature later)

log_event swallows failures so it can never break a caller.
get_events supports user_id / kind filtering for inspection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:03:42 +02:00
Danny
0e4bf65d5b feat: global exercise-name autocomplete
Autocomplete now draws from every user's logged exercises, not
just the requesting user's history. New users get suggestions from
day one.

- db.get_all_exercise_names(): case-insensitive grouping, ordered
  by usage count desc, alphabetical tiebreak, excludes names that
  only appear in soft-deleted workouts.
- server.api_get_exercise_names simplified to a one-liner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:56:53 +02:00
Danny
bc1d44b556 feat: per-user workout numbering (#7)
Display workouts as "#N" based on each user's own ordered list of
non-deleted workouts (rank by timestamp ascending). Global auto-
increment id stays the primary key, used only internally and in
exports. User-visible surfaces now all use the per-user number:
- /history listing
- /delete now accepts the per-user number
- Save confirmations (bot text and Mini App toast)

Deleting a workout renumbers the later ones downward, as expected
for a pure display transform.

New db helpers: get_user_workout_number, resolve_user_number, and
get_workouts now includes user_number per row via SQLite window
function.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:32:24 +02:00
Danny
7f061c5b11 feat(server): version badge now shows ISO date + short SHA
Format: 'YYYY-MM-DD <short-sha>'. Preferred path uses
`git log -1 --format='%cs %h'`.

Fallback path (no git on PATH) resolves HEAD (loose or packed refs)
and parses the loose commit object via zlib to extract committer
date, converted to UTC date. Degrades gracefully to SHA-only if
the commit object is packed or unreadable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:31:30 +02:00
Danny
0872d545d5 fix(server): pure-python fallback for version when git is not on PATH
The systemd service environment on the NixOS deploy host has a
minimal PATH without git, so subprocess.run(['git', ...]) fails
with FileNotFoundError and /api/version returned 'unknown'.

Fall back to reading .git/HEAD directly (resolving the ref) and
returning the short SHA. Loses tag/dirty detection, but unblocks
the version badge in deployed environments.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 18:39:26 +02:00
Danny
b4d76b0eca feat(webapp): show running version in Mini App footer
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>
2026-04-18 17:38:52 +02:00
Danny
6fb6207041 feat(tg-fitness-bot): soft delete, edit workouts, notes via API
Deleted workouts are marked with deleted_at instead of being removed.
All queries filter on deleted_at IS NULL. New update_workout() does
soft-delete + recreate preserving the original timestamp. PUT endpoint
at /api/workouts/{id}. POST /api/workouts now accepts a note field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:41:37 +02:00
Danny
a934c46746 feat(tg-fitness-bot): multi-set format, delete, export, SQL stats
Parser now supports per-set notation (8x25, 5x35, 6x40),
bodyweight exercises (3x10), and asterisk separators.
Failed parse lines get user-facing error feedback instead of
being silently ignored.

Added /delete <id> and /export commands. Stats computed in SQL
instead of loading all workouts into memory. API gains DELETE,
CSV and JSON export endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 22:46:10 +02:00
Danny
f2cfe72d63 Switch from localtunnel to cloudflared, fix static file serving
- Replace localtunnel with cloudflared (no interstitial password page)
- Wait for "Registered tunnel connection" before starting bot
- Serve index.html at / instead of directory listing
- Remove localtunnel npm package build from flake.nix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:35:05 +01:00
Danny
f025e5fd19 Add Telegram Mini App (web UI + API server + localtunnel)
- 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
2026-03-24 20:17:36 +01:00