merge(worktree): interactive maps for market pages

Self-hosted Leaflet 1.9.4 maps across 4 placements: markets hub
country bubbles, country overview city bubbles, city venue dots, and
a standalone opportunity map. New /api blueprint with 4 JSON endpoints.
New city_venue_locations SQLMesh serving model. No CDN — GDPR-safe.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
Deeman
2026-03-04 15:36:41 +01:00
16 changed files with 1073 additions and 0 deletions

View File

@@ -7,6 +7,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
### Added
- **Interactive Leaflet maps** — geographic visualization across 4 key placements using self-hosted Leaflet 1.9.4 (GDPR-safe, no CDN):
- **Markets hub** (`/markets`): country bubble map with circles sized by total venues, colored by avg market score (green ≥ 60, amber 30-60, red < 30). Click navigates to country overview.
- **Country overview articles**: city bubble map loads after article render, auto-fits bounds, click navigates to city page. Bubbles colored by market score.
- **City cost articles**: venue dot map centered on city lat/lon (zoom 13), navy dots per venue with tooltip showing name + court breakdown (indoor/outdoor).
- **Opportunity map** (`/<lang>/opportunity-map`): standalone full-width page with country selector. Circles sized by population, colored by opportunity score (green ≥ 70, amber 40-70, blue < 40). Existing venues shown as gray reference dots.
- New `/api` blueprint with 4 JSON endpoints (`/api/markets/countries.json`, `/api/markets/<country>/cities.json`, `/api/markets/<country>/<city>/venues.json`, `/api/opportunity/<country>.json`) — 1-hour public cache headers, all queries against `analytics.duckdb` via `fetch_analytics`.
- New SQLMesh serving model `city_venue_locations` exposing venue lat/lon + court counts per city.
- `pseo_city_costs_de` serving model: added `lat`/`lon` columns for city map data attributes in baked articles.
- Leaflet CSS included on all article pages (5KB, cached). JS loaded dynamically only when a map container is present.
- **Individualised article financial calculations with real per-country cost data** — ~30 CAPEX/OPEX calculator fields now scale to each country's actual cost level via Eurostat data, eliminating the identical DE-hardcoded numbers shown for every city globally.
- **New Eurostat datasets extracted** (8 new landing files): electricity prices (`nrg_pc_205`), gas prices (`nrg_pc_203`), labour costs (`lc_lci_lev`), and 5 price level index categories from `prc_ppp_ind` (construction, housing, services, misc, government).
- `extract/padelnomics_extract/src/padelnomics_extract/eurostat.py`: added 8 dataset entries; added `dataset_code` field support so multiple dict entries can share one Eurostat API endpoint (needed for 5 prc_ppp_ind variants).