Skip to content

F-019: ZIP Codes / Postal Areas

Status: Done · Priority: P1 · Branch: feature/F-019-zip-codes · Updated: Mar 5, 2026

Summary

Full postal code browsing system for Montreal rentals. Two levels of granularity: FSA (3-character prefix like H2T) pages with boundary polygons on Google Maps, and full 6-digit postal code pages (like H2T 2Y2) with pin markers. Index page shows all 193 Greater Montreal FSA boundaries on an interactive map.

Requirements

  • [x] postal_areas table — 193 FSAs with boundary polygons from Statistics Canada
  • [x] postal_codes table — ~101K full codes from GeoNames (CC BY 4.0)
  • [x] FSA boundary conversion (Statistics Canada shapefiles, EPSG:3347 → WGS84 via proj4)
  • [x] Seed script for postal areas (H + J prefix within ~50km of Montreal)
  • [x] Seed script for postal codes (batch insert 500 at a time, onConflictDoNothing)
  • [x] API: GET /postal-areas — list all FSAs with listing stats + boundaries
  • [x] API: GET /postal-areas/:fsa — FSA detail with boundary, listings, postal codes, stats
  • [x] API: GET /postal-areas/code/:code — full 6-digit postal code detail
  • [x] Index page with interactive FSA boundary map (color-coded by listing count, click popup)
  • [x] FSA detail page with boundary map, stats bar, postal codes grid, listings grid
  • [x] Full postal code detail page with pin center + FSA boundary context
  • [x] Header navigation link
  • [x] Bilingual translations (EN/FR)
  • [x] Fix: bedroom grouping (4+ instead of separate 4, 5)
  • [x] Fix: /mo/mo duplicate price suffix
  • [x] Documentation updates

Design

Data Sources

  • FSA boundaries: Statistics Canada census boundary files (NAD83/Lambert Conformal Conic → WGS84). 187 of 193 FSAs have polygons.
  • Postal code centroids: GeoNames CA_full.txt (free, CC BY 4.0). ~101K codes for Greater Montreal.
  • LDU boundaries: Not available as open data. Commercial sources (DMTI/CanMap, geocoder.ca) cost $800+. The boundary column on postal_codes is reserved for future generation from accumulated listing coordinate data.

Coverage

Greater Montreal: H-prefix (Montreal island, Laval) + J-prefix suburbs within ~50km of downtown (45.5, -73.57). Includes Brossard, Longueuil, South Shore, Laval, and surrounding areas.

Map Interactions

  • Index map: All FSA boundaries rendered as Google Maps Data layer. Blue fill scaled by listing count, gray for empty. Click shows AdvancedMarker popup with FSA info + "View area" link.
  • FSA map: Single boundary polygon + price markers for each listing.
  • Code map: Pin center for postal code + parent FSA boundary for context.

Discussion Notes

Mar 5, 2026

  • Built complete postal code browsing system: DB tables, seed scripts, API endpoints, frontend pages
  • Expanded from H-prefix only to full Greater Montreal (H + J prefix within 50km radius)
  • Seeded ~101K postal codes from GeoNames (56K H-prefix + 45K J-prefix)
  • Converted 187 FSA boundaries from Statistics Canada shapefiles (Lambert → WGS84 via proj4)
  • Fixed bedroom grouping bug (4+ bucket), /mo/mo display bug, missing ListingSummary fields
  • Index map: click shows popup tile (not direct navigation) per user request
  • LDU boundaries confirmed as commercially gated only — reserved boundary column for future data accumulation

Implementation Notes

Key Files

  • packages/database/src/schema.ts — postal_areas + postal_codes tables
  • packages/database/src/seed.ts — seedPostalAreas() + seedPostalCodes()
  • packages/database/data/fsa-boundaries-mtl.json — 187 FSA boundary polygons (WGS84)
  • packages/database/data/postal-codes-mtl.tsv — 101K postal code centroids
  • packages/database/scripts/convert-fsa-boundaries.ts — proj4 boundary conversion
  • services/api/src/routes/postal-areas.ts — 3 API endpoints
  • services/web/app/[locale]/postal/ — route pages
  • services/web/components/postal/ — all postal UI components
  • services/web/lib/api.ts — postalAreasApi client