* feat(mileage): suggest driving distance from the from/to addresses When both endpoints are typed in the trip form (create mode), a debounced lookup geocodes them via Nominatim and fetches the driving distance via OSRM, both proxied through /api/mileage/distance so addresses leave only our server, without user identifiers. The suggestion renders as a click-to-apply hint under the distance field, never auto-fills, and stays fully editable. Tooltip shows what the geocoder matched. In-instance caching (24h hits, 10min misses) plus 1.1s politeness spacing keep usage inside the OSM public-endpoint policies. OSMF is disclosed as a data recipient on the privacy page. Requested by a beta user: first-time routes had to be measured by hand; route memory (PR #1657) only helps from the second trip onward. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(mileage): resolve skeptic findings on the distance suggestion Compliance: routing switched from router.project-osrm.org (demo server, non-commercial use only) to FOSSGIS's routing.openstreetmap.de; the lookup is now click-triggered ("Foresla stracka") instead of as-you-type, per Nominatim's no-autocomplete policy; visible OpenStreetMap attribution next to the applied suggestion; privacy page reworked to name OSMF and FOSSGIS e.V. as independent recipients outside the sub-processor table, with an honest note that typed addresses can themselves be personal data. Correctness: suggestion-cache key separator changed from '|' (collidable by address text) to newline; routes rounding to 0.0 km are no longer suggested (the form rejects 0); the Nominatim politeness queue is bounded at 3s wait and bails to null instead of holding request handlers open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(mileage): resolve CodeRabbit findings on the distance suggestion A generation counter invalidates in-flight lookups when the route or km field changes or the dialog closes, so a slow response can never write an old route's distance into a changed form. Privacy page now states each recipient's actual payload (Nominatim gets address texts, FOSSGIS only coordinates), discloses the 24h in-memory server cache, and carries today's revision date. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
26 lines
1.1 KiB
TypeScript
26 lines
1.1 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import { ensureInitialized } from '@/lib/init'
|
|
import { withRouteContext } from '@/lib/api/with-route-context'
|
|
import { validateQuery } from '@/lib/api/validate'
|
|
import { MileageDistanceQuerySchema } from '@/lib/api/schemas'
|
|
import { fetchDistanceSuggestion } from '@/lib/mileage/distance'
|
|
import { guardSandbox } from '@/lib/sandbox/guard'
|
|
|
|
ensureInitialized()
|
|
|
|
// Proxies the OSM lookups server-side: the user's addresses never reach
|
|
// Nominatim/OSRM from their own browser, and the shared politeness caches
|
|
// live here. The sandbox guard keeps demo traffic off the public OSM
|
|
// budget, mirroring /api/currency/rate.
|
|
export const GET = withRouteContext('mileage.distance', async (request, { supabase, companyId }) => {
|
|
const params = validateQuery(request, MileageDistanceQuerySchema)
|
|
if (!params.success) return params.response
|
|
|
|
const blocked = await guardSandbox(supabase, companyId)
|
|
if (blocked) return blocked
|
|
|
|
// null simply means "no suggestion": the form shows nothing.
|
|
const suggestion = await fetchDistanceSuggestion(params.data.from, params.data.to)
|
|
return NextResponse.json({ data: suggestion })
|
|
})
|