fix(mobile): clear technical debt — real SHA-256, feed pagination, search

source_hash: BAS JSON import now computes SHA-256 via crypto.subtle.digest
instead of the '${id}-${length}' stub. No extra package — Hermes supports
Web Crypto API natively.

Feed pagination: useActivities(query, limit) accepts a LIMIT parameter.
The feed screen starts at 50, calls loadMore() via FlatList onEndReached
(threshold 0.3) to increment by 50 each time. useActivityCount(query)
drives the hasMore guard so loadMore is a no-op at the end of the list.

Feed search: compact TextInput below the header filters by title via
SQLite json_extract LIKE. Changing the query resets limit to PAGE_SIZE
so stale paginated results don't linger.

Docs: close the three resolved debt items; keep only the accepted
background-polling limitation as a known gap.
This commit is contained in:
Davide Scaini
2026-04-27 11:53:43 +02:00
parent 93247d510f
commit 7a65ed2078
4 changed files with 68 additions and 40 deletions
+3 -31
View File
@@ -985,41 +985,13 @@ and re-extracted server-side.
This section documents mismatches between what the plan describes and what is
actually implemented, plus features not yet in the plan.
### Remaining stubs
**`source_hash` for BAS JSON import is not SHA-256** (`mobile/app/(tabs)/import.tsx`)
BAS JSON import records `source_hash = "${detail.id}-${text.length}"` — a rough
stand-in. FIT/GPX/TCX imports (via Pyodide) correctly compute SHA-256 of the file
bytes. The BAS JSON path still uses the stub; dedup works in practice (activity IDs
are unique) but the hash is not a real content fingerprint.
**`auto_import_path` only triggers on app open, not in background**
### `auto_import_path` only triggers on app open, not in background
The watch-folder scan runs when the Import tab mounts and when the app comes to
foreground (`AppState` → `'active'`). There is no true background task that fires
while the app is closed. Full background polling would require `expo-background-fetch`
but cannot use the Pyodide WebView (a UI component).
### Missing from the plan entirely
**Feed pagination**
`useActivities()` in `mobile/db/queries.ts` calls `getAllSync` with no `LIMIT`.
This is fine for tens of activities, but will cause noticeable lag at hundreds.
Should add cursor-based pagination or a virtual list with lazy loading.
**Individual activity deletion**
There is no way to delete a single activity, local or remote. "Reset synced data"
nukes all remote activities at once. A long-press or swipe-to-delete gesture on
activity cards is needed, with a server-side `DELETE /api/activity/{id}` endpoint
for remote activities.
**Feed search and filter**
No search bar, no sport filter, no date picker. The feed is a flat reverse-
chronological list. As the feed grows this becomes a usability problem.
but cannot use the Pyodide WebView (a UI component). Accepted limitation — the
on-open trigger covers the primary Karoo use case (open app after a ride).
**Token expiry and the reconnect flow**