# Property Map Interactive UK property intelligence map. The app combines transaction, EPC, postcode, neighbourhood, transport, POI, and travel-time data into local parquet files, serves fast geospatial aggregations from Rust, and renders the result as a React/deck.gl map. The public product is branded as Perfect Postcodes, while this repository is still named `property-map`. ## What Is In Here - `frontend/` - React 18, TypeScript, Tailwind, MapLibre, and deck.gl. The app has a landing page, map dashboard, saved searches/properties, account pages, pricing, invites, and shareable URLs. - `server-rs/` - Rust Axum API. It loads the generated parquet data into memory, builds spatial indexes, serves H3/postcode aggregations, proxies PocketBase, serves PMTiles, handles AI filter parsing, screenshots, exports, checkout, and telemetry. - `pipeline/` - Python/Polars download and transform pipeline. `Makefile.data` orchestrates the data DAG. - `r5-java/` - Batch travel-time generator using Conveyal R5. It writes sparse per-destination parquet files for car, bicycle, walking, and transit. - `screenshot/` - Playwright/Express service used by the Rust API for map screenshots and Open Graph images. - `property-data/` and `manual-data/` - Local generated/downloaded data. These are runtime inputs, not source code. ## Runtime Data The Rust server expects these files or directories to exist: ```text property-data/properties.parquet property-data/postcode.parquet property-data/filtered_uk_pois.parquet property-data/places.parquet property-data/uk.pmtiles property-data/postcode_boundaries/ property-data/travel-times/ ``` Most data can be downloaded or generated through `Makefile.data`. Some inputs are deliberately manual: - `manual-data/certificates.csv` from the EPC register - `manual-data/crime/` CSV exports from police.uk - postcode boundaries, generated from OA boundaries, INSPIRE polygons, and UPRN lookup data Build the main property datasets with: ```bash uv sync make -f Makefile.data prepare make -f Makefile.data tiles make -f Makefile.data download-places make -f Makefile.data generate-postcode-boundaries ``` `generate-postcode-boundaries` writes to `manual-data/postcode_boundaries/`. The running server expects the same structure under `property-data/postcode_boundaries/`; copy or symlink it if needed. Travel times are built separately because they are expensive: ```bash make -f Makefile.data download-transit-network ./r5-java/run.sh --threads 8 --heap 40g ``` For a quick R5 smoke test: ```bash ./r5-java/run.sh --demo ``` ## Local Development With the required files in `property-data/`, the full stack can be started with Docker Compose: ```bash docker compose up --build ``` Services: - frontend: http://localhost:3001 - API: http://localhost:8001 - PocketBase: http://localhost:8090 - screenshot service: http://localhost:8002 The frontend dev server proxies `/api` and `/s` to the Rust API and `/pb` to PocketBase. To run pieces directly: ```bash cd frontend npm install npm run dev ``` Export the server's service configuration first: ```bash export SCREENSHOT_URL=http://localhost:8002 export PUBLIC_URL=http://localhost:3001 export POCKETBASE_URL=http://localhost:8090 export POCKETBASE_ADMIN_EMAIL=... export POCKETBASE_ADMIN_PASSWORD=... export GEMINI_API_KEY=... export GEMINI_MODEL=... export GOOGLE_MAPS_API_KEY=... export STRIPE_SECRET_KEY=... export STRIPE_WEBHOOK_SECRET=... export STRIPE_REFERRAL_COUPON_ID=... export GOOGLE_OAUTH_CLIENT_ID=... export GOOGLE_OAUTH_CLIENT_SECRET=... ``` ```bash cd server-rs cargo run -- \ --properties ../property-data/properties.parquet \ --postcode-features ../property-data/postcode.parquet \ --pois ../property-data/filtered_uk_pois.parquet \ --places ../property-data/places.parquet \ --tiles ../property-data/uk.pmtiles \ --postcodes ../property-data/postcode_boundaries \ --travel-times ../property-data/travel-times ``` ## Checks Run the combined local check script: ```bash ./check.sh ``` It runs Python lint/tests, frontend lint/format/typecheck/tests, screenshot service tests, and Rust clippy/format/tests. Useful focused commands: ```bash uv run ruff check . uv run pytest cd frontend npm run lint npm run typecheck npm run test npm run build cd ../server-rs cargo clippy --all-targets -- -D warnings cargo fmt --all --check cargo test ``` ## Production Build The root `Dockerfile` builds the frontend and Rust server into a runtime image. Data is mounted at `/app/data`; it is not baked into the image. ```bash docker build -t property-map . ``` The container entrypoint runs `property-map-server` with the expected data paths under `/app/data` and serves `frontend/dist` when `--dist` is present.