Skip to content

feat: geocoder 국가 기준 라우팅 및 Google Places 연동 - #72

Open
minsour wants to merge 6 commits into
mainfrom
feature/GM-112-overseas-geocoding
Open

feat: geocoder 국가 기준 라우팅 및 Google Places 연동#72
minsour wants to merge 6 commits into
mainfrom
feature/GM-112-overseas-geocoding

Conversation

@minsour

@minsour minsour commented Aug 16, 2026

Copy link
Copy Markdown
Member

📌 Related Issue

GM-112

🚀 Description

인스타 게시글에서 뽑은 장소를 국가 기준으로 다른 지오코더에 태웁니다. 국내는 Kakao, 해외는 Google Places(Text Search)로 갑니다.

AI 추출 스키마에 country_code(ISO 3166-1 alpha-2)를 추가하고 그 값으로 provider를 고릅니다. supports()는 provider의 능력만 답하고, 무엇을 우선 쓸지는 GEOCODER_PROVIDERS 주입 순서가 정합니다.

Kakao를 국가로 먼저 거르는 이유는, 해외 질의에 0건이 아니라 이름이 겹치는 국내 장소를 줄 수 있기 때문입니다(예: "파리 에펠탑" → 상호에 에펠탑이 든 국내 업소). 오탐은 0건보다 나쁘고 "0건이면 다른 provider로" 같은 fallback으로는 감지되지 않아서, 라우팅 신호를 앞단에서 잡았습니다.

해외 인스타 URL로 실호출까지 확인했습니다.

✅ Done

  • Places API (New) 활성화
  • 서버용 API 키 발급 (Places API (New) 전용 제한)
  • GeoQuery.countryCode + GeocoderProvider.supports() 도입, searchAllsearch
  • GoogleProvider 구현 (Places API New searchText) 및 [kakao, google] 등록
  • GOOGLE_MAPS_API_KEY 필수 env 추가
  • 도달 불가였던 GEOCODER_ALL_PROVIDERS_FAILED, provider 혼합 시절 설계였던 PROVIDER_PRIORITY·completeness 랭킹 제거
  • 테스트: unit 122 / e2e 9 통과

📢 Notes

📢 클라이언트 영향 (계약 변경 4건)

  1. matches 순서 변경 — 자체 랭킹을 없애고 provider 순서를 그대로 냅니다. Kakao는 주소 기준 거리순, Google은 자체 relevance로 이미 정렬해 주므로 재정렬이 그 신호를 덮기만 했습니다
  2. phone 필드 제거 — Google에서 전화번호는 상위 요금 티어(Enterprise) 필드라, 이 한 줄에 월 무료 한도가 5,000건 → 1,000건으로 줄어듭니다. Kakao도 맞춰서 제거했습니다. 국내 장소도 전화번호가 없어지므로 기획 확인이 필요할 수 있습니다
  3. address가 지번 → 도로명 (도로명 없는 장소는 지번 폴백)
  4. extracted.countryCode 추가

💰 비용

https://app.notion.com/p/Google-Places-API-3bebee7f599680e28efbee2509bae910?source=copy_link
위 문서를 참고해주세요.

알려진 한계

  • regionCode는 하드 필터가 아니라 편향이라 국경 근처·동명 장소는 다른 나라 결과가 섞일 수 있습니다
  • 국가 오분류 시 다른 provider로 재시도하는 fallback을 두지 않았습니다. 0건은 이미 정상 계약이고(응답 스펙·mock에 빈 케이스 포함), 오분류는 재시도로 덮기보다 프롬프트에서 잡는 게 맞다고 판단했습니다. 오분류율은 실제 게시글로 측정이 필요합니다
  • places.phone 컬럼은 남겼습니다. 아직 places에 쓰는 코드가 없고 마이그레이션 번호 충돌 우려가 있어 영속화 작업에서 함께 다룹니다
  • distance는 소비처 없이 유지 중입니다 (Kakao 주소 경로에서만 채워짐)

