thinking about edits...

This commit is contained in:
Davide Scaini
2026-03-29 11:12:02 +02:00
parent eadfb1a0fa
commit 7327861c4a
+123
View File
@@ -144,6 +144,123 @@ vite: {
},
```
## Activity sidecar edits — design spec
Users edit activities via **sidecar markdown files** that live alongside BAS JSON in the data dir.
No database, no server — consistent with the project's static-files-only philosophy.
### File naming
```
~/bincio_data/
2024-05-15T10:30:00Z_cycling.json ← immutable extract output (never touched)
2024-05-15T10:30:00Z_cycling.md ← user edits (sidecar)
```
Same stem as the JSON, `.md` extension. `bincio extract` never writes `.md` files,
so re-running extract is always safe and will never clobber user edits.
### Sidecar format
YAML frontmatter + optional Markdown body:
```markdown
---
title: "Epic climb up Monte Grappa"
sport: cycling # override detected sport
hide_stats: [cadence] # suppress specific stat panels in detail view
highlight: true # pin/feature in feed (shown first, maybe badged)
private: false # exclude from public feed
gear: "Trek Domane" # freeform gear note
---
Rode with Marco and Giulia. Legs felt great after the rest week...
```
- All frontmatter keys are optional; omit means "keep extracted value"
- The Markdown body becomes the activity's `description`, rendered as HTML in the detail page
- `hide_stats` takes stat panel names: `elevation`, `speed`, `heart_rate`, `cadence`, `power`
### Where overrides are applied: the render stage
The **render stage** (`bincio render`) is the right place — not extract, not the browser.
- Extract → clean BAS JSON (immutable)
- Render → merges sidecars → Astro build consumes enriched data
A `bincio.render.merge` module walks the data dir, finds `*.md` sidecars,
and produces either enriched JSON files or a separate `overrides/index.json`
that Astro reads at build time. The site never needs to fetch a `.md` file
at runtime — all merging is build-time, keeping the static-first guarantee.
### Federation angle
Sidecars work for *remote* activities too: if you include someone else's BAS feed,
you can write local `.md` sidecars for their activity IDs. Your render stage applies
your overrides on top of their data. This is a natural extension of the local case.
### Editing UX: `bincio edit --serve`
A separate FastAPI server (`bincio edit --serve`, default port 4041) handles all writes.
The static site and Astro are untouched — no hybrid mode, no dead-code API routes in prod.
**How it works:**
```
bincio edit --serve --data ~/bincio_data # starts on :4041
```
- Serves a bundled Svelte UI (single compiled HTML, reuses existing Svelte investment)
- `GET /api/activity/{id}` — returns merged BAS JSON + existing sidecar fields
- `POST /api/activity/{id}` — writes `edits/{id}.md` to the data dir
- `POST /api/activity/{id}/images` — multipart upload → `edits/images/{id}/{filename}`
- The Astro dev server's file watcher picks up `.md` writes → incremental rebuild
**Edit UI features:**
- Title text input (pre-filled from BAS JSON)
- Sport dropdown (pre-filled, shows all known sport types)
- Markdown textarea for description, with minimal toolbar (bold, italic, link, image insert)
- Live markdown preview panel
- `hide_stats` checkbox group: elevation, speed, heart_rate, cadence, power
- `highlight` toggle (feature in feed)
- `private` toggle (suppress from feed at render time)
- Image drag-and-drop zone → uploads to `edits/images/{id}/`, inserts `![]()` into textarea
- Save button → POST to API → success toast
**Workflow (typical):**
1. User browses the Astro dev server on :4040
2. Activity detail page has an "Edit" button (rendered only when `PUBLIC_EDIT_URL` env var is set)
3. Button links to `:4041/edit/{id}` — opens the FastAPI-served edit UI
4. User fills in form, saves → sidecar written → Astro rebuilds → refreshing :4040 shows changes
The `PUBLIC_EDIT_URL` env var in `.env` controls whether the Edit button appears;
leave it unset for production builds, set to `http://localhost:4041` for local dev.
### Image storage
```
~/bincio_data/
edits/
2024-05-15T10:30:00Z_cycling.md
images/
2024-05-15T10:30:00Z_cycling/
col-summit.jpg
group-photo.jpg
```
Images are referenced in the markdown body with relative paths: `![Summit](col-summit.jpg)`.
The render stage resolves relative image paths against `edits/images/{id}/` and copies them
to `site/public/images/activities/{id}/` so they're served from the static site.
### Decided
- **Sidecar location**: `edits/` subdirectory (not co-located with JSON) — cleaner, easier to
backup/sync just your customisations independently of the extracted data
- **`private: true`**: suppresses from `index.json` at render time (not client-side hide) —
safer for public hosting
- **`highlight`**: visual badge in feed + sorted before non-highlighted activities
- **Edit UI**: `bincio edit --serve` FastAPI server (Option B) — not integrated into Astro
## Known issues / next steps
- `bincio render` Python CLI is a stub — site is built via `npm run build` directly
@@ -165,3 +282,9 @@ vite: {
- [ ] Map thumbnail in activity cards (SVG path from GeoJSON)
- [ ] GitHub Actions template for auto-publish
- [ ] Karoo/Garmin Connect importers beyond Strava
- [ ] `bincio.render.merge` module: walk `edits/`, parse sidecars, produce enriched data for Astro
- [ ] `bincio render --watch` incremental rebuild on sidecar changes
- [ ] Sidecar `.md` format: title, sport, description, hide_stats, highlight, private, images
- [ ] `bincio edit --serve` FastAPI server with Svelte edit UI (port 4041)
- [ ] Edit button on activity detail pages (visible when `PUBLIC_EDIT_URL` env var set)
- [ ] Image upload → `edits/images/{id}/`, render stage copies to `public/images/activities/{id}/`