+ {[
+ 'Walk the streets before the listing search narrows your options.',
+ 'Test the commute from a real front door, not a borough name.',
+ 'Compare viewings with evidence already in hand.',
+ ].map((item) => (
+
diff --git a/frontend/src/hooks/useMapData.ts b/frontend/src/hooks/useMapData.ts
index e37d2cd..e47e9a7 100644
--- a/frontend/src/hooks/useMapData.ts
+++ b/frontend/src/hooks/useMapData.ts
@@ -40,6 +40,9 @@ interface UseMapDataOptions {
viewFeature: string | null;
activeFeature: string | null;
travelTimeEntries: TravelTimeEntry[];
+ /** Share-link code from the URL; appended to data fetches so the backend
+ * grants bbox-scoped access for unlicensed recipients. */
+ shareCode?: string;
}
export function useMapData({
@@ -48,6 +51,7 @@ export function useMapData({
viewFeature,
activeFeature,
travelTimeEntries,
+ shareCode,
}: UseMapDataOptions) {
const [rawData, setRawData] = useState([]);
const [postcodeData, setPostcodeData] = useState([]);
@@ -148,6 +152,7 @@ export function useMapData({
params.set('fields', fieldsParam);
if (dragTravelParam) params.set('travel', dragTravelParam);
if (viewFeatureIsEnum && dataViewFeature) params.set('enum_dist', dataViewFeature);
+ if (shareCode) params.set('share', shareCode);
fetch(apiUrl('postcodes', params), authHeaders({ signal: dragAbortRef.current.signal }))
.then((res) => res.json())
@@ -166,6 +171,7 @@ export function useMapData({
params.set('fields', fieldsParam);
if (dragTravelParam) params.set('travel', dragTravelParam);
if (viewFeatureIsEnum && dataViewFeature) params.set('enum_dist', dataViewFeature);
+ if (shareCode) params.set('share', shareCode);
fetch(apiUrl('hexagons', params), authHeaders({ signal: dragAbortRef.current.signal }))
.then((res) => res.json())
@@ -194,6 +200,7 @@ export function useMapData({
buildTravelParam,
dataViewFeature,
viewFeatureIsEnum,
+ shareCode,
]);
// Fetch hexagons or postcodes when bounds/filters change
@@ -226,6 +233,7 @@ export function useMapData({
params.set('travel', travelParam);
}
if (viewFeatureIsEnum && dataViewFeature) params.set('enum_dist', dataViewFeature);
+ if (shareCode) params.set('share', shareCode);
const res = await fetch(
apiUrl('postcodes', params),
authHeaders({
@@ -260,6 +268,7 @@ export function useMapData({
params.set('travel', travelParam);
}
if (viewFeatureIsEnum && dataViewFeature) params.set('enum_dist', dataViewFeature);
+ if (shareCode) params.set('share', shareCode);
const res = await fetch(
apiUrl('hexagons', params),
authHeaders({
@@ -311,6 +320,7 @@ export function useMapData({
viewFeatureIsEnum,
usePostcodeView,
travelParam,
+ shareCode,
]);
// Use drag data when it matches the current view feature, otherwise fall back to rawData
diff --git a/frontend/src/hooks/useUrlSync.ts b/frontend/src/hooks/useUrlSync.ts
index c8cf6d1..630080d 100644
--- a/frontend/src/hooks/useUrlSync.ts
+++ b/frontend/src/hooks/useUrlSync.ts
@@ -11,7 +11,8 @@ export function useUrlSync(
features: FeatureMeta[],
selectedPOICategories: Set,
rightPaneTab: 'properties' | 'area',
- travelTimeEntries?: TravelTimeEntry[]
+ travelTimeEntries?: TravelTimeEntry[],
+ share?: string
) {
const urlDebounceRef = useRef | null>(null);
@@ -26,7 +27,8 @@ export function useUrlSync(
features,
selectedPOICategories,
rightPaneTab,
- travelTimeEntries
+ travelTimeEntries,
+ share
);
const search = params.toString();
const newUrl = search ? `${window.location.pathname}?${search}` : window.location.pathname;
@@ -36,5 +38,13 @@ export function useUrlSync(
return () => {
if (urlDebounceRef.current) clearTimeout(urlDebounceRef.current);
};
- }, [currentView, filters, features, selectedPOICategories, rightPaneTab, travelTimeEntries]);
+ }, [
+ currentView,
+ filters,
+ features,
+ selectedPOICategories,
+ rightPaneTab,
+ travelTimeEntries,
+ share,
+ ]);
}
diff --git a/frontend/src/i18n/locales/de.ts b/frontend/src/i18n/locales/de.ts
index f43e4a9..0b7fdda 100644
--- a/frontend/src/i18n/locales/de.ts
+++ b/frontend/src/i18n/locales/de.ts
@@ -101,6 +101,9 @@ const de: Translations = {
registerAndUpgrade: 'Registrieren & Upgraden',
alreadyHaveAccount: 'Bereits ein Konto? Anmelden',
continueWithDemo: 'Mit Demo fortfahren',
+ backToSharedArea: 'Zurück zum geteilten Gebiet',
+ sharedAreaDescription:
+ 'Sie sehen ein geteiltes Gebiet. Um darüber hinaus zu erkunden, sichern Sie sich lebenslangen Zugriff auf jede Postleitzahl, jeden Filter und jede Nachbarschaft in England.',
checkoutFailed: 'Bezahlvorgang fehlgeschlagen',
},
@@ -343,51 +346,48 @@ const de: Translations = {
exploreTheMap: 'Passende Postleitzahlen finden',
seeTheDifference: 'So funktioniert es',
showcaseHeader: 'Produktvorschau',
- showcaseContext: 'Käufersuche in ganz England',
- showcaseStep1Tab: 'Beschreiben',
- showcaseStep1Title: 'Beschreiben Sie das Leben, das Sie möchten',
+ showcaseContext: 'So funktioniert Perfect Postcode',
+ showcaseStep1Tab: 'Filtern',
+ showcaseStep1Title: 'Filter kombinieren, die Portale gar nicht haben',
showcaseStep1Body:
- 'Nutzen Sie natürliche Sprache oder Filter, um komplexe Kaufkriterien in eine Suche zu verwandeln.',
- showcaseStep1Prompt:
- '2 Schlafzimmer unter £525k, 45 Min. zur Arbeit, ruhige Straßen, gute Schulen',
- showcaseStep1Chip1: '<= £525k',
- showcaseStep1Chip2: '2+ Schlafzimmer',
- showcaseStep1Chip3: '45 Min. Pendeln',
- showcaseStep1Chip4: 'Wenig Straßenlärm',
- showcaseStep2Tab: 'Entdecken',
- showcaseStep2Title: 'Zeigen Sie Orte, die Sie nicht erwogen hatten',
+ 'Wählen Sie, was wirklich zählt — jenseits von Preis und Zimmern. Wo sich Ihre Filter überlappen, das ist Ihre echte Shortlist.',
+ showcaseStep1Chip1: 'Ruhige Straßen',
+ showcaseStep1Chip2: 'Top-Grundschulen',
+ showcaseStep1Chip3: 'Unter £500k',
+ showcaseStep1VennCenter: 'Postleitzahlen, die alle drei erfüllen',
+ showcaseStep2Tab: 'Abgleichen',
+ showcaseStep2Title: 'Abgeglichen mit 13M Verkäufen und neuesten staatlichen Studien',
showcaseStep2Body:
- 'Die Karte markiert passende Postleitzahlen, auch außerhalb Ihrer bisherigen Shortlist.',
- showcaseStep2Metric: '47 passende Postleitzahlen',
- showcaseStep2Note: 'jenseits der offensichtlichen Shortlist',
- showcaseKnownAreas: 'Bekannte Gegenden',
- showcaseNewMatches: 'Neue Treffer',
- showcaseKnownAreaStatus: 'wenige Treffer',
+ 'Jedes Hexagon in England wird gegen Ihre Filter bewertet. Die Karte leuchtet dort, wo sich Treffer häufen.',
+ showcaseStep2Region: 'Großraum London',
+ showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
+ showcaseStep2ClustersLabel: 'Passende Cluster',
showcaseStep3Tab: 'Prüfen',
- showcaseStep3Title: 'Verstehen Sie, warum jede Postleitzahl passt',
+ showcaseStep3Title: 'Jedes Viertel in einem Panel lesen',
showcaseStep3Body:
- 'Öffnen Sie einen Treffer und prüfen Sie die Belege, bevor Sie ein Wochenende für Besichtigungen opfern.',
- showcaseStep3Postcode: 'Postleitzahl-Beispiel',
- showcaseStep3Area: 'Penge',
- showcaseStep3Code: 'SE20',
- showcaseStep3Score: 'Starker Fit',
- showcaseEvidence1: '42 Min. Pendelzeit',
- showcaseEvidence2: 'Weniger Straßenlärm',
- showcaseEvidence3: 'Gute Grundschuloptionen',
- showcaseEvidence4: 'Verkaufspreise im Budget',
- showcaseStep4Tab: 'Vergleichen',
- showcaseStep4Title: 'Kompromisse vor Besichtigungen vergleichen',
+ 'Öffnen Sie ein Hexagon und Sie sehen Verkaufspreis-Trends, Kriminalität, Demografie und Schulen — ohne Tab-Jonglieren.',
+ showcaseStep3HeaderArea: 'Penge · SE20',
+ showcaseStep3HeaderFit: 'Starker Fit · 7/8',
+ showcaseStep3Stat1Label: 'Verkaufspreis-Trend',
+ showcaseStep3Stat2Label: 'Kriminalität',
+ showcaseStep3Stat2Value: 'Unter Borough-Schnitt',
+ showcaseStep3Stat3Label: 'Median-Alter',
+ showcaseStep3Stat4Label: 'Breitband',
+ showcaseStep3Stat4Value: '1 Gbps verfügbar',
+ showcaseStep3Stat5Label: 'Grundschulen',
+ showcaseStep3Stat5Value: '3 „outstanding“ in 1 Meile',
+ showcaseStep4Tab: 'Exportieren',
+ showcaseStep4Title: 'Shortlist sichern und losziehen',
showcaseStep4Body:
- 'Erstellen Sie eine Shortlist danach, was Sie gewinnen und aufgeben, nicht nur nach Ruf.',
- showcaseCompare1: 'Penge: Londoner Bahnanschluss, mehr Platz',
- showcaseCompare2: 'Totterdown: fußläufige Straßen in Bristol',
- showcaseCompare3: 'Walkley: größere Häuser, guter Gegenwert',
- showcaseMapLabel: 'Passende Postleitzahlen',
- showcaseSaveLabel: 'Shortlist bereit',
- showcaseMatchPenge: 'London im Budget',
- showcaseMatchAbbeyWood: 'Elizabeth line + Grünflächen',
- showcaseMatchTotterdown: 'Bristol gut zu Fuß',
- showcaseMatchWalkley: 'Sheffield: Platz + Schulen',
+ 'Mit einem Klick landet jede passende Postleitzahl — samt Belegen — in einer Tabelle. Jetzt wissen Sie genau, wo Sie suchen sollen.',
+ showcaseStep4FileName: 'perfect-postcode-shortlist.xlsx',
+ showcaseStep4ExportLabel: 'Nach Excel exportieren',
+ showcaseStep4ColPostcode: 'Postleitzahl',
+ showcaseStep4ColScore: 'Fit',
+ showcaseStep4ColCommute: 'Pendeln',
+ showcaseStep4ColPrice: 'Median verkauft',
+ showcaseStep4Conclusion:
+ 'Schluss mit Raten — besichtigen Sie Häuser dort, wo bereits alles passt.',
statProperties: 'historische Verkäufe',
statFilters: 'kombinierbare Filter',
statEvery: 'Jede',
@@ -406,17 +406,6 @@ const de: Translations = {
streetCard2Title: 'Sehen Sie Kompromisse vor Besichtigungen',
streetCard2Body:
'Vergleichen Sie Preis, Platz, Pendelzeit, Sicherheit, Schulen, Breitband, Lärm und Energieeffizienz, bevor Sie Wochenenden mit Besichtigungen verbringen.',
- howToUseIt: 'So funktioniert es',
- howStep1Title: 'Beschreiben Sie das Leben, das Sie brauchen',
- howStep1Desc: 'Budget, Pendelzeit, Immobilientyp, Schulen, Sicherheit, Platz und Alltag.',
- howStep2Title: 'Passende Postleitzahlen anzeigen',
- howStep2Desc: 'Die Karte markiert Orte, die Ihre Filter erfüllen, auch unbekanntere Gegenden.',
- howStep3Title: 'Die Belege prüfen',
- howStep3Desc:
- 'Prüfen Sie Verkaufspreise, Wohnfläche, EPC, Straßenlärm, Breitband, Kriminalität und Schulen.',
- howStep4Title: 'Shortlist vor der Listingsuche',
- howStep4Desc:
- 'Gehen Sie mit besseren Suchgebieten zu Rightmove, Zoopla, Maklern und Besichtigungen.',
othersVs: 'Andere vs',
checkMyPostcode: 'Immobilienportale',
areaGuides: 'Postleitzahl-Berichte',
@@ -553,42 +542,41 @@ const de: Translations = {
dsElectionUse:
'Ergebnisse auf Kandidatenebene der britischen Parlamentswahl vom Juli 2024. Aggregiert auf Wahlkreisebene: Wahlbeteiligung (%) und Parteistimmenanteile (%). Über den Wahlkreiscode (pcon) aus dem NSPL-Postleitzahlenverzeichnis mit Immobilien verknüpft.',
// FAQ section titles
- faqFindingTitle: 'Ihr Gebiet finden',
- faqCommuteTitle: 'Pendelweg und Reisezeit',
- faqBudgetTitle: 'Budget und Preis-Leistung',
+ faqFindingTitle: 'Suchstrategie',
+ faqCommuteTitle: 'Reisezeit-Routing',
+ faqBudgetTitle: 'Geschätzte Preise',
faqSafetyTitle: 'Sicherheit und Nachbarschaft',
faqFamiliesTitle: 'Familien und Schulen',
faqEnvironmentTitle: 'Umwelt und Lebensqualität',
+ faqDueDiligenceTitle: 'Umfang und Due Diligence',
+ faqPrivacyTitle: 'Datenschutz',
faqWhyTitle: 'Warum Perfect Postcode',
- faqPricingTitle: 'Preise und Zugang',
+ faqPricingTitle: 'Zugang',
faqTipsTitle: 'Tipps und Tricks',
// FAQ items — Finding Your Area
- faqFinding1Q:
- 'Ich weiß nicht einmal, welche Gebiete ich mir ansehen soll. Kann mir das helfen?',
+ faqFinding1Q: 'Wo soll ich suchen, wenn die offensichtlichen Gebiete zu teuer sind?',
faqFinding1A:
- 'Genau dafür ist es da. Legen Sie Ihre Filter fest (Budget, Pendelzeit, geringe Kriminalität, gute Schulen) und die Karte leuchtet auf, um Ihnen jedes Gebiet zu zeigen, das alle Kriterien erfüllt. Kein nächtliches Googeln nach „beste Wohngegenden bei Manchester“ mehr.',
+ 'Setzen Sie Budget, Immobilientyp, Wohnfläche, Pendelzeit, Schulen, Kriminalität, Lärm, Breitband, Parks und andere Muss-Kriterien. Die Karte entfernt Postleitzahlen, die diese Tests nicht bestehen, sodass übersehene Gebiete sichtbar werden, bevor Sie in Portalen suchen.',
faqFinding2Q: 'Ich ziehe irgendwohin, wo ich noch nie war. Wie fange ich überhaupt an?',
faqFinding2A:
'Stellen Sie Ihre Filter für das ein, was Ihnen wichtig ist, und die Karte hebt sofort die passenden Gebiete hervor. Sie gehen von „Ich kenne keine einzige Straße“ zu einer Auswahlliste in wenigen Minuten.',
- faqFinding3Q: 'Wie finde ich Gebiete, die alle meine Kriterien gleichzeitig erfüllen?',
+ faqFinding3Q: 'Was mache ich, wenn die Suche zu viele oder zu wenige Gebiete zeigt?',
faqFinding3A:
- 'Kombinieren Sie mehrere Filter (Kriminalität unter dem Durchschnitt, gute Schulen, Pendelweg unter 40 Minuten) und färben Sie die Karte nach Preis, um die Gebiete mit dem besten Preis-Leistungs-Verhältnis zu finden. Die Karte aktualisiert sich in Echtzeit, wenn Sie die Regler bewegen.',
+ 'Beginnen Sie mit harten Grenzen und färben Sie die Karte dann nach einem Trade-off wie Preis pro m², Straßenlärm, Schulscore oder Reisezeit. Wenn die Karte zu eng wird, lockern Sie einen Regler und sehen sofort, welcher Kompromiss neue Optionen öffnet.',
// FAQ items — Commute and Travel
- faqCommute1Q:
- 'Kann ich sehen, wie lange mein Pendelweg aus verschiedenen Gebieten tatsächlich dauern würde?',
+ faqCommute1Q: 'Wie werden die Reisezeiten berechnet?',
faqCommute1A:
- 'Legen Sie Ihren Arbeitsplatz als Ziel fest und wir färben jede Postleitzahl nach Fahrzeit – ob mit Auto, Fahrrad oder öffentlichen Verkehrsmitteln. Filtern Sie nach Ihrer maximalen Pendelzeit und der Rest verschwindet.',
- faqCommute2Q: 'Wie ist das besser als Google Maps?',
+ 'Die Reisezeiten werden mit Conveyal R5 vorab berechnet, einer Routing-Engine für Verkehrsanalysen. Für jedes unterstützte Ziel routen wir zu erreichbaren Postleitzahlen über das Straßen- und ÖPNV-Netz und speichern schlanke Postleitzahl-Reisezeitdateien für Auto, Fahrrad, Fußweg und öffentliche Verkehrsmittel. Dadurch kann die Karte viele Postleitzahlen schnell filtern, statt jede Route einzeln abzufragen.',
+ faqCommute2Q: 'Was sollte ich über die Reisezeitwerte wissen?',
faqCommute2A:
- 'Google Maps zeigt Ihnen eine Fahrt auf einmal. Wir färben jede Postleitzahl in England nach Pendelzeit in einem Blick, sodass Sie Hunderte von Gebieten nebeneinander vergleichen können, anstatt sie einzeln zu suchen.',
+ 'ÖPNV-Zeiten verwenden ein morgendliches Abfahrtsfenster von 07:30 bis 08:30. Standard ist die Medianzeit, also der typische Wert in diesem Fenster; die Best-Case-Option nutzt das 5. Perzentil für gut getimte Abfahrten. Es sind modellierte Vergleichswerte, keine Live-Störungen, Verkehrslagen oder Bahnsteigwechsel-Prognosen.',
// FAQ items — Budget and Value
- faqBudget1Q: 'Wie finde ich Gebiete, in denen ich am meisten Wohnfläche für mein Geld bekomme?',
+ faqBudget1Q: 'Wie funktioniert der Algorithmus für den geschätzten aktuellen Preis?',
faqBudget1A:
- 'Filtern Sie nach Preis pro m² und Sie sehen sofort, welche Postleitzahlen am meisten Fläche pro Pfund bieten. Kombinieren Sie es mit dem Energiebewertungsfilter, um Immobilien mit hohen Heizkosten zu vermeiden.',
- faqBudget2Q:
- 'Wie stelle ich sicher, dass ein günstiges Gebiet nicht aus gutem Grund günstig ist?',
+ 'Die proprietäre Schätzung beginnt mit dem letzten HM-Land-Registry-Verkaufspreis. Dieser wird mit einem Repeat-Sales-Index auf heute angepasst, gelernt aus Immobilien mit mehreren Verkäufen und gegliedert nach Postleitzahlsektor und Immobilientyp. Dünn besetzte Gebiete werden Richtung District-, Area-, nationalem und hedonischem Fallback-Modell geschrumpft und räumlich geglättet. Danach wird das Ergebnis mit einer Nächste-Nachbarn-Schätzung aus nahe gelegenen, kürzlich verkauften, ähnlichen Immobilien auf Basis von Preis pro m² und EPC-Wohnfläche gemischt.',
+ faqBudget2Q: 'Warum den geschätzten aktuellen Preis statt des letzten Verkaufspreises nutzen?',
faqBudget2A:
- 'Legen Sie Benachteiligungswerte, Kriminalitätsstatistiken, Schulbewertungen und Breitbandgeschwindigkeiten neben den Preis. Wenn eine Postleitzahl erschwinglich ist und bei allem, was zählt, gut abschneidet, haben Sie echten Wert gefunden – nicht nur einen niedrigen Preis mit Kompromissen, die Sie noch nicht bemerkt haben.',
+ 'Der letzte Verkaufspreis kann Jahre oder Jahrzehnte alt sein, und aktuelle Angebotspreise zeigen nur, was gerade auf dem Markt ist. Der geschätzte aktuelle Preis bringt alte Verkäufe näher an heutige Marktbedingungen, damit Sie mehr Immobilien vergleichen, geschätzten Preis pro m² berechnen und gute Werte erkennen können, bevor passende Inserate erscheinen. Es ist ein Screening-Wert, keine formale Bewertung.',
// FAQ items — Safety and Neighbourhood
faqSafety1Q: 'Wie kann ich prüfen, ob ein Gebiet sicher ist, bevor ich dorthin ziehe?',
faqSafety1A:
@@ -610,12 +598,29 @@ const de: Translations = {
'Kann ich energieeffiziente Wohnungen finden, die nicht an einer lauten Straße liegen?',
faqEnv1A:
'Filtern Sie nach EPC-Bewertung (A bis C), dann überlagern Sie die Straßenlärmdaten, um alles über Ihrem Schwellenwert auszuschließen. Färben Sie nach einem der beiden Kriterien, um ruhige, effiziente Straßen auf einen Blick zu erkennen.',
- faqEnv2Q: 'Zeigt es Hochwasser- oder Senkungsrisiken?',
+ faqEnv2Q: 'Zeigt es Hochwasser-, Senkungs- oder Gutachterrisiken?',
faqEnv2A:
- 'Wir integrieren Bodenstabilitätsdaten, damit Sie vor dem Kauf auf Senkungen, Schrumpf-Quell-Tone und andere geologische Risiken prüfen können. Schließen Sie Risikogebiete frühzeitig aus.',
+ 'Nicht als Live-Filter. Wir zeigen Daten wie Straßenlärm, EPC, Baualter und lokale Umweltindikatoren, aber Hochwassersuchen, Grundbuchthemen, bauliche Mängel und Finanzierbarkeit müssen weiterhin durch Anwälte, Kreditgeber und Gutachter geprüft werden.',
faqEnv3Q: 'Kann ich Gebiete mit schnellem Breitband finden, die wirklich ruhig sind?',
faqEnv3A:
'Überlagern Sie den Breitbandfilter mit den Straßenlärmdaten, um Straßen mit guter Anbindung und wenig Verkehrslärm zu finden. Färben Sie nach einem der beiden Kriterien, um Gebiete auf einen Blick zu vergleichen.',
+ // FAQ items — Listing Portals and Due Diligence
+ faqDueDiligence1Q: 'Sollte ich das vor oder nach Rightmove nutzen?',
+ faqDueDiligence1A:
+ 'Nutzen Sie Perfect Postcode vor und neben Listing-Portalen. Rightmove, Zoopla und OnTheMarket bleiben für aktuelle Verfügbarkeit, Fotos, Maklerkontakt, Besichtigungen und Benachrichtigungen zuständig. Perfect Postcode hilft zu entscheiden, welche Postleitzahlen die Suche überhaupt wert sind.',
+ faqDueDiligence2Q: 'Kann ich nach Garten, Garage, Grundriss oder Anzeigentext filtern?',
+ faqDueDiligence2A:
+ 'Nur, wenn die Information in strukturierten offiziellen Daten vorhanden ist. Perfect Postcode kann nach Wohnfläche, Immobilientyp, Eigentumsform, EPC, Verkaufspreisen und lokalen Daten filtern. Gärten, Garagen, Ausrichtung, Raumaufteilung und Maklerformulierungen müssen weiterhin in der Anzeige und bei der Besichtigung geprüft werden.',
+ faqDueDiligence3Q: 'Kann ich Preisreduzierungen oder die Online-Dauer eines Listings sehen?',
+ faqDueDiligence3A:
+ 'Derzeit nicht. Perfect Postcode basiert auf offiziellen Verkaufspreis-, EPC-, Postleitzahl-, Reisezeit- und Nachbarschaftsdaten, nicht auf Live-Listing-Feeds. Sie können aber Transaktionsdatum, Verkaufshistorie, geschätzten aktuellen Wert und Preis pro m² nutzen, um einen Angebotspreis einzuordnen.',
+ faqDueDiligence4Q: 'Was sollte ich vor einem Angebot trotzdem prüfen?',
+ faqDueDiligence4A:
+ 'Nutzen Sie Perfect Postcode für den Gebiets- und Wert-Check, prüfen Sie danach aber Listing-Details, Eigentumsform, Laufzeit eines Leaseholds, Service Charge, Planungshistorie, Hochwasserrisiko, Grundbuchthemen, Kreditgeberanforderungen und Gutachten über den üblichen professionellen Prozess.',
+ // FAQ items — Privacy and Data Protection
+ faqPrivacy1Q: 'Speichern Sie personenbezogene Daten über mich?',
+ faqPrivacy1A:
+ 'Wir speichern keine personenbezogenen Daten in den Immobilien- und Nachbarschaftsdatensätzen. Diese Datensätze stammen aus offiziellen und öffentlichen Quellen und dienen der Postleitzahlen- und Immobilienrecherche. Wenn Sie ein Konto erstellen, speichern wir nur, was für den Betrieb des Dienstes erforderlich ist, etwa E-Mail-Adresse, Lizenzstatus, Newsletter-Einstellung, gespeicherte Suchen, gespeicherte Immobilien und Zahlungskennungen, die über Stripe verarbeitet werden. Diese Kontodaten behandeln wir nach UK GDPR und dem Data Protection Act 2018.',
// FAQ items — Why Perfect Postcode
faqWhy1Q: 'Ich benutze bereits Rightmove. Was bringt mir das zusätzlich?',
faqWhy1A:
@@ -630,9 +635,9 @@ const de: Translations = {
faqPricing1Q: 'Lohnt es sich wirklich, für ein Immobilien-Suchtool zu bezahlen?',
faqPricing1A:
'Ein Hauskauf ist wahrscheinlich die größte Anschaffung Ihres Lebens. Ein einziges Warnsignal zu erkennen (eine laute Straße, schlechtes Breitband, steigende Kriminalität) bevor Sie sich festlegen, könnte Ihnen Jahre des Bedauerns ersparen. Das kostet weniger als eine Tankfüllung.',
- faqPricing2Q: 'Ist das ein Abonnement?',
+ faqPricing2Q: 'Was bedeutet lebenslanger Zugang?',
faqPricing2A:
- 'Nein. Einmalzahlung, Ihres für immer. Nutzen Sie es intensiv während Ihrer Suche, kommen Sie zurück, wenn Sie neugierig auf ein neues Gebiet sind, und es ist immer noch da, falls Sie erneut umziehen.',
+ 'Lebenslanger Zugang bedeutet, dass eine Zahlung Ihrem Konto laufenden Zugriff auf die kostenpflichtige Perfect-Postcode-Karte für die Lebensdauer des Dienstes gibt. Es ist kein Monats- oder Jahresabo, und normale Datenaktualisierungen sind enthalten. Sie können es während dieser Suche nutzen, später zurückkommen und weiterhin Zugriff haben, wenn Sie erneut umziehen.',
faqPricing3Q: 'Was kann ich mit der kostenlosen Version nutzen?',
faqPricing3A:
'Kostenlose Nutzer können alle Funktionen im Demogebiet erkunden (Innenstadt London, ungefähr Zonen 1 bis 2). Für den Zugang zu Daten für den Rest Englands benötigen Sie den lebenslangen Zugang.',
diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts
index e5375fe..ce0d1cd 100644
--- a/frontend/src/i18n/locales/en.ts
+++ b/frontend/src/i18n/locales/en.ts
@@ -99,6 +99,9 @@ const en = {
registerAndUpgrade: 'Register & Upgrade',
alreadyHaveAccount: 'Already have an account? Log in',
continueWithDemo: 'Continue with demo',
+ backToSharedArea: 'Back to shared area',
+ sharedAreaDescription:
+ 'You’re viewing a shared area. To explore beyond it, get lifetime access to every postcode, every filter, and every neighbourhood in England.',
checkoutFailed: 'Checkout failed',
},
@@ -339,49 +342,47 @@ const en = {
exploreTheMap: 'Find my matching postcodes',
seeTheDifference: 'See how it works',
showcaseHeader: 'Product showcase',
- showcaseContext: 'England-wide buyer search',
- showcaseStep1Tab: 'Describe',
- showcaseStep1Title: 'Describe the life you want',
+ showcaseContext: 'How Perfect Postcode works',
+ showcaseStep1Tab: 'Filter',
+ showcaseStep1Title: 'Turn vague needs into a tight search',
showcaseStep1Body:
- 'Use natural language or filters to turn messy buyer criteria into one search.',
- showcaseStep1Prompt: '2-bed under £525k, 45 mins to work, quiet streets, good schools',
- showcaseStep1Chip1: '<= £525k',
- showcaseStep1Chip2: '2+ beds',
- showcaseStep1Chip3: '45 min commute',
- showcaseStep1Chip4: 'Low road noise',
- showcaseStep2Tab: 'Discover',
- showcaseStep2Title: 'Reveal places you had not considered',
+ 'Set what matters and see exactly how many wrong-fit postcodes each requirement keeps out of your search.',
+ showcaseStep1Chip1: 'Quiet streets',
+ showcaseStep1Chip2: 'Top-rated primaries',
+ showcaseStep1Chip3: 'Under £500k',
+ showcaseStep1VennCenter: 'Postcodes that meet all three',
+ showcaseStep2Tab: 'Match',
+ showcaseStep2Title: 'Let the map surface places you would not have typed',
showcaseStep2Body:
- 'The map lights up matching postcodes, including areas outside your usual shortlist.',
- showcaseStep2Metric: '47 matching postcodes',
- showcaseStep2Note: 'beyond the obvious shortlist',
- showcaseKnownAreas: 'Known areas',
- showcaseNewMatches: 'New matches',
- showcaseKnownAreaStatus: 'few matches',
- showcaseStep3Tab: 'Check',
- showcaseStep3Title: 'Understand why each postcode fits',
+ 'Scan England by fit instead of starting from familiar area names. Hidden pockets become visible before listing portals narrow your imagination.',
+ showcaseStep2Region: 'Greater London',
+ showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
+ showcaseStep2ClustersLabel: 'Matching clusters',
+ showcaseStep3Tab: 'Inspect',
+ showcaseStep3Title: 'Inspect why a postcode made the cut',
showcaseStep3Body:
- 'Open a result and check the evidence before you give up a weekend for viewings.',
- showcaseStep3Postcode: 'Postcode example',
- showcaseStep3Area: 'Penge',
- showcaseStep3Code: 'SE20',
- showcaseStep3Score: 'Strong fit',
- showcaseEvidence1: '42 min commute',
- showcaseEvidence2: 'Lower road noise',
- showcaseEvidence3: 'Good primary options',
- showcaseEvidence4: 'Sold prices in budget',
- showcaseStep4Tab: 'Compare',
- showcaseStep4Title: 'Compare trade-offs before viewings',
- showcaseStep4Body: 'Shortlist areas by what you gain and give up, not by reputation alone.',
- showcaseCompare1: 'Penge: London rail links, more space',
- showcaseCompare2: 'Totterdown: walkable Bristol streets',
- showcaseCompare3: 'Walkley: larger homes, strong value',
- showcaseMapLabel: 'Matching postcodes',
- showcaseSaveLabel: 'Shortlist ready',
- showcaseMatchPenge: 'London budget fit',
- showcaseMatchAbbeyWood: 'Elizabeth line + green space',
- showcaseMatchTotterdown: 'Bristol walkability',
- showcaseMatchWalkley: 'Sheffield space + schools',
+ 'Open any matching area and check prices, safety, schools, broadband, and trade-offs in one pane before you spend a weekend there.',
+ showcaseStep3HeaderArea: 'Penge · SE20',
+ showcaseStep3HeaderFit: 'Strong fit · 7/8',
+ showcaseStep3Stat1Label: 'Sold price trend',
+ showcaseStep3Stat2Label: 'Crime rate',
+ showcaseStep3Stat2Value: 'Below borough avg.',
+ showcaseStep3Stat3Label: 'Median age',
+ showcaseStep3Stat4Label: 'Broadband',
+ showcaseStep3Stat4Value: '1 Gbps available',
+ showcaseStep3Stat5Label: 'Primary schools',
+ showcaseStep3Stat5Value: '3 outstanding within 1 mile',
+ showcaseStep4Tab: 'Scout',
+ showcaseStep4Title: 'Scout it out yourself',
+ showcaseStep4Body:
+ 'Take three grounded starting points into the real world. Walk the streets, test the commute, and compare viewings with context.',
+ showcaseStep4FileName: 'areas-to-scout.xlsx',
+ showcaseStep4ExportLabel: 'Export to Excel',
+ showcaseStep4ColPostcode: 'Postcode',
+ showcaseStep4ColScore: 'Fit',
+ showcaseStep4ColCommute: 'Commute',
+ showcaseStep4ColPrice: 'Median sold',
+ showcaseStep4Conclusion: 'You can start your journey from here. You are no longer lost.',
statProperties: 'historical sales',
statFilters: 'combinable filters',
statEvery: 'Every',
@@ -400,17 +401,6 @@ const en = {
streetCard2Title: 'See the trade-offs before viewings',
streetCard2Body:
'Compare price, space, commute, safety, schools, broadband, noise, and energy ratings before you spend weekends travelling between viewings.',
- howToUseIt: 'How to use it',
- howStep1Title: 'Describe the life you need',
- howStep1Desc: 'Budget, commute, property type, schools, safety, space, and daily essentials.',
- howStep2Title: 'Reveal matching postcodes',
- howStep2Desc:
- 'The map highlights the places that pass your filters, including unfamiliar areas.',
- howStep3Title: 'Check the evidence',
- howStep3Desc:
- 'Inspect sold prices, floor area, EPC, road noise, broadband, crime, and schools.',
- howStep4Title: 'Shortlist before you browse listings',
- howStep4Desc: 'Take a better search area to Rightmove, Zoopla, agents, and viewings.',
othersVs: 'Others vs',
checkMyPostcode: 'Listing portals',
areaGuides: 'Postcode reports',
@@ -467,7 +457,7 @@ const en = {
dataSourcesIntro:
'This application combines {{count}} open datasets covering property prices, energy performance, transport, demographics, crime, environment, and more.',
faqIntro:
- 'Whether you’re buying in London, comparing commuter towns, or sanity-checking an unfamiliar postcode, here’s how Perfect Postcode helps you work out where to look.',
+ 'Whether you’re narrowing a first-time buyer search, checking an unfamiliar postcode, or building a viewing shortlist, here’s how Perfect Postcode helps you work out where to look.',
supportIntro: 'Have a question? Check our FAQ or reach out to us directly.',
source: 'Source:',
optOut: 'Opt out of public disclosure',
@@ -546,95 +536,113 @@ const en = {
dsElectionUse:
'Candidate-level results for the July 2024 UK General Election. Aggregated to constituency level: voter turnout (%) and party vote shares (%). Joined to properties via the parliamentary constituency code (pcon) from the NSPL postcode lookup.',
// FAQ section titles
- faqFindingTitle: 'Finding Your Area',
- faqCommuteTitle: 'Commute and Travel',
- faqBudgetTitle: 'Budget and Value',
+ faqFindingTitle: 'Search Strategy',
+ faqCommuteTitle: 'Travel-Time Routing',
+ faqBudgetTitle: 'Estimated Prices',
faqSafetyTitle: 'Safety and Neighbourhood',
faqFamiliesTitle: 'Families and Schools',
faqEnvironmentTitle: 'Environment and Quality of Life',
+ faqDueDiligenceTitle: 'Scope and Due Diligence',
+ faqPrivacyTitle: 'Privacy and Data Protection',
faqWhyTitle: 'Why Perfect Postcode',
- faqPricingTitle: 'Pricing and Access',
+ faqPricingTitle: 'Access',
faqTipsTitle: 'Tips and Tricks',
// FAQ items — Finding Your Area
- faqFinding1Q: 'I don’t even know which areas to look at. Can this help?',
+ faqFinding1Q: 'Where should I look once the obvious areas are too expensive?',
faqFinding1A:
- 'That is exactly what it is for. Set your filters (budget, commute time, low crime, good schools, broadband, road noise) and the map lights up to show every postcode that fits. You can discover areas before you know their names.',
- faqFinding2Q: 'I’m moving somewhere I’ve never been. How do I even start?',
+ 'Set your budget, property type, floor area, commute, schools, crime, noise, broadband, parks, and other must-haves. The map removes postcodes that fail those tests, so overlooked areas can surface before you start searching listings.',
+ faqFinding2Q: 'How do I find good postcodes in places I do not know well?',
faqFinding2A:
- 'Set what matters and the map highlights the postcodes that qualify. You go from "I do not know a single street" to a shortlist you can inspect in minutes.',
- faqFinding3Q: 'How do I find areas that tick all my boxes at once?',
+ 'Filter the whole map by your hard requirements, then inspect the clusters that remain. You can compare unfamiliar postcodes by commute, sold prices, schools, crime, broadband, noise, and amenities instead of relying on reputation.',
+ faqFinding3Q: 'What should I do when my search returns too many or too few areas?',
faqFinding3A:
- 'Stack multiple filters (crime below average, good schools, commute under 40 minutes) then colour the map by price to spot the best value areas. The map updates live as you drag sliders, so you can see results change in real time.',
+ 'Start with hard limits, then colour the map by a trade-off such as price per sqm, road noise, school score, or commute time. If the map gets too narrow, relax one slider and you can see exactly which compromise opens up more options.',
// FAQ items — Commute and Travel
- faqCommute1Q: 'Can I see how long my commute would actually be from different areas?',
+ faqCommute1Q: 'How are the travel times calculated?',
faqCommute1A:
- 'Set your workplace as a destination and we’ll colour every postcode by journey time, whether that’s by car, bike, or public transport. Filter to your max commute and the rest disappears.',
- faqCommute2Q: 'How is that better than checking Google Maps?',
+ 'Travel times are precomputed with Conveyal R5, a routing engine used for transport analysis. For each supported destination we route to reachable postcodes over the street and transit network, then store sparse postcode travel-time files for car, cycling, walking, and public transport. That lets the map filter thousands of postcodes quickly instead of calling a route API one postcode at a time.',
+ faqCommute2Q: 'What should I know about the travel-time numbers?',
faqCommute2A:
- 'Google Maps shows you one journey at a time. We colour every postcode in England by commute time in one go, so you can compare hundreds of areas side by side instead of searching them one by one.',
+ 'Public transport times use a morning peak departure window, 07:30 to 08:30. The default is the median journey time, which is the typical result across that window; the best-case toggle uses the 5th percentile for well-timed departures. They are modelled comparison times, not live disruption, traffic, or platform-change predictions.',
// FAQ items — Budget and Value
- faqBudget1Q: 'How do I find areas where I get the most space for my money?',
+ faqBudget1Q: 'How does the estimated current price algorithm work?',
faqBudget1A:
- 'Filter by price per sqm and you’ll instantly see which postcodes give you the most space per pound. Pair it with the energy rating filter to avoid properties with high heating costs.',
- faqBudget2Q: 'How do I make sure a cheap area isn’t cheap for a reason?',
+ 'The proprietary estimate starts with the last HM Land Registry sale price. It adjusts that price to today using a repeat-sales index learned from properties that sold more than once, stratified by postcode sector and property type. Sparse areas are shrunk toward district, area, national, and hedonic fallback models, then spatially smoothed. Finally, the result is blended with a nearest-neighbour estimate from nearby, recently sold, same-type homes using adjusted price per sqm and EPC floor area.',
+ faqBudget2Q: 'Why use estimated current price instead of last sold price?',
faqBudget2A:
- 'Layer deprivation scores, crime stats, school ratings, and broadband speeds alongside price. If a postcode is affordable and scores well on everything that matters, you’ve found genuine value, not just a low price with trade-offs you haven’t spotted yet.',
+ 'Last sold price can be years or decades old, and live asking prices only cover whatever happens to be listed today. Estimated current price puts old sales into current-market terms so you can compare more properties, calculate estimated price per sqm, and spot areas that look good value before listings appear. It is a screening estimate, not a formal valuation.',
// FAQ items — Safety and Neighbourhood
- faqSafety1Q: 'How can I check if an area is safe before I move there?',
+ faqSafety1Q: 'What type of crime is common around this postcode?',
faqSafety1A:
- 'We overlay real police-recorded crime data, broken down by type, onto every neighbourhood in England. Filter by violent crime, burglary, or antisocial behaviour and instantly see which postcodes have the lowest numbers.',
- faqSafety2Q:
- 'I keep finding flats that look great online, then the area turns out to be rough.',
+ 'Police-recorded crime is broken down by type, including violence, burglary, robbery, vehicle crime, antisocial behaviour, shoplifting, drugs, and public order. You can filter by the specific risks you care about instead of relying on a single vague safety score.',
+ faqSafety2Q: 'What should I check before viewing an unfamiliar street?',
faqSafety2A:
- 'That’s exactly why this exists. Stack crime rates, noise levels, deprivation scores, nearby pubs and parks, and broadband speeds all on one map so you know what a neighbourhood is actually like before you book a viewing.',
+ 'Check crime, road noise, deprivation, broadband, parks, groceries, schools, and commute before you book. The listing photos can still be useful, but they should not be the first time you learn what the street is like.',
// FAQ items — Families and Schools
- faqFamilies1Q: 'Can I find areas with good schools AND low crime in one search?',
+ faqFamilies1Q: 'Which areas have the right mix of schools, space, safety, and commute?',
faqFamilies1A:
- 'Yes. Stack filters for Ofsted ratings, crime rates, parks, and whatever else matters to your family, and the map highlights only the areas that tick every box. No more cross-referencing five different websites.',
- faqFamilies2Q: 'How do I know if a neighbourhood has parks and playgrounds nearby?',
+ 'Stack Ofsted ratings, crime, parks, commute, floor area, property type, and budget on one map. The result is a practical family shortlist rather than a pile of separate school, crime, listing, and transport searches.',
+ faqFamilies2Q: 'Does this prove I am inside a school catchment?',
faqFamilies2A:
- 'Toggle on the parks and green spaces POI layer to see them right on the map. You can also filter by how many are within walking distance of each postcode.',
+ 'No. We show nearby school quality and area-level education data, but admissions boundaries and priority rules can change. Treat Perfect Postcode as a shortlist tool, then verify catchments and admissions with the school or local authority.',
// FAQ items — Environment and Quality of Life
- faqEnv1Q: 'Can I find energy-efficient homes that aren’t on a noisy road?',
+ faqEnv1Q: 'How do I avoid a noisy road without losing commute or broadband quality?',
faqEnv1A:
- 'Filter by EPC rating (A to C), then layer on road noise data to rule out anything above your threshold. Colour-code by either feature to spot quiet, efficient streets at a glance.',
- faqEnv2Q: 'Does it show flood or subsidence risk?',
+ 'Filter by road noise, then keep commute time, broadband speed, price, and property filters active. You can colour by any one feature while the others keep the shortlist honest.',
+ faqEnv2Q: 'Do you show flood risk, subsidence, or survey issues?',
faqEnv2A:
- 'We include ground stability data so you can check for subsidence, shrink-swell clay, and other geological hazards before committing to a property. Filter out risky areas early.',
- faqEnv3Q: 'Can I find areas with fast broadband that are actually quiet?',
+ 'Not as live filters today. We show data such as road noise, EPC, construction age, and local environment indicators, but flood searches, title checks, structural issues, and mortgageability still need proper conveyancing, lender checks, and a survey.',
+ faqEnv3Q: 'What running-cost checks can I do before viewing?',
faqEnv3A:
- 'Layer the broadband speed filter with road noise data to find streets with great connectivity and low traffic noise. Colour-code by either metric to compare areas at a glance.',
+ 'You can screen for EPC rating, total floor area, construction age, council tax authority, broadband, and noise before viewing. That will not predict your exact bills, but it helps you avoid obvious mismatches early.',
+ // FAQ items — Listing Portals and Due Diligence
+ faqDueDiligence1Q: 'Should I use this before or after checking Rightmove?',
+ faqDueDiligence1A:
+ 'Use Perfect Postcode before and alongside listing portals. Rightmove, Zoopla, and OnTheMarket are still where you check live availability, photos, agent contact, viewings, and alerts. Perfect Postcode helps you work out which postcodes are worth searching in the first place.',
+ faqDueDiligence2Q: 'Why can’t I filter by garden, garage, or layout?',
+ faqDueDiligence2A:
+ 'Only where the information exists in structured official data. Perfect Postcode can filter by things like floor area, property type, tenure, EPC, sold prices, and local data. Gardens, garages, aspect, room layout, and estate-agent wording still need to be checked in the listing and at the viewing.',
+ faqDueDiligence3Q: 'Do you track listing price cuts and time on market?',
+ faqDueDiligence3A:
+ 'Not currently. Perfect Postcode is built around official sold-price, EPC, postcode, travel-time, and neighbourhood data rather than live listing feeds. You can still use date of last transaction, sold price history, estimated current value, and price per sqm to judge whether a live asking price looks stretched.',
+ faqDueDiligence4Q: 'What should I still verify before making an offer?',
+ faqDueDiligence4A:
+ 'Use Perfect Postcode to sanity-check the area and value, then verify the live listing details, tenure, lease terms, service charge, planning history, flood risk, title issues, lender requirements, and survey findings through the usual professional process.',
+ // FAQ items — Privacy and Data Protection
+ faqPrivacy1Q: 'Do you store personal data about me?',
+ faqPrivacy1A:
+ 'We do not store personal data in the property and neighbourhood datasets. Those datasets are built from official and public sources for postcode and property research. If you create an account, we store only what is needed to run the service, such as your email address, licence status, newsletter preference, saved searches, saved properties, and payment identifiers handled through Stripe. We handle that account data under UK GDPR and the Data Protection Act 2018.',
// FAQ items — Why Perfect Postcode
- faqWhy1Q: 'I already use Rightmove. What does this add?',
+ faqWhy1Q: 'What does this show that listing portals usually do not?',
faqWhy1A:
- 'Rightmove shows you listings. Perfect Postcode shows you where to look. Crime rates, school ratings, broadband speeds, noise levels, sold prices, floor area, EPC data, and more are all filterable on one map before you open listings.',
- faqWhy2Q: 'Can’t I just research all this myself for free?',
+ 'Listing portals start from homes that are for sale right now. Perfect Postcode starts from the places that fit your life and budget, using sold prices, floor area, commute, schools, crime, noise, broadband, EPC, tenure, and amenities before you open the listings.',
+ faqWhy2Q: 'How much manual research does this save?',
faqWhy2A:
- 'You could cross-reference police data, Ofsted reports, EPC registers, Land Registry records, ONS statistics, Street View and commute tools one postcode at a time. Or you could have the evidence filterable and colour-coded on one map.',
- faqWhy3Q: 'Where does the data actually come from?',
+ 'You can, but it means stitching together Land Registry, EPC, police, Ofsted, Ofcom, ONS, Defra, travel-time, and map data one postcode at a time. Perfect Postcode makes those sources filterable across England in one place.',
+ faqWhy3Q: 'How reliable are the underlying sources?',
faqWhy3A:
- 'Every dataset comes from official UK government sources: Land Registry, the EPC register, ONS, Ofsted, Ofcom, data.police.uk, and Defra. We don’t scrape estate agents or make anything up. You can verify any record against the original source.',
+ 'The core datasets come from official or authoritative sources such as HM Land Registry, EPC records, ONS, Ofsted, Ofcom, data.police.uk, Defra, Ordnance Survey, and OpenStreetMap. They are excellent for shortlisting and comparison, but any purchase decision still needs current checks and professional advice.',
// FAQ items — Pricing and Access
- faqPricing1Q: 'Is it really worth paying for a property search tool?',
+ faqPricing1Q: 'Why pay when postcode reports are free?',
faqPricing1A:
- 'Buying a home is likely the biggest purchase you’ll make. Spotting one red flag (a noisy road, weak broadband, awkward commute, poor school access, or bad value) before committing could save you years of regret.',
- faqPricing2Q: 'Is this a subscription?',
+ 'Free postcode tools are useful once you already know what to check. Perfect Postcode is for scanning every postcode in England against your criteria, combining filters, comparing trade-offs, saving searches, and exporting a shortlist before you commit weekends to viewings.',
+ faqPricing2Q: 'What does lifetime access mean?',
faqPricing2A:
- 'No. One-time payment, yours forever. Use it intensively during your search, come back whenever you’re curious about a new area, and it’s still there if you ever move again.',
+ 'Lifetime access means one payment gives your account ongoing access to the paid Perfect Postcode map for the lifetime of the service. It is not a monthly or annual subscription, and normal data updates are included. You can use it during this search, come back later, and still have access if you move again.',
faqPricing3Q: 'What can I access on the free tier?',
faqPricing3A:
'Free users can explore all features within the demo area (inner London, roughly zones 1 to 2). To access data for the rest of England, you need lifetime access.',
// FAQ items — Tips and Tricks
- faqTips1Q: 'How do I use the AI filter instead of adding filters one by one?',
+ faqTips1Q: 'How do I describe a search in plain English?',
faqTips1A:
- 'Type what you want in plain English, something like "2-bed under £525k, 45 minutes to work, quiet, good broadband", and it will set up the relevant filters in one go. Tweak any of them manually afterwards.',
+ 'Type something like "freehold 3-bed under £550k, 45 minutes to work, quiet, good broadband", and the AI filter will set up the matching filters it understands. It will also tell you when a request, such as garden size, is not available as a structured filter.',
faqTips2Q: 'Can I save a search and come back to it later?',
faqTips2A:
'Hit the save button and everything is captured: your filters, zoom level, and which data layer you’re colouring by. Pick up exactly where you left off or share the link with your partner.',
faqTips3Q: 'Can I export the data I’m looking at?',
faqTips3A:
- 'Use the export button to download the currently filtered properties as a spreadsheet. The export respects all your active filters, so you get exactly the data you want.',
+ 'Use the export button to download the currently filtered properties as a spreadsheet. The export respects your active filters, so you can take a clean shortlist into portals, viewings, spreadsheets, or conversations with someone buying with you.',
},
// ── Account Page ───────────────────────────────────
diff --git a/frontend/src/i18n/locales/fr.ts b/frontend/src/i18n/locales/fr.ts
index 6fa5075..45e2b02 100644
--- a/frontend/src/i18n/locales/fr.ts
+++ b/frontend/src/i18n/locales/fr.ts
@@ -102,6 +102,9 @@ const fr: Translations = {
registerAndUpgrade: 'S’inscrire et passer à la version complète',
alreadyHaveAccount: 'Vous avez déjà un compte ? Connectez-vous',
continueWithDemo: 'Continuer avec la démo',
+ backToSharedArea: 'Retour à la zone partagée',
+ sharedAreaDescription:
+ 'Vous consultez une zone partagée. Pour explorer au-delà, obtenez un accès à vie à chaque code postal, chaque filtre et chaque quartier d’Angleterre.',
checkoutFailed: 'Échec du paiement',
},
@@ -347,51 +350,48 @@ const fr: Translations = {
exploreTheMap: 'Trouver mes codes postaux',
seeTheDifference: 'Voir comment ça marche',
showcaseHeader: 'Aperçu du produit',
- showcaseContext: 'Recherche d’acheteur en Angleterre',
- showcaseStep1Tab: 'Décrire',
- showcaseStep1Title: 'Décrivez la vie que vous voulez',
+ showcaseContext: 'Comment fonctionne Perfect Postcode',
+ showcaseStep1Tab: 'Filtrer',
+ showcaseStep1Title: 'Combinez des filtres absents des portails',
showcaseStep1Body:
- 'Utilisez le langage naturel ou les filtres pour transformer des critères complexes en une seule recherche.',
- showcaseStep1Prompt:
- '2 chambres sous £525k, 45 min jusqu’au travail, rues calmes, bonnes écoles',
- showcaseStep1Chip1: '<= £525k',
- showcaseStep1Chip2: '2+ chambres',
- showcaseStep1Chip3: '45 min de trajet',
- showcaseStep1Chip4: 'Faible bruit routier',
- showcaseStep2Tab: 'Découvrir',
- showcaseStep2Title: 'Révélez des lieux que vous n’aviez pas envisagés',
+ 'Choisissez ce qui compte vraiment — au-delà du prix et des chambres. Là où vos filtres se croisent, voilà votre vraie sélection.',
+ showcaseStep1Chip1: 'Rues calmes',
+ showcaseStep1Chip2: 'Écoles primaires bien notées',
+ showcaseStep1Chip3: 'Moins de £500k',
+ showcaseStep1VennCenter: 'Codes postaux qui cochent les trois',
+ showcaseStep2Tab: 'Comparer',
+ showcaseStep2Title: 'Recoupé avec 13M de ventes et les dernières études publiques',
showcaseStep2Body:
- 'La carte met en évidence les codes postaux compatibles, y compris hors de votre sélection habituelle.',
- showcaseStep2Metric: '47 codes postaux compatibles',
- showcaseStep2Note: 'au-delà de la sélection évidente',
- showcaseKnownAreas: 'Zones connues',
- showcaseNewMatches: 'Nouvelles correspondances',
- showcaseKnownAreaStatus: 'peu de résultats',
- showcaseStep3Tab: 'Vérifier',
- showcaseStep3Title: 'Comprenez pourquoi chaque code postal correspond',
+ 'Chaque hexagone en Angleterre est noté selon vos filtres. La carte s’éclaire là où les correspondances se regroupent.',
+ showcaseStep2Region: 'Grand Londres',
+ showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
+ showcaseStep2ClustersLabel: 'Grappes correspondantes',
+ showcaseStep3Tab: 'Inspecter',
+ showcaseStep3Title: 'Lisez chaque quartier dans un seul panneau',
showcaseStep3Body:
- 'Ouvrez un résultat et vérifiez les preuves avant de réserver votre week-end pour des visites.',
- showcaseStep3Postcode: 'Exemple de code postal',
- showcaseStep3Area: 'Penge',
- showcaseStep3Code: 'SE20',
- showcaseStep3Score: 'Très bon ajustement',
- showcaseEvidence1: '42 min de trajet',
- showcaseEvidence2: 'Bruit routier plus faible',
- showcaseEvidence3: 'Bonnes écoles primaires',
- showcaseEvidence4: 'Prix vendus dans le budget',
- showcaseStep4Tab: 'Comparer',
- showcaseStep4Title: 'Comparez les compromis avant les visites',
+ 'Ouvrez n’importe quel hexagone : tendances de prix vendus, criminalité, démographie et écoles, sans jongler entre les onglets.',
+ showcaseStep3HeaderArea: 'Penge · SE20',
+ showcaseStep3HeaderFit: 'Très bon · 7/8',
+ showcaseStep3Stat1Label: 'Tendance des prix vendus',
+ showcaseStep3Stat2Label: 'Criminalité',
+ showcaseStep3Stat2Value: 'Sous la moyenne du borough',
+ showcaseStep3Stat3Label: 'Âge médian',
+ showcaseStep3Stat4Label: 'Débit internet',
+ showcaseStep3Stat4Value: '1 Gbps disponible',
+ showcaseStep3Stat5Label: 'Écoles primaires',
+ showcaseStep3Stat5Value: '3 « outstanding » à moins d’un mile',
+ showcaseStep4Tab: 'Exporter',
+ showcaseStep4Title: 'Sauvegardez votre sélection et lancez-vous',
showcaseStep4Body:
- 'Sélectionnez les zones selon ce que vous gagnez et perdez, pas seulement selon leur réputation.',
- showcaseCompare1: 'Penge : liaisons londoniennes, plus d’espace',
- showcaseCompare2: 'Totterdown : rues accessibles à pied à Bristol',
- showcaseCompare3: 'Walkley : logements plus grands, bon rapport qualité-prix',
- showcaseMapLabel: 'Codes postaux compatibles',
- showcaseSaveLabel: 'Sélection prête',
- showcaseMatchPenge: 'budget compatible à Londres',
- showcaseMatchAbbeyWood: 'Elizabeth line + espaces verts',
- showcaseMatchTotterdown: 'Bristol accessible à pied',
- showcaseMatchWalkley: 'espace + écoles à Sheffield',
+ 'En un clic, chaque code postal correspondant — avec ses preuves — s’exporte vers un tableur. Vous savez maintenant exactement où chercher.',
+ showcaseStep4FileName: 'perfect-postcode-shortlist.xlsx',
+ showcaseStep4ExportLabel: 'Exporter vers Excel',
+ showcaseStep4ColPostcode: 'Code postal',
+ showcaseStep4ColScore: 'Ajust.',
+ showcaseStep4ColCommute: 'Trajet',
+ showcaseStep4ColPrice: 'Prix médian',
+ showcaseStep4Conclusion:
+ 'Fini les suppositions — visitez des biens dans des lieux déjà validés.',
statProperties: 'ventes historiques',
statFilters: 'filtres combinables',
statEvery: 'Chaque',
@@ -410,19 +410,6 @@ const fr: Translations = {
streetCard2Title: 'Voyez les compromis avant les visites',
streetCard2Body:
'Comparez prix, surface, trajet, sécurité, écoles, débit internet, bruit et énergie avant de passer vos week-ends à courir les visites.',
- howToUseIt: 'Comment l’utiliser',
- howStep1Title: 'Décrivez la vie dont vous avez besoin',
- howStep1Desc:
- 'Budget, trajet, type de bien, écoles, sécurité, surface et essentiels du quotidien.',
- howStep2Title: 'Révélez les codes postaux compatibles',
- howStep2Desc:
- 'La carte met en évidence les lieux qui passent vos filtres, y compris les zones moins connues.',
- howStep3Title: 'Vérifiez les preuves',
- howStep3Desc:
- 'Consultez prix vendus, surface, DPE, bruit routier, débit internet, criminalité et écoles.',
- howStep4Title: 'Faites votre sélection avant les annonces',
- howStep4Desc:
- 'Arrivez sur Rightmove, Zoopla, chez les agents et aux visites avec de meilleures zones de recherche.',
othersVs: 'Les autres vs',
checkMyPostcode: 'Portails d’annonces',
areaGuides: 'Rapports de code postal',
@@ -558,40 +545,41 @@ const fr: Translations = {
dsElectionUse:
'Résultats par candidat des élections générales britanniques de juillet 2024. Agrégés au niveau de la circonscription : participation électorale (%) et parts des voix par parti (%). Reliés aux propriétés via le code de circonscription parlementaire (pcon) du répertoire de codes postaux NSPL.',
// FAQ section titles
- faqFindingTitle: 'Trouver votre quartier',
- faqCommuteTitle: 'Trajet et déplacements',
- faqBudgetTitle: 'Budget et rapport qualité-prix',
+ faqFindingTitle: 'Stratégie de recherche',
+ faqCommuteTitle: 'Calcul des temps de trajet',
+ faqBudgetTitle: 'Prix estimés',
faqSafetyTitle: 'Sécurité et voisinage',
faqFamiliesTitle: 'Familles et écoles',
faqEnvironmentTitle: 'Environnement et qualité de vie',
+ faqDueDiligenceTitle: 'Périmètre et vérifications',
+ faqPrivacyTitle: 'Confidentialité et protection des données',
faqWhyTitle: 'Pourquoi Perfect Postcode',
- faqPricingTitle: 'Tarifs et accès',
+ faqPricingTitle: 'Accès',
faqTipsTitle: 'Astuces',
// FAQ items — Finding Your Area
- faqFinding1Q: 'Je ne sais même pas quelles zones regarder. Est-ce que ça peut m’aider ?',
+ faqFinding1Q: 'Où chercher quand les zones évidentes sont trop chères ?',
faqFinding1A:
- 'C’est exactement à ça que ça sert. Définissez vos filtres (budget, temps de trajet, faible criminalité, bonnes écoles) et la carte s’illumine pour montrer chaque zone qui coche toutes les cases. Fini de chercher « meilleures zones pour vivre près de Manchester » à minuit.',
+ 'Définissez le budget, le type de bien, la surface, le trajet, les écoles, la criminalité, le bruit, le débit internet, les parcs et vos autres critères indispensables. La carte retire les codes postaux qui échouent à ces tests, ce qui fait apparaître des zones moins évidentes avant même de chercher des annonces.',
faqFinding2Q: 'Je déménage dans un endroit que je ne connais pas du tout. Par où commencer ?',
faqFinding2A:
'Définissez vos filtres pour ce qui compte et la carte met instantanément en évidence les zones qui correspondent. Vous passez de « je ne connais pas une seule rue » à une sélection en quelques minutes.',
- faqFinding3Q: 'Comment trouver des zones qui cochent toutes mes cases en une seule fois ?',
+ faqFinding3Q: 'Que faire si ma recherche renvoie trop ou trop peu de zones ?',
faqFinding3A:
- 'Empilez plusieurs filtres (criminalité sous la moyenne, bonnes écoles, trajet de moins de 40 minutes) puis colorez la carte par prix pour repérer les zones au meilleur rapport qualité-prix. La carte se met à jour en temps réel quand vous bougez les curseurs.',
+ 'Commencez par vos limites fermes, puis colorez la carte selon un compromis comme le prix au m², le bruit routier, le score des écoles ou le temps de trajet. Si la carte devient trop restrictive, relâchez un curseur et voyez immédiatement quel compromis ouvre de nouvelles options.',
// FAQ items — Commute and Travel
- faqCommute1Q: 'Puis-je voir combien de temps durerait mon trajet depuis différentes zones ?',
+ faqCommute1Q: 'Comment les temps de trajet sont-ils calculés ?',
faqCommute1A:
- 'Définissez votre lieu de travail comme destination et nous colorons chaque code postal par temps de trajet, que ce soit en voiture, à vélo ou en transports en commun. Filtrez par votre trajet maximum et le reste disparaît.',
- faqCommute2Q: 'En quoi c’est mieux que Google Maps ?',
+ 'Les temps de trajet sont précalculés avec Conveyal R5, un moteur de routage utilisé pour l’analyse des transports. Pour chaque destination prise en charge, nous calculons les trajets vers les codes postaux atteignables sur le réseau de rues et de transports, puis stockons des fichiers de temps de trajet par code postal pour la voiture, le vélo, la marche et les transports publics. La carte peut ainsi filtrer beaucoup de codes postaux rapidement au lieu d’appeler une API itinéraire un par un.',
+ faqCommute2Q: 'Que faut-il savoir sur ces temps de trajet ?',
faqCommute2A:
- 'Google Maps vous montre un trajet à la fois. Nous colorons chaque code postal d’Angleterre par temps de trajet en une seule vue, pour que vous puissiez comparer des centaines de zones côte à côte au lieu de les chercher une par une.',
+ 'Les temps en transports publics utilisent une fenêtre de départ du matin, de 07:30 à 08:30. Par défaut, nous affichons la médiane, c’est-à-dire le résultat typique sur cette fenêtre ; l’option best-case utilise le 5e percentile pour un départ bien synchronisé. Ce sont des temps de comparaison modélisés, pas des données en direct sur les perturbations, le trafic ou les changements de quai.',
// FAQ items — Budget and Value
- faqBudget1Q: 'Comment trouver les zones où j’ai le plus d’espace pour mon argent ?',
+ faqBudget1Q: 'Comment fonctionne l’algorithme de prix actuel estimé ?',
faqBudget1A:
- 'Filtrez par prix au m² et vous verrez instantanément quels codes postaux offrent le plus d’espace par livre. Combinez avec le filtre de classement énergétique pour éviter les biens aux coûts de chauffage élevés.',
- faqBudget2Q:
- 'Comment m’assurer qu’une zone bon marché ne l’est pas pour de mauvaises raisons ?',
+ 'L’estimation propriétaire part du dernier prix de vente HM Land Registry. Elle l’ajuste à aujourd’hui avec un indice de ventes répétées appris à partir de biens vendus plusieurs fois, segmenté par secteur de code postal et type de bien. Les zones peu fournies sont rapprochées de modèles district, zone, national et hédonique, puis lissées spatialement. Le résultat est ensuite mélangé avec une estimation par plus proches voisins, à partir de biens similaires vendus récemment à proximité, du prix au m² ajusté et de la surface EPC.',
+ faqBudget2Q: 'Pourquoi utiliser le prix actuel estimé plutôt que le dernier prix vendu ?',
faqBudget2A:
- 'Superposez les scores de défaveur, les statistiques de criminalité, les notes des écoles et les débits internet à côté du prix. Si un code postal est abordable et obtient de bons scores sur tout ce qui compte, vous avez trouvé une vraie bonne affaire, pas juste un prix bas avec des compromis que vous n’avez pas encore repérés.',
+ 'Le dernier prix vendu peut dater de plusieurs années ou décennies, et les prix demandés ne couvrent que les biens en vente aujourd’hui. Le prix actuel estimé remet les anciennes ventes dans des conditions de marché plus actuelles, afin de comparer davantage de biens, calculer un prix estimé au m² et repérer les zones de valeur avant l’arrivée des annonces. C’est un outil de tri, pas une évaluation formelle.',
// FAQ items — Safety and Neighbourhood
faqSafety1Q: 'Comment vérifier si une zone est sûre avant d’y déménager ?',
faqSafety1A:
@@ -613,12 +601,30 @@ const fr: Translations = {
'Puis-je trouver des logements économes en énergie qui ne sont pas sur une route bruyante ?',
faqEnv1A:
'Filtrez par classement EPC (A à C), puis superposez les données de bruit routier pour exclure tout ce qui dépasse votre seuil. Colorez par l’un ou l’autre critère pour repérer les rues calmes et économes d’un coup d’œil.',
- faqEnv2Q: 'Est-ce que ça montre le risque d’inondation ou d’affaissement ?',
+ faqEnv2Q: 'Affichez-vous le risque d’inondation, d’affaissement ou de survey ?',
faqEnv2A:
- 'Nous incluons des données de stabilité du sol pour que vous puissiez vérifier les risques d’affaissement, de retrait-gonflement des argiles et d’autres aléas géologiques avant de vous engager. Excluez les zones à risque dès le départ.',
+ 'Pas sous forme de filtres en direct aujourd’hui. Nous affichons des données comme le bruit routier, l’EPC, l’âge de construction et certains indicateurs locaux, mais les recherches d’inondation, les titres, les problèmes structurels et la capacité de financement doivent toujours être vérifiés par les professionnels habituels.',
faqEnv3Q: 'Puis-je trouver des zones avec un bon débit internet qui soient aussi calmes ?',
faqEnv3A:
'Superposez le filtre de débit internet avec les données de bruit routier pour trouver des rues avec une bonne connectivité et peu de bruit. Colorez par l’un ou l’autre critère pour comparer les zones d’un coup d’œil.',
+ // FAQ items — Listing Portals and Due Diligence
+ faqDueDiligence1Q: 'Faut-il l’utiliser avant ou après Rightmove ?',
+ faqDueDiligence1A:
+ 'Utilisez Perfect Postcode avant et en parallèle des portails d’annonces. Rightmove, Zoopla et OnTheMarket restent utiles pour la disponibilité en temps réel, les photos, le contact avec l’agent, les visites et les alertes. Perfect Postcode sert à décider quels codes postaux valent la peine d’être recherchés.',
+ faqDueDiligence2Q: 'Puis-je filtrer par jardin, garage, agencement ou texte d’annonce ?',
+ faqDueDiligence2A:
+ 'Seulement lorsque l’information existe dans des données officielles structurées. Perfect Postcode peut filtrer la surface, le type de bien, le régime foncier, l’EPC, les prix de vente et les données locales. Les jardins, garages, orientation, agencements et formulations d’agent doivent encore être vérifiés dans l’annonce et lors de la visite.',
+ faqDueDiligence3Q:
+ 'Puis-je voir l’historique des baisses de prix ou la durée de mise en ligne ?',
+ faqDueDiligence3A:
+ 'Pas actuellement. Perfect Postcode s’appuie sur les prix de vente officiels, l’EPC, les codes postaux, les temps de trajet et les données de quartier plutôt que sur des flux d’annonces en direct. Vous pouvez tout de même utiliser la date de dernière transaction, l’historique des ventes, la valeur actuelle estimée et le prix au m² pour juger un prix demandé.',
+ faqDueDiligence4Q: 'Que dois-je encore vérifier avant de faire une offre ?',
+ faqDueDiligence4A:
+ 'Utilisez Perfect Postcode pour vérifier la zone et la valeur, puis contrôlez les détails de l’annonce, le régime foncier, les conditions de leasehold, les charges, l’historique d’urbanisme, le risque d’inondation, les titres, les exigences du prêteur et le survey via le processus professionnel habituel.',
+ // FAQ items — Privacy and Data Protection
+ faqPrivacy1Q: 'Stockez-vous des données personnelles me concernant ?',
+ faqPrivacy1A:
+ 'Nous ne stockons pas de données personnelles dans les jeux de données immobilières et de quartier. Ces données proviennent de sources officielles et publiques et servent à la recherche par code postal et par propriété. Si vous créez un compte, nous stockons uniquement ce qui est nécessaire au fonctionnement du service, comme votre adresse e-mail, votre statut de licence, votre préférence newsletter, vos recherches enregistrées, vos biens enregistrés et les identifiants de paiement traités par Stripe. Ces données de compte sont traitées conformément au UK GDPR et au Data Protection Act 2018.',
// FAQ items — Why Perfect Postcode
faqWhy1Q: 'J’utilise déjà Rightmove. Qu’est-ce que ça apporte de plus ?',
faqWhy1A:
@@ -634,9 +640,9 @@ const fr: Translations = {
'Est-ce que ça vaut vraiment le coup de payer pour un outil de recherche immobilière ?',
faqPricing1A:
'L’achat d’un logement est probablement le plus gros achat de votre vie. Repérer un seul signal d’alerte (une route bruyante, un mauvais débit, une criminalité en hausse) avant de vous engager pourrait vous épargner des années de regrets. Ça coûte moins qu’un plein d’essence.',
- faqPricing2Q: 'Est-ce un abonnement ?',
+ faqPricing2Q: 'Que signifie l’accès à vie ?',
faqPricing2A:
- 'Non. Paiement unique, à vous pour toujours. Utilisez-le intensivement pendant votre recherche, revenez quand vous êtes curieux d’une nouvelle zone, et c’est toujours là si vous déménagez à nouveau.',
+ 'L’accès à vie signifie qu’un paiement donne à votre compte un accès continu à la carte payante Perfect Postcode pendant la durée de vie du service. Ce n’est pas un abonnement mensuel ou annuel, et les mises à jour normales des données sont incluses. Vous pouvez l’utiliser pendant cette recherche, revenir plus tard et conserver l’accès si vous déménagez à nouveau.',
faqPricing3Q: 'Que puis-je faire avec la version gratuite ?',
faqPricing3A:
'Les utilisateurs gratuits peuvent explorer toutes les fonctionnalités dans la zone de démonstration (centre de Londres, approximativement zones 1 à 2). Pour accéder aux données du reste de l’Angleterre, il faut l’accès à vie.',
diff --git a/frontend/src/i18n/locales/hu.ts b/frontend/src/i18n/locales/hu.ts
index 93d94d2..c0d0fb2 100644
--- a/frontend/src/i18n/locales/hu.ts
+++ b/frontend/src/i18n/locales/hu.ts
@@ -102,6 +102,9 @@ const hu: Translations = {
registerAndUpgrade: 'Regisztráció és frissítés',
alreadyHaveAccount: 'Már van fiókod? Jelentkezz be',
continueWithDemo: 'Folytatás demóval',
+ backToSharedArea: 'Vissza a megosztott területre',
+ sharedAreaDescription:
+ 'Egy megosztott területet nézel. Ha tovább szeretnél felfedezni, szerezz élethosszig tartó hozzáférést Anglia minden irányítószámához, szűrőjéhez és környékéhez.',
checkoutFailed: 'A fizetés sikertelen',
},
@@ -340,50 +343,48 @@ const hu: Translations = {
exploreTheMap: 'Megfelelő irányítószámok keresése',
seeTheDifference: 'Így működik',
showcaseHeader: 'Termékbemutató',
- showcaseContext: 'Vevői keresés egész Angliában',
- showcaseStep1Tab: 'Leírás',
- showcaseStep1Title: 'Írd le, milyen életet szeretnél',
+ showcaseContext: 'Így működik a Perfect Postcode',
+ showcaseStep1Tab: 'Szűrés',
+ showcaseStep1Title: 'Olyan szűrőket kombinálj, amelyek a portálokon nincsenek is',
showcaseStep1Body:
- 'Természetes nyelvvel vagy szűrőkkel alakítsd a bonyolult vevői igényeket egy kereséssé.',
- showcaseStep1Prompt: '2 háló £525k alatt, 45 perc munkáig, csendes utcák, jó iskolák',
- showcaseStep1Chip1: '<= £525k',
- showcaseStep1Chip2: '2+ háló',
- showcaseStep1Chip3: '45 perc ingázás',
- showcaseStep1Chip4: 'Alacsony útzaj',
- showcaseStep2Tab: 'Felfedezés',
- showcaseStep2Title: 'Mutasd meg azokat a helyeket, amelyekre nem gondoltál',
+ 'Válaszd, ami tényleg számít — áron és hálószobaszámon túl. Ahol a szűrőid metszik egymást, az a valódi listád.',
+ showcaseStep1Chip1: 'Csendes utcák',
+ showcaseStep1Chip2: 'Kiváló általános iskolák',
+ showcaseStep1Chip3: '£500k alatt',
+ showcaseStep1VennCenter: 'Mindhárom feltételt teljesítő irányítószámok',
+ showcaseStep2Tab: 'Egyeztetés',
+ showcaseStep2Title: 'Összevetve 13M eladással és a legfrissebb állami tanulmányokkal',
showcaseStep2Body:
- 'A térkép kiemeli a megfelelő irányítószámokat, a megszokott listádon kívül is.',
- showcaseStep2Metric: '47 megfelelő irányítószám',
- showcaseStep2Note: 'a kézenfekvő listán túl',
- showcaseKnownAreas: 'Ismert területek',
- showcaseNewMatches: 'Új találatok',
- showcaseKnownAreaStatus: 'kevés találat',
- showcaseStep3Tab: 'Ellenőrzés',
- showcaseStep3Title: 'Értsd meg, miért illik egy irányítószám',
+ 'Anglia minden hexagonját pontozzuk a szűrőid alapján. A térkép ott világít, ahol a találatok csoportosulnak.',
+ showcaseStep2Region: 'Nagy-London',
+ showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
+ showcaseStep2ClustersLabel: 'Találati klaszterek',
+ showcaseStep3Tab: 'Vizsgálat',
+ showcaseStep3Title: 'Olvasd ki a környéket egyetlen panelben',
showcaseStep3Body:
- 'Nyiss meg egy találatot és ellenőrizd az adatokat, mielőtt egy hétvégét nézelődésre szánsz.',
- showcaseStep3Postcode: 'Irányítószám példa',
- showcaseStep3Area: 'Penge',
- showcaseStep3Code: 'SE20',
- showcaseStep3Score: 'Erős egyezés',
- showcaseEvidence1: '42 perc ingázás',
- showcaseEvidence2: 'Alacsonyabb útzaj',
- showcaseEvidence3: 'Jó általános iskolák',
- showcaseEvidence4: 'Eladási árak a kereten belül',
- showcaseStep4Tab: 'Összevetés',
- showcaseStep4Title: 'Hasonlítsd össze a kompromisszumokat megtekintés előtt',
+ 'Nyisd meg bármelyik hexagont, és a jobb panelen láthatod az ártrendet, bűnözést, demográfiát és iskolákat — fülek nélkül.',
+ showcaseStep3HeaderArea: 'Penge · SE20',
+ showcaseStep3HeaderFit: 'Erős egyezés · 7/8',
+ showcaseStep3Stat1Label: 'Eladási ár trend',
+ showcaseStep3Stat2Label: 'Bűnözési ráta',
+ showcaseStep3Stat2Value: 'Borough-átlag alatt',
+ showcaseStep3Stat3Label: 'Medián életkor',
+ showcaseStep3Stat4Label: 'Internet',
+ showcaseStep3Stat4Value: '1 Gbps elérhető',
+ showcaseStep3Stat5Label: 'Általános iskolák',
+ showcaseStep3Stat5Value: '3 „outstanding” 1 mérföldön belül',
+ showcaseStep4Tab: 'Exportálás',
+ showcaseStep4Title: 'Mentsd a listád és indulj',
showcaseStep4Body:
- 'A nyereségek és veszteségek alapján szűkíts, ne csak a környék híre alapján.',
- showcaseCompare1: 'Penge: londoni vasút, több tér',
- showcaseCompare2: 'Totterdown: gyalogos Bristol-utcák',
- showcaseCompare3: 'Walkley: nagyobb otthonok, jó érték',
- showcaseMapLabel: 'Megfelelő irányítószámok',
- showcaseSaveLabel: 'Lista kész',
- showcaseMatchPenge: 'London a kereten belül',
- showcaseMatchAbbeyWood: 'Elizabeth line + zöldterület',
- showcaseMatchTotterdown: 'Bristol gyalogosan élhető',
- showcaseMatchWalkley: 'Sheffield: tér + iskolák',
+ 'Egy kattintás, és minden találat — a bizonyítékaikkal együtt — táblázatba kerül. Most már pontosan tudod, hol kezdj keresni.',
+ showcaseStep4FileName: 'perfect-postcode-shortlist.xlsx',
+ showcaseStep4ExportLabel: 'Exportálás Excelbe',
+ showcaseStep4ColPostcode: 'Irányítószám',
+ showcaseStep4ColScore: 'Egyezés',
+ showcaseStep4ColCommute: 'Ingázás',
+ showcaseStep4ColPrice: 'Medián eladási ár',
+ showcaseStep4Conclusion:
+ 'Találgatás helyett indulj olyan helyekre, amelyek már átmentek a teszteden.',
statProperties: 'korábbi eladás',
statFilters: 'kombinálható szűrő',
statEvery: 'Minden',
@@ -402,18 +403,6 @@ const hu: Translations = {
streetCard2Title: 'Lásd a kompromisszumokat megtekintés előtt',
streetCard2Body:
'Hasonlítsd össze az árat, méretet, ingázást, biztonságot, iskolákat, internetet, zajt és energiahatékonyságot, mielőtt hétvégéket töltesz megtekintésekkel.',
- howToUseIt: 'Hogyan használd',
- howStep1Title: 'Írd le, milyen életre van szükséged',
- howStep1Desc:
- 'Költségvetés, ingázás, ingatlantípus, iskolák, biztonság, tér és napi szükségletek.',
- howStep2Title: 'Fedd fel a megfelelő irányítószámokat',
- howStep2Desc: 'A térkép kiemeli azokat a helyeket, amelyek átmennek a szűrőiden.',
- howStep3Title: 'Ellenőrizd a bizonyítékokat',
- howStep3Desc:
- 'Nézd meg az eladási árakat, alapterületet, EPC-t, zajt, internetet, bűnözést és iskolákat.',
- howStep4Title: 'Szűkíts listát hirdetések előtt',
- howStep4Desc:
- 'Menj Rightmove-ra, Zooplára, ügynökökhöz és megtekintésekre jobb keresési területekkel.',
othersVs: 'Mások vs.',
checkMyPostcode: 'Ingatlanportálok',
areaGuides: 'Irányítószám-riportok',
@@ -550,40 +539,41 @@ const hu: Translations = {
dsElectionUse:
'Jelöltszintű eredmények a 2024. júliusi brit parlamenti választásról. Választókerületi szintre aggregálva: részvételi arány (%) és pártszavazatarányok (%). Az ingatlanokhoz az NSPL irányítószám-keresőből származó parlamenti választókerületi kódon (pcon) keresztül csatolva.',
// FAQ section titles
- faqFindingTitle: 'Területed megtalálása',
- faqCommuteTitle: 'Ingazás és utazás',
- faqBudgetTitle: 'Költségvetés és érték',
+ faqFindingTitle: 'Keresési stratégia',
+ faqCommuteTitle: 'Utazási idő számítása',
+ faqBudgetTitle: 'Becsült árak',
faqSafetyTitle: 'Biztonság és szomszédság',
faqFamiliesTitle: 'Családok és iskolák',
faqEnvironmentTitle: 'Környezet és életminőség',
+ faqDueDiligenceTitle: 'Korlátok és ellenőrzések',
+ faqPrivacyTitle: 'Adatvédelem',
faqWhyTitle: 'Miért a Perfect Postcode',
- faqPricingTitle: 'Árak és hozzáférés',
+ faqPricingTitle: 'Hozzáférés',
faqTipsTitle: 'Tippek és trükkök',
// FAQ items — Finding Your Area
- faqFinding1Q: 'Fogalmam sincs, hol keressek. Segít ebben?',
+ faqFinding1Q: 'Hol keressek, ha a nyilvánvaló környékek túl drágák?',
faqFinding1A:
- 'Pont erre való. Állítsd be a szűrőket (költségvetés, ingazási idő, alacsony bűnözés, jó iskolák), és a térkép kivilgítja minden területet, ami megfelel. Nem kell többé éjfélkor guglizni, hogy “hol a legjobb lakni Manchester közelében”.',
+ 'Állítsd be a költségvetést, ingatlantípust, alapterületet, ingázást, iskolákat, bűnözést, zajt, szélessávot, parkokat és más kötelező feltételeket. A térkép eltávolítja azokat az irányítószámokat, amelyek nem felelnek meg, így a kevésbé nyilvánvaló területek is láthatóvá válnak, mielőtt hirdetéseket keresnél.',
faqFinding2Q: 'Olyan helyre költözöm, ahol még soha nem voltam. Hogyan kezdjem?',
faqFinding2A:
'Állítsd be a szűrőket arra, ami fontos, és a térkép azonnal kiemeli a megfelelő területeket. Az “egyetlen utcát sem ismerek”-ből percek alatt rövid listához jutsz.',
- faqFinding3Q:
- 'Hogyan találom meg azokat a területeket, amelyek minden feltételemnek megfelelnek?',
+ faqFinding3Q: 'Mit tegyek, ha a keresés túl sok vagy túl kevés területet ad?',
faqFinding3A:
- 'Kombinálj több szűrőt (bűnözés átlag alatt, jó iskolák, ingazás 40 perc alatt), majd színezd a térképet ár szerint a legjobb értékű területek megtalálásához. A térkép élőben frissül, ahogy a csúszákat húzod.',
+ 'Kezdd a kemény korlátokkal, majd színezd a térképet egy kompromisszum szerint, például négyzetméterár, közúti zaj, iskolai pontszám vagy utazási idő alapján. Ha túl szűk a találat, lazíts egy csúszkán, és azonnal látod, melyik kompromisszum nyit új lehetőségeket.',
// FAQ items — Commute and Travel
- faqCommute1Q: 'Láthatom, mennyi lenne az ingazásom különböző területekről?',
+ faqCommute1Q: 'Hogyan számítjátok az utazási időket?',
faqCommute1A:
- 'Állítsd be a munkahelyed úticélként, és minden irányítószámot kiszínezünk utazási idő szerint, legyen az autó, kerékpár vagy tömegközlekedés. Szűrj a maximális ingazási időre, és a többi eltűnik.',
- faqCommute2Q: 'Miért jobb ez, mint a Google Maps?',
+ 'Az utazási idők előre vannak kiszámítva a Conveyal R5 közlekedési elemző útvonaltervezővel. Minden támogatott célhoz elérhető irányítószámokra számítunk útvonalakat az utcai és tömegközlekedési hálózaton, majd ritka irányítószám-utazási idő fájlokat tárolunk autóra, kerékpárra, gyaloglásra és tömegközlekedésre. Így a térkép sok irányítószámot gyorsan tud szűrni, nem kell egyesével útvonal API-t hívni.',
+ faqCommute2Q: 'Mit kell tudni az utazási idő számokról?',
faqCommute2A:
- 'A Google Maps egyszerre egy utazást mutat. Mi Anglia összes irányítószámát kiszínezzük ingazási idő szerint egyszerre, így száznál több területet hasonlíthatsz össze egyetlen pillantással, ahelyett hogy egyenként keres-gétnéd őket.',
+ 'A tömegközlekedési idők a reggeli 07:30-08:30 indulási ablakot használják. Az alapértelmezett érték a medián, vagyis a tipikus eredmény ebben az ablakban; a best-case kapcsoló az 5. percentilist használja jól időzített indulásokhoz. Ezek modellezett összehasonlító idők, nem élő fennakadási, forgalmi vagy peronváltási előrejelzések.',
// FAQ items — Budget and Value
- faqBudget1Q: 'Hogyan találom meg, hol kapom a legtöbb helyet a pénzememért?',
+ faqBudget1Q: 'Hogyan működik a becsült jelenlegi ár algoritmusa?',
faqBudget1A:
- 'Szűrj négyzetméterár szerint, és azonnal látod, mely irányítószámok adják a legtöbb helyet fontonként. Párosítsd az energetikai minősítés szűrővel, hogy elkerüld a magas fűtési költségű ingatlanokat.',
- faqBudget2Q: 'Hogyan bizonyosodjak meg, hogy egy olcsó terület nem ok nélkül olcsó?',
+ 'A saját becslés a legutóbbi HM Land Registry eladási árból indul. Ezt egy ismételt eladásokból tanult index igazítja a jelenhez, irányítószám-szektor és ingatlantípus szerint. A kevés adattal rendelkező területek district, area, országos és hedonikus tartalékmodellek felé vannak húzva, majd térben simítva. Végül az eredmény keveredik közeli, frissen eladott, hasonló típusú ingatlanok legközelebbi szomszéd becslésével, korrigált négyzetméterár és EPC alapterület alapján.',
+ faqBudget2Q: 'Miért használjam a becsült jelenlegi árat a legutóbbi eladási ár helyett?',
faqBudget2A:
- 'Rétegezd rá a deprivációs pontokat, bűnözési statisztikákat, iskolai minősítéseket és szélessáv-sebességeket az ár mellé. Ha egy irányítószám megfizethető és minden fontos szempont szerint jól teljesít, valódi értéket találtál, nem csak alacsony árat észrevétlen kompromisszumokkal.',
+ 'A legutóbbi eladási ár akár évekkel vagy évtizedekkel korábbi lehet, az aktuális irányárak pedig csak a ma hirdetett ingatlanokat fedik le. A becsült jelenlegi ár a régi eladásokat közelebb hozza a mai piachoz, így több ingatlant hasonlíthatsz össze, becsült négyzetméterárat számíthatsz, és jó értékű területeket találhatsz még a hirdetések előtt. Ez szűrési becslés, nem hivatalos értékbecslés.',
// FAQ items — Safety and Neighbourhood
faqSafety1Q: 'Hogyan ellenőrizhetem, biztonságos-e egy terület, mielőtt odaköltözöm?',
faqSafety1A:
@@ -603,12 +593,30 @@ const hu: Translations = {
faqEnv1Q: 'Találhatok energiahatékony otthonokat, amelyek nincsenek zajos úton?',
faqEnv1A:
'Szűrj EPC minősítés szerint (A-C), majd rétegezd rá a közúti zajadatokat, hogy kiszűrd a küszöbértéked feletti területeket. Színezd bármelyik jellemző szerint, hogy egy pillantással észrevedd a csendes, hatékony utcákat.',
- faqEnv2Q: 'Mutatja az árvíz- vagy süllyedeskockázatot?',
+ faqEnv2Q: 'Mutat árvíz-, süllyedés- vagy felmérési kockázatot?',
faqEnv2A:
- 'Tartalmazunk talajstabilitási adatokat, így ellenőrizheted a süllyeedést, agyagtalan zsugorodás-duzzadást és egyéb geológiai veszélyeket, mielőtt elköteleznéd magad egy ingatlan mellett. Szűrd ki a kockázatos területeket korán.',
+ 'Jelenleg nem élő szűrőként. Mutatunk például közúti zajt, EPC-t, építési kort és helyi környezeti mutatókat, de az árvízkeresést, tulajdoni lapot, szerkezeti problémákat és hitelezhetőséget továbbra is ügyvéddel, hitelezővel és felmérővel kell ellenőrizni.',
faqEnv3Q: 'Találhatok területeket gyors internettel, amelyek tényleg csendesek?',
faqEnv3A:
'Rétegezd a szélessáv-sebesség szűrőt a közúti zajadatokkal, hogy megtaláld a kitűnő kapcsolattal és alacsony forgalmi zajjal rendelkező utcákat. Színezd bármelyik mérőszám szerint a területek összehasonlításához.',
+ // FAQ items — Listing Portals and Due Diligence
+ faqDueDiligence1Q: 'Rightmove előtt vagy után használjam?',
+ faqDueDiligence1A:
+ 'Használd a Perfect Postcode-ot a hirdetési portálok előtt és mellett. A Rightmove, Zoopla és OnTheMarket továbbra is az aktuális elérhetőség, fotók, ügynöki kapcsolat, megtekintések és értesítések helye. A Perfect Postcode abban segít, hogy mely irányítószámokat érdemes egyáltalán keresni.',
+ faqDueDiligence2Q: 'Szűrhetek kertre, garázsra, alaprajzra vagy hirdetésszövegre?',
+ faqDueDiligence2A:
+ 'Csak akkor, ha az információ strukturált hivatalos adatban elérhető. A Perfect Postcode tud szűrni alapterületre, ingatlantípusra, tulajdonformára, EPC-re, eladási árakra és helyi adatokra. A kertet, garázst, tájolást, szobaelrendezést és ügynöki megfogalmazást továbbra is a hirdetésben és a megtekintésen kell ellenőrizni.',
+ faqDueDiligence3Q:
+ 'Láthatom az árcsökkentések történetét vagy hogy mióta van fent egy hirdetés?',
+ faqDueDiligence3A:
+ 'Jelenleg nem. A Perfect Postcode hivatalos eladási árakra, EPC-re, irányítószám-, utazási idő- és környékadatokra épül, nem élő hirdetésfolyamokra. A legutóbbi tranzakció dátumát, eladási előzményeket, becsült aktuális értéket és négyzetméterárat viszont használhatod az irányár megítéléséhez.',
+ faqDueDiligence4Q: 'Mit kell még ellenőriznem ajánlattétel előtt?',
+ faqDueDiligence4A:
+ 'A Perfect Postcode-dal ellenőrizd a környéket és az értéket, majd a szokásos szakmai folyamatban vizsgáld meg a hirdetés részleteit, tulajdonformát, leasehold feltételeket, service charge-ot, tervezési előzményeket, árvízkockázatot, tulajdoni kérdéseket, hitelezői feltételeket és felmérési eredményeket.',
+ // FAQ items — Privacy and Data Protection
+ faqPrivacy1Q: 'Tároltok rólam személyes adatokat?',
+ faqPrivacy1A:
+ 'Az ingatlan- és környékadatok között nem tárolunk személyes felhasználói adatokat. Ezek az adatkészletek hivatalos és nyilvános forrásokból készülnek, irányítószám- és ingatlankutatáshoz. Ha fiókot hozol létre, csak a szolgáltatás működtetéséhez szükséges adatokat tároljuk, például az e-mail címet, licencállapotot, hírlevél-beállítást, mentett kereséseket, mentett ingatlanokat és a Stripe-on keresztül kezelt fizetési azonosítókat. Ezeket a fiókadatokat a UK GDPR és a Data Protection Act 2018 szerint kezeljük.',
// FAQ items — Why Perfect Postcode
faqWhy1Q: 'Már használom a Rightmove-ot. Mit ad ez hozzá?',
faqWhy1A:
@@ -623,9 +631,9 @@ const hu: Translations = {
faqPricing1Q: 'Tényleg megéri fizetni egy ingatlan-kereső eszközért?',
faqPricing1A:
'Egy lakásvásárlás valószínűleg a legnagyobb vásárlásod lesz. Egyetlen figyelmeztető jel felismerése (zajos út, gyenge internet, növekvő bűnözés) elköteleződés előtt éveknűi megbánást takaríthat meg. Ez kevesebbe kerül, mint egy tank benzin.',
- faqPricing2Q: 'Ez előfizetés?',
+ faqPricing2Q: 'Mit jelent az élethosszig tartó hozzáférés?',
faqPricing2A:
- 'Nem. Egyszeri fizetés, örökre a tied. Használd intenzíven a keresés során, gyere vissza bármikor, ha kíváncsi vagy egy új területre, és még mindig ott van, ha újra költözöl.',
+ 'Az élethosszig tartó hozzáférés azt jelenti, hogy egy fizetéssel a fiókod folyamatos hozzáférést kap a fizetős Perfect Postcode térképhez a szolgáltatás élettartamára. Ez nem havi vagy éves előfizetés, és a szokásos adatfrissítések benne vannak. Használhatod a mostani kereséshez, később visszatérhetsz, és akkor is hozzáférsz, ha újra költözöl.',
faqPricing3Q: 'Mit érhetek el az ingyenes szinten?',
faqPricing3A:
'Az ingyenes felhasználók a demó területen (Belső-London, megközelítőleg az 1-2. zóna) fedezhetik fel az összes funkciót. Anglia többi részének adataihoz élethosszig tartó hozzáférés szükséges.',
diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts
index 4d47bd5..e01d602 100644
--- a/frontend/src/i18n/locales/zh.ts
+++ b/frontend/src/i18n/locales/zh.ts
@@ -100,6 +100,9 @@ const zh: Translations = {
registerAndUpgrade: '注册并升级',
alreadyHaveAccount: '已有账户?请登录',
continueWithDemo: '继续使用演示版',
+ backToSharedArea: '返回共享区域',
+ sharedAreaDescription:
+ '您正在查看一个共享区域。要在此之外进行探索,请获取对英格兰每个邮政编码、每个筛选器和每个社区的终身访问权限。',
checkoutFailed: '结账失败',
},
@@ -335,46 +338,45 @@ const zh: Translations = {
exploreTheMap: '找到匹配的邮编',
seeTheDifference: '查看使用方式',
showcaseHeader: '产品展示',
- showcaseContext: '英格兰买家搜索示例',
- showcaseStep1Tab: '描述',
- showcaseStep1Title: '描述您想要的生活',
- showcaseStep1Body: '用自然语言或筛选条件,把复杂的买房需求变成一次搜索。',
- showcaseStep1Prompt: '2房,£525k以内,45分钟到工作地点,安静街道,好学校',
- showcaseStep1Chip1: '<= £525k',
- showcaseStep1Chip2: '2+卧室',
- showcaseStep1Chip3: '45分钟通勤',
- showcaseStep1Chip4: '低道路噪音',
- showcaseStep2Tab: '发现',
- showcaseStep2Title: '发现您没有考虑过的地方',
- showcaseStep2Body: '地图会点亮匹配的邮编,包括您原本候选范围之外的区域。',
- showcaseStep2Metric: '47个匹配邮编',
- showcaseStep2Note: '超出显而易见的候选范围',
- showcaseKnownAreas: '熟悉区域',
- showcaseNewMatches: '新匹配',
- showcaseKnownAreaStatus: '匹配较少',
+ showcaseContext: 'Perfect Postcode 的工作流程',
+ showcaseStep1Tab: '筛选',
+ showcaseStep1Title: '组合那些房源门户根本没有的筛选条件',
+ showcaseStep1Body:
+ '挑选真正重要的条件——而不只是价格和卧室数。多个筛选条件交集的地方,才是真正的候选名单。',
+ showcaseStep1Chip1: '安静街道',
+ showcaseStep1Chip2: '顶级小学',
+ showcaseStep1Chip3: '£500k 以内',
+ showcaseStep1VennCenter: '同时满足三项条件的邮编',
+ showcaseStep2Tab: '匹配',
+ showcaseStep2Title: '与1300万笔成交记录和最新政府研究比对',
+ showcaseStep2Body: '英格兰的每一个六边形都会按您的筛选条件打分。匹配集中的地方,地图就会亮起。',
+ showcaseStep2Region: '大伦敦',
+ showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
+ showcaseStep2ClustersLabel: '匹配集群',
showcaseStep3Tab: '检查',
- showcaseStep3Title: '了解每个邮编为什么匹配',
- showcaseStep3Body: '打开结果,在周末看房前先检查证据。',
- showcaseStep3Postcode: '邮编示例',
- showcaseStep3Area: 'Penge',
- showcaseStep3Code: 'SE20',
- showcaseStep3Score: '高度匹配',
- showcaseEvidence1: '42分钟通勤',
- showcaseEvidence2: '较低道路噪音',
- showcaseEvidence3: '不错的小学选择',
- showcaseEvidence4: '成交价符合预算',
- showcaseStep4Tab: '比较',
- showcaseStep4Title: '看房前比较取舍',
- showcaseStep4Body: '根据得到什么和放弃什么来筛选,而不是只看区域名声。',
- showcaseCompare1: 'Penge:伦敦铁路连接,空间更大',
- showcaseCompare2: 'Totterdown:布里斯托可步行街区',
- showcaseCompare3: 'Walkley:更大住房,更高性价比',
- showcaseMapLabel: '匹配邮编',
- showcaseSaveLabel: '候选名单已准备好',
- showcaseMatchPenge: '伦敦预算匹配',
- showcaseMatchAbbeyWood: 'Elizabeth line + 绿地',
- showcaseMatchTotterdown: '布里斯托步行便利',
- showcaseMatchWalkley: '谢菲尔德空间 + 学校',
+ showcaseStep3Title: '在一个面板里读懂每个社区',
+ showcaseStep3Body:
+ '打开任意六边形,右侧面板会展示成交价走势、犯罪率、人口结构和学校——无需在多个标签页之间来回切换。',
+ showcaseStep3HeaderArea: 'Penge · SE20',
+ showcaseStep3HeaderFit: '高度匹配 · 7/8',
+ showcaseStep3Stat1Label: '成交价走势',
+ showcaseStep3Stat2Label: '犯罪率',
+ showcaseStep3Stat2Value: '低于本区平均水平',
+ showcaseStep3Stat3Label: '中位年龄',
+ showcaseStep3Stat4Label: '宽带',
+ showcaseStep3Stat4Value: '可用 1 Gbps',
+ showcaseStep3Stat5Label: '小学',
+ showcaseStep3Stat5Value: '1英里内3所「outstanding」',
+ showcaseStep4Tab: '导出',
+ showcaseStep4Title: '保存名单,开始实地行动',
+ showcaseStep4Body: '一键将所有匹配邮编及其证据导入电子表格。现在您清楚地知道该从哪里开始。',
+ showcaseStep4FileName: 'perfect-postcode-shortlist.xlsx',
+ showcaseStep4ExportLabel: '导出到 Excel',
+ showcaseStep4ColPostcode: '邮编',
+ showcaseStep4ColScore: '匹配',
+ showcaseStep4ColCommute: '通勤',
+ showcaseStep4ColPrice: '成交中位价',
+ showcaseStep4Conclusion: '不再凭猜测——直接去看那些已经通过您测试的地方。',
statProperties: '历史成交记录',
statFilters: '可组合筛选条件',
statEvery: '覆盖',
@@ -393,15 +395,6 @@ const zh: Translations = {
streetCard2Title: '看房前先看清取舍',
streetCard2Body:
'在把周末花在看房之前,先比较价格、空间、通勤、安全、学校、宽带、噪音和能源评级。',
- howToUseIt: '使用方法',
- howStep1Title: '描述您需要的生活',
- howStep1Desc: '预算、通勤、房产类型、学校、安全、空间和日常生活设施。',
- howStep2Title: '显示匹配的邮编',
- howStep2Desc: '地图会高亮通过筛选的地方,包括不熟悉的区域。',
- howStep3Title: '查看证据',
- howStep3Desc: '查看成交价、建筑面积、EPC、道路噪音、宽带、犯罪率和学校。',
- howStep4Title: '先筛区域,再看房源',
- howStep4Desc: '带着更好的搜索区域去 Rightmove、Zoopla、中介和看房。',
othersVs: '其他平台 vs',
checkMyPostcode: '房源门户',
areaGuides: '邮编报告',
@@ -529,39 +522,41 @@ const zh: Translations = {
dsElectionUse:
'2024年7月英国大选的候选人级别结果。聚合到选区级别:投票率(%)和各政党得票率(%)。通过NSPL邮编查询中的议会选区代码(pcon)关联到房产。',
// FAQ section titles
- faqFindingTitle: '寻找理想区域',
- faqCommuteTitle: '通勤与出行',
- faqBudgetTitle: '预算与性价比',
+ faqFindingTitle: '搜索策略',
+ faqCommuteTitle: '出行时间算法',
+ faqBudgetTitle: '估计价格',
faqSafetyTitle: '安全与社区环境',
faqFamiliesTitle: '家庭与学校',
faqEnvironmentTitle: '环境与生活质量',
+ faqDueDiligenceTitle: '范围与尽职调查',
+ faqPrivacyTitle: '隐私与数据保护',
faqWhyTitle: '为什么选择 Perfect Postcode',
- faqPricingTitle: '价格与访问权限',
+ faqPricingTitle: '访问权限',
faqTipsTitle: '使用技巧',
// FAQ items — Finding Your Area
- faqFinding1Q: '我完全不知道该看哪些区域,这个工具能帮到我吗?',
+ faqFinding1Q: '明显的区域太贵时,我应该去哪里找?',
faqFinding1A:
- '这正是它的用途。设置您的筛选条件(预算、通勤时间、低犯罪率、好学校),地图就会亮起来,显示所有符合条件的区域。不用再半夜搜索"曼彻斯特附近最好的居住区"了。',
+ '设置预算、房产类型、室内面积、通勤、学校、犯罪率、噪音、宽带、公园等硬性条件。地图会排除不符合这些条件的邮编,让容易被忽略的区域在您开始看房源之前先浮现出来。',
faqFinding2Q: '我要搬到一个从未去过的地方,该从何开始?',
faqFinding2A:
'设置您关心的筛选条件,地图会立即高亮显示符合条件的区域。从"我一条街都不认识"到得出候选名单,只需几分钟。',
- faqFinding3Q: '如何找到同时满足我所有要求的区域?',
+ faqFinding3Q: '搜索结果太多或太少时该怎么办?',
faqFinding3A:
- '叠加多个筛选条件(犯罪率低于平均水平、好学校、通勤时间少于 40 分钟),然后按价格为地图着色,找出性价比最高的区域。拖动滑块时地图会实时更新,让您即时看到变化。',
+ '先设置硬性限制,再按一个取舍指标为地图着色,例如每平方米价格、道路噪音、学校评分或通勤时间。如果结果太少,放宽一个滑块,就能看到哪个妥协会打开更多选择。',
// FAQ items — Commute and Travel
- faqCommute1Q: '我能看到从不同区域到公司的实际通勤时间吗?',
+ faqCommute1Q: '出行时间是如何计算的?',
faqCommute1A:
- '设置您的工作地点作为目的地,我们会按通勤时间为每个邮编着色——无论是开车、骑车还是公共交通。筛选出您的最大通勤时间,其余区域就会消失。',
- faqCommute2Q: '这比查 Google Maps 好在哪里?',
+ '出行时间使用 Conveyal R5 预先计算,这是一个用于交通分析的路径引擎。对于每个支持的目的地,我们会沿街道和公共交通网络计算可到达邮编的路线,并为开车、骑车、步行和公共交通存储稀疏的邮编出行时间文件。这样地图可以快速筛选大量邮编,而不是逐个调用路线 API。',
+ faqCommute2Q: '这些出行时间数字有什么限制?',
faqCommute2A:
- 'Google Maps 一次只能查看一条路线。我们一次性将英格兰每个邮编按通勤时间着色,让您可以同时比较数百个区域,而不是逐个搜索。',
+ '公共交通时间使用早高峰 07:30 到 08:30 的出发窗口。默认值是中位数,代表该窗口内的典型行程;best-case 开关使用第 5 百分位,表示出发时间配合较好时的情况。这些是用于比较的模型时间,不是实时延误、交通状况或换乘站台预测。',
// FAQ items — Budget and Value
- faqBudget1Q: '如何找到单位面积性价比最高的区域?',
+ faqBudget1Q: '估计当前价格算法是如何工作的?',
faqBudget1A:
- '按每平方米价格筛选,您会立即看到哪些邮编的单位面积价格最低。搭配能源评级筛选,避免取暖费用过高的房产。',
- faqBudget2Q: '怎么确定一个便宜的区域不是因为有问题才便宜?',
+ '这个专有估算从 HM Land Registry 的最近成交价开始。它使用从多次成交房产中学习出的重复销售指数,将价格调整到当前市场,并按邮编分区和房产类型分层。数据较少的区域会向 district、area、全国和享乐模型回退,并进行空间平滑。最后,结果会与附近近期成交、同类型房产的最近邻估算混合,使用调整后的每平方米价格和 EPC 室内面积。',
+ faqBudget2Q: '为什么要用估计当前价格,而不是最近成交价?',
faqBudget2A:
- '将贫困指数、犯罪统计、学校评级和宽带速度叠加在价格旁边查看。如果一个邮编价格实惠且在各项重要指标上表现良好,那您就找到了真正的高性价比——而不是隐藏着您还没发现的问题的低价。',
+ '最近成交价可能是几年甚至几十年前的价格,而实时挂牌价只覆盖今天正在出售的房源。估计当前价格把旧成交放到更接近当前市场的尺度上,方便比较更多房产、计算估计每平方米价格,并在房源出现前发现可能有价值的区域。它是筛选估算,不是正式估值。',
// FAQ items — Safety and Neighbourhood
faqSafety1Q: '搬家前如何查看一个区域是否安全?',
faqSafety1A:
@@ -580,12 +575,29 @@ const zh: Translations = {
faqEnv1Q: '能找到不在嘈杂马路旁的节能住宅吗?',
faqEnv1A:
'按 EPC 评级(A 至 C)筛选,然后叠加道路噪音数据,排除超过您阈值的区域。按任一指标为地图着色,一目了然地找到安静且节能的街道。',
- faqEnv2Q: '有洪水或地基沉降风险数据吗?',
+ faqEnv2Q: '是否显示洪水、地基沉降或验房风险?',
faqEnv2A:
- '我们包含地基稳定性数据,让您在购房前检查沉降、膨胀收缩黏土和其他地质风险。尽早排除高风险区域。',
+ '目前不作为实时筛选项提供。我们会显示道路噪音、EPC、建造年代和本地环境指标等数据,但洪水查询、产权问题、结构问题和贷款适配性仍需要通过律师、贷款机构和专业验房流程确认。',
faqEnv3Q: '能找到宽带速度快又安静的区域吗?',
faqEnv3A:
'将宽带速度筛选与道路噪音数据叠加,找到连接速度快且交通噪音低的街道。按任一指标着色,一目了然地比较各区域。',
+ // FAQ items — Listing Portals and Due Diligence
+ faqDueDiligence1Q: '应该在查看 Rightmove 前还是之后使用?',
+ faqDueDiligence1A:
+ 'Perfect Postcode 适合在房源平台之前和同时使用。Rightmove、Zoopla 和 OnTheMarket 仍然用于查看实时房源、照片、中介联系方式、预约看房和提醒。Perfect Postcode 帮助您先判断哪些邮编值得搜索。',
+ faqDueDiligence2Q: '可以按花园、车库、户型或房源描述筛选吗?',
+ faqDueDiligence2A:
+ '只有当这些信息存在于结构化官方数据中时才可以。Perfect Postcode 可以按面积、房产类型、产权类型、EPC、成交价和本地数据筛选。花园、车库、朝向、户型和中介描述仍需要在房源页面和看房时核实。',
+ faqDueDiligence3Q: '可以看到降价历史或房源上线多久了吗?',
+ faqDueDiligence3A:
+ '目前不支持。Perfect Postcode 基于官方成交价、EPC、邮编、通勤时间和社区数据,而不是实时房源信息流。您仍可以用最近成交日期、成交历史、估计当前价值和每平方米价格来判断挂牌价是否偏高。',
+ faqDueDiligence4Q: '出价前还需要核实什么?',
+ faqDueDiligence4A:
+ '可以先用 Perfect Postcode 检查区域和价值,再通过常规专业流程核实实时房源细节、产权类型、租赁年限、服务费、规划历史、洪水风险、产权问题、贷款要求和验房结果。',
+ // FAQ items — Privacy and Data Protection
+ faqPrivacy1Q: '你们会存储关于我的个人数据吗?',
+ faqPrivacy1A:
+ '我们不会在房产和社区数据集中存储用户个人数据。这些数据集来自官方和公开来源,用于邮编和房产研究。如果您创建账户,我们只会存储运行服务所需的信息,例如邮箱地址、许可状态、新闻邮件偏好、已保存的搜索、已保存的房产,以及通过 Stripe 处理的付款标识符。我们会根据 UK GDPR 和 Data Protection Act 2018 处理这些账户数据。',
// FAQ items — Why Perfect Postcode
faqWhy1Q: '我已经在用 Rightmove 了,这个工具有什么额外价值?',
faqWhy1A:
@@ -600,9 +612,9 @@ const zh: Translations = {
faqPricing1Q: '花钱买一个找房工具真的值得吗?',
faqPricing1A:
'买房可能是您一生中最大的一笔支出。在做决定之前发现一个问题(嘈杂的马路、差劲的宽带、上升的犯罪率)就可能让您避免多年的后悔。而这个工具的费用还不到一箱油钱。',
- faqPricing2Q: '这是订阅制吗?',
+ faqPricing2Q: '终身访问是什么意思?',
faqPricing2A:
- '不是。一次性付款,永久使用。在找房期间密集使用,对新区域好奇时随时回来看,将来再搬家时它依然在。',
+ '终身访问指一次付款后,您的账户可在 Perfect Postcode 服务存续期间持续访问付费地图。它不是月度或年度订阅,并包含正常的数据更新。您可以在本次找房期间使用,之后再回来查看;如果将来再次搬家,也仍然保留访问权限。',
faqPricing3Q: '免费版能用哪些功能?',
faqPricing3A:
'免费用户可以在演示区域(伦敦市中心,大约 1 至 2 区)内探索所有功能。要访问英格兰其他地区的数据,需要获取终身访问权限。',
diff --git a/frontend/src/lib/url-state.ts b/frontend/src/lib/url-state.ts
index 59f0153..bfb93f0 100644
--- a/frontend/src/lib/url-state.ts
+++ b/frontend/src/lib/url-state.ts
@@ -70,10 +70,18 @@ export function parseUrlState(): {
tab?: 'properties' | 'area';
travelTime?: TravelTimeInitial;
postcode?: string;
+ share?: string;
} {
const params = new URLSearchParams(window.location.search);
const result: ReturnType = {};
+ // Share-link code: grants bbox-scoped access to the area the link references
+ // even for unlicensed users. The backend looks the code up against PocketBase.
+ const share = params.get('share');
+ if (share && /^[a-z0-9]{1,20}$/i.test(share)) {
+ result.share = share;
+ }
+
// View state: separate lat/lon/zoom params
const lat = params.get('lat');
const lon = params.get('lon');
@@ -146,10 +154,15 @@ export function stateToParams(
features: FeatureMeta[],
selectedPOICategories: Set,
rightPaneTab: 'properties' | 'area',
- travelTimeEntries?: TravelTimeEntry[]
+ travelTimeEntries?: TravelTimeEntry[],
+ share?: string
): URLSearchParams {
const params = new URLSearchParams();
+ if (share) {
+ params.set('share', share);
+ }
+
if (viewState) {
params.set('lat', viewState.latitude.toFixed(4));
params.set('lon', viewState.longitude.toFixed(4));
diff --git a/pipeline/transform/postcode_boundaries/voronoi.py b/pipeline/transform/postcode_boundaries/voronoi.py
index 7911ae4..cdff159 100644
--- a/pipeline/transform/postcode_boundaries/voronoi.py
+++ b/pipeline/transform/postcode_boundaries/voronoi.py
@@ -1,8 +1,7 @@
from collections import defaultdict
import numpy as np
-from scipy.spatial import Voronoi
-from scipy.spatial.qhull import QhullError
+from scipy.spatial import QhullError, Voronoi
from shapely import make_valid
from shapely.geometry import MultiPolygon, Polygon
from shapely.ops import unary_union
@@ -24,12 +23,15 @@ def compute_voronoi_regions(
# Deduplicate points, keeping one per (location, postcode) pair.
# Multiple postcodes at the same coordinate each get their own point,
# jittered by a tiny offset (0.01m) so Voronoi can distinguish them.
+ # Coords are rounded to mm precision for stable hashing — UPRN inputs are
+ # already integer metres, but the float64 cast can introduce ULP noise.
+ GOLDEN_ANGLE = np.pi * (3.0 - np.sqrt(5.0))
seen: dict[tuple[float, float, str], bool] = {}
unique_pts = []
unique_pcs = []
coord_counts: dict[tuple[float, float], int] = defaultdict(int)
for i in range(len(points)):
- coord = (points[i, 0], points[i, 1])
+ coord = (round(float(points[i, 0]), 3), round(float(points[i, 1]), 3))
key = (coord[0], coord[1], postcodes[i])
if key not in seen:
seen[key] = True
@@ -38,11 +40,10 @@ def compute_voronoi_regions(
if jitter_idx == 0:
unique_pts.append(points[i].copy())
else:
- # Tiny jitter so Voronoi sees distinct points (0.01m per step)
+ # Golden-angle spacing distributes any number of jittered
+ # points evenly around (and outward from) the original coord.
jittered = points[i].copy()
- angle = (
- 2 * np.pi * jitter_idx / max(coord_counts[coord], jitter_idx + 1)
- )
+ angle = jitter_idx * GOLDEN_ANGLE
jittered[0] += 0.01 * np.cos(angle)
jittered[1] += 0.01 * np.sin(angle)
unique_pts.append(jittered)
diff --git a/server-rs/logs/server.log.2026-05-04 b/server-rs/logs/server.log.2026-05-04
new file mode 100644
index 0000000..42aa26f
--- /dev/null
+++ b/server-rs/logs/server.log.2026-05-04
@@ -0,0 +1,1620 @@
+2026-05-04T16:24:26.361386Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:24:26.361534Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:24:26.361545Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:24:26.536642Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:24:26.536654Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:24:29.416013Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:24:29.416046Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:24:32.703052Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:24:32.703062Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:24:32.828025Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:24:33.156275Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:24:34.291666Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:24:35.567759Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:24:36.731373Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:24:44.067059Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:24:44.067224Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:24:44.067239Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:24:44.132872Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:24:44.132883Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:24:46.752832Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:24:46.752925Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:24:51.431716Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:24:51.431726Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:24:51.555919Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:24:51.929914Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:24:53.386992Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:24:54.755992Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:24:55.968130Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:24:58.228125Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:24:58.228135Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:24:59.203922Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T16:25:04.927897Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T16:25:08.105335Z INFO property_map_server::data::property: Data loading complete
+2026-05-04T16:25:09.830771Z INFO property_map_server: Allocator trim label="property data load" trimmed=true rss_before_mib=12855.6 rss_after_mib=3403.5 released_mib=9452.2
+2026-05-04T16:25:09.830783Z INFO property_map_server: Property data loaded rows=14525100 features=69 enums=6
+2026-05-04T16:25:09.830786Z INFO property_map_server: Building spatial grid index (0.01° cells)
+2026-05-04T16:25:09.942635Z INFO property_map_server: Precomputing H3 cells at resolution 12
+2026-05-04T16:25:09.942645Z INFO property_map_server::data::property: Precomputing H3 cells at resolution 12
+2026-05-04T16:25:10.306827Z INFO property_map_server::data::property: H3 precomputation complete (14525100 cells)
+2026-05-04T16:25:10.306857Z INFO property_map_server: Loading POI data from /app/data/filtered_uk_pois.parquet
+2026-05-04T16:25:10.306864Z INFO property_map_server::data::poi: Loading POI data from "/app/data/filtered_uk_pois.parquet"...
+2026-05-04T16:25:10.369598Z INFO property_map_server::data::poi: Loaded 567534 POIs
+2026-05-04T16:25:10.513535Z INFO property_map_server::data::poi: POI string columns interned category_unique=94 group_unique=11 emoji_unique=71
+2026-05-04T16:25:10.514657Z INFO property_map_server::data::poi: POI data loading complete.
+2026-05-04T16:25:10.560531Z INFO property_map_server: Allocator trim label="poi data load" trimmed=true rss_before_mib=3810.0 rss_after_mib=3621.0 released_mib=189.0
+2026-05-04T16:25:10.560541Z INFO property_map_server: POI data loaded pois=567534
+2026-05-04T16:25:10.560543Z INFO property_map_server: Building POI spatial grid index
+2026-05-04T16:25:10.567362Z INFO property_map_server: Loading place data from /app/data/places.parquet
+2026-05-04T16:25:10.567374Z INFO property_map_server::data::places: Loading place data from "/app/data/places.parquet"...
+2026-05-04T16:25:10.569093Z INFO property_map_server::data::places: Loaded 3474 places
+2026-05-04T16:25:10.570039Z INFO property_map_server::data::places: Place data loaded places=3474 types=2 with_population=71 with_city=3392
+2026-05-04T16:25:10.573398Z INFO property_map_server: Allocator trim label="place data load" trimmed=true rss_before_mib=3630.1 rss_after_mib=3625.7 released_mib=4.4
+2026-05-04T16:25:10.573403Z INFO property_map_server: Place data loaded places=3474
+2026-05-04T16:25:10.573411Z INFO property_map_server: Loading postcode boundaries from /app/data/postcode_boundaries
+2026-05-04T16:25:10.573415Z INFO property_map_server::data::postcodes: Loading postcode boundaries from "/app/data/postcode_boundaries"
+2026-05-04T16:25:10.584080Z INFO property_map_server::data::postcodes: Found GeoJSON files to process files=2361
+2026-05-04T16:25:18.723063Z INFO property_map_server::data::postcodes: Postcode boundary data ready postcodes=1490140
+2026-05-04T16:25:19.054258Z INFO property_map_server: Allocator trim label="postcode boundary load" trimmed=true rss_before_mib=10946.3 rss_after_mib=10753.6 released_mib=192.8
+2026-05-04T16:25:19.054270Z INFO property_map_server: Postcode boundaries loaded postcodes=1490140
+2026-05-04T16:25:19.195126Z INFO property_map_server::data::postcodes: Outcode data derived from postcodes outcodes=2361
+2026-05-04T16:25:19.195176Z INFO property_map_server: Loading PMTiles from /app/data/uk.pmtiles
+2026-05-04T16:25:19.212588Z INFO property_map_server: PMTiles loaded successfully
+2026-05-04T16:25:19.249528Z INFO property_map_server: No --dist provided; static serving and OG injection disabled
+2026-05-04T16:25:19.314387Z INFO property_map_server: Screenshot service configured: http://screenshot:8002
+2026-05-04T16:25:19.314534Z INFO property_map_server: Precomputed features response groups=8
+2026-05-04T16:25:19.314548Z INFO property_map_server: PocketBase configured: http://pocketbase:8090
+2026-05-04T16:25:19.420784Z INFO property_map_server::pocketbase: PocketBase users collection already has all required fields
+2026-05-04T16:25:19.449243Z INFO property_map_server::pocketbase: PocketBase collection 'saved_searches' API rules updated
+2026-05-04T16:25:19.465332Z INFO property_map_server::pocketbase: PocketBase collection 'saved_properties' API rules updated
+2026-05-04T16:25:23.979357Z INFO property_map_server::pocketbase: PocketBase meta.appURL set to https://perfect-postcodes.co.uk/pb
+2026-05-04T16:25:24.002744Z INFO property_map_server::pocketbase: PocketBase OAuth configured on users collection
+2026-05-04T16:25:24.002796Z INFO property_map_server: Gemini configured (model: gemini-3-flash-preview)
+2026-05-04T16:25:24.002816Z INFO property_map_server: Loading travel time data from /app/data/travel-times
+2026-05-04T16:25:24.067846Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="bicycle" destinations=2753
+2026-05-04T16:25:24.094429Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="walking" destinations=2753
+2026-05-04T16:25:24.164916Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="car" destinations=2753
+2026-05-04T16:25:24.195787Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="transit" destinations=2752
+2026-05-04T16:25:24.195823Z INFO property_map_server: Travel time store loaded modes=4
+2026-05-04T16:25:24.195890Z INFO property_map_server: Precomputed AI filters system prompt
+2026-05-04T16:25:59.854933Z INFO property_map_server: All memory pages locked (mlockall)
+2026-05-04T16:25:59.854973Z INFO property_map_server: Server listening on 0.0.0.0:8001
+2026-05-04T16:33:12.504278Z INFO property_map_server::routes::pois: GET /api/pois results=337 candidates=34206 categories=1 categories_raw="Bakery" ms=1.5
+2026-05-04T16:33:12.507287Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=501590 parallel=true cells_before_filter=43 cells_after_filter=34 truncated=false bounds=51.4639,-0.2078,51.5523,0.0016 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=4.3 json_ms=0.0 total_ms=4.3
+2026-05-04T16:33:12.753975Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=501590 filters=2 travel=0 total=8128 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" ms=2.3
+2026-05-04T16:33:15.076379Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=156212 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4941,-0.1494,51.5403,-0.0399 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.7 json_ms=0.0 total_ms=0.7
+2026-05-04T16:33:15.081953Z INFO property_map_server::routes::pois: GET /api/pois results=146 candidates=15316 categories=1 categories_raw="Bakery" ms=0.3
+2026-05-04T16:33:15.777094Z INFO property_map_server::routes::pois: GET /api/pois results=1234 candidates=191594 categories=1 categories_raw="Bakery" ms=2.3
+2026-05-04T16:33:15.813170Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=6 rows=5259222 parallel=true cells_before_filter=48 cells_after_filter=48 truncated=false bounds=50.6262,-1.8129,51.8797,1.1415 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=0 travel_entries=0 grid_ms=0.1 agg_ms=38.3 json_ms=0.0 total_ms=38.4
+2026-05-04T16:33:16.051536Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5259222 filters=2 travel=0 total=245108 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" ms=27.8
+2026-05-04T16:33:17.789858Z INFO property_map_server::routes::pois: GET /api/pois results=3 candidates=173 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:33:17.789972Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=7000 parallel=false cells_before_filter=0 cells_after_filter=0 truncated=false bounds=52.4593,0.8156,52.5646,1.0709 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.0 total_ms=0.1
+2026-05-04T16:33:17.996574Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=7000 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" ms=0.1
+2026-05-04T16:33:18.491913Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=13 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:33:18.491954Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=2208 parallel=false cells_before_filter=0 cells_after_filter=0 truncated=false bounds=52.4951,0.9091,52.5324,0.9996 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.0 json_ms=0.0 total_ms=0.0
+2026-05-04T16:33:18.755504Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=2208 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" ms=0.0
+2026-05-04T16:33:19.464638Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5813 parallel=false cells_before_filter=0 cells_after_filter=0 truncated=false bounds=52.4761,0.8660,52.5482,1.0407 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.0 total_ms=0.1
+2026-05-04T16:33:19.465914Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=106 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:33:19.713721Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5813 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" ms=0.1
+2026-05-04T16:33:21.541755Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5813 parallel=false cells_before_filter=212 cells_after_filter=200 truncated=false bounds=52.4761,0.8660,52.5482,1.0407 filters=1 filters_raw="Outstanding primary schools within 5km:0:13" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T16:33:21.689938Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5813 parallel=false cells_before_filter=0 cells_after_filter=0 truncated=false bounds=52.4761,0.8660,52.5482,1.0407 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:4:4" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.0 total_ms=0.1
+2026-05-04T16:33:21.935287Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5813 parallel=false cells_before_filter=212 cells_after_filter=200 truncated=false bounds=52.4761,0.8660,52.5482,1.0407 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.3 json_ms=0.2 total_ms=0.5
+2026-05-04T16:33:22.184166Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5813 filters=2 travel=0 total=5813 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:33:23.065248Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194162883ffff resolution=9 total_count=8 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:33:23.382213Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=100 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:33:23.382464Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=3843 parallel=false cells_before_filter=136 cells_after_filter=131 truncated=false bounds=52.4761,0.8897,52.5482,1.0170 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T16:33:23.632327Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=3843 filters=2 travel=0 total=3843 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.0
+2026-05-04T16:33:24.723887Z INFO property_map_server::routes::screenshot: Fetching screenshot from: http://screenshot:8002/screenshot?og=1&lat=52.5122&lon=0.9534&zoom=13.1&school=primary%3Aoutstanding%3A5%3A0%3A13&school=secondary%3Aoutstanding%3A5%3A0%3A4&poi=Bakery
+2026-05-04T16:33:28.689144Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:28.689206Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:28.797267Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=106 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:33:29.148232Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5749 filters=2 travel=0 total=5749 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.0
+2026-05-04T16:33:31.157780Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:31.158900Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:32.275864Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:32.275869Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:32.654590Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:32.655162Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.6 json_ms=0.0 total_ms=0.6
+2026-05-04T16:33:32.655169Z INFO property_map_server::routes::pois: GET /api/pois results=136 candidates=14319 categories=1 categories_raw="Bakery" ms=0.6
+2026-05-04T16:33:32.656028Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:32.656467Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=4490 parallel=false cells_before_filter=139 cells_after_filter=126 truncated=false bounds=52.4892,0.8813,52.5352,1.0255 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T16:33:32.657565Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=92 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:33:32.853023Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:32.853024Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:32.908907Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.6
+2026-05-04T16:33:33.165458Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:33.165461Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:33.408861Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:33.408859Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:33.636864Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:33.636880Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:33.844608Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:33.844612Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:34.174004Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:34.175086Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:34.378600Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:34.378602Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:34.504438Z INFO property_map_server::routes::pois: GET /api/pois results=620 candidates=66807 categories=1 categories_raw="Bakery" ms=1.3
+2026-05-04T16:33:34.602799Z WARN property_map_server::routes::screenshot: Screenshot service returned 500 Internal Server Error: {"error":"Screenshot failed"}
+2026-05-04T16:33:34.602833Z ERROR tower_http::trace::on_failure: response failed classification=Status code: 502 Bad Gateway latency=9878 ms
+2026-05-04T16:33:34.756167Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=1555849 filters=2 travel=0 total=452550 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=8.5
+2026-05-04T16:33:35.982661Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.5 json_ms=0.0 total_ms=0.5
+2026-05-04T16:33:35.984926Z INFO property_map_server::routes::pois: GET /api/pois results=136 candidates=14319 categories=1 categories_raw="Bakery" ms=0.3
+2026-05-04T16:33:36.255875Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.4
+2026-05-04T16:33:39.615709Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:33:39.615713Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:33:39.807124Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=71850 parallel=true cells_before_filter=281 cells_after_filter=221 truncated=false bounds=51.5024,-0.1686,51.5276,-0.0914 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=4.0 json_ms=0.1 total_ms=4.2
+2026-05-04T16:33:40.495077Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=71850 parallel=true cells_before_filter=281 cells_after_filter=221 truncated=false bounds=51.5024,-0.1686,51.5276,-0.0914 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.5 json_ms=0.2 total_ms=3.7
+2026-05-04T16:34:07.509866Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:07.509946Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:07.611127Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:07.612193Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:07.889701Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.7 total_ms=2.7
+2026-05-04T16:34:14.334723Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:14.337390Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:14.491807Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:14.493124Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:14.778805Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.2 json_ms=0.6 total_ms=3.8
+2026-05-04T16:34:43.581458Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:43.588215Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:43.713295Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:43.714928Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:43.997860Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.5 total_ms=2.2
+2026-05-04T16:34:51.018981Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:51.018985Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:51.170017Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:34:51.172856Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:34:51.445786Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.4 total_ms=2.0
+2026-05-04T16:35:33.953632Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:35:33.954861Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:35:34.097014Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:35:34.098093Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:35:34.374003Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.5 total_ms=2.0
+2026-05-04T16:35:42.141838Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:35:42.143317Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:35:42.274342Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:35:42.274559Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:35:42.545901Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.4 total_ms=1.9
+2026-05-04T16:36:20.658389Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:36:20.658391Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:36:20.795952Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:36:20.797839Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:36:21.077586Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.5 total_ms=2.0
+2026-05-04T16:36:30.210679Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:36:30.210688Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:36:30.347013Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:36:30.348059Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:36:30.634397Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.4 total_ms=1.8
+2026-05-04T16:37:00.881004Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:37:00.881756Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:37:01.014400Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:37:01.015618Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:37:01.298842Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.5 total_ms=2.1
+2026-05-04T16:37:07.528356Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:37:07.534379Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:37:07.683099Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:37:07.684122Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:37:07.964419Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.4 json_ms=0.5 total_ms=2.0
+2026-05-04T16:41:53.484148Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:41:53.484270Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:41:53.625058Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:41:53.627511Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:41:53.941582Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.4 json_ms=0.5 total_ms=1.8
+2026-05-04T16:42:10.923902Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:42:10.924042Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:42:10.924049Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:42:11.094026Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:42:11.094035Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:42:13.827665Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:42:13.827705Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:42:17.729486Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:42:17.729497Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:42:17.849623Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:42:18.291464Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:42:19.592229Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:42:27.719470Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:42:27.719671Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:42:27.719681Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:42:27.793178Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:42:27.793189Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:42:30.659605Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:42:30.659645Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:42:50.820991Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:42:50.821208Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:42:50.821219Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:42:50.918750Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:42:50.918761Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:42:57.851045Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:42:57.851212Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:42:57.851222Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:42:57.931582Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:42:57.931593Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:43:00.770232Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:43:00.770272Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:43:04.255567Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:43:04.255577Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:43:04.391949Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:43:04.774580Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:43:06.026169Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:43:09.128196Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:43:12.906716Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:43:16.270759Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:43:16.270789Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:43:18.401462Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T16:43:27.431736Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T16:43:30.335068Z INFO property_map_server::data::property: Data loading complete
+2026-05-04T16:45:19.338545Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:45:19.338692Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:45:19.338704Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:45:19.412115Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:45:19.412126Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:45:22.338627Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:45:22.338667Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:45:25.112569Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:45:25.112579Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:45:25.239061Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:45:25.639028Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:45:26.973065Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:45:28.297017Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:45:30.086686Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:45:42.387619Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:45:42.387628Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:46:26.166388Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:46:26.166547Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:46:26.166557Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:46:26.235389Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:46:26.235399Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:46:29.258413Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:46:29.258459Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:46:31.897499Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:46:31.897509Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:46:32.031482Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:46:32.419698Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:46:33.763754Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:46:35.076058Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:46:36.278281Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:46:38.340164Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:46:38.340172Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:46:39.172699Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T16:46:44.579476Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T16:46:47.660894Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:46:47.661061Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:46:47.661070Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:46:47.743195Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:46:47.743207Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:47:00.841916Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:47:00.842064Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:47:00.842075Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:47:00.908914Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:47:00.908923Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:47:03.639664Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:47:03.639695Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:47:06.148292Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:47:06.148303Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:47:06.279025Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:47:06.652207Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:47:07.840677Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:47:09.177884Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:47:10.365612Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:47:12.564052Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:47:12.564060Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:47:13.560189Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T16:47:19.116752Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T16:51:59.629509Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:51:59.629660Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:51:59.629669Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:51:59.697083Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:51:59.697094Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:52:02.401421Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:52:02.401453Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:52:05.016345Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:52:05.016356Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:52:05.141380Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:52:05.500468Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:52:06.879667Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:52:08.239559Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:52:09.441595Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:52:11.513183Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:52:11.513191Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:52:12.358820Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T16:52:17.933075Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T16:52:21.489218Z INFO property_map_server::data::property: Data loading complete
+2026-05-04T16:52:22.907975Z INFO property_map_server: Allocator trim label="property data load" trimmed=true rss_before_mib=12322.4 rss_after_mib=3296.5 released_mib=9025.8
+2026-05-04T16:52:22.907987Z INFO property_map_server: Property data loaded rows=14525100 features=69 enums=6
+2026-05-04T16:52:22.907990Z INFO property_map_server: Building spatial grid index (0.01° cells)
+2026-05-04T16:52:23.018806Z INFO property_map_server: Precomputing H3 cells at resolution 12
+2026-05-04T16:52:23.018816Z INFO property_map_server::data::property: Precomputing H3 cells at resolution 12
+2026-05-04T16:52:23.436522Z INFO property_map_server::data::property: H3 precomputation complete (14525100 cells)
+2026-05-04T16:52:23.436556Z INFO property_map_server: Loading POI data from /app/data/filtered_uk_pois.parquet
+2026-05-04T16:52:23.436564Z INFO property_map_server::data::poi: Loading POI data from "/app/data/filtered_uk_pois.parquet"...
+2026-05-04T16:52:23.506644Z INFO property_map_server::data::poi: Loaded 567534 POIs
+2026-05-04T16:52:23.661450Z INFO property_map_server::data::poi: POI string columns interned category_unique=94 group_unique=11 emoji_unique=71
+2026-05-04T16:52:23.662610Z INFO property_map_server::data::poi: POI data loading complete.
+2026-05-04T16:52:23.710519Z INFO property_map_server: Allocator trim label="poi data load" trimmed=true rss_before_mib=3704.2 rss_after_mib=3513.9 released_mib=190.3
+2026-05-04T16:52:23.710531Z INFO property_map_server: POI data loaded pois=567534
+2026-05-04T16:52:23.710533Z INFO property_map_server: Building POI spatial grid index
+2026-05-04T16:52:23.717701Z INFO property_map_server: Loading place data from /app/data/places.parquet
+2026-05-04T16:52:23.717714Z INFO property_map_server::data::places: Loading place data from "/app/data/places.parquet"...
+2026-05-04T16:52:23.719392Z INFO property_map_server::data::places: Loaded 3474 places
+2026-05-04T16:52:23.720489Z INFO property_map_server::data::places: Place data loaded places=3474 types=2 with_population=71 with_city=3392
+2026-05-04T16:52:23.724484Z INFO property_map_server: Allocator trim label="place data load" trimmed=true rss_before_mib=3523.0 rss_after_mib=3518.6 released_mib=4.4
+2026-05-04T16:52:23.724490Z INFO property_map_server: Place data loaded places=3474
+2026-05-04T16:52:23.724499Z INFO property_map_server: Loading postcode boundaries from /app/data/postcode_boundaries
+2026-05-04T16:52:23.724510Z INFO property_map_server::data::postcodes: Loading postcode boundaries from "/app/data/postcode_boundaries"
+2026-05-04T16:52:23.725513Z INFO property_map_server::data::postcodes: Found GeoJSON files to process files=2361
+2026-05-04T16:52:32.438645Z INFO property_map_server::data::postcodes: Postcode boundary data ready postcodes=1490140
+2026-05-04T16:52:32.834664Z INFO property_map_server: Allocator trim label="postcode boundary load" trimmed=true rss_before_mib=10832.1 rss_after_mib=10645.7 released_mib=186.3
+2026-05-04T16:52:32.834676Z INFO property_map_server: Postcode boundaries loaded postcodes=1490140
+2026-05-04T16:52:32.988891Z INFO property_map_server::data::postcodes: Outcode data derived from postcodes outcodes=2361
+2026-05-04T16:52:32.988947Z INFO property_map_server: Loading PMTiles from /app/data/uk.pmtiles
+2026-05-04T16:52:33.010108Z INFO property_map_server: PMTiles loaded successfully
+2026-05-04T16:52:33.046813Z INFO property_map_server: No --dist provided; static serving and OG injection disabled
+2026-05-04T16:52:33.083599Z INFO property_map_server: Screenshot service configured: http://screenshot:8002
+2026-05-04T16:52:33.083763Z INFO property_map_server: Precomputed features response groups=8
+2026-05-04T16:52:33.083775Z INFO property_map_server: PocketBase configured: http://pocketbase:8090
+2026-05-04T16:52:33.158769Z INFO property_map_server::pocketbase: PocketBase users collection already has all required fields
+2026-05-04T16:52:33.166182Z INFO property_map_server::pocketbase: PocketBase collection 'saved_searches' API rules updated
+2026-05-04T16:52:33.169642Z INFO property_map_server::pocketbase: PocketBase collection 'saved_properties' API rules updated
+2026-05-04T16:52:34.891679Z INFO property_map_server::pocketbase: PocketBase meta.appURL set to https://perfect-postcodes.co.uk/pb
+2026-05-04T16:52:34.898075Z INFO property_map_server::pocketbase: PocketBase OAuth configured on users collection
+2026-05-04T16:52:34.898119Z INFO property_map_server: Gemini configured (model: gemini-3-flash-preview)
+2026-05-04T16:52:34.898137Z INFO property_map_server: Loading travel time data from /app/data/travel-times
+2026-05-04T16:52:34.899509Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="bicycle" destinations=2753
+2026-05-04T16:52:34.900985Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="walking" destinations=2753
+2026-05-04T16:52:34.902638Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="car" destinations=2753
+2026-05-04T16:52:34.903880Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="transit" destinations=2752
+2026-05-04T16:52:34.903900Z INFO property_map_server: Travel time store loaded modes=4
+2026-05-04T16:52:34.903948Z INFO property_map_server: Precomputed AI filters system prompt
+2026-05-04T16:52:43.879829Z INFO property_map_server: All memory pages locked (mlockall)
+2026-05-04T16:52:43.879872Z INFO property_map_server: Server listening on 0.0.0.0:8001
+2026-05-04T16:52:44.837043Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:52:44.838743Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:52:46.237131Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=8.9 json_ms=4.5 total_ms=13.4
+2026-05-04T16:52:50.343572Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:52:50.343601Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:52:50.654459Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=4.9 json_ms=0.6 total_ms=5.4
+2026-05-04T16:52:50.924418Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.9 json_ms=0.5 total_ms=2.4
+2026-05-04T16:52:55.327723Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=4.1 json_ms=0.5 total_ms=4.6
+2026-05-04T16:52:59.123773Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:52:59.124405Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:52:59.309646Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.9 json_ms=0.6 total_ms=2.4
+2026-05-04T16:52:59.856314Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:52:59.856333Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:53:06.621399Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:53:12.319647Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:53:12.320043Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:53:12.505843Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.5 total_ms=1.9
+2026-05-04T16:53:12.847079Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:53:12.847083Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:53:13.768136Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:53:20.023336Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.5 total_ms=2.2
+2026-05-04T16:53:31.973189Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.5 total_ms=2.1
+2026-05-04T16:53:36.438564Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.5 total_ms=2.2
+2026-05-04T16:53:40.877291Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.5 total_ms=2.2
+2026-05-04T16:53:45.260349Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.4 json_ms=0.5 total_ms=1.9
+2026-05-04T16:53:52.933614Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.5 json_ms=0.5 total_ms=3.0
+2026-05-04T16:53:57.242184Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=122687 parallel=true cells_before_filter=928 cells_after_filter=889 truncated=false bounds=51.3737,-0.0587,51.4622,0.0559 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.6 total_ms=2.2
+2026-05-04T16:54:11.694784Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:54:11.696755Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:54:11.886944Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=106 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:54:11.959114Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5749 parallel=false cells_before_filter=205 cells_after_filter=193 truncated=false bounds=52.4771,0.8684,52.5473,1.0384 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T16:54:12.166041Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5749 filters=2 travel=0 total=5749 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:54:54.425156Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:54:54.426587Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:54:54.663377Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.8 json_ms=0.4 total_ms=4.2
+2026-05-04T16:54:54.908059Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.5 json_ms=0.4 total_ms=3.9
+2026-05-04T16:55:30.573292Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:55:30.573295Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:55:30.830914Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.3 total_ms=2.3
+2026-05-04T16:56:20.574567Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T16:56:20.574750Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T16:56:20.574761Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T16:56:20.727321Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T16:56:20.727332Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T16:56:23.848405Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T16:56:23.848446Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T16:56:28.900388Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T16:56:28.900399Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T16:56:29.024977Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T16:56:29.390713Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T16:56:30.749182Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T16:56:32.160165Z INFO property_map_server::data::property: Building enum features
+2026-05-04T16:56:33.392343Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T16:56:35.651195Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T16:56:35.651205Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T16:56:36.629897Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T16:56:42.602979Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T16:56:45.386258Z INFO property_map_server::data::property: Data loading complete
+2026-05-04T16:56:46.870061Z INFO property_map_server: Allocator trim label="property data load" trimmed=true rss_before_mib=11393.9 rss_after_mib=3417.4 released_mib=7976.5
+2026-05-04T16:56:46.870073Z INFO property_map_server: Property data loaded rows=14525100 features=69 enums=6
+2026-05-04T16:56:46.870077Z INFO property_map_server: Building spatial grid index (0.01° cells)
+2026-05-04T16:56:46.984635Z INFO property_map_server: Precomputing H3 cells at resolution 12
+2026-05-04T16:56:46.984644Z INFO property_map_server::data::property: Precomputing H3 cells at resolution 12
+2026-05-04T16:56:47.414376Z INFO property_map_server::data::property: H3 precomputation complete (14525100 cells)
+2026-05-04T16:56:47.414403Z INFO property_map_server: Loading POI data from /app/data/filtered_uk_pois.parquet
+2026-05-04T16:56:47.414408Z INFO property_map_server::data::poi: Loading POI data from "/app/data/filtered_uk_pois.parquet"...
+2026-05-04T16:56:47.439121Z INFO property_map_server::data::poi: Loaded 567534 POIs
+2026-05-04T16:56:47.592475Z INFO property_map_server::data::poi: POI string columns interned category_unique=94 group_unique=11 emoji_unique=71
+2026-05-04T16:56:47.593681Z INFO property_map_server::data::poi: POI data loading complete.
+2026-05-04T16:56:47.644111Z INFO property_map_server: Allocator trim label="poi data load" trimmed=true rss_before_mib=3825.5 rss_after_mib=3635.0 released_mib=190.5
+2026-05-04T16:56:47.644123Z INFO property_map_server: POI data loaded pois=567534
+2026-05-04T16:56:47.644126Z INFO property_map_server: Building POI spatial grid index
+2026-05-04T16:56:47.652418Z INFO property_map_server: Loading place data from /app/data/places.parquet
+2026-05-04T16:56:47.652433Z INFO property_map_server::data::places: Loading place data from "/app/data/places.parquet"...
+2026-05-04T16:56:47.655243Z INFO property_map_server::data::places: Loaded 3474 places
+2026-05-04T16:56:47.656242Z INFO property_map_server::data::places: Place data loaded places=3474 types=2 with_population=71 with_city=3392
+2026-05-04T16:56:47.659926Z INFO property_map_server: Allocator trim label="place data load" trimmed=true rss_before_mib=3644.2 rss_after_mib=3639.7 released_mib=4.5
+2026-05-04T16:56:47.659933Z INFO property_map_server: Place data loaded places=3474
+2026-05-04T16:56:47.659941Z INFO property_map_server: Loading postcode boundaries from /app/data/postcode_boundaries
+2026-05-04T16:56:47.659946Z INFO property_map_server::data::postcodes: Loading postcode boundaries from "/app/data/postcode_boundaries"
+2026-05-04T16:56:47.676634Z INFO property_map_server::data::postcodes: Found GeoJSON files to process files=2361
+2026-05-04T16:56:56.616118Z INFO property_map_server::data::postcodes: Postcode boundary data ready postcodes=1490140
+2026-05-04T16:56:56.999856Z INFO property_map_server: Allocator trim label="postcode boundary load" trimmed=true rss_before_mib=10961.0 rss_after_mib=10765.9 released_mib=195.1
+2026-05-04T16:56:56.999867Z INFO property_map_server: Postcode boundaries loaded postcodes=1490140
+2026-05-04T16:56:57.159359Z INFO property_map_server::data::postcodes: Outcode data derived from postcodes outcodes=2361
+2026-05-04T16:56:57.159430Z INFO property_map_server: Loading PMTiles from /app/data/uk.pmtiles
+2026-05-04T16:56:57.168952Z INFO property_map_server: PMTiles loaded successfully
+2026-05-04T16:56:57.206010Z INFO property_map_server: No --dist provided; static serving and OG injection disabled
+2026-05-04T16:56:57.232621Z INFO property_map_server: Screenshot service configured: http://screenshot:8002
+2026-05-04T16:56:57.232814Z INFO property_map_server: Precomputed features response groups=8
+2026-05-04T16:56:57.232849Z INFO property_map_server: PocketBase configured: http://pocketbase:8090
+2026-05-04T16:56:57.281369Z INFO property_map_server::pocketbase: PocketBase users collection already has all required fields
+2026-05-04T16:56:57.285433Z INFO property_map_server::pocketbase: PocketBase collection 'saved_searches' API rules updated
+2026-05-04T16:56:57.288969Z INFO property_map_server::pocketbase: PocketBase collection 'saved_properties' API rules updated
+2026-05-04T16:56:58.609462Z INFO property_map_server::pocketbase: PocketBase meta.appURL set to https://perfect-postcodes.co.uk/pb
+2026-05-04T16:56:58.614311Z INFO property_map_server::pocketbase: PocketBase OAuth configured on users collection
+2026-05-04T16:56:58.614349Z INFO property_map_server: Gemini configured (model: gemini-3-flash-preview)
+2026-05-04T16:56:58.614367Z INFO property_map_server: Loading travel time data from /app/data/travel-times
+2026-05-04T16:56:58.654171Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="bicycle" destinations=2753
+2026-05-04T16:56:58.679772Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="walking" destinations=2753
+2026-05-04T16:56:58.709956Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="car" destinations=2753
+2026-05-04T16:56:58.743398Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="transit" destinations=2752
+2026-05-04T16:56:58.743442Z INFO property_map_server: Travel time store loaded modes=4
+2026-05-04T16:56:58.743498Z INFO property_map_server: Precomputed AI filters system prompt
+2026-05-04T16:57:02.850161Z INFO property_map_server: All memory pages locked (mlockall)
+2026-05-04T16:57:02.850207Z INFO property_map_server: Server listening on 0.0.0.0:8001
+2026-05-04T16:57:04.355091Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=106 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:57:04.356014Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5749 parallel=false cells_before_filter=205 cells_after_filter=193 truncated=false bounds=52.4771,0.8684,52.5473,1.0384 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.3 json_ms=0.2 total_ms=0.5
+2026-05-04T16:57:04.601910Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5749 filters=2 travel=0 total=5749 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:57:06.048394Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194162c6bffff resolution=9 total_count=1 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:57:06.367641Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=3843 parallel=false cells_before_filter=136 cells_after_filter=130 truncated=false bounds=52.4771,0.8914,52.5473,1.0154 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T16:57:06.369945Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=97 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:57:06.616929Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=3843 filters=2 travel=0 total=3843 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.0
+2026-05-04T16:57:07.424823Z INFO property_map_server::routes::screenshot: Fetching screenshot from: http://screenshot:8002/screenshot?og=1&share=pp3xxg72&lat=52.5122&lon=0.9534&zoom=13.1&school=primary%3Aoutstanding%3A5%3A0%3A13&school=secondary%3Aoutstanding%3A5%3A0%3A4&poi=Bakery
+2026-05-04T16:57:11.553390Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:11.558010Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:11.763671Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:11.763679Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:11.915058Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:11.919901Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:11.931486Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=6.2 json_ms=0.3 total_ms=6.5
+2026-05-04T16:57:12.096817Z INFO property_map_server::routes::pois: GET /api/pois results=2 candidates=106 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:57:12.171317Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=5749 parallel=false cells_before_filter=205 cells_after_filter=193 truncated=false bounds=52.4771,0.8684,52.5473,1.0384 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T16:57:12.358432Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:12.358437Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:12.411186Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=5749 filters=2 travel=0 total=5749 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:57:12.536798Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:12.536868Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:12.700634Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:12.700638Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:12.865329Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:12.865848Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:13.044744Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:13.044745Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:13.262950Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:13.262954Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:13.443061Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:13.443560Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:13.630643Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:13.631971Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:13.780658Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:13.780661Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:13.948593Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:13.948597Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:14.131284Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:14.131289Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:14.308283Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:14.308302Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:14.501404Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:14.501448Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:14.690626Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:14.690636Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:14.858729Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:14.860095Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:15.027207Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:15.027205Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:15.214232Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:15.214637Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:15.381513Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:15.381514Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:15.537921Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:15.541833Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:15.705519Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:15.705552Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:15.869023Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:15.869537Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:16.033918Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:16.033920Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:16.247673Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:16.248375Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:16.412004Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:16.412032Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:16.626881Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:16.626907Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:16.794209Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:16.794231Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:16.997566Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:16.997568Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:17.174350Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:17.174380Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:17.335021Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:17.335027Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:17.539926Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:17.539930Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:17.705442Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:17.705446Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:18.127037Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:18.127040Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:18.295345Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:18.295351Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:18.473546Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:18.473550Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:18.636387Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:18.637454Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:18.843085Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:18.843089Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:19.020688Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:19.020692Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:19.201992Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:19.201997Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:19.369243Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:19.369297Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:19.535715Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:19.535824Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:19.760089Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:19.761305Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:19.935717Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:19.935721Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:20.162450Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:20.162454Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:20.333244Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:20.333303Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:20.547095Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:20.547113Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:20.734211Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:20.734214Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:20.933985Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:20.935086Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:21.117872Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:21.118620Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:21.314798Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:21.314812Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:21.414208Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=0 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:57:21.414913Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=106 parallel=false cells_before_filter=17 cells_after_filter=17 truncated=false bounds=52.5012,0.9270,52.5245,0.9835 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.0 json_ms=0.0 total_ms=0.1
+2026-05-04T16:57:21.568965Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:21.569086Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:21.706044Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=106 filters=2 travel=0 total=106 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.0
+2026-05-04T16:57:21.756890Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:21.757039Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:21.955414Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:21.955448Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:22.147162Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:22.147165Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:22.330539Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:22.332673Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:22.426605Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=14 categories=1 categories_raw="Bakery" ms=0.0
+2026-05-04T16:57:22.426755Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=2226 parallel=false cells_before_filter=70 cells_after_filter=69 truncated=false bounds=52.4917,0.9019,52.5346,1.0058 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.1 total_ms=0.2
+2026-05-04T16:57:22.541861Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:22.541871Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:22.681029Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=2226 filters=2 travel=0 total=2226 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.0
+2026-05-04T16:57:22.741493Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:22.742137Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:22.936184Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:22.937320Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:23.113311Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:23.115082Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:23.316783Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:23.316849Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:23.508060Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:23.508083Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:23.704874Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:23.704878Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:23.887959Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:23.887962Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:24.104294Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=14 categories=2 categories_raw="Bakery,Airport" ms=0.0
+2026-05-04T16:57:24.117936Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:24.118035Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:24.306274Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:24.306279Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:24.504949Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:24.504987Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:24.681516Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:24.683038Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:24.878853Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:24.878857Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:25.074316Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:25.074329Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:25.300703Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:25.300731Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:25.491570Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:25.491616Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:25.582060Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=14 categories=3 categories_raw="Bakery,Airport,Aldi" ms=0.0
+2026-05-04T16:57:25.711228Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:25.711231Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:25.883944Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:25.883951Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:26.080336Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:26.080340Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:26.419818Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:26.419822Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:26.427398Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=14 categories=4 categories_raw="Bakery,Airport,Aldi,Asda" ms=0.0
+2026-05-04T16:57:26.623712Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:26.623719Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:26.976432Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:26.976605Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:27.158303Z INFO property_map_server::routes::pois: GET /api/pois results=0 candidates=14 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.0
+2026-05-04T16:57:27.165617Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:27.165649Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:27.519358Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:27.519367Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:27.712236Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:27.712251Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:28.079929Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:28.079940Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:28.261204Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:28.261360Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:28.450319Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:28.452104Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:28.610701Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:28.610706Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:28.787485Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:28.787523Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:28.836508Z INFO property_map_server::routes::pois: GET /api/pois results=9 candidates=469 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.1
+2026-05-04T16:57:28.837299Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=15604 parallel=false cells_before_filter=618 cells_after_filter=618 truncated=false bounds=52.4290,0.7821,52.5750,1.1357 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.6 json_ms=0.3 total_ms=0.9
+2026-05-04T16:57:28.961952Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:28.961954Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:29.114483Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=15604 filters=2 travel=0 total=15604 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.1
+2026-05-04T16:57:29.149020Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:29.150154Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:29.325989Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:29.326049Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:29.509513Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:29.509562Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:29.681383Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:29.681452Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:29.860032Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:29.860130Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:30.037351Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:30.037362Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:30.218280Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:30.219884Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:30.396337Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:30.396391Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:30.600189Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:30.600218Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:30.769945Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:30.769962Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:30.922902Z INFO property_map_server::routes::pois: GET /api/pois results=12 candidates=866 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.1
+2026-05-04T16:57:30.949401Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:30.949408Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:31.118825Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:31.118826Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:31.168572Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=31273 filters=2 travel=0 total=31273 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.2
+2026-05-04T16:57:31.304370Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:31.304375Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:31.470466Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:31.470477Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:31.654850Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:31.654851Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:31.830251Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:31.830253Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:32.025962Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:32.025964Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:32.187866Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:32.187874Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:32.363389Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:32.363395Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:32.526389Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:32.526388Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:32.708754Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:32.708756Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:32.874828Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:32.874835Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:33.066317Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:33.066344Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:33.178764Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.5 json_ms=0.0 total_ms=0.5
+2026-05-04T16:57:33.184576Z INFO property_map_server::routes::pois: GET /api/pois results=818 candidates=14319 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=1.1
+2026-05-04T16:57:33.231876Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:33.231880Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:33.415747Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:33.415752Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:33.428604Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.5
+2026-05-04T16:57:33.590144Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:33.590174Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:33.769332Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:33.769378Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:33.944883Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:33.944901Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:34.156932Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:34.157036Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:34.321339Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:34.321423Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:34.508651Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:34.508727Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:34.672554Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:34.672596Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:34.812145Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=107108 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4998,-0.1465,51.5383,-0.0553 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.8 json_ms=0.0 total_ms=0.8
+2026-05-04T16:57:34.813887Z INFO property_map_server::routes::pois: GET /api/pois results=870 candidates=13715 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.8
+2026-05-04T16:57:34.848347Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:34.849823Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:35.013624Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:35.013633Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:35.086005Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=107108 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.7
+2026-05-04T16:57:35.186931Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:35.187028Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:35.361580Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:35.361635Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:35.544543Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:35.544565Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:35.717843Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:35.717900Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:35.901422Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:35.901512Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:36.080739Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:36.080803Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:36.256927Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:36.256980Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:36.425042Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:36.425096Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:36.597991Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:36.598058Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:36.774872Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:36.774922Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:36.945925Z INFO property_map_server::routes::pois: GET /api/pois results=6519 candidates=55638 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=4.4
+2026-05-04T16:57:36.955770Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:36.955772Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:37.128544Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:37.128545Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:37.193684Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=1124084 filters=2 travel=0 total=210501 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=7.2
+2026-05-04T16:57:37.303108Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:37.303116Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:37.474117Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:37.474121Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:37.659956Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:37.660038Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:37.835019Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:37.835029Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.013537Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:38.014575Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.178135Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:38.178138Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.365886Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:38.365888Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.528940Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:38.528988Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.649036Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.5 json_ms=0.0 total_ms=0.5
+2026-05-04T16:57:38.651162Z INFO property_map_server::routes::pois: GET /api/pois results=818 candidates=14319 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.8
+2026-05-04T16:57:38.703757Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:38.703765Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.878318Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:38.878376Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:38.923539Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.4
+2026-05-04T16:57:39.077673Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:39.077857Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:39.391489Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:39.391528Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:39.574670Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:39.574675Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:39.744998Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:39.745109Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:39.921045Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:39.921052Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:40.094946Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:40.095013Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:40.271084Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:40.271102Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:40.442667Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:40.442720Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:40.615514Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:40.615515Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:40.781681Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:40.781694Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:40.958954Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:40.961294Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:41.146209Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:41.146218Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:41.174410Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:41.174416Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:41.335491Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:41.335496Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:41.380501Z INFO property_map_server::routes::pois: GET /api/pois results=818 candidates=14319 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.9
+2026-05-04T16:57:41.384727Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.5 json_ms=0.0 total_ms=0.5
+2026-05-04T16:57:41.505426Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:41.505550Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:41.632660Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.7
+2026-05-04T16:57:41.692939Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:41.694600Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:41.866758Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:41.866801Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:42.054415Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:42.054430Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:44.925653Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=67753 parallel=true cells_before_filter=0 cells_after_filter=0 truncated=false bounds=51.5462,-0.1779,51.5847,-0.0868 filters=2 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.4 json_ms=0.0 total_ms=0.4
+2026-05-04T16:57:44.925825Z INFO property_map_server::routes::pois: GET /api/pois results=544 candidates=4484 categories=10 categories_raw="Bakery,Airport,Aldi,Asda,Bus station,Bus stop,Ferry,Rail station,Taxi rank,Tube station" ms=0.6
+2026-05-04T16:57:45.171774Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=67753 filters=2 travel=0 total=0 filters_raw="Outstanding primary schools within 5km:0:13;;Outstanding secondary schools within 5km:0:4" ms=0.4
+2026-05-04T16:57:57.458132Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:57:57.459237Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:57:57.943610Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=5.4 json_ms=0.5 total_ms=5.9
+2026-05-04T16:58:28.777550Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T16:58:28.777658Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T16:58:29.127088Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.3 total_ms=1.9
+2026-05-04T16:58:29.288159Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.3 total_ms=1.8
+2026-05-04T20:30:19.557826Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T20:30:19.557989Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T20:30:19.557997Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T20:30:19.661100Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T20:30:19.661114Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T20:30:22.562738Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T20:30:22.562783Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T20:30:26.039464Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T20:30:26.039472Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T20:30:26.192620Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T20:30:26.565556Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T20:30:27.922455Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T20:30:29.213846Z INFO property_map_server::data::property: Building enum features
+2026-05-04T20:30:30.356475Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T20:30:32.289458Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T20:30:32.289466Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T20:30:33.124493Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T20:30:38.166699Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T20:30:40.831663Z INFO property_map_server::data::property: Data loading complete
+2026-05-04T20:30:42.537764Z INFO property_map_server: Allocator trim label="property data load" trimmed=true rss_before_mib=12145.1 rss_after_mib=3347.9 released_mib=8797.2
+2026-05-04T20:30:42.537774Z INFO property_map_server: Property data loaded rows=14525100 features=69 enums=6
+2026-05-04T20:30:42.537777Z INFO property_map_server: Building spatial grid index (0.01° cells)
+2026-05-04T20:30:42.639662Z INFO property_map_server: Precomputing H3 cells at resolution 12
+2026-05-04T20:30:42.639670Z INFO property_map_server::data::property: Precomputing H3 cells at resolution 12
+2026-05-04T20:30:42.983845Z INFO property_map_server::data::property: H3 precomputation complete (14525100 cells)
+2026-05-04T20:30:42.983892Z INFO property_map_server: Loading POI data from /app/data/filtered_uk_pois.parquet
+2026-05-04T20:30:42.983899Z INFO property_map_server::data::poi: Loading POI data from "/app/data/filtered_uk_pois.parquet"...
+2026-05-04T20:30:43.020359Z INFO property_map_server::data::poi: Loaded 567534 POIs
+2026-05-04T20:30:43.162023Z INFO property_map_server::data::poi: POI string columns interned category_unique=94 group_unique=11 emoji_unique=71
+2026-05-04T20:30:43.163139Z INFO property_map_server::data::poi: POI data loading complete.
+2026-05-04T20:30:43.208910Z INFO property_map_server: Allocator trim label="poi data load" trimmed=true rss_before_mib=3756.2 rss_after_mib=3565.4 released_mib=190.8
+2026-05-04T20:30:43.208921Z INFO property_map_server: POI data loaded pois=567534
+2026-05-04T20:30:43.208924Z INFO property_map_server: Building POI spatial grid index
+2026-05-04T20:30:43.215749Z INFO property_map_server: Loading place data from /app/data/places.parquet
+2026-05-04T20:30:43.215762Z INFO property_map_server::data::places: Loading place data from "/app/data/places.parquet"...
+2026-05-04T20:30:43.216707Z INFO property_map_server::data::places: Loaded 3474 places
+2026-05-04T20:30:43.217692Z INFO property_map_server::data::places: Place data loaded places=3474 types=2 with_population=71 with_city=3392
+2026-05-04T20:30:43.221077Z INFO property_map_server: Allocator trim label="place data load" trimmed=true rss_before_mib=3574.5 rss_after_mib=3570.1 released_mib=4.4
+2026-05-04T20:30:43.221082Z INFO property_map_server: Place data loaded places=3474
+2026-05-04T20:30:43.221088Z INFO property_map_server: Loading postcode boundaries from /app/data/postcode_boundaries
+2026-05-04T20:30:43.221092Z INFO property_map_server::data::postcodes: Loading postcode boundaries from "/app/data/postcode_boundaries"
+2026-05-04T20:30:43.222031Z INFO property_map_server::data::postcodes: Found GeoJSON files to process files=2361
+2026-05-04T20:30:51.654250Z INFO property_map_server::data::postcodes: Postcode boundary data ready postcodes=1490140
+2026-05-04T20:30:52.077729Z INFO property_map_server: Allocator trim label="postcode boundary load" trimmed=true rss_before_mib=10882.4 rss_after_mib=10688.5 released_mib=193.9
+2026-05-04T20:30:52.077742Z INFO property_map_server: Postcode boundaries loaded postcodes=1490140
+2026-05-04T20:30:52.220308Z INFO property_map_server::data::postcodes: Outcode data derived from postcodes outcodes=2361
+2026-05-04T20:30:52.220362Z INFO property_map_server: Loading PMTiles from /app/data/uk.pmtiles
+2026-05-04T20:30:52.273585Z INFO property_map_server: PMTiles loaded successfully
+2026-05-04T20:30:52.309238Z INFO property_map_server: No --dist provided; static serving and OG injection disabled
+2026-05-04T20:30:52.338585Z INFO property_map_server: Screenshot service configured: http://screenshot:8002
+2026-05-04T20:30:52.338730Z INFO property_map_server: Precomputed features response groups=8
+2026-05-04T20:30:52.338742Z INFO property_map_server: PocketBase configured: http://pocketbase:8090
+2026-05-04T20:30:52.419011Z INFO property_map_server::pocketbase: PocketBase users collection already has all required fields
+2026-05-04T20:30:52.424109Z INFO property_map_server::pocketbase: PocketBase collection 'saved_searches' API rules updated
+2026-05-04T20:30:52.427292Z INFO property_map_server::pocketbase: PocketBase collection 'saved_properties' API rules updated
+2026-05-04T20:30:52.513510Z INFO property_map_server::pocketbase: PocketBase meta.appURL set to https://perfect-postcodes.co.uk/pb
+2026-05-04T20:30:52.516839Z INFO property_map_server::pocketbase: PocketBase OAuth configured on users collection
+2026-05-04T20:30:52.516862Z INFO property_map_server: Gemini configured (model: gemini-3-flash-preview)
+2026-05-04T20:30:52.516881Z INFO property_map_server: Loading travel time data from /app/data/travel-times
+2026-05-04T20:30:52.518702Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="bicycle" destinations=2753
+2026-05-04T20:30:52.520363Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="walking" destinations=2753
+2026-05-04T20:30:52.522195Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="car" destinations=2753
+2026-05-04T20:30:52.523772Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="transit" destinations=2752
+2026-05-04T20:30:52.523786Z INFO property_map_server: Travel time store loaded modes=4
+2026-05-04T20:30:52.523828Z INFO property_map_server: Precomputed AI filters system prompt
+2026-05-04T20:31:09.448584Z INFO property_map_server: All memory pages locked (mlockall)
+2026-05-04T20:31:09.448653Z INFO property_map_server: Server listening on 0.0.0.0:8001
+2026-05-04T20:31:09.954559Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:31:22.353875Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:31:22.353952Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:31:23.626789Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=6.3 json_ms=0.3 total_ms=6.6
+2026-05-04T20:32:15.348905Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:32:15.350168Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:32:15.807753Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=4.1 json_ms=0.2 total_ms=4.4
+2026-05-04T20:32:19.685730Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:32:19.685759Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:32:19.966538Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.5 json_ms=0.3 total_ms=3.7
+2026-05-04T20:32:27.438356Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:32:27.438476Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:32:27.784172Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.4 total_ms=2.4
+2026-05-04T20:32:54.407882Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:32:54.407932Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:32:54.660005Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.4 json_ms=0.3 total_ms=2.7
+2026-05-04T20:33:09.800713Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:33:09.800731Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:33:10.426238Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.3 total_ms=1.8
+2026-05-04T20:33:12.770380Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.9 json_ms=0.3 total_ms=2.2
+2026-05-04T20:33:53.200280Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:33:53.203908Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:18.328076Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:18.328080Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:18.583018Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.3 total_ms=1.8
+2026-05-04T20:34:23.052991Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=312 cells_after_filter=300 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.2 total_ms=1.2
+2026-05-04T20:34:25.158814Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89195da49c3ffff resolution=9 total_count=238 filters=0 filters_raw="-" ms=0.2
+2026-05-04T20:34:25.576335Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=64311 parallel=true cells_before_filter=249 cells_after_filter=229 truncated=false bounds=51.4958,-0.1632,51.5342,-0.0968 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.2 total_ms=1.7
+2026-05-04T20:34:26.166477Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=88195da49dfffff resolution=8 total_count=1598 filters=0 filters_raw="-" ms=1.1
+2026-05-04T20:34:26.198050Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=87195da49ffffff resolution=7 total_count=7707 filters=0 filters_raw="-" ms=2.9
+2026-05-04T20:34:26.276613Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=86195da4fffffff resolution=6 total_count=94429 filters=0 filters_raw="-" ms=38.2
+2026-05-04T20:34:26.465598Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=6 rows=7286993 parallel=true cells_before_filter=1523 cells_after_filter=1523 truncated=false bounds=49.8232,-2.2817,52.4581,2.2344 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.2 agg_ms=39.6 json_ms=1.1 total_ms=40.9
+2026-05-04T20:34:27.933150Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=87195da48ffffff resolution=7 total_count=15303 filters=0 filters_raw="-" ms=6.4
+2026-05-04T20:34:28.584652Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=7 rows=597761 parallel=true cells_before_filter=972 cells_after_filter=972 truncated=false bounds=50.7289,-1.6798,51.3320,-0.6488 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.7 json_ms=0.4 total_ms=4.1
+2026-05-04T20:34:28.905846Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=88195da481fffff resolution=8 total_count=1907 filters=0 filters_raw="-" ms=0.9
+2026-05-04T20:34:29.424084Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=8 rows=186703 parallel=true cells_before_filter=945 cells_after_filter=941 truncated=false bounds=50.8643,-1.4587,51.1420,-0.9843 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.5 total_ms=2.1
+2026-05-04T20:34:30.488144Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=8819598e67fffff resolution=8 total_count=7 filters=0 filters_raw="-" ms=0.1
+2026-05-04T20:34:31.111777Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=8819598e2dfffff resolution=8 total_count=60 filters=0 filters_raw="-" ms=0.1
+2026-05-04T20:34:31.378980Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=8919598e2c3ffff resolution=9 total_count=0 filters=0 filters_raw="-" ms=0.0
+2026-05-04T20:34:31.842706Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=1307 parallel=false cells_before_filter=65 cells_after_filter=52 truncated=false bounds=50.9992,-1.2517,51.0771,-1.1185 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.1 total_ms=0.1
+2026-05-04T20:34:32.910988Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=2465 parallel=false cells_before_filter=94 cells_after_filter=82 truncated=false bounds=51.0079,-1.2472,51.0858,-1.1141 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.1 total_ms=0.2
+2026-05-04T20:34:32.928239Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=8919598e2d7ffff resolution=9 total_count=44 filters=0 filters_raw="-" ms=0.1
+2026-05-04T20:34:33.808761Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:33.808804Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:34.471770Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.3 total_ms=2.0
+2026-05-04T20:34:34.717103Z INFO property_map_server::routes::screenshot: Fetching screenshot from: http://screenshot:8002/screenshot?og=1&lat=51.0468&lon=-1.1806&zoom=13.0
+2026-05-04T20:34:35.099478Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:35.099493Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:35.404694Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:35.404725Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:35.621134Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:35.621143Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:35.820743Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:35.820748Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:36.031322Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:36.031329Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:36.220252Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:36.220273Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:36.417725Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:36.417764Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:36.596564Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:36.596567Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:36.805201Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:36.807262Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:36.979234Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:36.980372Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:37.178187Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:37.178191Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:37.374722Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:37.374774Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:37.578691Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:37.578748Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:37.763311Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:37.763336Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:37.959917Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:37.961434Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.149214Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:38.149218Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.338272Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:38.338330Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.523357Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:38.523384Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.647361Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:38.648448Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.722548Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:38.722571Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.907929Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:38.908520Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:38.999919Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=3047 parallel=false cells_before_filter=155 cells_after_filter=134 truncated=false bounds=51.0079,-1.2718,51.0856,-1.0894 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.1 total_ms=0.2
+2026-05-04T20:34:39.103175Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:39.103190Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:39.297466Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:39.297503Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:39.496714Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:39.496723Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:39.690316Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:39.690319Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:39.885749Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:39.885750Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:40.071280Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:40.071281Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:40.272875Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:40.272877Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:40.455413Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:40.456062Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:40.650200Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:40.650208Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:40.845522Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:40.845559Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:41.038761Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:41.038768Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:41.229273Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:41.229275Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:41.430964Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:41.430979Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:41.623261Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:41.623265Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:41.824373Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:41.824375Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:42.019133Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:42.020313Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:42.212760Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:42.212863Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:42.411007Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:42.411009Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:42.607078Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:42.607110Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:42.793714Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:42.793749Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:42.989510Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:42.989513Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:43.183559Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:43.183560Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:43.387718Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:43.387725Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:43.585185Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:43.586557Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:43.779686Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:43.779689Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:43.967841Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:43.967853Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:44.166724Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:44.166725Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:44.394604Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:44.394609Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:44.588595Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:44.588598Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:44.787714Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:44.787719Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:44.984488Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:44.984510Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:45.180962Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:45.180969Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:45.376625Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=3047 parallel=false cells_before_filter=155 cells_after_filter=134 truncated=false bounds=51.0079,-1.2718,51.0856,-1.0894 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.2 json_ms=0.1 total_ms=0.3
+2026-05-04T20:34:45.387583Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:45.387593Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:45.580533Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:45.580596Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:45.773425Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:45.773473Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:45.967029Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:45.967068Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:46.166279Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:46.166350Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:46.357911Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:46.358486Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:46.550836Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:46.550891Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:46.784106Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:46.784160Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:46.983704Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:46.983708Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:47.198317Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:47.198328Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:47.394310Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:47.394315Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:47.610059Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:47.610060Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:47.800028Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:47.800044Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:48.014658Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:48.014666Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:48.219421Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:48.219435Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:48.434789Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:48.434790Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:48.647418Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:48.647423Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:48.898225Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:48.898228Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:49.108187Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:49.108205Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:49.342153Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:49.342155Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:49.545502Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:49.545518Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:49.778569Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:49.778587Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:49.999270Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:49.999274Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:50.333862Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:50.333934Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:50.544353Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:50.544371Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:50.798443Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:50.798447Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:51.000381Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:51.000385Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:51.374154Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:51.374161Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:51.570709Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:51.570714Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:51.916953Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:51.916957Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:52.125325Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:52.125330Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:52.482832Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:52.482835Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:52.670560Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:52.670564Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:52.872611Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:52.872615Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:53.060615Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:53.060616Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:53.251200Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:53.251202Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:53.428146Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:53.428148Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:53.623610Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:53.623614Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:53.811624Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:53.811663Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:54.009761Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:54.009828Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:54.190575Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:54.190579Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:54.379891Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:54.379898Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:54.567380Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:54.567402Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:54.758550Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:54.758551Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:54.935097Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:54.935104Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:55.122992Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:55.122997Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:55.305012Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:55.305016Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:55.488758Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:55.488771Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:55.661696Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:55.661743Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:55.850007Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:55.851110Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:56.021055Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:56.021093Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:56.204565Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:56.204571Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:56.378525Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:56.378554Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:56.569251Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:56.569259Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:56.751520Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:56.751531Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:57.240645Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:57.240996Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:57.241239Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=326 parallel=false cells_before_filter=41 cells_after_filter=41 truncated=false bounds=51.0213,-1.2578,51.0723,-1.1034 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.0 total_ms=0.1
+2026-05-04T20:34:57.424507Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:57.424534Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:57.599879Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:57.599944Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:57.770786Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:57.770819Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:57.956206Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:57.956233Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:58.135904Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:58.135908Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:58.321905Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:58.321912Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:58.497793Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:58.497797Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:58.695097Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:58.695098Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:58.884432Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:58.884442Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:59.074754Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:59.074757Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:59.257817Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:59.257819Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:59.443034Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:59.443038Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:59.616255Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:59.616264Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:59.806095Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:59.806096Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:34:59.996128Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:34:59.996198Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:00.202642Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:00.202647Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:00.415170Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:00.415200Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:00.622447Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:00.622452Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:00.819512Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:00.820079Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:01.018420Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:01.018432Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:01.223860Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:01.223861Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:01.428276Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:01.428296Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:01.632732Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:01.632734Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:01.825994Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:01.826009Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:02.010964Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:02.010970Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:02.207162Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:02.207165Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:02.383218Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:02.384358Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:02.571962Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:02.571993Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:02.751751Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:02.752992Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:02.941788Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:02.941802Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:03.116109Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:03.116116Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:03.304169Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:03.304171Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:03.480506Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:03.480515Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:03.664726Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:03.664730Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:03.832155Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:03.832156Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:04.018658Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:04.018659Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:04.195730Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:04.195732Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:04.378322Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:04.378331Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:04.543718Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:04.543724Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:04.732208Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:04.732669Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:04.912266Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:04.912342Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:05.102562Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:05.102568Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:05.284289Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:05.284345Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:05.481744Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:05.481770Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:05.669280Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:05.669312Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:05.854490Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:05.855575Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:53.196583Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:53.197811Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:53.878390Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:35:53.878412Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:35:54.470543Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.2 total_ms=1.6
+2026-05-04T20:36:09.276001Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:36:09.281237Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:36:09.367289Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:36:09.367312Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:02.804001Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:02.805317Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:02.885691Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:02.886138Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:19.771121Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:19.815442Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:19.884568Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:19.884572Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:41.735578Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:41.736828Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:41.847861Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:41.847873Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:57.095462Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:37:57.095764Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:57.200811Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:37:57.200824Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:38:11.018411Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:38:11.059896Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:38:11.133358Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:38:11.134108Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:38:52.095388Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:38:52.098225Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:38:53.368198Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:38:53.429393Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:38:54.163956Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.3 total_ms=1.4
+2026-05-04T20:39:06.050601Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:39:06.052116Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:39:06.570770Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.3 total_ms=2.1
+2026-05-04T20:39:23.011298Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.0 total_ms=1.1
+2026-05-04T20:39:23.243791Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.1
+2026-05-04T20:39:24.980683Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.3 total_ms=1.8
+2026-05-04T20:39:25.125095Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.1 total_ms=1.5
+2026-05-04T20:39:31.465483Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.1 total_ms=2.1
+2026-05-04T20:39:31.722990Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.3
+2026-05-04T20:39:38.401017Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:39:39.087171Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.1 total_ms=1.1
+2026-05-04T20:39:39.300308Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.7
+2026-05-04T20:41:08.067710Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:41:08.069119Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:41:08.529787Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.5 json_ms=0.3 total_ms=1.8
+2026-05-04T20:41:17.449649Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.0 total_ms=1.0
+2026-05-04T20:41:17.701651Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.4
+2026-05-04T20:41:19.350217Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.3 total_ms=1.6
+2026-05-04T20:41:19.498459Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.0 total_ms=1.1
+2026-05-04T20:41:25.104140Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.1 total_ms=1.9
+2026-05-04T20:41:25.354462Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.4
+2026-05-04T20:41:30.534640Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:41:31.159443Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.1 total_ms=1.0
+2026-05-04T20:41:31.409981Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.8
+2026-05-04T20:42:30.707655Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:42:30.708065Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:42:30.744186Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:42:30.745673Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:04.554809Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:04.554814Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:04.584716Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:04.587412Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:12.275304Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:12.275307Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:12.298346Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:12.299436Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:41.034309Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:41.039356Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:41.059494Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:41.059502Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:52.892976Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:43:52.894374Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:43:53.353713Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.2 total_ms=2.0
+2026-05-04T20:43:59.658270Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.0 total_ms=0.9
+2026-05-04T20:43:59.907585Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.4
+2026-05-04T20:44:00.977870Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.5 total_ms=2.2
+2026-05-04T20:44:01.129206Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.1 total_ms=1.8
+2026-05-04T20:44:05.395927Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.2 json_ms=0.2 total_ms=2.3
+2026-05-04T20:44:05.646861Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.5
+2026-05-04T20:44:10.435176Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:44:11.096593Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.1 total_ms=1.0
+2026-05-04T20:44:11.346615Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.9
+2026-05-04T20:44:25.051474Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=312 cells_after_filter=300 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.2 total_ms=1.1
+2026-05-04T20:44:27.031361Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=312 cells_after_filter=300 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=1 filters_raw="Income Score (rate):0:0.996" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.2 total_ms=1.5
+2026-05-04T20:44:27.281363Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=1 travel=0 total=83099 filters_raw="Income Score (rate):0:0.996" ms=2.4
+2026-05-04T20:44:27.603993Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=312 cells_after_filter=300 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=0 filters_raw="-" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.3 total_ms=1.7
+2026-05-04T20:44:27.762778Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=312 cells_after_filter=300 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=1 filters_raw="Income Score (rate):0:0.996" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.2 total_ms=1.3
+2026-05-04T20:44:27.996689Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=83099 parallel=true cells_before_filter=305 cells_after_filter=293 truncated=false bounds=51.4958,-0.1756,51.5342,-0.0844 filters=1 filters_raw="Income Score (rate):0.85:0.996" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.9 json_ms=0.2 total_ms=2.1
+2026-05-04T20:44:28.242605Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=83099 filters=1 travel=0 total=77783 filters_raw="Income Score (rate):0.85:0.996" ms=2.0
+2026-05-04T20:45:00.911232Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:45:00.914605Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:45:02.434769Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.7 json_ms=0.3 total_ms=2.0
+2026-05-04T20:45:07.311390Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.0 total_ms=1.3
+2026-05-04T20:45:07.554657Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.0
+2026-05-04T20:45:29.666656Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:45:29.667346Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:45:30.123472Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.3 total_ms=1.9
+2026-05-04T20:45:35.839057Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.0 total_ms=1.3
+2026-05-04T20:45:36.085660Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.2
+2026-05-04T20:46:46.804618Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:46:46.804924Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:46:48.403073Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.4 total_ms=2.4
+2026-05-04T20:46:53.927368Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.0 total_ms=1.0
+2026-05-04T20:46:54.173346Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.1
+2026-05-04T20:46:55.390070Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=2.1 json_ms=0.4 total_ms=2.5
+2026-05-04T20:46:55.535270Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.0 total_ms=1.3
+2026-05-04T20:47:00.487676Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.4 json_ms=0.2 total_ms=1.5
+2026-05-04T20:47:00.738490Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.2
+2026-05-04T20:47:05.776570Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:47:06.355877Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.1 total_ms=1.0
+2026-05-04T20:47:06.606689Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.7
+2026-05-04T20:47:32.866710Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:47:32.866743Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:32.885838Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:47:32.886993Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:49.386505Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:47:49.386515Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:49.401614Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:47:49.402891Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:57.416750Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:47:57.418210Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:58.098569Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.8 json_ms=0.3 total_ms=3.1
+2026-05-04T20:47:58.404720Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:47:58.405522Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:58.430526Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:47:58.430833Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:01.191206Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:01.192318Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:01.523111Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.3 total_ms=2.3
+2026-05-04T20:48:07.772669Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.2 json_ms=0.0 total_ms=1.3
+2026-05-04T20:48:08.027177Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.9
+2026-05-04T20:48:08.796621Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:08.796636Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:08.812196Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:08.813328Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:08.885819Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:08.886773Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:09.227901Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.5 json_ms=0.0 total_ms=2.6
+2026-05-04T20:48:11.122327Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=4.5
+2026-05-04T20:48:17.124780Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:17.125594Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:17.145187Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:17.147472Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:17.230192Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:48:17.230475Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:48:17.594663Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.6 json_ms=0.1 total_ms=1.6
+2026-05-04T20:50:12.098973Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:50:12.100126Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:50:13.707247Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.2 json_ms=0.3 total_ms=1.5
+2026-05-04T20:50:19.331174Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.0 total_ms=0.9
+2026-05-04T20:50:19.582430Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.1
+2026-05-04T20:50:20.799127Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.4 total_ms=2.1
+2026-05-04T20:50:20.942190Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.1 total_ms=1.1
+2026-05-04T20:50:25.736222Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.1 json_ms=0.2 total_ms=3.3
+2026-05-04T20:50:25.983567Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.6
+2026-05-04T20:50:30.835124Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:50:31.454678Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.8 json_ms=0.1 total_ms=1.0
+2026-05-04T20:50:31.700575Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.7
+2026-05-04T20:50:47.310479Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:50:47.310885Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:50:47.469513Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:50:47.469538Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:51:28.250512Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:51:28.250780Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:51:28.322463Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:51:28.323245Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:51:51.130489Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:51:51.147506Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:51:51.158397Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:51:51.158440Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:51:59.494152Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:51:59.494317Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:51:59.563015Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:51:59.564521Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:52:19.421059Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:52:19.422551Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:52:19.898720Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.3 total_ms=1.5
+2026-05-04T20:52:27.078291Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.0 total_ms=1.0
+2026-05-04T20:52:27.315257Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.2
+2026-05-04T20:52:28.560429Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=2.2 json_ms=0.4 total_ms=2.6
+2026-05-04T20:52:28.707137Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=2.5 json_ms=0.1 total_ms=2.5
+2026-05-04T20:52:34.007339Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.3 json_ms=0.3 total_ms=2.6
+2026-05-04T20:52:34.257812Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.6
+2026-05-04T20:52:39.215463Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:52:39.798060Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.1 total_ms=1.0
+2026-05-04T20:52:40.048243Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.7
+2026-05-04T20:52:42.277856Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:52:42.279501Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:52:42.372314Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:52:42.374214Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:53:11.233529Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:53:11.234510Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:53:11.336527Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:53:11.336577Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:53:22.955423Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:53:22.959946Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:53:24.369428Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.2 json_ms=0.3 total_ms=1.5
+2026-05-04T20:53:30.515118Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.4 json_ms=0.0 total_ms=1.4
+2026-05-04T20:53:30.765241Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.7
+2026-05-04T20:53:31.991439Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=2.7 json_ms=0.3 total_ms=3.1
+2026-05-04T20:53:32.133094Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.3 json_ms=0.1 total_ms=1.4
+2026-05-04T20:53:36.787086Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=2.7 json_ms=0.2 total_ms=2.9
+2026-05-04T20:53:37.045855Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.3
+2026-05-04T20:53:41.988437Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:53:42.536699Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.1 total_ms=1.2
+2026-05-04T20:53:42.787270Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.7
+2026-05-04T20:54:06.229359Z INFO property_map_server: Prometheus metrics initialized
+2026-05-04T20:54:06.229589Z INFO property_map_server: Loading property data from /app/data/properties.parquet, /app/data/postcode.parquet
+2026-05-04T20:54:06.229609Z INFO property_map_server::data::property: Loading postcode features from "/app/data/postcode.parquet"
+2026-05-04T20:54:06.354418Z INFO property_map_server::data::property: Postcode features loaded rows=1263786
+2026-05-04T20:54:06.354428Z INFO property_map_server::data::property: Loading properties from "/app/data/properties.parquet"
+2026-05-04T20:54:08.909626Z INFO property_map_server::data::property: Properties joined with postcodes rows=15268176
+2026-05-04T20:54:08.909665Z INFO property_map_server::data::property: Feature columns from config numeric=63 enums=6 total=69
+2026-05-04T20:54:11.687418Z WARN property_map_server::data::property: Dropped properties with missing postcode coordinates rows=743076
+2026-05-04T20:54:11.687429Z INFO property_map_server::data::property: Combined data selected rows=14525100
+2026-05-04T20:54:11.818997Z INFO property_map_server::data::property: Extracting numeric feature columns
+2026-05-04T20:54:12.212459Z INFO property_map_server::data::property: Computing histograms for numeric features
+2026-05-04T20:54:13.526055Z INFO property_map_server::data::property: Extracting string columns
+2026-05-04T20:54:14.916447Z INFO property_map_server::data::property: Building enum features
+2026-05-04T20:54:16.192264Z INFO property_map_server::data::property: Extracting renovation history
+2026-05-04T20:54:18.405306Z INFO property_map_server::data::property: Renovation history extracted properties_with_events=1741939
+2026-05-04T20:54:18.405317Z INFO property_map_server::data::property: Sorting rows by spatial locality
+2026-05-04T20:54:19.406915Z INFO property_map_server::data::property: Building interned strings
+2026-05-04T20:54:24.606232Z INFO property_map_server::data::property: Transposing to row-major layout (spatially sorted, quantized to u16)
+2026-05-04T20:54:27.365951Z INFO property_map_server::data::property: Data loading complete
+2026-05-04T20:54:28.895749Z INFO property_map_server: Allocator trim label="property data load" trimmed=true rss_before_mib=13477.7 rss_after_mib=3259.3 released_mib=10218.4
+2026-05-04T20:54:28.895760Z INFO property_map_server: Property data loaded rows=14525100 features=69 enums=6
+2026-05-04T20:54:28.895764Z INFO property_map_server: Building spatial grid index (0.01° cells)
+2026-05-04T20:54:29.002022Z INFO property_map_server: Precomputing H3 cells at resolution 12
+2026-05-04T20:54:29.002032Z INFO property_map_server::data::property: Precomputing H3 cells at resolution 12
+2026-05-04T20:54:29.380275Z INFO property_map_server::data::property: H3 precomputation complete (14525100 cells)
+2026-05-04T20:54:29.380348Z INFO property_map_server: Loading POI data from /app/data/filtered_uk_pois.parquet
+2026-05-04T20:54:29.380360Z INFO property_map_server::data::poi: Loading POI data from "/app/data/filtered_uk_pois.parquet"...
+2026-05-04T20:54:29.408407Z INFO property_map_server::data::poi: Loaded 567534 POIs
+2026-05-04T20:54:29.551580Z INFO property_map_server::data::poi: POI string columns interned category_unique=94 group_unique=11 emoji_unique=71
+2026-05-04T20:54:29.552752Z INFO property_map_server::data::poi: POI data loading complete.
+2026-05-04T20:54:29.598119Z INFO property_map_server: Allocator trim label="poi data load" trimmed=true rss_before_mib=3669.8 rss_after_mib=3477.2 released_mib=192.6
+2026-05-04T20:54:29.598128Z INFO property_map_server: POI data loaded pois=567534
+2026-05-04T20:54:29.598130Z INFO property_map_server: Building POI spatial grid index
+2026-05-04T20:54:29.605198Z INFO property_map_server: Loading place data from /app/data/places.parquet
+2026-05-04T20:54:29.605209Z INFO property_map_server::data::places: Loading place data from "/app/data/places.parquet"...
+2026-05-04T20:54:29.606706Z INFO property_map_server::data::places: Loaded 3474 places
+2026-05-04T20:54:29.607673Z INFO property_map_server::data::places: Place data loaded places=3474 types=2 with_population=71 with_city=3392
+2026-05-04T20:54:29.611580Z INFO property_map_server: Allocator trim label="place data load" trimmed=true rss_before_mib=3486.3 rss_after_mib=3481.9 released_mib=4.4
+2026-05-04T20:54:29.611588Z INFO property_map_server: Place data loaded places=3474
+2026-05-04T20:54:29.611595Z INFO property_map_server: Loading postcode boundaries from /app/data/postcode_boundaries
+2026-05-04T20:54:29.611605Z INFO property_map_server::data::postcodes: Loading postcode boundaries from "/app/data/postcode_boundaries"
+2026-05-04T20:54:29.615798Z INFO property_map_server::data::postcodes: Found GeoJSON files to process files=2361
+2026-05-04T20:54:37.460224Z INFO property_map_server::data::postcodes: Postcode boundary data ready postcodes=1490140
+2026-05-04T20:54:37.828187Z INFO property_map_server: Allocator trim label="postcode boundary load" trimmed=true rss_before_mib=10796.8 rss_after_mib=10613.1 released_mib=183.7
+2026-05-04T20:54:37.828199Z INFO property_map_server: Postcode boundaries loaded postcodes=1490140
+2026-05-04T20:54:37.978691Z INFO property_map_server::data::postcodes: Outcode data derived from postcodes outcodes=2361
+2026-05-04T20:54:37.978752Z INFO property_map_server: Loading PMTiles from /app/data/uk.pmtiles
+2026-05-04T20:54:37.982160Z INFO property_map_server: PMTiles loaded successfully
+2026-05-04T20:54:38.023911Z INFO property_map_server: No --dist provided; static serving and OG injection disabled
+2026-05-04T20:54:38.053118Z INFO property_map_server: Screenshot service configured: http://screenshot:8002
+2026-05-04T20:54:38.053290Z INFO property_map_server: Precomputed features response groups=8
+2026-05-04T20:54:38.053307Z INFO property_map_server: PocketBase configured: http://pocketbase:8090
+2026-05-04T20:54:38.117382Z INFO property_map_server::pocketbase: PocketBase users collection already has all required fields
+2026-05-04T20:54:38.127369Z INFO property_map_server::pocketbase: PocketBase collection 'saved_searches' API rules updated
+2026-05-04T20:54:38.131471Z INFO property_map_server::pocketbase: PocketBase collection 'saved_properties' API rules updated
+2026-05-04T20:54:39.029859Z INFO property_map_server::pocketbase: PocketBase meta.appURL set to https://perfect-postcodes.co.uk/pb
+2026-05-04T20:54:39.034138Z INFO property_map_server::pocketbase: PocketBase OAuth configured on users collection
+2026-05-04T20:54:39.034181Z INFO property_map_server: Gemini configured (model: gemini-3-flash-preview)
+2026-05-04T20:54:39.034199Z INFO property_map_server: Loading travel time data from /app/data/travel-times
+2026-05-04T20:54:39.044450Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="bicycle" destinations=2753
+2026-05-04T20:54:39.052389Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="walking" destinations=2753
+2026-05-04T20:54:39.061567Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="car" destinations=2753
+2026-05-04T20:54:39.069032Z INFO property_map_server::data::travel_time: Travel time mode discovered mode="transit" destinations=2752
+2026-05-04T20:54:39.069058Z INFO property_map_server: Travel time store loaded modes=4
+2026-05-04T20:54:39.069116Z INFO property_map_server: Precomputed AI filters system prompt
+2026-05-04T20:54:42.362073Z INFO property_map_server: All memory pages locked (mlockall)
+2026-05-04T20:54:42.362120Z INFO property_map_server: Server listening on 0.0.0.0:8001
+2026-05-04T20:54:44.656878Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:54:44.659588Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:54:45.153839Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=7.8 json_ms=0.3 total_ms=8.1
+2026-05-04T20:54:52.225820Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.0 total_ms=1.8
+2026-05-04T20:54:52.486600Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.3
+2026-05-04T20:54:53.693488Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=4.5 json_ms=0.3 total_ms=4.8
+2026-05-04T20:54:53.835597Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=2.0 json_ms=0.1 total_ms=2.1
+2026-05-04T20:54:59.069769Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.0 json_ms=0.2 total_ms=3.2
+2026-05-04T20:54:59.318387Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.1
+2026-05-04T20:55:04.869956Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.1
+2026-05-04T20:55:05.492428Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.1 total_ms=1.1
+2026-05-04T20:55:05.740336Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.9
+2026-05-04T20:56:01.654138Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:01.655404Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:01.767071Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:01.767084Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:10.929872Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:10.931080Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:11.027480Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:11.027485Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:18.496076Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:18.498033Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:18.609718Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:18.609722Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:25.513529Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:25.514564Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:25.597043Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:25.597046Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:31.486143Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:31.487527Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:56:31.606622Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:56:31.606639Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:58:22.820424Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=3047 parallel=false cells_before_filter=155 cells_after_filter=134 truncated=false bounds=51.0079,-1.2718,51.0856,-1.0894 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.1 json_ms=0.1 total_ms=0.3
+2026-05-04T20:58:24.198002Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:58:24.202971Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:58:30.601261Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:58:32.202753Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:58:32.204070Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:58:33.011967Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.2 total_ms=2.1
+2026-05-04T20:58:39.599425Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.0 total_ms=1.1
+2026-05-04T20:58:39.850441Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.4
+2026-05-04T20:58:41.031219Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.8 json_ms=0.3 total_ms=2.1
+2026-05-04T20:58:41.174917Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=2.1 json_ms=0.1 total_ms=2.1
+2026-05-04T20:58:46.162873Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=3.4 json_ms=0.2 total_ms=3.6
+2026-05-04T20:58:46.412423Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.4
+2026-05-04T20:58:50.430953Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.2
+2026-05-04T20:58:51.017617Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.0 json_ms=0.1 total_ms=1.1
+2026-05-04T20:58:51.263827Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.6
+2026-05-04T20:59:12.741182Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:59:14.169075Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:59:14.169081Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:59:14.985002Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T20:59:14.986260Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T20:59:15.452832Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=537 cells_after_filter=412 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=0 filters_raw="-" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.9 json_ms=0.4 total_ms=2.3
+2026-05-04T20:59:22.096990Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.0 total_ms=1.2
+2026-05-04T20:59:22.344347Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=192 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=2.2
+2026-05-04T20:59:23.588305Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=392 cells_after_filter=297 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=3 filters_raw="Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.4 json_ms=0.3 total_ms=1.6
+2026-05-04T20:59:23.737506Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=52 cells_after_filter=37 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:0:600000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=1 travel_entries=0 grid_ms=0.0 agg_ms=1.1 json_ms=0.0 total_ms=1.2
+2026-05-04T20:59:28.698263Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=152340 parallel=true cells_before_filter=261 cells_after_filter=182 truncated=false bounds=51.4943,-0.1794,51.5357,-0.0806 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=1.9 json_ms=0.2 total_ms=2.1
+2026-05-04T20:59:28.949287Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=152340 filters=4 travel=0 total=2266 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=3.4
+2026-05-04T20:59:33.021084Z INFO property_map_server::routes::hexagon_stats: GET /api/hexagon-stats h3=89194ad325bffff resolution=9 total_count=1 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=0.1
+2026-05-04T20:59:33.564060Z INFO property_map_server::routes::hexagons: GET /api/hexagons resolution=9 rows=108397 parallel=true cells_before_filter=183 cells_after_filter=134 truncated=false bounds=51.4943,-0.1671,51.5357,-0.0929 filters=4 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" fields=0 travel_entries=0 grid_ms=0.0 agg_ms=0.9 json_ms=0.1 total_ms=1.0
+2026-05-04T20:59:33.817368Z INFO property_map_server::routes::filter_counts: GET /api/filter-counts rows=108397 filters=4 travel=0 total=1583 filters_raw="Estimated current price:12976.594:1380000;;Number of bedrooms & living rooms:4:6;;Property type:Detached|Semi-Detached|Terraced;;Distance to nearest train or tube station (km):0:1" ms=1.9
+2026-05-04T21:01:19.542960Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T21:01:19.544562Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
+2026-05-04T21:01:19.556893Z INFO property_map_server::routes::features: GET /api/features
+2026-05-04T21:01:19.558130Z INFO property_map_server::routes::pois: GET /api/poi-categories count=94 groups=11
diff --git a/server-rs/src/data/property.rs b/server-rs/src/data/property.rs
index d275853..3126ae0 100644
--- a/server-rs/src/data/property.rs
+++ b/server-rs/src/data/property.rs
@@ -1227,7 +1227,7 @@ mod tests {
let mid_value = 50.0;
let bin = hist.bin_for_value(mid_value);
- assert!(bin >= 1 && bin <= 8);
+ assert!((1..=8).contains(&bin));
}
#[test]
@@ -1276,7 +1276,7 @@ mod tests {
#[test]
fn count_skips_nan() {
- let values = vec![1.0_f32, f32::NAN, 2.0, f32::NAN, 3.0];
+ let values = [1.0_f32, f32::NAN, 2.0, f32::NAN, 3.0];
let count = values.iter().filter(|v| v.is_finite()).count();
assert_eq!(count, 3);
}
diff --git a/server-rs/src/licensing.rs b/server-rs/src/licensing.rs
index 1992df3..5514bcf 100644
--- a/server-rs/src/licensing.rs
+++ b/server-rs/src/licensing.rs
@@ -1,17 +1,189 @@
+use std::time::Instant;
+
use axum::http::StatusCode;
use axum::response::IntoResponse;
-use serde_json::json;
+use parking_lot::RwLock;
+use rustc_hash::FxHashMap;
+use serde_json::{json, Value};
+use tracing::warn;
use crate::auth::PocketBaseUser;
use crate::consts::FREE_ZONE_BOUNDS;
+use crate::pocketbase::get_superuser_token;
+use crate::state::AppState;
+
+const SHARE_CACHE_TTL_SECS: u64 = 300;
+const SHARE_CACHE_MAX_ENTRIES: usize = 1024;
+
+#[derive(Clone, Copy, Debug)]
+pub struct ShareBounds {
+ pub south: f64,
+ pub west: f64,
+ pub north: f64,
+ pub east: f64,
+}
+
+/// Cache: code → resolved share bounds. We cache `None` too so an invalid
+/// code doesn't keep hammering PocketBase on every request from a malicious
+/// or stale client.
+pub struct ShareBoundsCache {
+ entries: RwLock, Instant)>>,
+}
+
+impl ShareBoundsCache {
+ pub fn new() -> Self {
+ Self {
+ entries: RwLock::new(FxHashMap::default()),
+ }
+ }
+
+ fn get(&self, code: &str) -> Option