← back to map
Methodology · Vantage Vancouver

How Vantage was built — from raw rolls to a clickable city

An end-to-end walkthrough of the data pipeline, the warehouse model, and the rendering layer behind this MVP. Everything below runs on public, audit-friendly sources — no scraped MLS, no gray-area licensing.

01

The problem

Vancouver real estate has rich public data — BC Assessment's annual valuations, City parcel polygons, zoning bylaws — but it sits in CSV dumps, shapefiles, and government APIs that don't talk to each other. Vantage stitches them into a single map-first explorer: click any parcel, drill into a building, and inspect every strata title within it.

02

Data layer

  • Sources — BC Assessment yearly roll (2016 – 2026), City of Vancouver parcel polygons, zoning bylaw shapefiles.
  • Store — PostgreSQL 18 + PostGIS 3.6 on Railway.
  • Schema — a wide core.property_current table (last-known state per PID), core.assessment_yearly for time series, and core.site_events for subdivisions / demolitions / redevelopments.
  • Lineage — a UUID per physical lot (lineage_id) groups strata titles and tracks parcels across PID churn.
03

The strata-to-lot link (the hard part)

BC Assessment doesn't expose a foreign key from a condo PID to its parent land parcel. The bridge is spatial: each STRATA centroid is point-in-polygon joined to the LAND parcel that covers it via ST_Covers(land.parcel_polygon, strata.centroid). That's how clicking 833 Seymour reveals all 374 strata titles inside Capitol Residences.

04

Backend

  • Stack — FastAPI + Pydantic + SQLAlchemy Core, deployed on Railway.
  • Endpoints— bbox parcel fetch with truncation guard, point-in-polygon lookup, address search, per-PID detail & history, per-lot timeline (events + aggregates), per-PID units list.
  • Performance — GiST spatial indexes on every polygon column, server-side bbox clipping, hard cap at 4,000 features per viewport request.
  • Governance — every response carries a disclaimer field; CORS locked at the edge; no auth surface (read-only public data).
05

Frontend

  • Stack — Next.js 16 (App Router) + React 19 + Tailwind 4 + TanStack Query.
  • Map — Mapbox GL JS with a Vancouver-constrained geocoder. Parcel layer is a choropleth keyed on assessed value or zoning category; clicking outlines the lot and opens the inspector drawer.
  • IA — two tabs per building: Building (aggregate story — total stack value, sparkline, lot events, yearly table) and Units (per-strata drill-in with search). Single-PID lots hide the Units tab.
  • UX — recent searches in localStorage, default landing on a 374-unit strata so the flow is visible on first paint, color-by toggle so the entire map carries information at a glance.
06

What's next

  • Optional sales data overlay (LTSA sample) for transaction prices.
  • Permit pipeline overlay — approved + under-review developments.
  • Comparables and $/sqft analytics within a buffer or neighborhood.
  • Portfolio overlay — paste your own PIDs and see your buildings highlighted.