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

65 lines
2.2 KiB
Markdown

# 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`
```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`.