Files
Davide Scaini e553e08663 feat: gear registry — manage bikes/shoes per athlete, set per activity
- New /api/gear CRUD endpoints (gear.json per user)
- Gear tab in AthleteView (owner-only): add, edit, retire items
- EditDrawer gear field becomes a dropdown when registry has items
- Strava API sync now resolves gear_id → name, adds to registry automatically
- Strava ZIP import reads Gear column from activities.csv
- POST /api/strava/import-gear for one-time backfill from stored originals
2026-05-24 12:33:41 +02:00

2.2 KiB

Gear Feature Plan

Why the gap exists

Neither sync path populates gear today. The Strava API returns gear_id per activity (brut's originals show b3437566, g10422777 etc.) but strava_to_parsed() ignores it. The ZIP path also ignores the gear column in activities.csv. Diego_p's "Rose Backroad" was set manually via the EditDrawer free-text field.


Data model — {user_dir}/gear.json

{
  "items": [
    {
      "id": "uuid-abc123",
      "name": "Rose Backroad",
      "type": "bike",
      "retired": false,
      "strava_id": "b3437566"
    }
  ]
}
  • type enum: bike | shoes | skis | other
  • Per-activity gear stays as a plain string (the gear name) — backward compatible with existing sidecars
  • strava_id is optional, used for deduplication during Strava sync

Build order

[x] Step 1 — gear.json CRUD API ✓

File: bincio/serve/routers/gear.py

  • GET /api/gear → list items (auth required)
  • POST /api/gear → add item (auto-generate UUID id)
  • PATCH /api/gear/{id} → update (name, type, retired)
  • DELETE /api/gear/{id} → delete File lives at {user_dir}/gear.json, same pattern as athlete.json. Add gear router to server.py.

[x] Step 2 — Gear tab in AthleteView (ownerOnly) ✓

  • Added 'gear' to Tab type and ALL_TABS in AthleteView.svelte
  • Inline gear management: list, add, edit, retire — no separate component

[x] Step 3 — EditDrawer gear selector ✓

  • At drawer open, fetches /api/gear
  • Shows <select> from registry (if items exist), with "Other…" revealing text input
  • Falls back to plain text input if no gear items registered
  • Value still stored as gear name string — backward compatible

[x] Step 4 — Strava sync gear extraction ✓

  • strava_api.py: added fetch_gear() + gear field on strava_to_parsed() via _gear_name meta key
  • ingest.py: during sync, resolves gear_id → name, adds new items to registry
  • New endpoint POST /api/strava/import-gear: one-time backfill from stored originals

[x] Step 5 — ZIP import gear column ✓

  • strava_zip.py: reads Gear column from activities.csv and sets parsed.gear

[x] Step 6 — One-time backfill endpoint ✓

POST /api/strava/import-gear implemented in strava.py.