Precompute run analysis and serve compact route previews
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# Persisted run analysis and compact routes
|
||||
|
||||
Imports and recording refreshes now calculate summaries, GAP, terrain breakdowns,
|
||||
lap GAP and charts from the full-resolution samples, in the same transaction as
|
||||
the activity. `analysis_version` identifies the calculation/display version.
|
||||
Current-version empty results distinguish incomplete recordings from pending
|
||||
backfills. Raw recordings remain intact.
|
||||
|
||||
The page reads `analysis_summary`; the detail JSON endpoint reads `display_data`.
|
||||
Both are deferred JSON columns so activity lists and record comparisons do not
|
||||
load them. No page request calculates full-resolution analysis or reads raw laps.
|
||||
Pending activities show unavailable derived metrics until backfilled.
|
||||
|
||||
Dashboard maps use the authorized `/activities/<id>/route` endpoint, which reads
|
||||
only the persisted `route_geometry` and returns coordinates. The full detail data
|
||||
remains protected by the same owner/friend/public-link access checks as before.
|
||||
No shared caching is introduced for private responses.
|
||||
|
||||
Route display combines Douglas-Peucker simplification (initial tolerance 3 m)
|
||||
with regular measurement samples for colours. Tolerance increases for complex
|
||||
routes to fit a target of 1,400 points across the recording. Each GPS segment's
|
||||
endpoints are retained, so heavily fragmented routes may exceed that target;
|
||||
gaps are never joined to meet a budget. Coordinates are rounded to six decimals.
|
||||
Map measurements use only distance, speed, HR and grade; other raw fields are
|
||||
omitted. Chart data retains up to 750 evenly spaced samples, including endpoints.
|
||||
Calculations and personal records always use full-resolution source data.
|
||||
|
||||
The dashboard replay uses canvas rendering and binary search through route edges
|
||||
instead of a linear search on each animation frame.
|
||||
|
||||
After the schema migration, backfill existing activities:
|
||||
|
||||
```sh
|
||||
flask --app app backfill-analysis --batch-size 25
|
||||
# Dokku avoids interpreting Flask's --app option as a Dokku option:
|
||||
dokku run stride env FLASK_APP=app flask backfill-analysis --batch-size 25
|
||||
```
|
||||
|
||||
Each batch commits independently and uses PostgreSQL row locks. Reruns skip
|
||||
current-version activities. `--owner-id ID` scopes the job; `--force` rebuilds
|
||||
current results. The job fixes an upper activity ID at start; concurrent imports
|
||||
calculate their own results. No downloads or Garmin authentication are needed.
|
||||
|
||||
Baseline measured on production on 2026-10-02, before this change: longest run
|
||||
6,845 samples; median of three internal authenticated requests: dashboard HTML
|
||||
8 ms, run HTML 156 ms, run JSON 213 ms / 2,654 KiB uncompressed. These timings
|
||||
exclude network transfer, browser rendering and map tile downloads.
|
||||
Reference in New Issue
Block a user