A real estate listing aggregation platform that scrapes Rightmove UK listings, extracts square meter data from floorplan images via OCR, calculates transit routes, and serves an interactive map-based web UI.
- **Async:** Scraper layer uses `async/await` throughout with `aiohttp`.
- **Models:** SQLModel for DB entities, Pydantic for request/response validation.
- **Service layer:** `services/` contains unified handlers used by both CLI and API — add new business logic here, not in API routes or CLI commands directly.
- **Repository pattern:** `repositories/` for database queries. Don't put raw SQL in services or API.
- **Tests:** pytest with `pytest-asyncio` (auto mode). Unit tests in `tests/unit/`, integration in `tests/integration/`.
- **Query splitting** works around Rightmove's ~1500-result API cap by adaptively splitting queries by district, bedrooms, and price bands (binary search). See `services/query_splitter.py`.
- **Circuit breaker** (`rec/circuit_breaker.py`) and **throttle detection** (`rec/throttle_detector.py`) protect against rate limiting.
- **Streaming API** uses NDJSON for progressive loading of large result sets.
- **Redis** serves dual duty as Celery broker and GeoJSON cache.
- **CI: GitHub Actions** (`.github/workflows/build-api.yml`, `build-frontend.yml`) builds + pushes Docker images to DockerHub on `master` push. **Keel** in the cluster watches `:latest` on `viktorbarzin/realestatecrawler` and `viktorbarzin/immoweb` and rolls the four `realestate-crawler-*` Deployments on digest change. No Woodpecker deploy POST — Keel is the rollout mechanism.
- Pull-secret on the namespace: `dockerhub-pull-secret`, synced from Vault `secret/viktor.dockerhub_registry_password` via ExternalSecret (codified in `infra/stacks/real-estate-crawler/main.tf`). Required because the DockerHub repos are private.
- Fallback: `.woodpecker/build-fallback-{api,frontend}.yml` (event: `deployment`, manual-only) preserves the in-cluster build path if GHA is down.
- Linting: GitHub Actions runs Ruff on PR diffs (`.github/workflows/ruff.yml`).