Commit Graph

56 Commits

Author SHA1 Message Date
Davide Scaini 37e91af5bd feat: move Ideas into Support page tab; remove Ideas from nav 2026-06-03 11:07:35 +02:00
Davide Scaini fa14d91359 feat: Support page with budget transparency (replaces About) 2026-06-03 10:34:18 +02:00
Davide Scaini a142e8732f fix: redirect login to bincio.org (bincio-auth) when PUBLIC_AUTH_URL is set
activity.bincio.org/login/ was issuing plain session tokens; bincio-activity
now validates JWTs, so that path silently broke. Auth wall and logout now
point to the central bincio-auth service instead.
2026-06-02 16:31:46 +02:00
Davide Scaini 2c69e75842 Show orange upload button when Strava/Garmin auth fails
GET /api/me/sync-status reads _strava_sync_status.json and
_garmin_sync_status.json for the logged-in user. On page load the nav
script checks this endpoint and, if either service has status=auth_error,
turns the upload arrow orange with a tooltip naming the disconnected
service(s).
2026-05-16 20:27:43 +02:00
Davide Scaini 8af6b7b04e nav: always show upload button on all screen sizes 2026-05-14 18:24:44 +02:00
Davide Scaini 5307ae287c Explore: personal GPS heatmap tab under Athlete page
- bincio/explore.py: bake_tracks() simplifies GPS coords (RDP ε=0.0001),
  strips to [lng,lat], groups by sport type, writes per-handle tracks.json
- bake-tracks CLI command; render CLI calls _bake_tracks() after each build;
  strava_zip runs it once at end of batch
- /api/me/tracks endpoint serves the baked file; wipe_user cleans it up
- Explore.svelte: MapLibre full-screen map with sidebar — type pills,
  year/month date filter, Lines / Heatmap (global or by-type) view modes
