소개
안녕하세요! 이번 글에서는 React와 Kakao Maps API를 활용해 다중경로최적화 지도 서비스를 개발하고 Vercel에 배포하는 과정을 상세히 공유합니다. 특별히 이 프로젝트는 Claude AI와 Cursor 에디터를 활용하여 개발했으며, AI 도구를 효과적으로 활용한 개발 방법론도 함께 소개합니다. 여러 목적지를 가장 효율적인 순서로 방문할 수 있는 경로를 계산해주는 이 서비스는 여행 계획이나 배송 경로 최적화 등에 유용하게 활용할 수 있습니다.
다중경로최적화란?
다중경로최적화(Multi-path Optimization)는 출발지에서 여러 목적지를 거쳐 최종 도착지까지 가는 가장 효율적인 경로를 찾는 과정입니다. 외판원 문제(Traveling Salesman Problem, TSP)의 변형으로, 거리, 시간, 비용 등을 최소화하는 최적의 경로를 계산합니다.
일상에서는 다음과 같은 상황에서 활용할 수 있습니다:
- 여행 계획에서 여러 관광지 방문 순서 최적화
- 배달 서비스의 효율적인 배달 경로 계획
- 영업사원의 고객사 방문 이동 경로 최적화
AI 기반 개발 도구 활용
Claude AI와 Cursor 에디터의 역할
이 프로젝트의 가장 큰 특징은 AI 도구를 적극 활용하여 개발 효율성을 높인 점입니다. 구체적으로 다음과 같은 방식으로 활용했습니다:
- Claude AI: 알고리즘 설계, 코드 구조화, 버그 디버깅에 Claude의 도움을 받았습니다. 특히 2-Opt 알고리즘 구현과 Kakao Maps API 연동 부분에서 Claude의 제안이 큰 도움이 되었습니다.
- Cursor 에디터: AI 기반 코드 에디터인 Cursor를 통해 코드 자동 완성과 리팩토링을 효율적으로 진행했습니다. Cursor의 AI 기능은 반복적인 패턴의 코드 작성 시간을 크게 단축시켰습니다.
AI 도구 활용의 구체적인 이점은 다음과 같았습니다:
- 개발 시간 단축 (약 40% 이상)
- 코드 품질 향상
- 버그 발견 및 수정 효율성 증가
- 알고리즘 최적화 아이디어 도출
개발 환경 설정
기술 스택
- 프론트엔드: React.js, Tailwind CSS
- 지도 API: Kakao Maps API
- 배포 플랫폼: Vercel
- 최적화 알고리즘: 2-Opt 알고리즘
- 개발 도구: Claude AI, Cursor 에디터
프로젝트 초기 설정
프로젝트 시작을 위해 Create React App을 사용해 기본 구조를 생성했습니다.
# React 프로젝트 생성
npx create-react-app multi-path-optimizer
# 필요 패키지 설치
cd multi-path-optimizer
npm install tailwindcss postcss autoprefixer
# Tailwind CSS 설정
npx tailwindcss init -p
Kakao Maps API 키 발급
지도 서비스 개발을 위해 Kakao Maps API 키가 필요합니다. 발급 과정은 다음과 같습니다:
- Kakao Developers 사이트에 가입 및 로그인
- 애플리케이션 추가
- 웹 플랫폼 등록 (localhost 및 배포 URL)
- JavaScript 키 발급 및 보안 설정
핵심 기능 구현
1. 지도 초기화 및 API 연동
가장 기본이 되는 지도 초기화 부분은 React의 useEffect 훅을 사용해 구현했습니다. 이 부분에서 Claude AI는 Kakao Maps API의 비동기 로딩 패턴을 제안해 주었습니다.
useEffect(() => {
const loadKakaoMap = () => {
// 이미 로드됐는지 확인
if (window.kakao && window.kakao.maps) {
initMap();
return;
}
const script = document.createElement('script');
script.async = true;
script.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.REACT_APP_KAKAO_MAP_API_KEY}&libraries=services&autoload=false`;
script.onload = () => {
window.kakao.maps.load(() => {
initMap();
});
};
document.head.appendChild(script);
};
loadKakaoMap();
}, []);
API 로드 후 지도를 초기화하는 함수도 추가했습니다.
const initMap = () => {
if (!mapRef.current) return;
const options = {
center: new window.kakao.maps.LatLng(37.5665, 126.9780),
level: 7
};
const map = new window.kakao.maps.Map(mapRef.current, options);
setKakaoMap(map);
// 검색 서비스 초기화
geocoder.current = new window.kakao.maps.services.Geocoder();
placesService.current = new window.kakao.maps.services.Places();
};
2. 위치 검색 기능
위치 검색 기능은 Kakao Maps API의 Places 서비스를 활용해 구현했습니다. Cursor 에디터의 AI 기능은 반복적인 코드 패턴을 인식하여 검색 결과 처리 부분을 효율적으로 작성하는 데 도움을 주었습니다.
const searchPlaces = () => {
if (!newLocation.trim() || !kakaoMap) return;
setIsSearching(true);
setSearchResults([]);
if (searchType === 'keyword') {
placesService.current.keywordSearch(newLocation, handleSearchResults);
} else {
geocoder.current.addressSearch(newLocation, handleSearchResults);
}
};
const handleSearchResults = (data, status) => {
if (status === window.kakao.maps.services.Status.OK) {
const results = data.map(item => ({
id: String(Date.now()) + Math.random(),
name: searchType === 'keyword' ? item.place_name : item.address_name,
lat: parseFloat(item.y),
lng: parseFloat(item.x),
address: item.address_name,
roadAddress: item.road_address?.address_name,
category: searchType === 'keyword' ? item.category_name : '주소'
}));
setSearchResults(results);
} else if (status === window.kakao.maps.services.Status.ZERO_RESULT) {
alert('검색 결과가 없습니다.');
}
setIsSearching(false);
};
3. 경로 최적화 알고리즘
경로 최적화의 핵심인 2-Opt 알고리즘을 구현했습니다. Claude AI는 이 복잡한 알고리즘의 구현에 필요한 핵심 로직을 제안해 주었고, Cursor는 코드 최적화를 도와주었습니다.
const twoOptAlgorithm = (locs, distanceMatrix) => {
// 초기 경로 설정
let route = [...Array(locs.length).keys()];
let bestDistance = calculateTotalDistance(route, distanceMatrix);
let improved = true;
let iterations = 0;
const maxIterations = 100;
while (improved && iterations < maxIterations) {
improved = false;
iterations++;
for (let i = 0; i < route.length - 2; i++) {
for (let j = i + 2; j < route.length; j++) {
const newRoute = twoOptSwap(route, i, j);
const newDistance = calculateTotalDistance(newRoute, distanceMatrix);
if (newDistance < bestDistance) {
route = newRoute;
bestDistance = newDistance;
improved = true;
break;
}
}
if (improved) break;
}
}
return route.map(index => locs[index]);
};
경로 최적화를 위한 거리 계산 함수도 구현했습니다.
const calculateDistance = (loc1, loc2) => {
const R = 6371; // 지구 반경 (km)
const dLat = deg2rad(loc2.lat - loc1.lat);
const dLng = deg2rad(loc2.lng - loc1.lng);
const a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(deg2rad(loc1.lat)) * Math.cos(deg2rad(loc2.lat)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
};
4. 시작점/도착점 지정 기능
사용자 경험을 개선하기 위해 시작점과 도착점을 고정하고, 중간 경유지의 순서만 최적화하는 기능을 추가했습니다. Claude AI의 도움으로 이 복잡한 로직을 간결하게 구현할 수 있었습니다.
const calculateOptimalRoute = () => {
if (locations.length < 2) {
alert('최소 2개 이상의 위치를 입력해주세요.');
return;
}
if (!startPoint || !endPoint) {
alert('시작점과 도착점을 모두 선택해주세요.');
return;
}
setIsCalculating(true);
try {
// 시작점/끝점을 제외한 중간 경유지만 최적화
const startLoc = locations.find(loc => loc.id === startPoint);
const endLoc = locations.find(loc => loc.id === endPoint);
const middlePoints = locations.filter(loc =>
loc.id !== startPoint && loc.id !== endPoint);
// 중간 경유지 최적화
const distanceMatrix = createDistanceMatrix(middlePoints);
const optimizedMiddlePoints = middlePoints.length > 0 ?
twoOptAlgorithm(middlePoints, distanceMatrix) : [];
// 최종 경로: 시작점 + 최적화된 중간경로 + 끝점
const finalRoute = [startLoc, ...optimizedMiddlePoints, endLoc];
displayOptimizedRoute(finalRoute);
setOptimizedRoute(finalRoute);
setIsCalculating(false);
} catch (error) {
setIsCalculating(false);
alert('경로 계산 중 오류가 발생했습니다.');
}
};
5. 경로 시각화
최적화된 경로를 지도 위에 시각적으로 표현하기 위해 마커와 폴리라인을 구현했습니다. Cursor 에디터의 AI 제안 기능은 이 코드의 가독성을 높이는 데 도움을 주었습니다.
const displayOptimizedRoute = (route) => {
if (!kakaoMap || !route || route.length < 2) return;
// 기존 마커와 경로 제거
clearRouteDisplay();
const newMarkers = [];
const pathCoordinates = [];
// 각 위치에 번호가 표시된 마커 생성
route.forEach((loc, index) => {
const position = new window.kakao.maps.LatLng(loc.lat, loc.lng);
pathCoordinates.push(position);
// 마커 이미지 설정
const markerSize = new window.kakao.maps.Size(35, 35);
const markerImage = new window.kakao.maps.MarkerImage(
`https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/marker_number_blue_${index + 1}.png`,
markerSize
);
// 마커 생성
const marker = new window.kakao.maps.Marker({
position: position,
map: kakaoMap,
image: markerImage
});
// 인포윈도우 설정
const infowindow = new window.kakao.maps.InfoWindow({
content: `
`,
removable: true
});
// 마커 클릭 이벤트
window.kakao.maps.event.addListener(marker, 'click', function() {
newMarkers.forEach(m => m.infowindow.close());
infowindow.open(kakaoMap, marker);
});
newMarkers.push({ marker, infowindow, location: loc });
});
// 경로선 그리기
const polyline = new window.kakao.maps.Polyline({
path: pathCoordinates,
strokeWeight: 4,
strokeColor: '#2196F3',
strokeOpacity: 0.7,
strokeStyle: 'solid'
});
polyline.setMap(kakaoMap);
setPolylines([polyline]);
// 마커 상태 업데이트
setMarkers(newMarkers);
// 지도 영역 조정
const bounds = new window.kakao.maps.LatLngBounds();
pathCoordinates.forEach(position => bounds.extend(position));
kakaoMap.setBounds(bounds, { padding: 150 });
};
UI/UX 디자인
반응형 레이아웃
모바일과 데스크톱 모두에서 사용하기 편리한 반응형 레이아웃을 Tailwind CSS로 구현했습니다. Claude AI는 효과적인 반응형 CSS 클래스 조합을 제안해 주었습니다.
<div className="min-h-screen bg-gray-50">
{/* 헤더 */}
<div className="bg-white shadow-sm border-b sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3">
<h1 className="text-xl sm:text-2xl font-bold text-gray-900">
다중경로최적화 지도
</h1>
</div>
</div>
{/* 메인 컨텐츠 */}
<div className="max-w-7xl mx-auto px-2 sm:px-4 lg:px-6 py-3 sm:py-6">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-3 sm:gap-6">
{/* 왼쪽 패널: 검색 및 컨트롤 */}
<div className="lg:col-span-1 space-y-3 sm:space-y-6">
{/* 검색 패널, 위치 목록 등 */}
</div>
{/* 오른쪽 패널: 지도 */}
<div className="lg:col-span-2 h-[calc(100vh-12rem)] lg:h-[calc(100vh-8rem)]">
{/* 지도 컨테이너 */}
</div>
</div>
</div>
</div>
AI 도구를 활용한 개발 워크플로우
Claude AI와 함께하는 개발 과정
프로젝트 진행 중 Claude AI를 활용한 주요 단계는 다음과 같습니다:
- 초기 설계: 프로젝트 구조와 핵심 기능을 Claude와 함께 설계했습니다.
- 알고리즘 개발: 2-Opt 알고리즘의 구현 방법을 Claude에게 질문하고 최적의 접근법을 도출했습니다.
- API 연동: Kakao Maps API 연동 시 발생한 문제들을 Claude의 제안을 통해 해결했습니다.
- 버그 디버깅: 발생한 버그의 원인을 Claude와 함께 분석하고 해결책을 찾았습니다.
- 코드 최적화: 완성된 코드를 Claude에게 보여주고 최적화 방안을 제안받았습니다.
Cursor 에디터의 활용
Cursor 에디터의 AI 기능은 다음과 같은 측면에서 개발 효율을 높였습니다:
- 코드 자동 완성: 반복적인 패턴의 코드를 빠르게 작성할 수 있었습니다.
- 리팩토링 제안: 더 효율적인 코드 구조로 리팩토링하는 제안을 받았습니다.
- 버그 탐지: 잠재적인 버그를 사전에 탐지하고 수정할 수 있었습니다.
- 문서화: 주석과 문서화를 자동으로 생성하여 코드 가독성을 높였습니다.
배포 과정
1. 환경 변수 설정
API 키 보안을 위해 환경 변수를 활용했습니다.
// .env 파일
REACT_APP_KAKAO_MAP_API_KEY=your_kakao_maps_api_key
2. GitHub 레포지토리 생성
프로젝트를 버전 관리하고 배포를 준비하기 위해 GitHub 레포지토리를 생성했습니다.
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/yourusername/multi-path-optimizer.git
git push -u origin main
3. Vercel 배포
무료로 배포하면서 환경 변수를 안전하게 관리할 수 있는 Vercel을 선택했습니다. Claude AI는 Vercel 배포 시 환경 변수 설정 방법을 상세히 안내해 주었습니다.
배포 과정은 다음과 같습니다:
- Vercel에 회원가입 및 로그인
- "New Project" 클릭 및 GitHub 레포지토리 가져오기
- 환경 변수 설정:
- NAME:
REACT_APP_KAKAO_MAP_API_KEY
- VALUE: 발급받은 Kakao Maps API 키
- NAME:
- "Deploy" 버튼 클릭
- 배포 완료 후 제공된 URL에서 서비스 확인
AI 도구를 활용한 개발의 이점과 교훈
개발 시간 단축
Claude AI와 Cursor 에디터를 활용함으로써 얻은 가장 큰 이점은 개발 시간 단축이었습니다. 특히 다음과 같은 작업에서 효율성이 크게 향상되었습니다:
- 복잡한 알고리즘 구현: 2-Opt 알고리즘 같은 복잡한 로직을 빠르게 구현
- API 연동 문제 해결: Kakao Maps API 연동 시 발생하는 문제들을 신속하게 해결
- UI 컴포넌트 구현: 반복적인 UI 패턴을 효율적으로 작성
한계와 교훈
AI 도구를 활용한 개발 과정에서 배운 몇 가지 교훈도 있습니다:
- 검증의 중요성: AI가 제안한 코드라도 항상 검증이 필요합니다.
- 맥락 이해의 한계: 프로젝트 전체 맥락을 AI에게 이해시키는 것은 쉽지 않습니다.
- 지식 업데이트 필요: 최신 API나 라이브러리에 대한 정보는 AI가 부족할 수 있습니다.
향후 개선 계획
이 프로젝트는 다음과 같은 방향으로 발전시킬 계획입니다:
- 실제 도로 네트워크 기반 경로 계산 추가
- 각 경로별 예상 소요 시간 계산 기능
- 사용자 경로 저장 및 공유 기능
- 실시간 교통 상황 반영
- AI 기반 최적 방문 시간 추천 기능
결론
React와 Kakao Maps API를 활용한 다중경로최적화 서비스를 Claude AI와 Cursor 에디터의 도움을 받아 개발한 과정은 매우 흥미롭고 효율적이었습니다. AI 도구는 복잡한 문제를 해결하는 과정에서 훌륭한 협업 파트너가 되어주었으며, 개발 효율성을 크게 향상시켰습니다.
이러한 AI 도구를 활용한 개발 방식은 앞으로 더욱 보편화될 것으로 보이며, 개발자들이 더 창의적이고 핵심적인 문제 해결에 집중할 수 있게 도와줄 것입니다.
이 글이 비슷한 프로젝트를 계획하고 있는 개발자분들, 특히 AI 도구를 활용한 개발에 관심이 있는 분들께 도움이 되길 바랍니다. 궁금한 점이나 의견이 있으시면 댓글로 남겨주세요.
배포된 어플리케이션: