# Route planner Open **Routes** in Stride. Select the start on the map, enter latitude/longitude, or use your location. Choose a loop or select a separate finish, distance (1–50 km), hill difficulty, surface preference and ranking priority. Generated candidates show their actual distance, ascent, route geometry, elevation profile and quality coverage. Save a named route privately, reopen it, download GPX, or delete it. ## Configuration Apply migrations with `uv run --locked flask --app app db upgrade`. Set `ORS_API_KEY` in the web process environment and restart the web process. For local development, the app also reads `instance/ors-api-key` when the environment key is absent. This private file is ignored by Git; production only uses environment configuration. Keep the file within your private Windows account/workspace. For Dokku, configure `ORS_API_KEY` through your normal secret-management workflow. The key stays server-side and is never included in rendered HTML or requests from the browser. Obtain a key at https://openrouteservice.org/ and review the provider's current quotas. The planner sends selected coordinates to the fixed ORS HTTPS endpoint. Browser map tiles use the app's existing OpenStreetMap tile service. Without a key, generation is disabled with a configuration notice; saved routes, maps and export remain available. No synthetic routes are shown in the real app. ## Generation and ranking The server makes at most three requests per generation, each with a 12-second network timeout and a 4 MB response limit. Requests use `foot-walking`, elevation, and `surface`/`waytype` extras. Loops use three deterministic round-trip seeds. Point-to-point candidates include a direct route and two estimated side waypoints to seek a longer route near the target. Duplicate geometries are removed. This bounded search can return fewer than three routes and cannot guarantee a distance or ascent target. The interface flags results outside ±5% distance. Preferences rank candidates; they are not strict exclusions. Hill targets are approximately 3, 12 or 25 metres ascent/km. The cost combines distance deviation, ascent mismatch, mapped road share, missing surface coverage, optional repeated edges and surface preference. The priority weights distance, hills or quality more strongly. This is an explainable heuristic, not a safety or fitness score. Quality percentages follow ORS documented waytype and surface IDs: - Paths/tracks: path, track, cycleway and footway. - Road share: state road, road and street; this does not measure traffic. - Paved: paved, asphalt, concrete, legacy cobblestone, metal and paving stones. - Missing surface data is unknown; absent extras do not become zero. - Repeated distance estimates subsequent traversals of the same rounded geometry edge in either direction. Different segmentation can miss repeated sections. Crossing counts, lighting, current access and live traffic are unverified. GPX includes the route and available elevation, without fictional timestamps. No direct Garmin course upload or place-name search is included in this version. ## Persistence and validation Candidates and saved routes are server-side and owner-scoped. Other users, including friends, cannot view, mutate or export them. Save and delete use CSRF protection. Unsaved candidates older than one day are cleaned on the owner's next generation. The library lists the latest 100 saved routes. Generation is limited to six requests/minute and 60/day using the existing limiter storage configuration. Offline tests mock ORS and cover input validation, ranking, point-to-point and round-trip request shapes, deduplication, missing attributes, repeated sections, CSRF, ownership, save/delete/export and draft cleanup. Live ORS verification needs a configured API key; mocked tests do not establish live provider availability. Live local verification on 2026-10-03 used public Centennial Park test coordinates. Loop and point-to-point routing each returned three distinct candidates; private save, reload and GPX export succeeded in a disposable in-memory test database. The best loop was 5,030.9 m with 61.5 m ascent and 90% mapped paths/footways. The local browser rendered the real route, quality figures and elevation profile without console errors. The suite passed 129 tests. Live provider category IDs arrive as decimal numbers; a regression test covers that response format. Provider references: https://giscience.github.io/openrouteservice/api-reference/endpoints/directions/extra-info/ https://giscience.github.io/openrouteservice/api-reference/endpoints/directions/extra-info/waytype https://giscience.github.io/openrouteservice/api-reference/endpoints/directions/extra-info/surface