6.6 Routes Pages

The Routes section exposes three views through a shared server-rendered shell:

  • /routes: the route browser for comparing ATLAS GTFS and OSM route definitions
  • /routes/non-gtfs: OSM public transport routes that do not appear in the OpenTransportData GTFS dataset and are excluded from route matching
  • /routes/gtfs-stop-id-sloid: a diagnostic map for the canonical GTFS stop_id ↔ ATLAS sloid mapping

All three views are rendered through templates/pages/routes.html with an active_view switch, so the page keeps one shared tab layout while loading view-specific data and JavaScript.

1. Shared Shell and Routing

backend/blueprints/routes.py provides:

  • routes_page() for the route list tab
  • non_gtfs_routes_page() for the non-GTFS route tab
  • routes_gtfs_stop_id_sloid_page() for the GTFS diagnostic map tab
  • _render_routes_template() to pass shared tab state and GTFS map limits into the template

The template renders page tabs at the top and then chooses between:

  • the filterable route-card UI
  • the non-GTFS route-card UI
  • the GTFS map shell with summary overlay, banner, and full-size Leaflet map container

2. Route Browser Tab

The default /routes tab provides these filters and controls:

  • ATLAS Operator (searchable multi-select dropdown)
  • OSM Route Operator (searchable multi-select dropdown)
  • Status (all, matched, unmatched, unmatched_atlas, unmatched_osm)
  • results per page (5, 10, 20, 50, or 100)
  • free-text route search

End-to-end flow

  1. User submits filters using the top toolbar.
  2. Flask route [backend/blueprints/routes.py](https://github.com/openTdataCH/stop_sync_osm_atlas/blob/main/backend/blueprints/routes.py)::routes_page normalizes query params.
  3. Backend builds a combined route query and applies matched-state filters, optional ATLAS and OSM operator constraints, and optional route-ID search.
  4. Matched pairs are returned once, then unmatched Atlas-only and OSM-only rows are appended into the same paginated result set.
  5. Results are expanded with route-stop details, itinerary matches, and route metadata.
  6. Template templates/pages/routes.html renders compact route cards.
  7. Each card starts collapsed and can be unfolded to inspect stops by direction or preview route position on an embedded map.

Stops and embedded map rendering

Stops are loaded from:

  • normalized stop_calls joined back to atlas_stops, osm_nodes, and stops_matched

Direction groups are sorted numeric-first, then grouped by uic_ref for a compact two-level stop rendering.

The embedded route preview map reuses the shared main-map stack:

  • the card exposes a route-scoped /api/data filter payload
  • markers use shared map helpers (createAtlasMarker, createOsmMarker)
  • bounds are fit after the route points load

3. Non-GTFS Routes Tab

The /routes/non-gtfs tab lists OSM route families marked is_non_gtfs. These routes are retained for inspection but are not included in ATLAS–OSM route matching. The tab reuses the route cards, stop details, embedded maps, and pagination shell from the main browser, but intentionally omits the main browser's search, status, and operator toolbar.

4. GTFS stop_idsloid Map Tab

The /routes/gtfs-stop-id-sloid tab is a full-page diagnostic Leaflet map backed by the imported gtfs_stops_raw and gtfs_stop_identity_resolution tables.

What it shows

  • GTFS stops with at least one imported coordinate source
  • ATLAS stops represented in the imported GTFS/ATLAS state table
  • visible matched line segments between GTFS and ATLAS points
  • a compact summary overlay showing GTFS coverage, ATLAS coverage, and assignment counts

Marker colors are intentionally fixed:

  • matched ATLAS: blue
  • unmatched ATLAS: red
  • matched GTFS: orange (#F0AD4E; described as yellow in the UI legend)
  • unmatched GTFS: gray

Backend APIs

The tab reads four dedicated JSON endpoints from backend/blueprints/routes.py:

  • /api/routes/gtfs-stop-id-sloid/summary
  • /api/routes/gtfs-stop-id-sloid/map
  • /api/routes/gtfs-stop-id-sloid/search
  • /api/routes/gtfs-stop-id-sloid/popup

The query and serialization logic lives in backend/services/gtfs_stop_id_sloid.py.

That service builds deduplicated coordinate subqueries from gtfs_stop_identity_resolution, computes matched/unmatched counts per side, and returns:

  • gtfs_stops
  • atlas_stops
  • matches
  • meta (zoom, cap state, overview/detail mode)

Overview/detail behavior

The map uses two density modes:

  • overview mode below zoom 11: limit 3000 GTFS rows and 3000 ATLAS rows
  • detail mode at zoom 11 and above: limit 5000 GTFS rows and 5000 ATLAS rows

Rows are fetched in a balanced way so matched and unmatched states do not starve each other inside a dense viewport.

Popup behavior

The frontend lazy-loads popup payloads per clicked marker.

GTFS popups include:

  • stop identifiers and coordinates
  • matched SLOID previews
  • same-UIC ATLAS candidate previews

ATLAS popups include:

  • SLOID and ATLAS metadata
  • matched GTFS stop previews
  • same-UIC GTFS candidate previews

The map keeps the shared draggable multi-popup behavior by reusing the common popup helpers and line handler logic.

Identifier search

The search endpoint accepts exact SLOID, UIC, and GTFS stop_id searches. It returns mappable targets, after which the frontend centers the map and reloads the viewport with the identifier filter applied.

5. Files and Responsibilities

  • backend/blueprints/routes.py
    • main and non-GTFS route-list query construction and pagination
    • GTFS tab page route and four GTFS JSON endpoints
    • shared routes template rendering
    • loading line_families, line_family_matches, itineraries, itinerary_matches, and stop_calls for route cards
  • backend/services/gtfs_stop_id_sloid.py
    • GTFS summary payloads
    • viewport payloads for GTFS/ATLAS markers and line segments
    • GTFS and ATLAS popup payload builders
  • templates/pages/routes.html
    • tab shell shared by both Routes views
    • route list toolbar, cards, and pagination
    • GTFS map shell, banner, and summary overlay host
  • static/js/pages/routes.js
    • route browser toolbar behavior and embedded route preview maps
  • static/js/pages/routes-gtfs-stop-id-sloid.js
    • GTFS map initialization, viewport fetching, marker rendering, summary updates, and popup loading

6. Maintenance Guidelines

  • Keep the canonical GTFS stop_idsloid matcher in matching_and_import_db/downloader/get_atlas_gtfs.py.
  • Keep GTFS map query logic in backend/services/gtfs_stop_id_sloid.py, not in the template or page controller.
  • Keep the Routes tab shell shared; add view-specific behavior behind active_view rather than splitting into parallel templates.
  • Preserve the fixed marker-color semantics because they are part of the debugging vocabulary used elsewhere in the docs.
Data update in progress
Elapsed: -- ETA: -- Phase: idle