Draw list routes from indexed polylines instead of downloading GPX files - #1168
Draw list routes from indexed polylines instead of downloading GPX files#1168mfortini wants to merge 5 commits into
Conversation
The lists overview map was empty because it required downloading every trail GPX sequentially before rendering. - Index each list's bounding box and trail polylines in Meilisearch - Render simplified preview routes on the overview map from polylines - Fit the viewport to the combined trail bounds with padding - Load full GPX only when a single trail is opened inside a list
slothful-vassal
left a comment
There was a problem hiding this comment.
Thanks for working on this — I agree with the goal of making the list view load quickly without pulling every GPX file up front.
Up front: I don't think this indexing approach should be merged as it stands, mainly because of trail permissions. A public list can currently expose the geometry and bounds of private trails it contains. I left a blocking inline comment on the geometry aggregation with the concrete code path and reproduction. And that isn't something tighter sync logic can fix — it follows from list documents owning trail geometry in the first place.
Related issues from the same root:
- Trail updates, deletions, and visibility changes don't reliably propagate to the derived list geometry, and removed geometry can linger in Meilisearch.
- The per-list polyline limit doesn't respect the global map limit, so the total amount of geometry can grow well past it across several lists.
What I'd suggest instead: keep geometry in the trail index and compose list previews server-side — resolve the trails visible in each list, batch-fetch their geometry from the trail index, enforce permissions in one place, deduplicate trails shared across lists, and apply a single global polyline budget. Meilisearch can't join the two indices itself, but a bounded server-side composition avoids both the duplication and N+1 requests, and leaves room for caching later if measurements show it's needed.
For what it's worth, I ran into the same bottleneck a while back in #555 and approached it from the lazy-loading side instead. I never finished it, but it's a reminder that this has been a real problem for a while.
There are also smaller implementation issues — the frontend typecheck is currently failing, plus a few map interaction and state-management regressions. Worth addressing in the rework, but secondary to the ownership and permission questions.
The UI work here is worth keeping either way. Up to you whether you adapt this PR or open a fresh one and carry it over. Happy to sketch out the endpoint shape or look at an early draft if that would help.
| "iri": r.GetString("iri"), | ||
| } | ||
|
|
||
| expandedTrails := r.ExpandedAll("trails") |
There was a problem hiding this comment.
Blocking: this can expose private trail geometry through a public list.
expandedTrails is populated server-side and is not scoped to the current viewer. The code below derives the list center, bounds, and polylines from every expanded trail without checking the trail’s visibility.
Anonymous Meilisearch tokens only restrict the lists index to public = true (db/routes/search_token.go:13-16); they do not reapply the referenced trails’ permissions. At the same time, the list editor explicitly allows making a list public while keeping its trails private (web/src/routes/lists/edit/[id]/+page.svelte, the keep-private path).
Reproduction:
- Create a private trail and add it to a list.
- Make the list public and choose to keep the trails private.
- Log out.
- Search for the list through POST /api/v1/search/lists.
- The result still contains trail_polylines, lat/lon, and min_/max_ derived from the private trail.
Filtering only public trails while indexing would not fully solve this either: the owner, shared users, and anonymous users can have different access to the trails, while the list has only one shared Meilisearch document. The geometry therefore needs to remain behind trail-level permissions.
List documents now store trail_ids only so overview map geometry can be composed from the trail index under each viewer's token.
Add a viewer-scoped preview endpoint with a global polyline budget, wire the lists overview map to it, and fix polylineToGeoJSON typing.
The lists overview map is empty or very slow because it required downloading every trail GPX sequentially before rendering.