chore: update changelog, remove stale files, scrub VPS IP

- CHANGELOG.md: add [Unreleased] 2026-04-16 section covering settings
  page, admin tools, password reset, re-extract, community page, SSE
  upload progress, and all bug fixes since 2026-04-10
- Remove docs-proposal.md (internal planning doc, not user-facing)
- Remove publish/ directory (leftover artefacts from publish.sh, not
  meant to be tracked)
- scripts/pull_feedback.sh: replace hardcoded default VPS IP with a
  required positional argument to avoid leaking server address
- docs/squash-for-github.md: document the squash-for-github commit
  strategy for future reference
This commit is contained in:
Davide Scaini
2026-04-16 18:09:32 +02:00
parent a78f6ee3bd
commit c68dfa9057
7 changed files with 175 additions and 441 deletions
+95
View File
@@ -1,5 +1,100 @@
# Changelog
## [Unreleased] — 2026-04-16
### New feature — Self-service user settings page
- **`site/src/pages/settings/index.astro`** — new `/settings/` page with three sections:
- **Account** — display name editor, storage quota view (uploaded activities + originals size)
- **Integrations** — per-user Strava client ID/secret (replaces instance-level credentials for
multi-user deployments); saved to `settings` table via `PATCH /api/me`
- **Danger zone** — two separate destructive actions:
- **Delete originals** — removes `{user_dir}/originals/` without touching activities
- **Delete all activities** — wipes all activities, edits, GeoJSON, and `_merged/`; triggers rebuild
- Nav visibility toggles — user can hide any combination of Feed / Stats / Athlete tabs from
their navigation; preference saved to `settings` table and applied in `Base.astro`
### New feature — Upload overwrite option
- **`POST /api/upload`** — new `overwrite: bool` form field; when true, an existing activity
with the same ID is replaced rather than returning 409. UI checkbox added to the upload modal.
### New feature — Admin tools
- **Ghost user detection** — `/admin/` now marks users whose handle has a data directory but
no entry in the `users` table (e.g. manually created dirs, or users deleted from DB); shown
with a "ghost" badge
- **Delete directory button** — admin can delete a user's entire data directory without
touching the DB entry; useful for cleaning up ghost dirs or corrupted accounts
- **Delete all activities** (`DELETE /api/admin/users/{handle}/activities`) — wipes
`activities/`, `edits/`, `_merged/`, and `index.json` for a handle, then triggers a rebuild;
admin page shows a confirmation `<dialog>` before firing
- **"Admin" nav link** — visible in the top-right for admins only
### New feature — Password reset (admin-generated one-time code)
No email infrastructure required. Flow:
1. Admin visits `/admin/` → clicks "Reset pwd" → a 24-hour code appears inline (click to copy)
2. Admin sends it out-of-band (Signal, Telegram, etc.)
3. User goes to `/reset-password/`, enters handle + code + new password
- `POST /api/admin/users/{handle}/reset-password-code` (admin) → `{code, expires_in_hours: 24}`
- `POST /api/auth/reset-password` (public) → body `{handle, code, password}`
- `reset_codes` table in `instance.db`; generating a new code invalidates prior unused codes;
used codes kept for audit
### New feature — Re-extract from Strava originals
- **`POST /api/admin/reextract`** — re-runs the extract pipeline over all
`{user_dir}/originals/strava/*.json` files without hitting the Strava API again;
streams progress via SSE; useful after pipeline improvements
- Runs as a subprocess to avoid OOM (`malloc_trim` + `gc.collect` every 50 activities);
processes in batches of 100 to bound peak RSS
### New feature — Community page
- **`/community/` tab** — sortable table of all registered users: display name, handle,
member since, invited by; replaces the earlier inline community section on the about page
### New feature — Streaming upload progress
- **`POST /api/upload`** now returns `text/event-stream` instead of JSON
- Per-file progress events: `↓ 3/47 (6%) — morning_ride.fit`
- Final `done` event: `"12 added, 35 duplicates"`
- Vite proxy configured to not buffer the stream
### Bug fixes
- **`elevation_gain_m` null for modern Garmin FIT files** — session message `total_ascent`
field now read as fallback when per-point elevation gain is zero
- **Map flash on activity detail** — map container height set before `fitBounds` to prevent
a zero-height frame during load
- **Absolute `track_url` / `detail_url` paths** — `ActivityDetail` and `loadActivity` now
handle both relative and absolute paths in BAS JSON
- **Corrupted time streams causing OOM** — `metrics.py` guards against non-monotonic or
pathologically large time arrays before allocating the 1 Hz dense array
- **Merge race condition** — `merge_all` wipe + rewrite is now guarded; concurrent upload
triggers can no longer interleave a `shutil.rmtree` with a write from another request
- **Temp ZIP leak** — upload temp files now written to `/tmp/` and always deleted in a
`finally` block; a startup hook auto-cleans any leftovers
- **`bincio init` always overwrites `private`** — fixed to preserve existing value when
`index.json` already exists
- **Auth wall flash** — `Base.astro` now sets the auth state synchronously from a cookie
hint before the `fetch('/api/me')` resolves, eliminating the visible flash
- **Single-user redirect loop** — `index.astro` no longer redirects to `/u/{handle}/` on
private (multi-user) instances
- **Theme-aware Plot tooltips** — forced black text on white background; was rendering
grey-on-white (unreadable in light mode) and white-on-dark (unreadable in dark mode)
- **Theme-aware chart axis colors** — axis labels and tick marks now use the correct
foreground color in both light and dark themes
- **TS type annotation in `define:vars` script** — removed; Astro injects `define:vars`
blocks as plain JS, not TypeScript
- **Image refs with spaces/parens in filenames** — local image references in markdown
descriptions are now stripped before rendering to avoid broken inline `<img>` tags
---
## [Unreleased] — 2026-04-10
### New feature — Per-instance user limit