- AthleteView: Explore tab visible only to profile owner (checks __bincioMe)
- Base.astro: fullscreen prop + Planner nav link
2026-05-14 14:31:21 +02:00
Davide Scaini e7c5af0d01 Nav: add Planner link for logged-in users (mirrors wiki link strategy) 2026-05-14 10:44:46 +02:00
Davide Scaini e4b53dde44 Nav: move Wiki to right-side menu (desktop + hamburger); fix missing element when PUBLIC_WIKI_URL unset in rebuilds 2026-05-13 20:50:04 +02:00
Davide Scaini a4b4d11fc0 Nav: move Ideas and About to right-side menu (desktop + hamburger) 2026-05-13 20:44:54 +02:00
Davide Scaini 38f2e51788 ideas: add Ideas page, nav link; remove feedback button from About
New /ideas/ page with Svelte component: card list sorted by votes,
inline submit form, optimistic vote toggling, delete for own/admin.
Bug report link moved to bottom of Ideas page. Feedback button removed
from About page.
2026-05-13 19:29:39 +02:00
Davide Scaini dd9f7a82dc Segments phase 2: /segments/ browse page, /segments/new/ creation flow, activity detail shortcut 2026-05-13 00:36:44 +02:00
Davide Scaini 93f6109028 Add hamburger menu for mobile nav 2026-05-11 11:37:33 +02:00
Davide Scaini 8fbbf460a9 Add PWA icons and manifest for iOS/Android home screen 2026-05-11 11:17:13 +02:00
Davide Scaini 14313ec59c Add Disconnect button to Strava section of upload modal 2026-05-10 17:12:55 +02:00
Davide Scaini 1eaf5c4e0b Remove TS annotation from define:vars script (caused parse error) 2026-05-10 17:10:38 +02:00
Davide Scaini 5be58f4e1c Fix Strava OAuth popup detection via postMessage (cross-origin safe) 2026-05-10 17:04:30 +02:00
Davide Scaini 82288a35ea feat(auth): wiki/activity access flags, SESSION_DOMAIN, wiki nav link 2026-05-01 21:56:02 +02:00
Davide Scaini 91d747c54a feat: seasonal race palette auto-detection on web
Inline script in Base.astro sets --accent / --accent-dim CSS variables
before first paint based on the current date. Switches to pink (Giro),
yellow (Tour), or red (Vuelta) during each Grand Tour window; falls back
to the default blue. Also aligns default --accent with the mobile app
(#60a5fa instead of #00c8ff).
2026-04-25 15:41:45 +02:00
Davide Scaini bb253cc2c1 site: accept gzip MIME types in upload file picker
Add application/gzip, application/x-gzip, and .gz to the accept
attribute so browsers show .gpx.gz / .fit.gz / .tcx.gz in the picker.
Browsers often ignore double-extension filters (.gpx.gz) without the
matching MIME type.
2026-04-16 18:54:18 +02:00
Davide Scaini a95dd07e22 fix: remove TS type annotation from define:vars script (plain JS only) 2026-04-15 20:48:11 +02:00
Davide Scaini 87a69bcc8b settings: add nav visibility prefs and per-user Strava credentials
- user_prefs table in db.py with get/set helpers
- GET/PUT /api/me/prefs endpoints for bulk pref management
- GET/PUT/DELETE /api/me/strava-credentials; PUT preserves existing
  secret when client_secret field is left blank
- _strava_creds() helper resolves per-user → instance fallback across
  all five Strava endpoints
- Settings page: Navigation card (hide Feed/Community/About toggles)
  and Strava credentials card
- Base.astro: ids on feed/community/about nav links; applies
  nav_hide_* prefs after login
2026-04-15 20:37:42 +02:00
Davide Scaini 4fd5ba428e settings: add self-service user settings page
API endpoints (all auth-gated to the logged-in user):
- GET  /api/me/storage        — per-category disk breakdown
- DELETE /api/me/originals    — free originals/ dir (post-extraction cleanup)
- DELETE /api/me/activities   — wipe all activity data (password confirm)
- DELETE /api/me              — delete account + all data (password confirm)
- PUT  /api/me/display-name   — update display name
- PUT  /api/me/password       — change password (requires current password)

Page at /settings/:
- Storage card: activities / originals / Strava originals / photos / total
  with one-click 'Delete original files' when originals exist
- Profile card: display name field with inline save
- Password card: change password form
- Danger zone: delete all activities or delete account (both require
  password confirmation in a modal before proceeding)

Nav: 'Settings' link appears in the top bar after login (same as Admin).
2026-04-15 20:24:04 +02:00
Davide Scaini 764da09130 upload: add overwrite option to replace existing activities
When 'Overwrite existing activities' is checked, duplicate activities are
re-extracted and replaced instead of silently skipped:
- Deletes {id}.json, .geojson, .timeseries.json from activities/ and _merged/
- Removes the stale index summary and dedup cache entry
- Ingests the new file fresh via ingest_parsed
- Reports 'overwritten' (↺) status in the SSE stream vs 'imported' (↓)
- done event includes 'overwritten' count; UI shows it alongside 'added'
2026-04-15 20:17:32 +02:00
Davide Scaini 5ad3aee8f6 rename privacy "private" → "unlisted"; enable GPS for unlisted
- "unlisted" = not shown in the public feed, but GPS track, timeseries
  and detail JSON are all accessible by direct URL (security by obscurity)
- "private" accepted as legacy alias everywhere (backward compat with
  existing data on disk)
- New writes from Strava sync / ZIP upload / sidecar use "unlisted"
- Only "no_gps" now suppresses the GPS track
- isUnlisted() helper in format.ts used by all Svelte/Astro components
- SCHEMA.md and CLAUDE.md document the privacy model and the distinction
  between "unlisted" and "no_gps"
2026-04-13 18:49:20 +02:00
Davide Scaini d659b90cd9 - DELETE /api/admin/users/{handle}/activities — deletes all activities/*.json, wipes _merged/ and
index.json, then triggers a rebuild. Admin-only.
  - /admin/ page — lists all users, each with a "Delete activities" button. Clicking asks for
  confirmation in a <dialog> before firing the request. Button shows "Deleted (N)" or an error inline.
  - "Admin" nav link — appears in the top-right for admins only, hidden for everyone else.
2026-04-12 17:46:28 +02:00
Davide Scaini f003fdd89f garmin sync first attempt 2026-04-12 15:36:21 +02:00
Davide Scaini 705e00f852 adding community tab 2026-04-11 14:39:19 +02:00
Davide Scaini 5de9967127 fix upload 500: add missing _file_suffix to serve server; fix iOS file picker accept types 2026-04-11 14:12:54 +02:00
Davide Scaini 8219db7bfa shorten bincioactivity to ba on mobile 2026-04-11 09:01:47 +02:00
Davide Scaini 82830222ba For users uploading:
- POST /api/upload now returns text/event-stream instead of JSON
  - Per-file progress events stream back as each file is processed: ↓ 3/47 (6%) — morning_ride.fit
  - Final done event shows the summary: "12 added, 35 duplicates"
  - The Vite proxy is configured to stream this properly (no buffering)

  For the admin:
  - New GET /api/admin/jobs endpoint (admin-only) returns the list of active upload jobs, each with
  user, started_at, total, done, current (filename being processed)
  - A pulsing amber badge appears in the nav bar for admins when any user has an active upload running
   — it shows e.g. "2 uploads running" with a tooltip listing each user's progress (@alice: 12/50
  files)
  - Polls every 5 seconds, disappears automatically when all jobs finish
2026-04-11 08:33:21 +02:00
Davide Scaini 01db4eb9ae ingest activities.csv 2026-04-11 08:13:27 +02:00
Davide Scaini bc30e0a2fc option to keep all activities private from strava zip, fix copy of register link 2026-04-10 22:51:29 +02:00
Davide Scaini da622131fd upload zip archive from strava 2026-04-10 22:26:11 +02:00
Davide Scaini fc6c00c6eb fix: mobile nav scrolls horizontally without spilling to page width
Logo and action buttons are shrink-0 anchors; nav links occupy the
remaining space with overflow-x:auto and a hidden scrollbar so they
scroll independently. body gets overflow-x:hidden to prevent the
whole page from drifting sideways on narrow screens.
2026-04-10 22:05:42 +02:00
Davide Scaini 3b8bc159c5 upload strava zip 2026-04-10 22:01:44 +02:00
Davide Scaini cf414a08ad fix strava import? 2026-04-10 18:13:32 +02:00
Davide Scaini 27f94cf581 fix: respect instancePrivate when determining single-user mode in Base.astro 2026-04-10 15:19:41 +02:00
Davide Scaini 4593478863 feedback page 2026-04-10 14:23:31 +02:00
Davide Scaini 469a5954cc "keep data on the server" opt-in/out 2026-04-10 13:01:21 +02:00
Davide Scaini 8ceb714765 bulk upload 2026-04-10 12:50:38 +02:00
Davide Scaini bf95097d75 fix image 2026-04-09 13:39:44 +02:00
Davide Scaini fb202b4edf Record / Convert tabs — now gated behind PUBLIC_MOBILE_APP=true. Hidden by default in VPS/dev mode; only show when explicitly opted into the mobile app build.
Edit/Upload UI — split into two concepts:
  - PUBLIC_EDIT_URL — the server base URL (empty = use proxy at /api/)
  - PUBLIC_EDIT_ENABLED=true — whether to show the edit/upload buttons at all

  bincio dev now sets PUBLIC_EDIT_ENABLED=true when instance.db exists (multi-user mode), so the upload button, edit button, and edit drawer all appear. The fetch calls already produce  correct relative URLs (${''}/api/upload = /api/upload) which the Vite proxy forwards to bincio serve.
2026-04-09 13:16:00 +02:00
Davide Scaini 509557ed6f fix: the user feed shows a page that nests again "feed stats athlete" that should be shown only if you are browsing a user that is not you 2026-04-09 10:35:58 +02:00
Davide Scaini cf7c71b8a3 (opus assessment) Fix auth wall flash, broken multi-user write API, and single-user redirect loop
Auth wall (Base.astro): set data-auth-pending on <body> at SSG time and hide
  it with inline CSS before any JS runs; remove the attribute after /api/me
  resolves. Eliminates the flash of protected content on private instances.

  Multi-user write API (serve/server.py): the previous _apply_sidecar_edit and
  strava_sync imports from bincio.edit.server were broken (those names don't
  exist as module-level exports) and the Strava sync mutated a global data_dir,
  making concurrent requests from different users racy. Fix: extract both
  operations into bincio/edit/ops.py as pure functions that take data_dir
  explicitly. Both edit/server.py and serve/server.py now import from there.

  Security: add rate limiting to POST /api/register (5 attempts / 15 min / IP,
  separate bucket from login). Add _check_id() activity ID validation to both
  GET and POST /api/activity/{id} in serve/server.py.

  Single-user mode: _write_root_manifest now forces instance.private=false when
  no instance.db exists, even if a previous run wrote true. Prevents the auth
  wall from firing and redirecting to /login/ when bincio serve isn't running.

  ActivityFeed: skip filterHandle when profileIndexUrl is set (per-user profile
  pages load the right shard directly; activities have no handle tag at that
  point, so the filter was producing an empty feed). Fix handle links to point
  to /u/{handle}/ instead of /{handle}/. Fix <a>-inside-<a> Svelte warning by
  converting the inner handle link to a <button>.
2026-04-09 09:19:48 +02:00
Davide Scaini 98c42dc443 unify single user and multi user behaviour 2026-04-09 08:59:40 +02:00
Davide Scaini f76cc0ce7e towards multi-user 2026-04-08 19:37:10 +02:00
Davide Scaini 36a91362d9 Strava sync improvements
- Fix first sync finding 0 activities: remove last_sync_at stamp at
    connect time so the first sync checks all Strava history (existence
    check skips already-extracted files without fetching streams)
  - Add POST /api/strava/reset with soft/hard modes: soft sets last_sync_at
    to the most recent activity already on disk; hard clears it entirely
  - Surface error_count in sync response and status message
  - Add Reset / Hard reset buttons below Sync now in the upload modal
  - Reload on bfcache restore so client:only components re-mount after
    back navigation
2026-04-08 14:23:52 +02:00
Davide Scaini 083c67d018 local activity storage and convert page fixes
- Replace rdp dependency with inline pure-Python RDP implementation
    so the bincio wheel runs in Pyodide (no pure-Python wheel existed for rdp)
  - Fix convert page script: remove define:vars so Vite bundles it and
    TypeScript imports (localstore, format) work correctly
  - Rename wheel to proper PEP 427 filename (bincio-0.1.0-py3-none-any.whl)
  - Use en-GB date format on convert result, consistent with the feed
  - Add /activity/local/ page + LocalActivityDetail for IDB-only activities;
    feed links local activities there instead of the SSG route
  - Fix getStaticPaths: try public/data symlink as fallback, never crash on
    missing index.json
  - Fix ActivityDetail.onMount: load detail even when detail_url is absent
    so locally converted activities show map and charts
  - Derive track_url and detail_url from id in toSummary() since they are
    not present in the detail JSON
  - Reload on bfcache restore (pageshow) so client:only components re-mount
    after back navigation
2026-04-08 14:14:42 +02:00
Davide Scaini 5bf0f3636c local conversion 2026-04-06 22:25:57 +02:00
Davide Scaini e940338816 planning 2026-04-06 19:31:52 +02:00