사이트 등록(/sites/new) 위저드의 "지도에서 선택" 모드, 사이트 상세 페이지의 폴리곤 표시에 Kakao Maps JavaScript SDK + Drawing 라이브러리 + Local Search API를 사용합니다.
앱 설정 → 플랫폼 → Web 메뉴는 폐기. 현재는 앱 → 플랫폼 키 → JavaScript 키 → JavaScript SDK 도메인에서 등록합니다. 개편 안내 docs
앱 1개를 등록한 뒤 JavaScript 키와 REST API 키를 발급받습니다. Web 플랫폼에 도메인 등록은 필수 — 미등록 도메인 호출 시 401.
.env.dev/.env.prod에 저장.
nurimaphttps://app.nurimap.com — 운영 앱https://dev-app.nurimap.com — 개발 앱 (Cloudflare Tunnel)http://localhost:3001 — 로컬 dev (envi2/app)nurimap.com, dev.nurimap.com)은 Maps SDK 안 씀 → 등록 불필요.SDK는 dapi.kakao.com/v2/maps/sdk.js에서 직접 로드. Drawing 사용 시 libraries=drawing 쿼리 추가.
// (protocol-relative)는 http/https 자동 매핑.autoload=false + kakao.maps.load(callback):// app/components/KakaoMapScript.tsx "use client"; import Script from "next/script"; export function KakaoMapScript() { const key = process.env.NEXT_PUBLIC_KAKAO_JS_KEY!; return ( <Script src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${key}&libraries=drawing&autoload=false`} strategy="afterInteractive" onLoad={() => { window.kakao.maps.load(() => { // 모든 maps API 초기화는 이 콜백 안에서 }); }} /> ); }
const container = document.getElementById("map"); const options = { center: new kakao.maps.LatLng(36.5, 127.5), // 한국 중앙 level: 13, // 줌 (낮을수록 확대) }; const map = new kakao.maps.Map(container, options);
LatLng(lat, lon)은 WGS84 EPSG:4326. PostGIS geometry(Polygon, 4326)과 좌표계 정확히 일치 — 변환 불필요.사용자가 폴리곤·마커·원으로 영역을 그리고, 좌표를 GeoJSON으로 추출해 POST /api/sites로 전송합니다.
const manager = new kakao.maps.drawing.DrawingManager({ map, drawingMode: [ kakao.maps.drawing.DrawingMode.MARKER, kakao.maps.drawing.DrawingMode.POLYGON, kakao.maps.drawing.DrawingMode.CIRCLE, ], polygonOptions: { draggable: true, removable: true, editable: true, strokeColor: "#10B981", fillColor: "#10B981", fillOpacity: 0.2, }, });
// 폴리곤 모드로 진입 manager.select(kakao.maps.drawing.OverlayType.POLYGON); // 그리기 완료 시 좌표 추출 kakao.maps.event.addListener(manager, "drawend", () => { const data = manager.getData(); // data.polygon : [{ points: [{x, y}, ...] }, ...] if (data.polygon.length > 0) { const coords = data.polygon[0].points.map(p => [p.x, p.y]); coords.push(coords[0]); // closed ring const geojson = { type: "Polygon", coordinates: [coords] }; } });
x=경도, y=위도. GeoJSON 표준 [lon, lat]과 동일.// GET /api/sites/{id}의 geom (GeoJSON Polygon) const polygon = new kakao.maps.Polygon({ path: geom.coordinates[0].map(([lon, lat]) => new kakao.maps.LatLng(lat, lon) ), strokeColor: "#047857", fillColor: "#10B981", fillOpacity: 0.25, }); polygon.setMap(map); // 폴리곤 중심으로 카메라 fit const bounds = new kakao.maps.LatLngBounds(); polygon.getPath().forEach(p => bounds.extend(p)); map.setBounds(bounds);
const circle = new kakao.maps.Circle({ center: new kakao.maps.LatLng(36.031, 129.389), radius: 1000, // meters strokeColor: "#10B981", fillColor: "#10B981", fillOpacity: 0.2, }); circle.setMap(map);
2026-05 기준. 비즈 앱과 일반 앱 동일.
| API | 일일 한도 | 설명 |
|---|---|---|
| Map SDK (JS / iOS / Android) | 300,000 | 지도 표시 + Drawing + 마커 (브라우저 SDK 모든 호출) |
| Local API (주소·키워드 검색) | 100,000 | REST API로 좌표↔주소 변환, 장소 검색 |
| Daum 검색 API | 50,000 | 웹 검색 (현재 미사용) |
| KakaoTalk 메시지·프로필 | 30,000 | (현재 미사용) |
두 가지 키를 모두 발급받고 용도별로 사용. 주소 검색은 서버 사이드(REST) 권장 — CORS 회피 + 키 노출 차단.
| 구분 | JavaScript SDK | REST API |
|---|---|---|
| 호출 위치 | 브라우저 | 서버 |
| 인증 키 | JavaScript 키 | REST API 키 (Authorization: KakaoAK ...) |
| 주 용도 | 지도 + Drawing + 마커 + 폴리곤 | 주소→좌표, 좌표→주소, 키워드 장소 검색 |
| 도메인 제약 | Web 플랫폼에 등록된 도메인만 | 없음 (서버 IP 기반) |
| 한도 | 300,000건/일 (Map SDK) | 100,000건/일 (Local API) |
| nurimap에서 | SiteMapPicker, 사이트 상세 미니맵 | GET /api/geocode/search?q=... |
// Spring Boot — KakaoLocalClient String url = "https://dapi.kakao.com/v2/local/search/address.json?query=" + URLEncoder.encode(q, StandardCharsets.UTF_8); HttpRequest req = HttpRequest.newBuilder(URI.create(url)) .header("Authorization", "KakaoAK " + restApiKey) .build(); // 응답: { "documents": [ { "address_name", "x"(lon), "y"(lat) }, ... ] }
nurimap 앱 진입 (OAuth용)KAKAO_REST_API_KEY)src/app/components/KakaoMapScript.tsx — next/script로 SDK 로드src/app/components/SiteMapPicker.tsx — Drawing Manager 래퍼src/app/components/SitePolygonView.tsx — 읽기 전용 폴리곤 표시(app)/sites/new/page.tsx 위저드 Step 3에서 <SiteMapPicker /> 사용(app)/sites/[id]/page.tsx 미니맵을 Kakao 폴리곤 view로 교체GET /api/geocode/search?q={주소} — Spring Boot가 Kakao Local Search 호출KakaoAK {REST_API_KEY} 설정[{ addressName, lat, lon }, ...]// envi2/app/src/app/(app)/layout.tsx import { KakaoMapScript } from "@/components/KakaoMapScript"; export default async function AppLayout({ children }) { // ... auth gate ... return ( <> <KakaoMapScript /> <div className="app">{/* ... */}</div> </> ); }
| 증상 | 원인 / 해결 |
|---|---|
Kakao is not defined | SDK 로드 전 호출 — 모든 maps 초기화는 kakao.maps.load(cb) 안에서. |
| 401 / 403 응답 | JavaScript SDK 도메인에 현재 도메인 미등록 — 앱 → 플랫폼 키 → JavaScript 키 → JavaScript SDK 도메인에서 추가. |
| 지도가 회색만 표시 | 컨테이너 <div> 너비/높이 0. CSS로 명시적 height: 360px 등 지정. |
kakao.maps.drawing undefined | SDK URL에 libraries=drawing 누락. |
| HTTP localhost 동작 안 함 | http://localhost:3001을 JavaScript SDK 도메인에 별도 등록 (https와 다른 항목). |
| 좌표가 거꾸로 (한국 → 일본) | LatLng(lat, lon) 순서 확인. Kakao x=lon, y=lat. |
| Local API CORS 차단 | 브라우저에서 직접 호출 금지 — Spring Boot 경유. |