fix(mobile/upload): activities now appear in browser after upload; reconcile synced_at on fresh server
Three bugs fixed:
- /api/upload/bas and /api/upload/raw never updated user_dir/index.json, so
merge_all couldn't include uploaded activities in year shards — they existed
on disk but were invisible to the browser feed. Fixed by _upsert_index_summary()
called before merge_all().
- Silent catch {} in uploadLocalActivities swallowed all per-activity errors;
replaced with console.warn so failures are visible in Expo logs.
- After a server wipe, synced_at flags on the device caused "Nothing to upload"
forever. uploadFeed() now reconciles against GET /api/feed at the start of each
upload: local activities not found on the server get synced_at cleared.
Also: live upload progress ("Uploading N / M…"), failed count in result message,
onProgress callback on uploadFeed(), countPendingUploads() helper.
This commit is contained in:
+16
-12
@@ -695,23 +695,27 @@ Implemented in `mobile/db/sync.ts` → `syncFeed()`.
|
||||
|
||||
### Upload (local → server)
|
||||
|
||||
Implemented in `mobile/db/sync.ts` → `uploadLocalActivities()`. Enabled when
|
||||
Implemented in `mobile/db/sync.ts` → `uploadFeed()` / `uploadLocalActivities()`. Enabled when
|
||||
`sync_upload = "true"` in settings, or triggered explicitly via the ↑ Upload button.
|
||||
|
||||
1. Query `activities WHERE origin = 'local' AND synced_at IS NULL`.
|
||||
2. For each: parse `detail_json` from the DB row and construct `{ id: row.id, ...detail }`.
|
||||
3. `POST {instance_url}/api/upload/bas` with body `{ activity, timeseries?, geojson? }`.
|
||||
4. On 200 (including `{ status: "duplicate" }`): set `synced_at = unixepoch()`.
|
||||
1. **Reconcile** against the server: fetch `GET /api/feed` and compare its activity IDs against local rows where `synced_at IS NOT NULL`. Any local activity that is marked as synced but absent from the server (e.g. server was wiped) has its `synced_at` cleared so it re-enters the upload queue. This is best-effort — if the feed fetch fails, upload proceeds with whatever is currently queued.
|
||||
2. Query `activities WHERE origin = 'local' AND synced_at IS NULL`.
|
||||
3. For each: parse `detail_json` from the DB row and construct `{ id: row.id, ...detail }`.
|
||||
4. `POST {instance_url}/api/upload/bas` with body `{ activity, timeseries?, geojson? }`.
|
||||
5. On 200 (including `{ status: "duplicate" }`): set `synced_at = unixepoch()`. On error: log to console, count as failed, continue with the next activity.
|
||||
|
||||
**Note:** `original_path` is not used in upload. An earlier implementation tried to read
|
||||
`original_path` as a JSON file, but `original_path` stores the path to the original binary
|
||||
FIT/GPX/TCX file — `JSON.parse()` always throws, silently skipping every activity. The correct
|
||||
approach is to use the already-extracted `detail_json` stored in SQLite.
|
||||
The UI shows live progress ("Uploading N / M…") during the batch and reports failures separately ("X uploaded, Y failed").
|
||||
|
||||
The server endpoint (`bincio/serve/server.py` → `POST /api/upload/bas`) accepts
|
||||
pre-extracted BAS JSON rather than raw FIT/GPX/TCX. It deduplicates by checking
|
||||
if the activity file already exists, writes geojson and timeseries if provided, then
|
||||
calls `merge_all()` to refresh the server's merged feed.
|
||||
pre-extracted BAS JSON rather than raw FIT/GPX/TCX. It writes the activity file,
|
||||
**updates `user_dir/index.json`** with a summary entry (so `merge_all` can include
|
||||
the activity in year shards and the browser feed), writes geojson and timeseries if
|
||||
provided, then calls `merge_all()` + `write_combined_feed()`.
|
||||
|
||||
> **Bug that was fixed:** earlier versions of both `/api/upload/bas` and `/api/upload/raw`
|
||||
> wrote activity files to disk but never updated `user_dir/index.json`. Since `merge_all`
|
||||
> builds year shards from the index, uploaded activities existed on disk but were invisible
|
||||
> to the browser feed. Fixed by `_upsert_index_summary()` called before `merge_all()`.
|
||||
|
||||
### Conflict handling
|
||||
|
||||
|
||||
Reference in New Issue
Block a user