chore(geocoding): remove Pelias + close 3 bypass paths to public Nominatim

Pelias was retired from the Mac mini on 2026-04-28; photon-self
(self-hosted Photon on mana-gpu) has been the live primary since then.
This removes the now-dead Pelias adapter, config, tests, and the
services/mana-geocoding/pelias/ stack — the entire compose file, the
geojsonify_place_details.js patch, the setup.sh import script.

Provider chain is now `photon-self → photon → nominatim`. The chain
keeps its `privacy: 'local' | 'public'` split, sensitive-query
blocking, coord quantization, and aggressive caching unchanged.

Three direct calls to nominatim.openstreetmap.org that bypassed
mana-geocoding now route through the wrapper:

- citycorners/add-city + citycorners/cities/[slug]/add use the shared
  searchAddress() client (browser → same-origin proxy → mana-geocoding
  → photon-self).
- memoro mobile drops its OSM reverse-geocoding fallback entirely;
  Expo's on-device reverse-geocoding stays as the sole path. Routing
  through the wrapper would require a memoro-server proxy endpoint —
  a follow-up if Expo's quality proves insufficient.

Other behavioral changes:

- CACHE_PUBLIC_TTL_MS dropped from 7d → 1h. The long TTL was a
  privacy-amplification trick from the Pelias era; with photon-self
  serving the bulk of traffic, a transient cross-LAN blip was pinning
  cached fallback answers for days. 1h gives quick recovery.
- /health/pelias renamed to /health/photon-self; prometheus blackbox
  config + status-page generator updated.
- mana-geocoding container no longer needs `extra_hosts:
  host.docker.internal:host-gateway` (was only there for the
  Pelias-on-host-network era).

113 tests passing. CLAUDE.md rewritten to reflect the post-Pelias
architecture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-28 22:12:26 +02:00
parent 7bca16dfa7
commit 2bbcf14aba
35 changed files with 330 additions and 1262 deletions

View file

@ -155,71 +155,26 @@ export const reverseGeocodeWithExpo = async (
};
/**
* Führt ein Reverse Geocoding mit OpenStreetMap/Nominatim durch
* @param latitude Breitengrad
* @param longitude Längengrad
* @returns Adressinformationen oder null bei Fehler
*/
export const reverseGeocodeWithOSM = async (
latitude: number,
longitude: number
): Promise<AddressInfo | null> => {
try {
const url = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}&addressdetails=1`;
const response = await fetch(url, {
headers: {
'User-Agent': 'Memoro App', // OSM erfordert einen User-Agent
},
});
if (!response.ok) {
throw new Error(`OSM API responded with status: ${response.status}`);
}
const data = await response.json();
if (data && data.address) {
return {
street: data.address.road || data.address.pedestrian || data.address.street,
streetNumber: data.address.house_number,
postalCode: data.address.postcode,
city: data.address.city || data.address.town || data.address.village,
district: data.address.suburb || data.address.neighbourhood,
region: data.address.state,
country: data.address.country,
name: data.name,
formattedAddress: data.display_name,
};
}
return null;
} catch (error) {
console.debug('Fehler beim Reverse Geocoding mit OSM:', error);
return null;
}
};
/**
* Führt ein Reverse Geocoding durch und versucht, die beste verfügbare Adresse zu ermitteln
* @param latitude Breitengrad
* @param longitude Längengrad
* @returns Adressinformationen oder null bei Fehler
* Führt ein Reverse Geocoding durch. Nutzt ausschließlich Expo's
* On-Device Reverse-Geocoding keine direkten Calls an
* nominatim.openstreetmap.org, weil das die User-IP + Coords ungeschützt
* an einen Public-Service leakt. Wenn Expo keine Adresse liefert,
* geben wir null zurück.
*
* Falls Expo's Qualität auf Dauer nicht reicht, ist der richtige Fix
* ein Proxy-Endpoint im memoro-server, der intern an mana-geocoding
* weiterreicht (Privacy-Hardening + Photon-Self).
*/
export const getAddressFromCoordinates = async (
latitude: number,
longitude: number
): Promise<AddressInfo | null> => {
try {
// Zuerst mit Expo versuchen
const expoResult = await reverseGeocodeWithExpo(latitude, longitude);
// Wenn Expo ein gutes Ergebnis liefert, dieses verwenden
if (expoResult && expoResult.street && expoResult.city) {
return expoResult;
}
// Ansonsten mit OSM versuchen
return await reverseGeocodeWithOSM(latitude, longitude);
return expoResult;
} catch (error) {
console.debug('Fehler beim Reverse Geocoding:', error);
return null;