Repository navigation
Kakao map provider + POI name search overlay - #173
Conversation
Pulls marker SVG/emoji rendering out of LeafletMap into src/components/maps/icon.ts so upcoming Kakao/Google adapters can reuse the exact same artwork. Introduces a shared UserFacingMapProps type in src/components/maps/types.ts. No behavior change.
Introduces MAP_PROVIDER (osm|kakao|google, default osm), KAKAO_MAP_APP_KEY, and GOOGLE_MAPS_API_KEY. The new /api/map-config controller returns the active provider and its key; it fails loudly (HTTP 500) when the selected provider's key is missing so misconfigured deployments surface rather than silently falling back. Also extends the CSP script-src with Kakao's SDK hosts only when MAP_PROVIDER=kakao, keeping the OSS/OSM path's allowlist untouched.
Introduces <UserFacingMap>, a dispatcher that reads /api/map-config
via react-query and renders one of three adapters sharing a common
UserFacingMapProps interface:
* LeafletAdapter — wraps the existing LeafletMap (OSS/OSM default)
* KakaoAdapter — Kakao Maps JS SDK, loads dapi.kakao.com script
lazily and reuses the shared icon artwork for visual parity
* GoogleAdapter — stub that throws until an SDK integration lands
On /api/map-config error (e.g. missing key) the dispatcher renders
a visible "Map unavailable" banner rather than silently falling
back to OSM, so operator misconfiguration is loud.
No call sites are migrated in this commit — the module is
introduced as inert code.
Swaps LeafletMap for UserFacingMap in the six user-facing call sites — places list/detail maps, event detail thumbnail + modal maps, and PlacePicker (selected + unselected). Props are unchanged; the dispatcher picks an adapter at runtime based on MAP_PROVIDER. Admin-facing maps (admin/countries, admin/banners H3 coverage) and the server-side static snapshot generator are intentionally untouched — they remain on Leaflet/OSM.
Clicking the red "new place" pin dropped by a map-click would fall through nearbyPlaces.find() and navigate to /places/new — "new" is a synthetic marker id, not a real place, so the destination 404s. Short-circuit id === "new" to open the existing check-in dialog instead, matching the Check In button's behavior.
Introduces KAKAO_MAP_REST_KEY (server-side only) and a typed poi-search service that wraps Kakao's local keyword search endpoint. The /api/places/poi-search controller accepts q/lat/lng/radius and returns a list of PoiCandidate results (name, address, road address, coords, distance). Fails loudly with HTTP 500 when the REST key is missing but MAP_PROVIDER=kakao. Backs the upcoming search overlay on the interactive maps; gated by MAP_PROVIDER so OSS/OSM deployments are unaffected (service throws ServiceError for non-kakao providers). Includes a small in-memory LRU cache keyed by (query, coarse-coord, radius) with 5-min TTL to avoid hammering Kakao on typeahead keystrokes.
Moves the tier-based zoom → radius (km) mapping out of routes/places/index.tsx and into src/lib/place.ts so that the upcoming POI-search overlay can reuse the same calibration as the nearby-check-in circle. No behavior change.
A floating search box that sits absolutely on top of a UserFacingMap. Debounced (250ms) typeahead against /api/places/poi-search, biased around the current map center and sized to a radius derived from the current zoom via the shared zoomToRadius helper. The radius is 2x the nearby-check-in radius so the net covers roughly the visible viewport instead of the tight "literally around me" circle. Returns null when MAP_PROVIDER !== "kakao", so OSM/OSS builds get no overlay at all (and can't render a broken search UI). Surfaces loading, error, and empty-results states in the dropdown so users always get visual feedback. Not wired into any route yet — next commit.
Adds the floating Kakao POI search on the two interactive maps:
* PlacePicker (organizer's event-create/edit flow) — the primary
target. On pick, the map pans and zooms to the POI; the existing
"New location" panel fills with the picked name.
* /places check-in page — on pick, the check-in dialog opens
pre-filled with the POI name; the map re-centers on the picked
coord.
Both sites now track the current zoom so the overlay's search radius
scales with what the user is looking at. The existing overflow-hidden
rounded frame on /places is kept inside a new positioning wrapper so
the overlay's dropdown isn't clipped.
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR implements a multi-provider map abstraction layer with support for OSM (Leaflet), Kakao Maps, and Google Maps. It introduces environment-driven provider selection, new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant UserFacingMap
participant useMapConfig
participant MapConfigAPI as /api/map-config
participant Adapter as Adapter<br/>(Kakao/Google/OSM)
Client->>UserFacingMap: render with props
UserFacingMap->>useMapConfig: fetch config
useMapConfig->>MapConfigAPI: GET /api/map-config
MapConfigAPI-->>useMapConfig: { provider, keys }
useMapConfig-->>UserFacingMap: config & loading/error state
alt config loading
UserFacingMap->>UserFacingMap: render skeleton
else config error
UserFacingMap->>UserFacingMap: render error container
else config ready
UserFacingMap->>Adapter: dispatch based on provider
Adapter->>Adapter: initialize & render map
Adapter-->>Client: interactive map UI
end
sequenceDiagram
participant User
participant MapSearchOverlay
participant Client as Browser
participant SearchAPI as /api/places/poi-search
participant KakaoService as Kakao Service
participant KakaoAPI as Kakao Local API
User->>MapSearchOverlay: type query + focus
MapSearchOverlay->>MapSearchOverlay: debounce 250ms
MapSearchOverlay->>SearchAPI: GET with q, lat, lng, radius
SearchAPI->>KakaoService: searchPois(params)
alt cache hit
KakaoService-->>SearchAPI: cached PoiCandidate[]
else cache miss
KakaoService->>KakaoAPI: keyword search request
KakaoAPI-->>KakaoService: documents
KakaoService->>KakaoService: normalize & cache
KakaoService-->>SearchAPI: PoiCandidate[]
end
SearchAPI-->>MapSearchOverlay: { candidates }
MapSearchOverlay->>MapSearchOverlay: render dropdown
User->>MapSearchOverlay: click candidate
MapSearchOverlay->>Client: onPick(candidate)
Client->>Client: update form state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Introduces a pluggable user-facing map provider abstraction (OSM default, Kakao, Google stub) driven by
MAP_PROVIDERenv, and adds a floating POI name-search overlay on top of the interactive maps that hits Kakao's local keyword search and focuses the map on the picked result. OSM/OSS builds get the existing Leaflet behavior unchanged; Kakao deployments get richer place discovery for organizers on/events/create+ check-in flows on/places.Closes #166 (core: provider abstraction + Kakao place search; reverse geocoding and modal UI mode remain as follow-ups). Also partially addresses #110 and #116 — full forward geocoding via Nominatim and an abstract geocoding interface are out of scope here.
Assisted-By: Claude Code(claude-opus-4-7)
Summary by CodeRabbit
Release Notes
New Features
Chores