New pref download_disabled_default (stored in user_prefs + mirrored to
_user_settings.json for the render pipeline). When true, apply_sidecar
marks all activities as download_disabled unless the sidecar explicitly
sets download_disabled: false (per-activity opt-in from the edit drawer).
Settings page gets an "Activity defaults" card with the toggle.
New endpoint: GET /api/activity/{id}/download/{bas|original|gpx}
- bas: streams the BAS detail JSON as an attachment
- original: streams the original FIT or GPX file from originals/
- gpx: generates a GPX from the timeseries (always available when GPS exists)
download_disabled flag stored in sidecar (edits/{id}.md), propagated to
the merged BAS detail JSON. When set, only the owner can download.
Backend: ops.py writes flag to sidecar; merge.py propagates it to detail
JSON; download.py implements the endpoint; server.py registers the router.
Frontend: EditDrawer gets a "No download" toggle button; ActivityDetail
shows a Download section (hidden when disabled and viewer is not the owner).
- Add bincio/extract/ingest.py as a facade over the extract internals (ingest_parsed, strava_sync), reducing coupling from 6+ imports to one
- Add merge_one() to merge.py — fast single-activity path for interactive edits (rewrites one file + index, skips full directory rebuild)
- Rewrite edit/ops.py to delegate to the new facade; fix broken run_strava_sync return (was referencing undefined locals)
- Remove duplicated SPORTS, STAT_PANELS, VALID_ACTIVITY_ID from edit/server.py — now imported from ops.py