후속 작업

  • 해외 장소의 외부 지도 앱 딥링크 기획 논의 — 카카오맵에 없을 수 있어 provider별 분기 필요 (PRD 미결 10번으로 추가)

- searchAll -> search: 모든 provider에 쏘고 병합하던 동작이 하나를 고르는 것으로
  바뀌어 이름이 맞지 않는다. 도달 불가였던 GEOCODER_ALL_PROVIDERS_FAILED도 제거한다.
- 후보가 한 provider에서만 오므로 PROVIDER_PRIORITY 랭킹 기준을 제거한다.
- 검색용 필드(place_name/area_name)는 국가 기준 표기로, relation은 원문 언어로 뽑도록 프롬프트를 수정한다.
GEOCODER_PROVIDERS가 [kakao, google]이 되면서 "국내는 Kakao, 나머지는 Google"이라는
정책이 주입 순서 하나로 표현된다.

- Places API (New) searchText는 주소와 상호명을 한 문자열로 처리하므로 Kakao 같은
  2단계 주소 검색을 두지 않는다. 왕복이 늘면 그만큼 요금이 붙는다.
- Kakao(무료 쿼터)와 달리 요청당 과금이라 FieldMask를 매핑에 쓰는 7개로 제한하고
  maxResultCount도 5로 잡는다.
- 응답은 값이 없는 필드를 빈 문자열이 아니라 생략하고, 0건이면 places 키 자체가
  빠지므로 스키마를 그에 맞춘다. searchText는 거리를 주지 않아 distance는 비운다.
- GOOGLE_MAPS_API_KEY는 필수 env로 둔다. 없으면 해외 장소가 조용히 0건이 된다.
Google Places는 전화번호가 상위 요금 티어(Enterprise) 필드여서 이 한 줄에
월 무료 한도가 5,000건에서 1,000건으로 줄어든다. Kakao 쪽도 함께 빼서
provider 간 후보 형태를 맞추고, 채우는 provider가 없어진 GeoCandidate.phone과
그 소비처(랭킹 점수·Swagger·mock)를 정리한다.

places.phone 컬럼은 아직 쓰는 코드가 없어 영속화 작업에서 함께 다룬다.
표시용으로 도로명이 적합하고, Google이 주는 formattedAddress도 도로명 기반이라
provider 간 주소 표기가 맞는다. 도로명이 없는 장소는 빈 문자열로 오므로 지번으로
떨어뜨린다. 스키마에만 있고 쓰이지 않던 road_address_name이 실제 소비처를 갖는다.
completeness 랭킹은 두 provider 후보를 한 풀에 섞던 시절의 설계였다. 한 질의를
한 provider가 처리하게 되면서 재정렬이 provider의 랭킹을 덮는 쪽으로만 작동한다.

Kakao는 주소 기준 거리순(sort=distance)으로, Google은 자체 relevance로 이미
정렬해서 준다. 특히 Google 후보는 distance가 없고 category 유무가 갈려서, 관련도와
무관한 신호로 1순위가 뒤로 밀릴 수 있었다.

matches 순서가 바뀌므로 클라이언트에 공유가 필요하다.
Google provider가 미구현이라는 서술이 거짓이 되어 국가 기준 라우팅으로 고치고,
운영 전 필요한 Places API 활성화·키 주입을 상태 표에 남긴다.

두 provider의 카테고리 체계가 실제로 공존하기 시작해 정규화 규칙 확정을 지도뷰의
선행 조건으로 올리고, 해외 장소 때문에 새로 생긴 미결 2건(외부 지도 앱 딥링크,
표시 이름 언어)을 추가한다.
@minsour minsour self-assigned this Aug 16, 2026
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b279a098-92e4-4887-976a-d874338490c1


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@labyrinth30 labyrinth30 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이제 해외도 되니까 좋네요. approve하겠습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants