Phase 1.2 of Route Optimization. Adds a provider-agnostic geocoding
service layer in the deployed src/ tree:
- GeocodingProvider interface + GeocodeResult type
- NominatimGeocodingProvider (default, free, self-hostable) with an
internal rate limiter enforcing the 1 req/sec Nominatim usage policy
- GoogleGeocodingProvider (optional fallback) keyed by the encrypted
businessSettings.googleMapsApiKey (decrypted via decryptSecret) or
GOOGLE_MAPS_API_KEY env fallback
- resolveGeocodingProvider() selecting on businessSettings.routeOptimizationProvider,
with safe fallback to Nominatim when google is configured but no usable key
- geocodeBatch() throttled batch utility (honors provider rate limit,
captures per-item errors, optional progress callback)
- 20 unit tests covering both providers, selection, throttle spacing, and batch
Co-Authored-By: Paperclip <noreply@paperclip.ing>