Skip to content

F-032: Apartments Near Metro Stations

Status: Done · Priority: P1 · Updated: Mar 10, 2026

Summary

Full metro/transit station browsing experience. Users can explore all Montreal transit stations (STM Metro, REM, Exo commuter trains), view nearby listings with interactive maps, and filter the main listings page by station proximity.

What Was Built

Pages

  • /metro — Index page listing all stations grouped by transit network (STM Metro lines, REM, Exo trains), with listing counts per station
  • /metro/[slug] — Station detail page with Google Map (station marker + listing markers), nearby listings with configurable radius (500m/1km/2km), per-bedroom price stats, line navigation (prev/next station)

API Endpoints

  • GET /metro-stations — List all transit stations with nearby listing counts
  • GET /metro-stations/:slug — Station detail with paginated nearby listings, stats, and line info

Listing Filter

  • Near Station filter in browse page — searchable station picker grouped by line (color-coded), radius selector (500m/1km/2km)
  • nearStation + radius query params on GET /listings — filters by proximity using Haversine distance

Data Pipeline

  • GTFS parsers for STM Metro, Exo commuter trains, REM
  • Station name title-casing with override table for tricky names (Berri-UQAM, McGill, etc.)
  • seed-transit.ts for seeding station data from GTFS feeds
  • Download script updated to fetch Exo + REM GTFS data

Shared Components

  • ListingMarkerLayer — Unified map marker component (price pills, clustering, click popups) used across search map, neighborhood detail, and station detail
  • transit-lines.ts — Static line definitions with 120+ stations, coordinates, colors, bilingual names

Bilingual Support

  • Full FR/EN translations for metro index, station detail, and filter UI

Implementation Notes

  • Station data stored in existing points_of_interest table with category metro/rem/train
  • Proximity filter uses bounding box pre-filter + Haversine distance for accuracy
  • Map markers use Supercluster for clustering at high zoom levels
  • Station slugs generated from station names via slugifyStation() helper