generated from ttipo/project-base
docs: 착수 전 조사와 공공데이터 점검 결과 정리
개발 전에 확정해야 할 전제(데이터 저장 가능 범위·지도 SDK·계정 리드타임)와 공공데이터 실측 결과를 남긴다. - pre-dev-check: 카카오 장소 데이터 저장·LLM 전송 금지 조건, 지도 SDK 비교 (네이버 권장), 스토어·위치기반서비스 신고 등 계정·승인 체크리스트 - data-openapi-review: 관광공사 국문·영문·반려동물, 상가정보, 단기예보 매뉴얼 검토 - data-check: 서울·부산·대구 점검 요약과 원자료(JSON, 키 미포함) 10-29 점검의 관광공사·반려동물 개수는 위치 검색으로 센 과소 집계였다. 2026-11-02 재측정 결과를 각 요약 맨 위에 정정 메모로 달았다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
# WanderGo 착수 전 계정·승인 체크리스트 (2026-10-29 조사)
|
||||
|
||||
> 범위: Flutter(iOS+Android) + NestJS, 한·영 출시. 소유자가 직접 신청한다는 전제로 **무엇을, 어떤 순서로, 어떤 서류로, 얼마나 걸리는지, 무엇이 무엇을 막는지**를 정리했다.
|
||||
> 기존 조사(`WanderGo 기획 검토 자료조사/public_apis.md`, `legal_policy.md`)의 쿼터·위치정보법 기본 내용은 반복하지 않고 **절차**만 더했다.
|
||||
>
|
||||
> **출처 표기**
|
||||
> - **[fetched]** 이번 세션에 원문 페이지를 직접 열어 확인
|
||||
> - **[snippet]** 검색 결과 요약으로만 확인(원문 미열람, 신뢰도 낮음)
|
||||
> - **[3rd-party]** 블로그·커뮤니티·타사 도움말(경험담)
|
||||
> - **[prior]** 기존 조사 노트에서 가져옴(그 노트의 표기 유지)
|
||||
> - **[inference]** 근거를 조합한 추정
|
||||
> - **unconfirmed** 확인 못 함 — 추측하지 않음
|
||||
>
|
||||
> **접근 제한**: developers.naver.com 은 WebFetch 와 브라우저 도구 양쪽에서 "safety restrictions" 로 차단되었다. 네이버 로그인 검수 항목은 전부 3rd-party 근거다. law.go.kr 대신 casenote.kr 미러를 썼다(기존 노트와 같은 방식).
|
||||
|
||||
---
|
||||
|
||||
## Takeaway
|
||||
|
||||
1. **가장 긴 리드타임은 Google Play 신규 개인 계정의 "12명 × 연속 14일 비공개 테스트 + 프로덕션 신청 심사(≤7일)"** 다. 최소 3–4주이므로 Android 빌드가 돌아가는 즉시 테스트를 시작해야 한다. 조직 계정으로 피하려면 D-U-N-S(최대 30일)가 필요하다.
|
||||
2. **도메인 + 홈페이지 + 개인정보처리방침·위치기반서비스 이용약관 + 계정 삭제 웹 페이지가 숨은 선행 조건**이다. Google 브랜드 인증, 카카오 공유 웹 도메인, Apple Services ID(Android 의 Apple 로그인), 네이버 검수, 공공데이터 활용사례, 스토어 등록이 모두 여기에 걸린다. 코드보다 먼저 만든다.
|
||||
3. **사업자등록은 대부분의 API 에 필요 없다.** 공공데이터포털, 카카오(개인 개발자 비즈 앱으로 이메일 선택 동의 가능), 네이버, Apple(개인), Google Play(개인)는 모두 개인으로 된다. **실질적으로 필요한 곳은 위치기반서비스사업 신고**다(신고서에 상호·사무소, 사업자등록증 확인). Apple 의 "조직" 등록은 **법인만** 된다(개인사업자는 개인으로 등록하고, 판매자명에 실명이 나온다).
|
||||
4. **한국 개발자 특유 요건 2가지**: (a) 2026-01-01부터 한국 기반 개발자는 Sign in with Apple **Services ID 등록·수정 시 서버-서버 알림 엔드포인트 필수**(Android/웹에서 Apple 로그인을 쓰면 해당). (b) 위치기반서비스사업 신고는 **수리가 필요한 신고**다(제9조⑤). 소상공인·1인 창조기업이 아니면 출시 전에 수리되어야 하고, 해당하면 개시 후 1개월 안에 신고하면 된다.
|
||||
5. **출시 직전 병목**은 네이버 로그인 검수(검수 전에는 등록한 테스트 ID 만 로그인 가능 → App Store 심사원이 로그인 못 함)와 공공데이터 운영계정(활용사례에 URL·개시일·화면 필요)이다. 카카오맵 무료 쿼터는 **개발자 계정에서 처음 활성화한 앱에만** 주므로, 첫날 **실서비스용 앱**에서 카카오맵을 켠다.
|
||||
|
||||
---
|
||||
|
||||
## 체크리스트 (의존 순서)
|
||||
|
||||
단계: **A = 코드 작성 전**, **B = 베타(TestFlight·Play 비공개 테스트) 전**, **C = 스토어 출시 전**
|
||||
|
||||
| # | 단계 | 어디서 | 사업자 필요? | 준비물 | 리드타임 | 막는 것 | 시점 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 0 | 사업 형태 결정 (개인 / 개인사업자 / 법인) | — | — | 위치 신고 특례(소상공인·1인 창조기업) 해당 여부 확인 | 결정만 | Apple 판매자명, Play 계정 유형, 위치 신고 경로 | A |
|
||||
| 1 | 사업자등록 (개인사업자 기준) | 홈택스 | — | 신분증, 사업장 주소, 업종 | 원칙 2일, 확인 필요 시 연장 [3rd-party] | #13 위치 신고(소상공인확인서 포함) | A (늦어도 B) |
|
||||
| 2 | 도메인 + 홈페이지 + 개인정보처리방침·위치기반서비스 이용약관 초안 + 계정 삭제 웹 페이지 | 도메인 등록업체, 정적 호스팅 | 아니오 | 앱 설명, 처리방침(위치·국외이전 포함) | 1–3일(법률 검토 별도) | #9 Services ID, #12 카카오 공유 도메인, #14 Google 브랜드 인증, #15 네이버 검수, #16 활용사례, #17 스토어 | A |
|
||||
| 3 | 공공데이터포털 가입 + 개발계정 5건: 국문 KorService2, 영문 EngService2, 반려동물, 단기예보, 중기예보 | data.go.kr | 아니오 [3rd-party] | 활용 목적 | 자동승인 = 즉시 [fetched] | 백엔드 수집기 개발 | A |
|
||||
| 4 | 카카오 앱 생성 → **카카오맵 사용 설정 ON(이 앱을 가장 먼저)** → 플랫폼 키(패키지명·키 해시·번들 ID) → 카카오 로그인 ON·리다이렉트 URI → 동의항목(닉네임/프로필). 이메일이 필요하면 **개인 개발자 비즈 앱 전환** | developers.kakao.com | 아니오(개인 개발자 비즈 앱 = 본인인증 + 앱 아이콘) | 번들 ID/패키지명 확정, 디버그 키 해시, 앱 아이콘 | 당일 | 로그인·장소검색·공유 개발 | A |
|
||||
| 5 | 네이버 개발자센터 앱 등록(개발 중, 테스트 ID 등록) / NCP 가입 + **결제수단 등록** + Maps Application | developers.naver.com / console.ncloud.com | 아니오 [3rd-party] / NCP 개인 회원은 신용카드만 [snippet] | 패키지명·번들 ID, 콜백 | 당일 | 네이버 로그인·지도 개발 | A |
|
||||
| 6 | Apple Developer Program | developer.apple.com | 개인 = 아니오 / 조직 = **법인 + D-U-N-S** | 2단계 인증 Apple 계정, 실명 | 개인: unconfirmed(보통 1–2일) / 조직: D-U-N-S 최대 5영업일 [snippet] + Apple 검토 | App ID, Sign in with Apple capability, TestFlight | A |
|
||||
| 7 | Google Play Console(개인, 25달러) + 앱 생성 | play.google.com/console | 개인 = 아니오 / 조직 = D-U-N-S(최대 30일) | 신원(결제 프로필 실명·주소), 이메일·전화 OTP 인증 | 신원 인증 수일(unconfirmed) | #11 비공개 테스트 시작, Play 앱 서명 키 SHA-1 | A |
|
||||
| 8 | Google Cloud OAuth: 동의 화면(Testing) + Android·iOS·Web 클라이언트 ID | console.cloud.google.com | 아니오 | 패키지명 + SHA-1, 번들 ID | 당일 | Google 로그인 개발 | A |
|
||||
| 9 | Sign in with Apple 키 + **Services ID(+ 서버-서버 알림 URL, 한국 필수)** | Apple Certificates, Identifiers & Profiles | 아니오 | 배포된 HTTPS 백엔드 엔드포인트, 도메인, 리턴 URL | 당일(엔드포인트 배포가 선행) | Android 의 Apple 로그인, 탈퇴 시 토큰 폐기 | B |
|
||||
| 10 | 릴리스 서명 반영: 업로드 키 + Play 앱 서명 키의 **키 해시(카카오)·SHA-1(Google)** 등록 | 카카오 / GCP | 아니오 | Play Console 앱 서명 키 정보 | 당일 | 베타에서 로그인 실패 방지 | B |
|
||||
| 11 | **Play 비공개 테스트 12명 이상 × 연속 14일 → "프로덕션 신청"** | Play Console | 아니오 | 테스터 12명 이상 확보, 동작하는 빌드 | 14일 + 심사 보통 7일 이내 [fetched] | Android 출시 | B 시작 → C |
|
||||
| 12 | 카카오톡 공유: [앱] > [제품 링크 관리] > 웹 도메인 등록, 템플릿 | developers.kakao.com | 아니오 | #2 도메인 | 당일 | 공유 링크 동작 | B |
|
||||
| 13 | **위치기반서비스사업 신고** (방송미디어통신위원회) | 과기정통부 전자민원센터 emsit.go.kr (간편인증) | **사실상 예**(사업자등록증 확인) [inference] | 신고서, 사업계획서, 위치정보 보호조치 증빙, 설비 위치 서류 / 특례: 소상공인확인서(또는 1인 창조기업 증빙) + 사업내용 설명자료 | 서류 1–2주 [prior] + 소상공인확인서 약 1주 + 수리 최대 약 2주 [3rd-party]; 수수료 없음 [3rd-party] | 일반 신고: **출시(사업 개시)** / 특례: 개시 후 1개월 안에 신고 | B에 제출 → C |
|
||||
| 14 | Google OAuth **게시(Published) + 브랜드 인증** | GCP Google Auth Platform | 아니오 | 인증된 도메인(Search Console), 홈페이지, 처리방침 | 자동 수분 / 수동 2–3영업일; 결과 7일 안에 게시 [fetched] | 테스트 사용자 외 로그인, 동의 화면 앱 이름 표시 | B 말–C |
|
||||
| 15 | **네이버 로그인 검수** | 네이버 개발자센터 | 아니오 [3rd-party] | 로그인~가입 완료 전 화면 캡처, 버튼 가이드 준수, 제공 정보 = 실제 가입 항목 | 3–4영업일 [3rd-party]; 반려 대비 1–2주 확보 | 일반 사용자의 네이버 로그인, App Store 심사 | C |
|
||||
| 16 | **공공데이터 운영계정**: 활용사례 등록 → 운영계정 신청(희망 트래픽 기재) | data.go.kr 마이페이지 | 아니오 | 활용사례명, 웹 URL, 서비스 개시일, 대표 이미지 [fetched gov.kr] | KTO 심의 보통 2–3일 / 기상청 자동승인 [fetched] | 출시 후 트래픽(개발계정 1,000/일) | C |
|
||||
| 17 | 스토어 제출: App Store(4.8 Apple 로그인, 5.1.1(v) 앱 내 탈퇴 + 토큰 폐기), Play(데이터 보안 + 삭제 URL) | App Store Connect / Play Console | 아니오 | 처리방침 URL, 삭제 웹 링크, 심사용 계정 | App Review: unconfirmed | 출시 | C |
|
||||
|
||||
**막힘 관계 요약**: #2 → #9·#12·#14·#15·#16·#17 / #1 → #13 / #7 → #10·#11 → Android 출시 / #6 → #9 → Android Apple 로그인 / #15 → iOS 심사(네이버 버튼이 있으면) / #13 수리(일반) → 출시
|
||||
|
||||
---
|
||||
|
||||
## 서비스별 근거
|
||||
|
||||
### 1. 공공데이터포털 — TourAPI · 기상청
|
||||
|
||||
**개발계정 vs 운영계정**
|
||||
- 신청 순서는 "1단계 개발계정 신청 → 2단계 운영계정 신청"이다. 단계 안내는 텍스트가 아니라 이미지로만 있다 — [data.go.kr 활용방법 [fetched]](https://www.data.go.kr/ugs/selectPublicDataUseGuideMetView.do)
|
||||
- 승인 방식 [fetched, 같은 페이지]
|
||||
- 자동승인: "별도 확인 없이 승인신청과 동시에 자동으로 승인되는 경우"
|
||||
- 심의승인: 제공기관 담당자 승인. "신청 후 보통 2~3일 정도 소요가 되며", 결과는 가입 이메일로 통보
|
||||
- 데이터셋별 심의유형·트래픽 [fetched]
|
||||
|
||||
| 데이터셋 | 심의유형 | 트래픽 |
|
||||
| --- | --- | --- |
|
||||
| 국문 관광정보 GW 15101578 | 개발 자동 / **운영 심의** [prior] | 개발 1,000 |
|
||||
| 영문 관광정보 GW 15101753 | "개발단계 : 자동승인 / 운영단계 : 심의승인" | 개발 1,000 |
|
||||
| 반려동물 동반여행 15135102 | 개발 자동 / **운영 심의** [prior] | 개발 1,000 |
|
||||
| 기상청 단기예보 15084084 | "개발단계 : 자동승인 / 운영단계 : 자동승인" | 개발 10,000 |
|
||||
| 기상청 중기예보 15059468 | "개발단계 : 자동승인 / 운영단계 : 자동승인" | 개발 10,000 |
|
||||
|
||||
운영계정 트래픽은 모두 "활용사례 등록시 신청하면 트래픽 증가 가능"이라고만 적혀 있고 **숫자는 공개되지 않았다** — [15101753](https://www.data.go.kr/data/15101753/openapi.do), [15084084](https://www.data.go.kr/data/15084084/openapi.do), [15059468](https://www.data.go.kr/data/15059468/openapi.do)
|
||||
- **활용사례 등록 항목** [fetched]: 활용 공공데이터, 활용 OpenAPI, 활용 사례명, 분류 체계, 개발유형, **웹 URL**, **서비스 개시일**, 개발자 소재지, 설명, 활용 목적, **대표 이미지**·추가 이미지. 접수기관 한국지능정보사회진흥원(1566-0025). 페이지 최종 수정 2024-10-28 — [정부24 공공데이터 활용사례 등록](https://www.gov.kr/portal/service/serviceInfo/PTR000050580)
|
||||
- 운영계정 신청 위치: "[마이페이지 > API 활용현황]에서 … [운영계정신청] 버튼", 신청 시 원하는 트래픽을 적는다 — [snippet; 다른 기관 포털 안내문에서 나온 문구로, data.go.kr 원문은 이미지라 미확인]
|
||||
- 사업자등록: "인증키 발급은 무료이며, 개인과 기업 모두 동일한 절차로 신청할 수 있습니다" — [studygov.kr 2026-02-06 [3rd-party]](https://studygov.kr/blog/13071-tourism-info-service/)
|
||||
- 개발계정 승인 "10분 ~ 3일" — [wikidocs [3rd-party, snippet]](https://wikidocs.net/292158)
|
||||
|
||||
**추정·주의 [inference]**
|
||||
- 활용사례에 URL·개시일·화면이 필요하므로 운영계정은 **베타 화면이 나온 뒤**에야 신청할 수 있다. 랜딩 페이지 URL과 베타 스크린샷으로 신청할 수 있는지는 unconfirmed.
|
||||
- 국문·영문·반려동물은 **각각 별도 활용신청**이므로 운영계정 신청도 3건이다.
|
||||
- 개발 단계에서는 전량 동기화를 하지 말고, 지역·유형을 좁힌 증분 수집으로 1,000/일 안에서 개발한다 [prior 노트의 권고와 같음].
|
||||
|
||||
**Unconfirmed**: 운영계정 승인 후 실제 트래픽 수치, 인증키 유효기간(흔히 "2년"이라 하지만 근거 못 찾음)과 연장 절차.
|
||||
|
||||
### 2. Kakao Developers — 로그인 · 공유 · 로컬(카카오맵)
|
||||
|
||||
**2025-12-03 콘솔 개편** [fetched]
|
||||
- 출처: [앱 키 마이그레이션](https://developers.kakao.com/docs/ko/getting-started/app-key-migration)
|
||||
- 플랫폼 설정이 앱 키별로 바뀌었다.
|
||||
- 리다이렉트 URI·클라이언트 시크릿은 [앱] > [플랫폼 키] > [REST API 키]로 옮겨졌다.
|
||||
- 웹 도메인은 두 곳으로 나뉜다.
|
||||
- API 호출 검증: [JavaScript 키] > JavaScript SDK 도메인
|
||||
- 카카오톡 메시지·공유 링크: **[앱] > [제품 링크 관리] > 웹 도메인**
|
||||
- 키는 종류별로 최대 5개까지 만들 수 있다.
|
||||
- 블로그·튜토리얼의 메뉴 경로는 대부분 개편 전 기준이다.
|
||||
- 2026-03-19부터 REST API 테스트 도구에서 어드민 키 인증이 빠졌다 [snippet].
|
||||
|
||||
**비즈 앱** [fetched]
|
||||
- 출처: [앱 설정](https://developers.kakao.com/docs/ko/app-setting/app)
|
||||
- 비즈 앱에서만 되는 것: 이메일을 **필수 동의**로 설정, 테스트 앱 생성(원본 앱당 최대 5개), 와일드카드 서브도메인, 비즈니스 인증 동의항목.
|
||||
- 공통 요건: 앱 아이콘. 비즈니스 정보는 오너만 등록할 수 있다.
|
||||
- 국내 사업자는 사업자등록번호를 쓴다.
|
||||
- **개인 개발자 비즈 앱**(사업자번호 없음)
|
||||
- 경로: [앱] > [일반] > [비즈니스 정보] > [개인 개발자 비즈 앱]
|
||||
- 조건: 오너가 **본인인증** 완료 + 카카오비즈니스 통합 서비스 약관 동의
|
||||
- 제한: 비즈니스 채널을 연결할 수 없다.
|
||||
- 약관상 정의는 2024-12-01부터 "사업자 정보가 등록되거나 개인 인증이 완료된 애플리케이션"이다 — [DevTalk 공지 2024-10-22 [fetched]](https://devtalk.kakao.com/t/topic/140256)
|
||||
- 같은 공지에서 쿼터 합산 기준이 개발자 계정에서 **앱 단위**로 바뀌었다.
|
||||
|
||||
**동의항목 권한** [fetched]
|
||||
- 출처: [카카오 로그인 활용](https://developers.kakao.com/docs/ko/kakaologin/utilize)
|
||||
- 닉네임·프로필 사진: 모든 앱에서 기본 제공
|
||||
- 카카오계정(이메일): **비즈 앱·테스트 앱**에서만
|
||||
- 이름·성별·연령대·생일·전화번호 등: "추가 기능 신청으로 권한을 받아야" 한다.
|
||||
- 검수 기간은 3–5영업일이다. 필수를 선택으로 낮추는 변경은 추가 검수가 없다 — [사전 설정 [fetched]](https://developers.kakao.com/docs/ko/kakaologin/prerequisite)
|
||||
- 추가 기능 신청에는 개인정보처리방침 URL이 필요하다. 처리방침에 수집 목적(회원가입), 수집 항목, 필수·선택 여부를 적어야 하고, 신청 내용과 일치해야 한다 — [같은 페이지 [fetched]]
|
||||
- "개인개발자 비즈앱도 이메일 선택동의 설정 하실 수 있습니다" — [DevTalk 2026-09-28 [3rd-party, 응답자 소속 미표시]](https://devtalk.kakao.com/t/id-1589651/151858). 개인 개발자 비즈 앱에서 **이메일 필수 동의**가 되는지는 unconfirmed.
|
||||
- 비즈니스 정보 심사 반려 사유 [fetched]
|
||||
- 출처: [DevTalk FAQ 2023-10-12](https://devtalk.kakao.com/t/faq/132272)
|
||||
- 기재 정보와 사업자등록증 사본이 다른 경우
|
||||
- 개인정보(주민번호 등)를 가리지 않은 경우
|
||||
- 소개 페이지도 없고 앱마켓 등록 앱도 없는 경우: 권한 신청이 제한된다.
|
||||
- 웹사이트가 없으면 앱마켓 정보로 대신 낼 수 있다.
|
||||
|
||||
**카카오 로그인 설정** [fetched, 사전 설정 페이지]
|
||||
- 상태가 OFF면 KOE004, 리다이렉트 URI가 등록값과 "완전히 동일"하지 않으면 KOE006.
|
||||
- REST API 키에 클라이언트 시크릿이 켜져 있으면 토큰 요청에 시크릿을 넣어야 한다.
|
||||
- **개인정보 국외 이전**(이전 국가·업체·연락처)을 입력하면 로그인 화면에 필수 동의가 추가된다.
|
||||
|
||||
**연결 끊기(탈퇴 시)** [fetched]
|
||||
- 출처: [REST API](https://developers.kakao.com/docs/ko/kakaologin/rest-api)
|
||||
- `POST https://kapi.kakao.com/v1/user/unlink`
|
||||
- 액세스 토큰 대신 **어드민 키 + `target_id_type=user_id` + `target_id`** 로 서버에서 호출할 수 있다. 사용자 토큰을 서버에 저장하지 않아도 된다.
|
||||
- 사용자가 카카오 쪽에서 연결을 끊으면 연결 해제 웹훅이 온다. 서비스는 탈퇴·파기 처리 후 응답해야 한다 [fetched, utilize 페이지].
|
||||
|
||||
**플랫폼 등록** [fetched, 앱 설정]
|
||||
- Android 패키지명 + **키 해시**(개발 환경별 등록), iOS 번들 ID
|
||||
- 불일치 시 `invalid android_key_hash or ios_bundle_id or web_site_url`
|
||||
- Flutter SDK 최소 요건: Flutter 3.38.0 / Dart 3.9.0 / Android API 21 / iOS 13 — [Flutter 시작하기 [fetched]](https://developers.kakao.com/docs/ko/flutter/getting-started)
|
||||
- URL 스킴 `kakao{NATIVE_APP_KEY}`, LSApplicationQueriesSchemes에 `kakaokompassauth`, `kakaolink` 추가 — [같은 페이지]
|
||||
- [inference] 릴리스 업로드 키와 Play 앱 서명 키의 키 해시도 추가해야 Play 배포본에서 로그인이 된다(일반 지식, 이번 세션 원문 미확인).
|
||||
|
||||
**카카오톡 공유** [fetched]
|
||||
- 출처: [공유 개요](https://developers.kakao.com/docs/ko/kakaotalk-share/common)
|
||||
- SDK 전용이다(REST 미지원). Flutter SDK 2.1.0 이상.
|
||||
- 비즈 앱·권한은 공유 대상 화면 커스터마이즈(친구만 보기 등)에만 필요하다. 기본 공유는 불필요.
|
||||
- 링크 도메인은 [제품 링크 관리] > 웹 도메인에 등록해야 한다. 미등록 도메인은 오류가 나거나 대표 도메인으로 이동한다 [snippet, DevTalk].
|
||||
- 쿼터·가격은 [prior](commercial_map_apis.md)에 있다: 30,000/일, 초과분 프로모션 10원(2027-12-31까지).
|
||||
|
||||
**로컬 API(장소 검색)** [fetched]
|
||||
- 출처: [카카오맵 이해하기](https://developers.kakao.com/docs/ko/kakaomap/common)
|
||||
- "[카카오맵] > [사용 설정]의 [상태]를 [ON]"으로 해야 한다. 2026-07-21부터 심사 없이 바로 활성화된다.
|
||||
- "카카오맵 API는 개발자 계정 기준 첫 번째로 활성화한 앱에만 무료 쿼터를 제공합니다." 두 번째 앱이나 무료 쿼터 초과분은 "비즈월렛 연결 후 유료 API 사용 설정"이 필요하다.
|
||||
- 무료량을 다 쓰면 429가 난다.
|
||||
- 비즈월렛에는 **자동결제 카드**가 필수다. 후불 세금계산서 정산은 없다 — [DevTalk 2026-07-13 [fetched]](https://devtalk.kakao.com/t/topic/150648)
|
||||
- 사업자 없이 비즈월렛을 만들 수 있는지는 unconfirmed.
|
||||
|
||||
### 3. Naver — 네이버 로그인 · NCP Maps
|
||||
|
||||
**네이버 로그인 검수** (전부 3rd-party — 공식 문서 열람 불가)
|
||||
- 검수 전 상태: "서비스가 '개발중' 상태이기 때문에 등록한 테스트 아이디를 통해 로그인 테스트"를 한다 — [snippet, 쇼핑몰 플랫폼 도움말]
|
||||
- 테스터 ID는 최대 20개이고, "정상 배포 후 검수 요청" 순서라는 개인 블로그가 있다 — [hajun2ya.tistory.com [snippet]](https://hajun2ya.tistory.com/m/65)
|
||||
- 제출물: 회원가입 화면 + 네이버 로그인 버튼부터 가입 완료까지 노출되는 **모든 화면 캡처** — [channel.io 도움말 [snippet]](https://docs.channel.io/clickn/ko/articles/네이버-아이디로-로그인-261c8aeb)
|
||||
- 대표적인 반려 사유
|
||||
- "선택한 제공 정보와 내 사이트에서 받는 실제 가입 정보가 다른 경우" [snippet]
|
||||
- 버튼 디자인 가이드 미준수("버튼 검수가 상당히 꼼꼼") [snippet]
|
||||
- 앱 이름이 의미를 알 수 없거나 서비스와 관련 없는 경우 [snippet]
|
||||
- 쓰지 않는 정보를 요청하거나, 처리방침에 없는 정보를 처리하는 경우 — 2026-10-03 GitHub PR이 검수 기준으로 인용 [3rd-party](https://github.com/kosairesearch/kosairesearch.github.io/pull/335). 같은 PR은 "네이버 로그인 이용약관(2026-09-07 개정) 1.2 ⑨ 버튼 가이드 준수"와 버튼 규격(녹색 #03A94D, 로고 16px)을 언급한다. **공식 확인 전에는 규격 숫자를 믿지 말 것.**
|
||||
- 처리 기간: "영업일 기준으로 3~4일" [snippet]. 검수 결과는 계정 이메일로 온다.
|
||||
- [inference] 검수 전에는 일반 사용자와 **App Store 심사원**이 네이버로 로그인할 수 없다. 출시 빌드에 네이버 버튼을 넣으려면 검수가 먼저 끝나야 한다. 반대로 검수가 "서비스 배포 후"를 요구하면 순환이 생긴다. 해결책은 두 가지다.
|
||||
- 베타(TestFlight·Play 비공개) 화면으로 검수 요청이 받아지는지 네이버에 문의한다.
|
||||
- 1.0에서는 원격 플래그로 네이버 버튼을 숨기고, 검수 통과 후 켠다.
|
||||
- [inference] 탈퇴 시 네이버 연동 해제(토큰 삭제 API)에는 사용자 액세스 토큰이 필요하다. 카카오처럼 어드민 키 방식이 있는지는 unconfirmed.
|
||||
|
||||
**NCP(Maps)**
|
||||
- "결제 수단을 등록하지 않은 계정인 경우, 콘솔에 접근할 수 없습니다." 개인·사업자 회원 모두 해당 — [NCP Organization 문제 해결, 2026-09-17 [fetched]](https://guide.ncloud-docs.com/docs/organization-troubleshoot)
|
||||
- 결제수단: 국내 사업자는 신용카드·계좌이체, 국내 개인은 신용카드만 — [네이버웍스 도움말 [snippet]](https://help.worksmobile.com/ko/getting-started-guides/register-payment/)
|
||||
- Maps 이용 절차 [fetched]: 콘솔에서 Application 등록 → Client ID/Secret 발급. 심사 단계는 언급이 없다. "일정 사용량 초과 시 과금되므로 이용 한도를 설정하거나 한도 초과시 통보 기능"을 쓰라고 권한다 — [NCP Maps 이용 절차](https://guide.ncloud-docs.com/docs/maps-procedure)
|
||||
- 무료 이용량(특히 Mobile Dynamic Map)은 여전히 unconfirmed [prior].
|
||||
|
||||
### 4. Apple — 4.8 · 5.1.1(v) · 토큰 폐기 · 한국 Services ID 요건 · 프로그램 등록
|
||||
|
||||
**Guideline 4.8 원문** [fetched](https://developer.apple.com/app-store/review/guidelines/)
|
||||
- 대상: 서드파티·소셜 로그인으로 "set up or authenticate the user's primary account"하는 앱은 "must also offer as an equivalent option another login service" 해야 한다.
|
||||
- 그 대체 로그인이 갖춰야 할 세 가지:
|
||||
- "limits data collection to the user's name and email address"
|
||||
- "allows users to keep their email address private"
|
||||
- "does not collect interactions with your app for advertising purposes without consent"
|
||||
- 예외(자체 계정만 사용, 대체 마켓, 교육·기업, 정부 전자ID, 특정 서드파티 클라이언트)는 WanderGo에 해당하지 않는다 [inference].
|
||||
- 카카오·네이버·Google이 이메일 비공개를 제공하지 않으므로, 실무상 Sign in with Apple이다 [prior·inference].
|
||||
|
||||
**5.1.1(v) 원문** [fetched, 같은 페이지]
|
||||
- "If your app supports account creation, you must also offer account deletion within the app."
|
||||
- "The app must also include a mechanism to revoke social network credentials and disable data access between the app and social network from within the app."
|
||||
- 같은 조항에 "An app may not store credentials or tokens to social networks off of the device"라는 문장이 있다. 서버에 소셜 토큰을 저장하는 설계(네이버 연동 해제용 토큰 등)와 부딪힐 수 있다. 카카오는 어드민 키 방식으로 피할 수 있다 → Open question.
|
||||
|
||||
**계정 삭제 페이지** [fetched](https://developer.apple.com/support/offering-account-deletion-in-your-app/)
|
||||
- 삭제 대상: 계정 기록 + 법적 보관 의무가 없는 관련 데이터 전부. 다른 사람과 공유한 UGC도 포함된다. 공동 편집 코스의 처리 정책이 필요하다(메모리의 미결 사항과 연결).
|
||||
- 일시 비활성화만으로는 불충분하다.
|
||||
- 웹에서 마무리하는 경우 해당 페이지로 직접 링크한다.
|
||||
- 규제 산업이 아니면 전화·이메일·채팅 절차를 요구할 수 없다.
|
||||
- 즉시 삭제가 아니어도 되지만 소요 기간을 알리고 완료를 확인해 줘야 한다.
|
||||
- 자동 갱신 구독이 있으면 결제가 Apple을 통해 계속된다는 점을 먼저 알린다.
|
||||
- Sign in with Apple은 "should use the Sign in with Apple REST API to revoke user tokens" 하고, 서버-서버 알림 엔드포인트로 계정 변경을 처리해야 한다.
|
||||
|
||||
**한국 개발자 요건** [fetched](https://developer.apple.com/news/?id=j9zukcr6)
|
||||
- 2025-10-09 공지: "Starting January 1, 2026, developers based in the Republic of Korea must provide a server‑to‑server notification endpoint when registering a new Services ID, or updating an existing Services ID"
|
||||
- 알림 내용: 이메일 전달 설정 변경, 앱 내 계정 삭제, Apple 계정 영구 삭제.
|
||||
- 포럼의 DTS 답변: 한국 기반 개발자에게만 해당한다. 실시간 처리 의무 여부는 법률 자문을 받으라고 했다 — [forum 805241 [snippet]](https://developer.apple.com/forums/thread/805241)
|
||||
- [inference] Android(또는 웹)에서 Apple 로그인을 하려면 Services ID가 필요하다. 따라서 **NestJS에 서명 JWT 검증 엔드포인트를 HTTPS로 배포한 뒤**에 Services ID를 등록할 수 있다.
|
||||
|
||||
**토큰 폐기 절차** (TN3194는 제목만 읽힘 → 아래는 일반 지식, 원문 대조 필요)
|
||||
1. authorization code 교환 시 받은 `refresh_token`을 서버에 저장한다.
|
||||
2. `.p8` 키로 ES256 client_secret JWT를 서명한다.
|
||||
3. `POST https://appleid.apple.com/auth/revoke`를 호출한다(`client_id`, `client_secret`, `token`, `token_type_hint`) — [TN3194](https://developer.apple.com/documentation/technotes/tn3194-handling-account-deletions-and-revoking-tokens-for-sign-in-with-apple)
|
||||
|
||||
**Developer Program 등록** [fetched](https://developer.apple.com/programs/enroll/)
|
||||
- "Individual or sole proprietor/single-person business"는 개인으로 등록한다. 실명을 써야 하고, "Your name will be displayed as the seller name"
|
||||
- 조직은 "must be a legal entity … We do not accept DBAs, fictitious business names, trade names, or branches" + D-U-N-S + 조직 도메인 이메일 + 실제 운영 중인 웹사이트가 필요하다.
|
||||
- 연 99 USD(현지 통화로 표시).
|
||||
- D-U-N-S는 "allow up to 5 business days" — [Apple D-U-N-S [snippet]](https://developer.apple.com/support/d-u-n-s/)
|
||||
- [inference] 한국 개인사업자는 법인격이 없으므로 **개인으로 등록**한다. 판매자명을 "WanderGo"/회사명으로 보이게 하려면 법인이 필요하다.
|
||||
|
||||
### 5. Google — Play 계정 삭제 · 비공개 테스트 · 계정 유형 · OAuth 인증
|
||||
|
||||
**Play 신규 개인 계정 테스트 요건** [fetched](https://support.google.com/googleplay/android-developer/answer/14151465)
|
||||
- 2023-11-13 이후 만든 개인 계정은 비공개 테스트에 테스터 **12명 이상**이 "opted in continuously for at least 14 days" 해야 한다.
|
||||
- 그 뒤 대시보드에서 "Apply for production"을 누른다.
|
||||
- 신청서는 테스트 모집 난이도, 피드백, 대상 사용자, 첫해 설치 예상, 출시 준비 근거를 묻는다.
|
||||
- 심사는 "usually takes seven days or less"다. 참여가 부족하면 추가 테스트를 요구받을 수 있다.
|
||||
|
||||
**계정 유형** [fetched](https://support.google.com/googleplay/android-developer/answer/13628312)
|
||||
- 개인: 법적 이름·주소(결제 프로필)를 인증해야 게시할 수 있다. 법적 이름·국가·개발자 이메일이 Play에 공개된다.
|
||||
- 조직: D-U-N-S가 없으면 생성할 수 없다. 발급은 "can take up to 30 days"
|
||||
- 연락처 이메일·전화는 OTP로 인증한다.
|
||||
- 수익화 결제 프로필 인증은 최대 5일.
|
||||
- 등록비 25달러와 신분증 요구 범위는 이 페이지에서 확인 못 함(unconfirmed).
|
||||
|
||||
**계정 삭제** [fetched](https://support.google.com/googleplay/android-developer/answer/13327111)
|
||||
- 필요한 것:
|
||||
- "in-app path to delete their app accounts and associated data"
|
||||
- 앱을 재설치하지 않고 요청할 수 있는 "web link resource"
|
||||
- 웹 페이지는 스토어 등록명과 같은 앱·개발자 이름을 쓰고, 삭제 경로를 눈에 띄게 보여 줘야 한다. 링크는 오류 없이 동작해야 한다.
|
||||
- 링크는 Play Console App content의 **Data safety 양식**에 입력한다.
|
||||
- 보안·사기 방지·법령 사유로 일부를 보관할 수 있으나 고지해야 한다.
|
||||
|
||||
**Google OAuth** [fetched]
|
||||
- 출처: [브랜드 인증](https://developers.google.com/identity/protocols/oauth2/production-readiness/brand-verification)
|
||||
- Testing 상태: "only available to users you add to the list of test users". 경고 화면이 뜨고, 사용자 수 상한과 리프레시 토큰 수명 제한이 있다.
|
||||
- 브랜드 인증은 External + Published이고 로고·이름을 표시할 때 필요하다.
|
||||
- Android 문서도 "Your brand must be verified for your app name to be visible to users on the Sign in with Google consent screen"이라고 한다 — [Android SIWG [fetched]](https://developer.android.com/identity/sign-in/credential-manager-siwg)
|
||||
- 브랜드 인증 요건
|
||||
- Search Console로 **소유를 인증한 도메인**
|
||||
- 로그인 페이지만 있는 것이 아닌 공개 홈페이지(Play 등록 페이지는 인정되지 않음)
|
||||
- 같은 도메인의 개인정보처리방침
|
||||
- 소요 시간: 자동이면 수분, 수동이면 "usually takes 2-3 business days". 인증 결과는 **7일 안에 게시**하지 않으면 다시 인증해야 한다.
|
||||
- openid/email/profile만 쓰면 민감·제한 범위 심사(데모 영상·보안 평가)는 해당하지 않는다. "verification review isn't mandatory" [snippet, GCP 도움말 13464323].
|
||||
- Android 클라이언트(패키지명 + SHA-1: 디버그·업로드·**Play 앱 서명 키**)와 Web 클라이언트 ID(`serverClientId`)를 등록한다 — 일반 지식, 원문에서 SHA-1 문구 미확인.
|
||||
|
||||
### 6. 위치기반서비스사업 신고 (방송미디어통신위원회)
|
||||
|
||||
- **누가**: "위치기반서비스사업을 하려는 자"(제9조①). 신고서에 상호·주된 사무소 소재지·사업 종류·위치정보시스템 등 주요 설비를 적는다 [prior].
|
||||
- 담당공무원이 **법인등기·사업자등록증**을 행정정보 공동이용으로 확인한다 — [정부24 민원안내 [fetched, 인코딩 일부 깨짐, 최종 수정 2021-01-26]](https://www.gov.kr/mw/AA020InfoCappView.do?HighCtgCD=A09001&CappBizCD=15701000085)
|
||||
- [inference] 사업자등록이 없는 개인이 신고할 수 있는지는 **unconfirmed**다. 신고서 구조와 확인서류로 보면 **개인사업자 등록 후 신고**가 현실적이다. 위치정보지원센터 02-588-0185에 확인한다.
|
||||
- **수리 요건**: 제9조⑤ "이 법에 적합하면 신고를 수리하여야 한다" — [casenote 제9조 [fetched]](https://casenote.kr/법령/위치정보의_보호_및_이용_등에_관한_법률/제9조). 처리 기한 조문은 없다.
|
||||
- [inference] 수리가 필요한 신고이므로 일반 신고자는 **수리 후 사업을 개시**한다.
|
||||
- **특례(제9조의2)**: 소상공인·1인 창조기업은 신고 없이 개시할 수 있고, "사업을 개시한 지 1개월이 지난 후에도" 계속하려면 신고한다 — [위치정보지원센터 [fetched]](https://www.lbsc.kr/front/content/contentViewer.do?contentId=CONTENT_0000091)
|
||||
- **어디서**: 과기정통부 전자민원센터 **emsit.go.kr** 온라인 접수(특례 신고 바로가기 `Cp1440000_0182_03Reg.do`) — [lbsc.kr [fetched]]. 신청 방법은 인터넷, 처리기관은 방송미디어통신위원회(방송미디어통신사무처) — [정부24 [fetched]](https://www.gov.kr/mw/AA020InfoCappView.do?HighCtgCD=A09001&CappBizCD=15701000086)
|
||||
- **서류**
|
||||
- 일반: 신고서, 사업계획서(사업자 현황·사업 내용), 주요 설비 위치·설치 확인 서류, 제16조 위치정보 보호조치 증명 서류 [prior·fetched 정부24]
|
||||
- 특례: 소상공인확인서 또는 1인 창조기업 확인 서류, 사업 종류·내용 설명자료(양식은 lbsc.kr) [fetched lbsc.kr]
|
||||
- **발급처** [3rd-party, catchsecu 2024-10-25](https://www.catchsecu.com/archives/14060)
|
||||
- 소상공인확인서: 중소기업현황정보시스템(sminfo.mss.go.kr). 재무제표 등이 필요하고 "약 1주일"
|
||||
- 1인 창조기업 증빙: K-Startup 자가진단 결과 캡처 + 건강보험 자격득실확인서
|
||||
- 접수는 간편인증으로 하고, 회원가입은 필요 없다. 수리까지 "최대 2주 정도". 직접 신고하면 수수료가 없다.
|
||||
- **언제** [inference]
|
||||
- 비공개 베타(지인 테스터)를 "사업 개시"로 볼지는 해석이 갈린다.
|
||||
- **베타 기간에 제출해 출시 전에 수리**받는 것이 가장 안전하다.
|
||||
- 특례 대상이면 공개 출시일부터 1개월 안이 법정 마감이다.
|
||||
- 보호조치 증빙(확인자료 자동 기록, 접근권한·접속기록, 암호화)은 **백엔드 설계 산출물**이므로 코드 작성 전에 요건으로 정해 둔다.
|
||||
|
||||
### 7. 공통 — 사업자등록
|
||||
|
||||
- 사업자등록증은 원칙적으로 신청일부터 2일 안에 발급된다. 확인이 필요하면 연장되는데, 연장 기한은 출처마다 5일 또는 7일로 다르다. 사업 개시 전에도 신청할 수 있다 — [3rd-party snippet, 법령 원문 미확인](https://www.heumtax.com/contents/posts/business-registration-deadline)
|
||||
- 구독 판매 시 통신판매업 신고 여부는 이번 범위 밖이다. [prior] legal_policy.md 5절 미결.
|
||||
|
||||
---
|
||||
|
||||
## Open questions
|
||||
|
||||
1. **사업 형태**: 개인사업자로 시작할지, 법인을 세울지. 결정에 따라 Apple 판매자명(실명 vs 회사명), Play 계정(개인 = 12명 × 14일 테스트 / 조직 = D-U-N-S 최대 30일), 위치 신고 경로(특례 가능 여부)가 갈린다.
|
||||
2. 사업자등록 없는 **개인이 위치기반서비스사업 신고**를 할 수 있는지, 특례 대상 확인서를 신생 사업자가 바로 발급받을 수 있는지(재무제표가 없는 경우). 위치정보지원센터 02-588-0185에 문의.
|
||||
3. **네이버 로그인 검수가 출시 전(베타 빌드) 화면으로 가능한지.** 안 되면 1.0에서 네이버 버튼을 플래그로 숨긴다. 공식 검수 가이드 원문은 이번 세션에서 열람 불가.
|
||||
4. **Apple 5.1.1(v)의 "tokens to social networks off of the device" 문구**와 서버 측 토큰 저장(네이버 연동 해제, Apple refresh token)의 관계. 카카오는 어드민 키 해제로 저장을 피할 수 있다. 네이버 연동 해제에 서버 저장 없이 되는 경로가 있는지 확인.
|
||||
5. 카카오 **개인 개발자 비즈 앱에서 이메일 "필수" 동의가 되는지**(선택은 커뮤니티 답변으로 확인). 이메일 자동 연결 정책을 정하기 전에 확인하되, Apple 비공개 이메일을 고려해 **이메일에 의존하지 않는 설계**를 권장한다.
|
||||
6. 공공데이터 운영계정의 **실제 부여 트래픽**과, 출시 전 랜딩 URL·베타 화면으로 활용사례를 등록할 수 있는지. 인증키 유효기간과 연장 절차.
|
||||
7. 카카오 **비즈월렛을 사업자 없이 만들 수 있는지**(유료 초과분이 필요해질 때만 해당).
|
||||
8. NCP Maps(새 Maps)의 Mobile Dynamic Map 무료 이용량. 지도 SDK 결정과 연결된다.
|
||||
9. Apple Developer Program 개인 등록 승인 소요, Play 신원 인증 소요와 신분증 요구, App Review 평균 소요 — 이번 세션에서 원문 확인 못 함.
|
||||
10. 비공개 테스트 단계의 지인 테스터 위치 수집이 위치정보법상 "사업 개시"인지(전문가 확인).
|
||||
@@ -0,0 +1,253 @@
|
||||
# Kakao 장소 ID만 저장한 코스는 다시 그릴 수 있나 — 2026-10-29 확인
|
||||
|
||||
> Builds on `WanderGo 기획 검토 자료조사/commercial_map_apis.md` §7. That file established the rule: Kakao Local results can't be stored; place ID and URL can.
|
||||
> Legend: **(fetched)** = I opened the page and read it. **(snippet)** = search-engine summary only. **[inference]** = my reasoning, not stated by a source.
|
||||
> Answers in DevTalk come from the accounts **"Map"** and **"C.L"**. The fetched page text doesn't show a staff badge, but these accounts answer policy questions on Kakao's behalf in every thread. I treat them as Kakao staff [inference].
|
||||
|
||||
---
|
||||
|
||||
## Takeaway
|
||||
|
||||
1. **There's no legitimate way to turn a Kakao place ID back into its name, address or coordinates.** Kakao has said there's no single-place lookup by ID 7 times between 2020 and 2026-10-28. The `place.map.kakao.com` JSON is "공식적으로 지원하는 방법이 아닙니다". The only official use of an ID is **landing on Kakao Map**: `place_url` or `https://map.kakao.com/link/map|to|roadview/{장소ID}`.
|
||||
2. **The rule got stricter in September 2026.** You can't store a Kakao name, address, coordinates or category, even if the user confirmed or edited it, even only on the device, and even just to use for re-searching. Earlier answers (July and August 2026) allowed storing the name text, but later answers replace them. Separately, **Local results must not be sent to an external LLM** (2026-09-08). This hits WanderGo's AI course builder directly.
|
||||
3. **What you *can* store:** the Kakao ID and URL; text the user types themselves (not pre-filled from the API); data from independent public sources (TourAPI, 소상공인 상가정보, and similar).
|
||||
4. **Recommendation:** course stops point to WanderGo's own `place` table, built from public data and user-typed places. The Kakao ID and URL are kept only as an optional "카카오맵에서 보기" link. Kakao Local is used only for the live "장소 추가" search screen.
|
||||
5. **Google and Naver don't fix this.** Google only lets you store the ID for free, charges the Pro rate for names, and requires a Google map. Naver's search API 특약 (in force since 2026-09) bans storing results beyond short caches, according to secondary sources.
|
||||
|
||||
---
|
||||
|
||||
## Cited findings
|
||||
|
||||
### A. Is there any ID → details path? (Q1)
|
||||
|
||||
| Date | Source | What it says |
|
||||
|---|---|---|
|
||||
| 2020-05-29 | [DevTalk 104683 (fetched)](https://devtalk.kakao.com/t/api-id-data-api/104683), C.L | "그와 같은 사용은 허용하지 않고, ID로 상세 정보를 조회하는 API는 제공 계획이 없습니다." (The asker wanted to store IDs and fetch details later.) |
|
||||
| 2021-12-29 | [DevTalk 120361 (fetched)](https://devtalk.kakao.com/t/place-map-api/120361), lea.ju | On `https://place.map.kakao.com/main/v/{place_id}`: "공식적으로 지원하는 방법이 아닙니다." "REST API에서 제공하는 정보만 사용해주셔야 합니다." |
|
||||
| 2026-08-21 | [DevTalk 151265 (fetched)](https://devtalk.kakao.com/t/api-id-place-url/151265), Map | Q4: "장소ID만으로 해당 장소를 단건 조회 가능한 API는 없습니다." |
|
||||
| 2026-09-08 | [DevTalk 151545 (fetched)](https://devtalk.kakao.com/t/api-llm-place-url-webview/151545), Map | "현재 장소 ID 기반의 단건 조회 API는 제공되지 않습니다." |
|
||||
| 2026-09-16 | [DevTalk 151647 (fetched)](https://devtalk.kakao.com/t/api/151647), Map | "장소ID 기반의 단건 조회 API는 없습니다." |
|
||||
| 2026-09-16 | [DevTalk 151720 (fetched)](https://devtalk.kakao.com/t/topic/151720), Map | "장소 ID 기반 단건 호출 API는 별도로 제공되지 않으며, 카카오맵 상세 URL 연결이나 실시간 재검색 등 서비스 구조에 맞춰 직접 구현하셔야 하는 영역입니다." |
|
||||
| 2026-10-23 | [DevTalk 152312 (fetched)](https://devtalk.kakao.com/t/api/152312), C.L | "장소 ID만으로 상세 정보를 다시 조회하는 공개 API는 제공하지 않으며," |
|
||||
| 2026-10-28 | [DevTalk 152447 (fetched)](https://devtalk.kakao.com/t/local-api/152447), C.L | "장소 ID만으로 상세 정보를 조회하는 공개 API는 현재 제공하지 않습니다." Store details must come from live search or a link to the place URL. |
|
||||
|
||||
- **REST API docs (fetched)**: the Local API has 6 endpoints: address search, coord2regioncode, coord2address, transcoord, keyword search, category search. **None of them takes a place ID as input.** `id` and `place_url` appear only in the output. Example `place_url`: `http://place.map.kakao.com/26338954` — [Kakao Local dev guide](https://developers.kakao.com/docs/ko/local/dev-guide)
|
||||
- **Official ID-based links (fetched)**: the Kakao Maps API guide's "지도 URL" section lists `/link/map/장소ID`, `/link/to/장소ID` and `/link/roadview/장소ID` on base `https://map.kakao.com`, for example `https://map.kakao.com/link/map/18577297`. Multi-stop `/link/by/{mode}/...` takes only `이름,위도,경도`, not IDs. Up to 5 waypoints; transit doesn't support waypoints — [apis.map.kakao.com/web/guide](https://apis.map.kakao.com/web/guide/)
|
||||
- **App URL scheme `kakaomap://place?id=`**: I found no official doc for it **(unconfirmed)**. One DevTalk asker reports that `kakaomap://look` opens at building level and can't target a specific business — [DevTalk 151335 (fetched)](https://devtalk.kakao.com/t/db-id/151335)
|
||||
- **Map SDK POI tap**: the place name delivered by a base-map POI label click event also can't be stored — "카카오맵 SDK의 POI 라벨 클릭 이벤트를 통해 전달되는 장소명 역시 그대로 저장하여 반복 활용하는 방식은 허용하지 않습니다." (Map, 2026-08-24) — [DevTalk 151294 (fetched)](https://devtalk.kakao.com/t/sdk-poi/151294)
|
||||
|
||||
**Answer to Q1: no.** There's no REST, SDK, deep-link or place-URL route that returns the name, address or coordinates for an ID. A deep link only opens Kakao Map, which shows the information inside Kakao's own app or page.
|
||||
|
||||
### B. What may be stored — the rule as of late Oct 2026
|
||||
|
||||
**Operating policy text (fetched)** — [Kakao Developers 운영정책](https://developers.kakao.com/terms/ko/site-policies), effective **2026-04-20** (제19조):
|
||||
- 제5조 제20호 prohibits "앱에서 사용자 환경을 개선하기 위한 목적 외 다른 목적으로 카카오에서 받은 데이터를 캐시하거나 캐시 후 최신 데이터로 유지하지 않는 행위".
|
||||
- 제5조 제30호 prohibits copying or replicating obtained information, or entering it into a search engine or directory, without Kakao's prior consent.
|
||||
- Staff said storing names or addresses in a DB "제5조 제20항(캐시 목적)에 해당하지 않아 정책상 허용되지 않습니다" (Map, 2026-09-16) — [151720 (fetched)](https://devtalk.kakao.com/t/topic/151720)
|
||||
|
||||
**Storage rulings, most recent first (all fetched):**
|
||||
- **2026-10-28, C.L** [152447](https://devtalk.kakao.com/t/local-api/152447):
|
||||
- Storage is not allowed even on the device or as a past-visit record: "개인 단말에만 보관하거나 과거 방문·예정 기록으로 사용하는 경우에도, 카카오 API에서 받은 장소명·주소를 장기 저장하여 재사용하는 것은 허용하지 않습니다."
|
||||
- The test is where the value came from: "구분 기준은 저장되는 정보의 출처입니다." "사용자가 독립적으로 작성한 메뉴명·식사 날짜·메모 등은 보관할 수 있습니다." Renaming an auto-filled field to "메모" doesn't make it user-authored.
|
||||
- Cleanup: you can't relabel old API data as "수기 입력" to keep it.
|
||||
- **2026-10-23, C.L** [152312](https://devtalk.kakao.com/t/api/152312):
|
||||
- "사용자가 직접 선택한 장소이거나 본인에게만 보이는 기록이라도, 로컬 API에서 받은 장소명·카테고리·주소·좌표 등을 저장하여 이후에도 계속 사용하는 형태는 허용하지 않습니다."
|
||||
- "장소 ID와 URL은 카카오맵으로 연결하는 용도로 보관할 수 있습니다."
|
||||
- "재검색을 위한 목적이라도 응답받은 장소명·좌표를 함께 저장하여 사용하는 것은 허용 범위에 해당하지 않습니다."
|
||||
- **2026-10-19/20, Map** [152228](https://devtalk.kakao.com/t/api-id/152228):
|
||||
- "좌표와 주소 정보를 저장하여 활용하는 형태는 허용하지 않습니다."
|
||||
- Publishing the data as static JSON is also not allowed.
|
||||
- "장소ID, URL은 저장하여 카카오맵으로 랜딩하는 구조로 활용할 수 있습니다."
|
||||
- **2026-10-20:** "로컬API 응답값 내 장소ID 및 URL만 저장하고 별도 확보한 주소를 공공기관 API로 변환한 좌표로 저장하여 지도에 표시하는 방식은 가능합니다." Staff added that the public data's own terms apply.
|
||||
- A browser `services.Places` lookup on marker tap "해당 구조는 실시간 호출에 해당합니다".
|
||||
- **2026-10-19, Map** [152223](https://devtalk.kakao.com/t/1-id/152223): asked to allow storing "ID + 장소명", staff answered "로컬 API에서 제공하는 장소명은 저장하여 활용할 수 없으며 실시간 호출로만 이용 가능합니다."
|
||||
- **2026-09-17, Map** [151727](https://devtalk.kakao.com/t/id/151727): "사용자가 일부 확인, 수정 과정을 거치더라도 로컬API 결과를 기반으로 한 데이터이므로 … 정책 상 API 결과값의 DB저장에 해당" / "장소ID 및 URL은 저장 및 활용은 가능합니다."
|
||||
- **2026-09-16, Map** [151647](https://devtalk.kakao.com/t/api/151647):
|
||||
- "설명해 주신 일회성 조회로 활용 및 사용자 직접 입력 구조(API 호출 결과값이 아닌)는 허용됩니다."
|
||||
- "장소ID는 저장 가능하며, 장소명, 주소 등의 응답값을 함께 저장하여 활용하는 형태는 허용되지 않습니다."
|
||||
- The asker's case was a user typing a business name directly and pinning a location on the map, without going through a Kakao response.
|
||||
- **2026-09-07, Map** [151514](https://devtalk.kakao.com/t/topic/151514): "API 응답 데이터를 그대로 DB에 저장하는 것은 허용되지 않으므로, 나)의 방식보단 가) 방식처럼 사용자 직접 텍스트 입력 구조를 권장합니다."
|
||||
- (가) was an input box where the user types or confirms a name.
|
||||
- [inference] Under 151727 (09-17), a box **pre-filled** with the API name no longer qualifies. The box must start empty, or the user must type independently.
|
||||
- **2026-08-24, Map** [151294](https://devtalk.kakao.com/t/sdk-poi/151294): coordinates based on Local results "사용자가 화면에서 확인하거나 확정하는 절차를 거치더라도 별도로 저장하여 활용할 수 없습니다". Calling the API live at each display and drawing the returned coordinates is allowed.
|
||||
|
||||
**Superseded (older, looser) answers — don't rely on them:**
|
||||
- **2026-07-28, Map** [150888 (fetched)](https://devtalk.kakao.com/t/api/150888): "설명하신 사용 범위 내 장소명 텍스트를 저장하여 활용하는 것은 가능합니다."
|
||||
- **2026-08-21, Map** [151265 (fetched)](https://devtalk.kakao.com/t/api-id-place-url/151265): storing "카카오 장소 ID, 장소명, place_url" for places the user saved or put in a course — "저장 범위에 허용됩니다". This was a dating/travel course app much like WanderGo.
|
||||
- [inference] These conflict with the 5+ later answers from 09-16 to 10-28. Treat the later answers as the current rule.
|
||||
|
||||
**Public data + Kakao ID matching (fetched):**
|
||||
- **2026-08-10, Map** [151052](https://devtalk.kakao.com/t/tourapi-local-api/151052): own or public place ledger (TourAPI, public data) plus live Local checks:
|
||||
- "장소 정보 매핑 관련 추가 확인을 위해 로컬API를 활용할 수 있습니다." "장소ID 및 URL은 저장하여 활용 가능합니다."
|
||||
- Recording whether a place was checked, and when: "확인 여부 및 일자를 기록하는 것은 무방합니다."
|
||||
- Using non-Kakao coordinates on a Kakao map: "가능합니다."
|
||||
- **But** "지역 구분을 위한 기계적인 API 대량 호출은 허용하지 않습니다."
|
||||
- **2026-08-26, Map** [151335](https://devtalk.kakao.com/t/db-id/151335): matching your own public-data DB to Kakao IDs and storing only the ID and `place_url` — "허용됩니다."
|
||||
- The follow-up asked about a one-time operator batch over about 2,000 records and attribution. **No staff reply yet.**
|
||||
- **2026-10-01, Map** [151916](https://devtalk.kakao.com/t/topic/151916):
|
||||
- Live matching plus storing the Kakao ID next to your own DB row: "실시간 호출 기반이라면 허용되며, 장소ID는 저장하여 사용 가능합니다."
|
||||
- Using a tapped coordinate only to find the nearest own-DB place, then storing that place's ID: "장소ID 저장은 가능합니다."
|
||||
- Drawing own public-data coordinates as markers on the Kakao JS map: "이슈 없습니다."
|
||||
- Showing phone or address on marker tap: staff "장소URL을 통한 카카오맵 랜딩 구조를 권장".
|
||||
- **2026-10-21, C.L** [152192](https://devtalk.kakao.com/t/api/152192): using Kakao coordinates once to query your own public parcel DB, then storing the public-data ID, address and center — "독립적으로 확보한 공공데이터의 값이라면 … 일회성 조회로 판단할 수 있습니다."
|
||||
|
||||
**LLM and WebView (fetched) — 2026-09-08, Map** [151545](https://devtalk.kakao.com/t/api-llm-place-url-webview/151545):
|
||||
- "API 응답 데이터를 외부 LLM으로 전송하는 것은 허용되지 않습니다." This applies even with minimal fields, or only for translation or sentence generation.
|
||||
- "응답 속도 개선을 위한 단기 캐싱 역시 제한 대상입니다."
|
||||
- "place_url은 외부 브라우저 호출 방식으로 이용해 주시기 바랍니다." / "별도의 출처 표기 의무는 없습니다."
|
||||
- ⚠️ **Conflict:** one day earlier, [151514](https://devtalk.kakao.com/t/topic/151514) (09-07) allowed rendering `place_url` in an in-app view as-is ("설명하신 구조의 활용은 허용됩니다", but don't cover the Kakao Map CI). **Use the external browser to be safe.**
|
||||
|
||||
**User's own search query** — [151190 (fetched)](https://devtalk.kakao.com/t/local-api/151190), C.L 2026-08-18: "사용자가 직접 입력한 쿼리 외에 카카오맵 API 호출을 통해 응답받은 결과를 저장하여 반복 사용하는 것은 허용하지 않습니다."
|
||||
- [inference] This sentence carves the user's query out of the ban. It does **not** say query storage is allowed.
|
||||
- No thread I found rules directly on storing the query (recent searches) or on re-searching with a stored user-typed label. **Unconfirmed — ask.**
|
||||
|
||||
### C. Other sources (Q2 c–e)
|
||||
|
||||
**Public data — storable (all fetched from data.go.kr):**
|
||||
- **TourAPI 국문 관광정보 서비스_GW** — [15101578](https://www.data.go.kr/data/15101578/openapi.do):
|
||||
- "이용허락범위 제한 없음", free.
|
||||
- Images are 공공누리 1유형 and 3유형, and use as corporate CI/BI is banned.
|
||||
- Dev traffic 1,000; production traffic can be raised by registering a use case. Production approval is reviewed (심의승인).
|
||||
- **한국관광공사 반려동물 동반여행 서비스** — [15135102](https://www.data.go.kr/data/15135102/openapi.do):
|
||||
- "이용허락범위 제한 없음", update cycle real-time.
|
||||
- Covers "관광지, 숙소, 음식점, 쇼핑시설 등" with pet conditions. Cafés aren't named.
|
||||
- **소상공인시장진흥공단 상가(상권)정보 API** — [15012005](https://www.data.go.kr/data/15012005/openapi.do):
|
||||
- "이용허락범위 제한 없음", auto-approval for dev and production, dev traffic 10,000.
|
||||
- Fields: "상가업소번호, 상호명, 주소, 상권업종명, 표준산업분류명, 경도, 위도 등". Source: 국세청 and card companies.
|
||||
- **This is the best storable POI set for 음식점/카페 with names and WGS84 coordinates.**
|
||||
- **행정안전부 식품_휴게음식점 조회서비스** — [15154921](https://www.data.go.kr/data/15154921/openapi.do):
|
||||
- "이용허락범위 제한 없음", updated daily.
|
||||
- Coordinates are in "Bessel 중부원점TM(EPSG:5174)" and need conversion.
|
||||
- Useful for 영업상태 (open/closed) checks.
|
||||
- **LOCALDATA → 공공데이터포털:** MOIS moved 195 licensing datasets (including 일반음식점) and 14 convenience datasets into data.go.kr, all available as APIs. The old portal ran in parallel "4월 15일까지" — [뉴스서울 2026-01-26 (fetched)](https://newsseoul.co.kr/news/view/1065579617179088)
|
||||
- Kakao staff confirmed that storing public-data coordinates and drawing them on a Kakao map is fine (151052, 151916, 152228 above). The public source's own terms apply.
|
||||
|
||||
**Google Places (New):**
|
||||
- Pricing (fetched, page updated 2026-10-28) — [pricing](https://developers.google.com/maps/billing-and-pricing/pricing):
|
||||
|
||||
| SKU | Monthly free cap | Price per 1,000 |
|
||||
|---|---|---|
|
||||
| Place Details Essentials (IDs Only) | Unlimited | — |
|
||||
| Place Details Essentials | 10,000 | $5 |
|
||||
| Place Details Pro | 5,000 | $17 |
|
||||
| Text Search Essentials (IDs Only) | Unlimited | — |
|
||||
|
||||
- Fields (fetched) — [data fields](https://developers.google.com/maps/documentation/places/web-service/data-fields):
|
||||
- **IDs Only** = attributions, consumerAlert, id, movedPlace, movedPlaceId, name (resource name), photos. **No `displayName`, no `location`.**
|
||||
- `location` and `formattedAddress` are Essentials. **`displayName` is Pro.**
|
||||
- [inference] So showing a Korean name plus a pin costs at the Pro rate: $17/1k after 5k free per month. The free SKU can only refresh IDs (`movedPlaceId`).
|
||||
- Policies (fetched) — [Places policies](https://developers.google.com/maps/documentation/places/web-service/policies):
|
||||
- "You can therefore store place ID values indefinitely."
|
||||
- "Places API results displayed on a map must be shown on a Google Map".
|
||||
- Latitude/longitude may be cached up to 30 consecutive days, per archived Service Specific Terms — [maps-service-terms (snippet; live page didn't render)](https://cloud.google.com/maps-platform/terms/maps-service-terms)
|
||||
- Korean `languageCode=ko` displayName output for Korean places: **unverified.** It needs a live test.
|
||||
|
||||
**Naver 검색 API (지역):**
|
||||
- Official terms page `developers.naver.com/products/terms/` **could not be fetched** (tool blocked).
|
||||
- Secondary sources (fetched):
|
||||
- The 검색 API 특약 was announced 2026-08-07 and took effect 2026-09-07 (Developers Center). One source says 2026-09-20 for NAVER API HUB.
|
||||
- Copying, storing or caching is prohibited, except server history lookup up to 21 days and personalization or device cache of 24 hours or until the next query.
|
||||
- Results must be shown as Naver results, with attribution and a link to the original.
|
||||
- Feeding results into AI is prohibited.
|
||||
- Developers Center keys end 2027-06-30; local search moves to API HUB with metered billing.
|
||||
- Sources: [waffleboard (fetched)](https://waffleboard.io/blog/naver-search-api-terms-ai-ads-storage), which cites the [official notice](https://developers.naver.com/notice/article/33400); [GitHub issue summary (fetched)](https://github.com/HITENEKEN/blog-auto-poster/issues/27); [brunch 2026-09-16 (fetched)](https://brunch.co.kr/@ainote/123)
|
||||
- API limits: max 5 results per call, no paging, 25,000/day — [NCP API HUB local search (fetched)](https://api.ncloud-docs.com/docs/naver-api-hub-search-local.md)
|
||||
|
||||
---
|
||||
|
||||
## Options table
|
||||
|
||||
| Option | Allowed? | Cost | UX | Risk |
|
||||
|---|---|---|---|---|
|
||||
| **a) Store Kakao ID + URL, plus a label the user types** | **Yes.** ID/URL: 7+ staff answers. User-typed text: allowed by 151647 (09-16) and 152447 (10-28), **only if typed independently** — a box pre-filled from the API doesn't count (151727). | Kakao search only when adding a place: 100k/day free, then 2원 per call. Links are free. | Weak. No pin or route on WanderGo's map unless you re-search (option b). Name quality depends on the user. "카카오맵에서 보기" opens externally. | Low policy risk. Users type sloppy labels or skip the step, so the route has no coordinates. |
|
||||
| **b) Re-search at display time** | **Partly.** Live calls are fine (151294, 152228). Using **stored API names or coordinates as the query is banned** (152312). Using the **user's own typed label** as the query is **unconfirmed** — 151190 only carves the query out of the ban. | N keyword calls per course view. At about 8k/day it stays in the free quota. | Pins can show, but matches fail when there's no `x,y` (Kakao coordinates can't be stored; public-data or region-center coordinates would work). Adds latency. | Medium: the policy is unconfirmed, and the stored ID may not be in the top 45 results. Staff also warned against "기계적인 API 대량 호출" (151052). |
|
||||
| **c) Storable sources: TourAPI, 반려동물 동반여행, 소상공인 상가정보, 인허가, user-entered places** | **Yes.** "이용허락범위 제한 없음" on all four data.go.kr pages. Kakao OKs drawing these coordinates on its map and attaching Kakao IDs (151052, 151335, 151916, 152228). | Free. Engineering cost: ETL, EPSG:5174→WGS84 conversion, dedup, and periodic sync. | Good. Stored name, pin and category show offline. Shareable. Can be fed to the AI. Trendy or new spots may be missing or stale; names may differ from what users know. | Data coverage and freshness, not policy. Also check TourAPI image license types (1유형 vs 3유형). |
|
||||
| **d) Google Places** | ID storage forever: yes. Name or coordinates: only by live fetch, **and only on a Google map**. Lat/lng cache ≤30 days (snippet). | IDs Only: free, but no name or coordinates. Name needs Pro: $17/1k after 5k/month. Address/coordinates need Essentials: $5/1k after 10k/month. | Needs a Google base map, which clashes with a Kakao or Naver map. Korean name output unverified. | High: can't mix with a Kakao map, unpredictable cost, weaker Korean POIs ([inference] per the earlier notes). |
|
||||
| **e) Naver 지역 검색** | **No** for persistent storage (21-day/24h exceptions, secondary sources). Attribution and link required. AI input banned. | Metered on API HUB from 2026-09. 25k/day; max 5 results. | Poor: 5 results, no paging. | High: terms just tightened, and the endpoint is migrating. |
|
||||
|
||||
---
|
||||
|
||||
## Recommendation (MVP)
|
||||
|
||||
**Build course stops on WanderGo's own `place` table (option c). Attach Kakao ID + URL only as an outbound link (option a). Keep Kakao Local as a live search screen only, never as stored data or AI input.**
|
||||
|
||||
How it works:
|
||||
1. **Candidate pool for AI and curation** = TourAPI (관광지, 축제, 반려동물 동반), 소상공인 상가정보 (음식점, 카페), and optionally 인허가 영업상태 for closed-business checks.
|
||||
- Sync these into `place` with a nightly or weekly batch.
|
||||
- **The AI only ever sees `place` rows.** Kakao results never go to the LLM (151545).
|
||||
2. **Kakao link**: when the user or operator confirms a place, store the Kakao `id` and `place_url` (plus the check date) in `place_external_link`.
|
||||
- Use one live keyword search per place, at the moment someone acts on it — not a mechanical bulk sweep (151052).
|
||||
- The detail screen shows our stored name and address from public data. The button "카카오맵에서 보기 / 길찾기" opens `https://map.kakao.com/link/map/{id}` or `/link/to/{id}` **in an external browser or the Kakao app**.
|
||||
- Phone, hours and reviews are shown only through that link-out, never stored.
|
||||
3. **"장소 직접 추가"** (a place not in our DB):
|
||||
- Run a live Kakao search for display only.
|
||||
- On save, show an **empty** name box the user types into (not pre-filled).
|
||||
- Store the typed label, Kakao ID and URL.
|
||||
- For location, either snap to the nearest own-DB place (151916 Q4), or leave the stop without coordinates. It then shows in the list and opens in Kakao, but isn't routed.
|
||||
- Storing a raw map-tap coordinate is **unconfirmed**; ask before using it.
|
||||
4. **Routes**: compute them live from our stored public-data coordinates. Don't cache Kakao route results. Whether routes may be cached is a separate open question.
|
||||
|
||||
**DB fields:**
|
||||
|
||||
`place` (our data):
|
||||
- `id`
|
||||
- `source` (`TOUR_API` | `TOUR_PET` | `SBIZ` | `LICENSE` | `USER`)
|
||||
- `source_ref` (contentid / 상가업소번호 / 관리번호)
|
||||
- `name`, `category_code` (own taxonomy), `address`, `lat`, `lng` (WGS84) — **all from the public source**, or user-typed for `USER`
|
||||
- `pet_policy` (JSON from TourAPI pet)
|
||||
- `license_note`, `image_license_type`
|
||||
- `source_synced_at`, `is_active`
|
||||
|
||||
`place_external_link`:
|
||||
- `place_id`, `provider` (`KAKAO`)
|
||||
- `external_id` (Kakao 장소 ID), `external_url` (`place_url`)
|
||||
- `checked_at`, `match_status` (`MATCHED` | `NOT_FOUND` | `AMBIGUOUS`)
|
||||
- **Nothing else from Kakao.**
|
||||
|
||||
`course_stop`:
|
||||
- `id`, `course_id`, `seq`
|
||||
- `place_id` (nullable FK)
|
||||
- `user_label` (user-typed, nullable)
|
||||
- `kakao_place_id`, `kakao_place_url` (nullable, only for user-added stops without a `place` row)
|
||||
- `user_memo`, `planned_start`, `stay_minutes`, `move_mode_to_next`, `created_at`
|
||||
|
||||
**Never store:** Kakao `place_name`, `address_name`, `road_address_name`, `x`/`y`, `category_*`, `phone`, `distance`, POI-tap names, or route polylines and durations (pending an answer). Don't pre-fill `user_label` from the API.
|
||||
|
||||
**Trade-offs:**
|
||||
- Public data misses newer trendy spots and sometimes uses legal business names. Fix this with an operator curation queue and "직접 추가".
|
||||
- More ETL work up front.
|
||||
- In return: zero per-view API cost, offline and shareable courses, AI-safe inputs, and no dependence on Kakao's shifting DevTalk answers.
|
||||
|
||||
---
|
||||
|
||||
## Open questions — draft DevTalk posts (카카오맵 API 지도/로컬 카테고리)
|
||||
|
||||
**Q1. 사용자가 직접 입력한 라벨로 표시 시점 재검색**
|
||||
> 안녕하세요. 데이트·당일 여행 코스 앱(WanderGo)을 개발하고 있습니다. 사용자가 로컬 API 검색 결과에서 장소를 고르면 장소 ID와 place_url만 저장합니다. 이어서 비어 있는 입력창을 띄워 사용자가 장소 이름을 직접 타이핑하게 하고, 이 텍스트를 저장합니다. 입력창에 API의 장소명을 미리 채우지 않습니다.
|
||||
> 1) 이렇게 사용자가 독립적으로 입력한 라벨을 저장하는 것은 허용되는지요?
|
||||
> 2) 코스 화면을 열 때 이 라벨을 query로 키워드 검색 API를 실시간 호출하고, 응답 중 저장된 장소 ID와 같은 항목의 이름·좌표를 화면에만 표시한 뒤 저장 없이 폐기하는 구조가 허용되는지요? (152312에서 "응답받은 장소명·좌표를 저장해 재검색"하는 것은 불가하다고 안내받았습니다. 이 질문은 사용자가 직접 입력한 텍스트만 query로 쓰는 경우입니다.)
|
||||
|
||||
**Q2. 공공데이터 원장과 카카오 장소 ID의 운영자 배치 매칭**
|
||||
> 한국관광공사 TourAPI와 소상공인 상가(상권)정보로 자체 장소 원장(이름·주소·좌표, 약 2~5만 건)을 구축합니다. 운영자가 원장 장소마다 키워드 검색(상호명 + 원장 좌표 반경 300m)을 한 번 호출합니다. 주소·거리로 명확히 일치할 때만 카카오 장소 ID와 place_url, 확인 일자를 저장하고, 그 밖의 응답값은 저장하지 않습니다.
|
||||
> 1) 151335·151052에서 ID 매칭은 허용되지만 "기계적인 대량 호출"은 안 된다고 하셨는데, 위와 같은 일회성 배치는 어디에 해당하는지요?
|
||||
> 2) 폐업 확인 등을 위해 같은 배치를 주기적으로(예: 분기 1회) 다시 실행해도 되는지요?
|
||||
|
||||
**Q3. 지도 탭 좌표 저장**
|
||||
> 사용자가 카카오맵 SDK 지도에서 빈 곳을 길게 눌러 고른 좌표(로컬 API 응답이 아닌 지도 탭 좌표)를 사용자가 직접 입력한 장소명과 함께 코스 경유지로 저장해도 되는지요? 151190에 같은 질문(추가 질문 2번)이 있었으나 답변이 없어 다시 여쭙습니다.
|
||||
|
||||
**Q4. place_url 앱 내 표시 방식**
|
||||
> 151514(9/7)에서는 place_url 상세 페이지를 앱 안에서 그대로 렌더링하는 구조가 허용된다고 하셨고, 151545(9/8)에서는 외부 브라우저 호출 방식으로 이용해 달라고 하셨습니다. Flutter 앱에서 `https://map.kakao.com/link/map/{장소ID}` 또는 place_url을 열 때 인앱 WebView(또는 Custom Tabs/SFSafariViewController)를 써도 되는지, 외부 브라우저·카카오맵 앱으로만 열어야 하는지 확인 부탁드립니다.
|
||||
|
||||
**Q5. 경로 API 결과 저장**
|
||||
> 도보·대중교통 경로 조회 API로 받은 소요 시간(분)과 경로선을 코스 공유 링크에서 다시 보여주려고 합니다. 이 결과도 로컬 API와 같이 실시간 호출만 허용되는지요? 아니면 사용자가 만든 코스의 일부로 소요 시간 숫자만 저장하는 것은 가능한지요?
|
||||
|
||||
---
|
||||
|
||||
## Gaps
|
||||
|
||||
- No official Kakao doc for `kakaomap://place?id=`. Only the web `map.kakao.com/link/...{장소ID}` formats are documented.
|
||||
- The license terms for user-address geocoding via public APIs (juso.go.kr 좌표제공, VWorld) weren't checked. Needed only if "직접 추가" should take a typed address.
|
||||
- Naver 특약 clause text wasn't read first-hand.
|
||||
- The Google lat/lng 30-day rule came from snippets of archived terms only.
|
||||
- Google `languageCode=ko` output for Korean places is untested.
|
||||
- 소상공인 상가정보 field-level freshness and coverage of cafés, date spots and pop-ups weren't measured.
|
||||
@@ -0,0 +1,214 @@
|
||||
# 지도 SDK 선정 (Flutter) — 2026-10-29 기준
|
||||
|
||||
> Builds on `WanderGo 기획 검토 자료조사/commercial_map_apis.md` §1, §2, §3, §7, §8. Don't re-read those for basics.
|
||||
> Legend: **(fetched)** = I opened the page, API JSON or source file myself. **(snippet)** = I only saw a search-engine summary. **(inference)** = my reasoning, not stated by a source.
|
||||
> Project baseline, read from `flutter/` in this repo: Flutter 3.41.4, Dart `^3.11.1`, AGP 8.11.1, Gradle 8.14, iOS deployment target 13.0.
|
||||
|
||||
---
|
||||
|
||||
## Takeaway
|
||||
|
||||
1. **Recommended map: Naver, via `flutter_naver_map` 1.4.4.** It's native and covers every map feature WanderGo needs: path/polyline overlays, built-in clustering with a custom cluster builder, widget-to-image markers, fitBounds, `onCameraIdle` + `getContentBounds` for "이 지역 검색", and a map `locale` setting (ko/en/ja/zh).
|
||||
2. **Naver is free at our scale.** The NCP pricing page (fetched today) shows **Dynamic Map, which covers Web JS, Android SDK and iOS SDK, free up to 6,000,000 calls/month**, for one 대표 계정 only. The old AI·NAVER API map products have no free tier. This settles the conflict in the earlier notes.
|
||||
3. **Neither Kakao option works for the MVP.** `kakao_maps_flutter` 0.2.2 has no polyline API and needs Flutter ≥3.44. `kakao_map_plugin` 1.0.0 is complete but runs in a WebView, and the Kakao JS API has no label-language option. The native Kakao SDK v2 has `setPoiLanguage("en")`, but neither Flutter package exposes it.
|
||||
4. **Google is the fallback.** Its labels follow the device language (ko/en/ja/zh). It's best-maintained, and map loads are free and unlimited. But in Korea it has no driving, walking or biking directions and no traffic layer, and Places results can only be shown on a Google map.
|
||||
5. **Data rules don't block us.** TourAPI is "이용허락범위 제한 없음", so its coordinates can go on any map. Kakao confirmed in writing again on 2026-06-29 that Local results may be shown on another vendor's SDK, real-time only, and nothing newer contradicts that. **The main risk with Naver is maintenance:** one maintainer, no release since 2025-12-20, and open bugs in clustering and multi-instance use. A 1-day spike should test exactly those.
|
||||
|
||||
---
|
||||
|
||||
## Comparison table
|
||||
|
||||
Assumption for the cost row: 10k MAU × 6 sessions/month × about 3 map views per session ≈ **180k map loads/month (~6k/day)** (inference).
|
||||
|
||||
| | `flutter_naver_map` | `kakao_maps_flutter` | `kakao_map_plugin` | `google_maps_flutter` |
|
||||
|---|---|---|---|---|
|
||||
| Latest version / date | **1.4.4 / 2025-12-20** (fetched) | **0.2.2 / 2026-08-24** (fetched) | **1.0.0 / 2026-09-11** (fetched) | **2.19.0 / 2026-10-14** (fetched) |
|
||||
| Publisher, 30-day downloads, likes | note11.dev (verified); 29,247; 116 | seunghwanly.xyz; 351; 9 | kkensu.com; 2,192; 48 | flutter.dev; 1,095,480; 4,630 |
|
||||
| SDK constraint vs. our Flutter 3.41 | Flutter ≥3.22, Dart ≥3.0 — **OK** | Flutter ≥3.44, Dart ^3.12 — **incompatible** (needs an upgrade) | Flutter ≥3.19, Dart ≥3.3 — **OK** | 2.19.0 needs Flutter ≥3.47 — **use 2.18.1** (Flutter ≥3.38) or upgrade |
|
||||
| Native or WebView | Native (Naver SDK 3.23.0, pinned) | Native (Kakao Maps SDK v2: Android 2.15.1, iOS ~>2.12.19) | **WebView** over the Kakao JS API (iframe on web) | Native |
|
||||
| Min OS | Android 6.0 (SDK 23), iOS 12 | Android SDK 23, iOS 13 | Android SDK 19/20+, iOS 9+ | Android SDK 24+, iOS 15+ (from the earlier notes) |
|
||||
| Polyline / route line | **Yes**: `NPathOverlay`, `NMultipartPathOverlay`, `NArrowheadPathOverlay`, `NPolylineOverlay` | **No.** The controller has no polyline/shape/route API, though the native SDK has RouteLine and Shape | **Yes**: `Polyline`, plus `getPolylineLength`, `onPolylineTap` | Yes |
|
||||
| Clustering | **Yes, native**: `NClusterableMarker` + `NaverMapClusteringOptions` with a custom `clusterMarkerBuilder` | **Only LOD label competition** on mobile (overlaps hidden, not count bubbles). True clusterer is web-only | **Yes**: `Clusterer` + `ClustererStyle` | Yes (`ClusterManager` in recent versions; not re-verified today) |
|
||||
| Custom markers (number circles) | `NOverlayImage.fromWidget` (rasterized, no interaction), `.fromByteArray`, `.fromAssetImage` | `MarkerStyle` from PNG bytes (render the widget yourself) | `MarkerIcon.fromWidget`, `MarkerIcon.pin`, plus live `KakaoMapWidgetOverlay` | `BitmapDescriptor` from bytes/asset; Advanced Markers need a Map ID |
|
||||
| Fit to bounds / "search this area" | `NCameraUpdate.fitBounds(bounds, padding)`; `onCameraIdle` + `getContentBounds()` | `CameraUpdate.fromBounds`; `getViewportBounds()` | `fitBounds(points, padding)`, `panToBounds` | Yes (standard API) |
|
||||
| Map label languages | **ko / en / ja / zh**, settable per map (`NaverMapViewOptions.locale`) | Native SDK: `setPoiLanguage("ko"/"en")` plus `getSupportedLanguages()`; **not exposed by the package** | **Korean only.** No language option found in the Kakao JS docs or the plugin | Follows the **device** language; ko, en, ja, zh-CN, zh-TW are supported |
|
||||
| Cost at 10k MAU (~180k loads/mo) | **0원**: within 6M/month free (대표 계정 only). With no free tier, about 18,000원/month at 0.1원 (price unconfirmed) | **0원**: 300,000/day free | **0원**: JS SDK 300,000/day free | **$0**: mobile loads unlimited |
|
||||
| Open issues / risk | 20 open, including clustering flicker and icon reverts, an Android leak on API 30–32, an iOS leak, two-map gestures, and an AGP 9 PR | 2 open, tiny user base | 1 open (AGP 9 / Gradle 9 build failure) | Low |
|
||||
|
||||
---
|
||||
|
||||
## Cited findings
|
||||
|
||||
### Q1. `flutter_naver_map` and NCP Maps pricing
|
||||
|
||||
**Package state**
|
||||
- 1.4.4 was published **2025-12-20T20:30Z**. Earlier releases: 1.4.3 on 2025-12-19, 1.4.2 on 2025-12-14 (Naver SDK upgraded to 3.23.0), 1.4.1 on 2025-07-30, and 1.4.0 on 2025-07-15. Requires Dart `>=3.0.0 <4.0.0` and Flutter `>=3.22.0`. Source: [pub.dev API](https://pub.dev/api/packages/flutter_naver_map) (fetched).
|
||||
- Score 140/160, 116 likes, 29,247 downloads in 30 days. Platforms: Android and iOS only, with Swift Package Manager support. Source: [pub.dev score API](https://pub.dev/api/packages/flutter_naver_map/score) (fetched).
|
||||
- Minimum OS: "flutter_naver_map은 Android 6.0(SDK 23), iOS 12.0부터 지원합니다." Source: [README](https://github.com/note11g/flutter_naver_map/blob/main/README.md) (fetched).
|
||||
- At tag v1.4.4, the Android build pins `com.naver.maps:map-sdk:3.23.0` with `minSdkVersion 23` and `compileSdk 36`. The iOS podspec pins `NMapsMap 3.23.0` with `platform :ios, '12.0'`. Source: [repo @v1.4.4](https://github.com/note11g/flutter_naver_map/tree/v1.4.4) (fetched).
|
||||
- The native Naver Android SDK is now at **3.24.0 (2026-09-09)**, after 3.23.1 (2026-01-26), 3.23.2 (2026-03-30) and 3.23.3 (2026-07-13). 3.23.0 (2025-09-22) added map-data attribution (`OnAttributionChangeListener`). So the plugin lags the native SDK by four releases. Source: [android-map-sdk CHANGELOG](https://github.com/navermaps/android-map-sdk/blob/master/CHANGELOG.md) (fetched).
|
||||
- Repo activity: 182 stars, last push 2026-07-07. The latest commits on main are two `MissingPluginException` fixes (2026-02-12 and 2026-03-23), which are unreleased. Branches `dev/1.4.5` and `dev/v2` exist, and issue #261 "Prepare v2.0" has been open since 2024-08. Source: [GitHub API](https://api.github.com/repos/note11g/flutter_naver_map) (fetched).
|
||||
|
||||
**Feature support, verified in source at v1.4.4**
|
||||
- Overlays: `path_overlay.dart`, `multipart_path_overlay.dart`, `arrow_head_path_overlay.dart`, `polyline_overlay.dart`, `polygon_overlay.dart` (fetched).
|
||||
- Clustering: `NClusterableMarker`, `NaverMapClusteringOptions(enableZoomRange, animationDuration, mergeStrategy, clusterMarkerBuilder)`. The doc comment says that when the builder is null, `defaultClusterMarkerBuilder` runs (fetched).
|
||||
- Custom markers: `NOverlayImage.fromWidget({widget, size, context})`. The doc comment says the widget is rasterized, so it isn't interactive, and warns against putting `Image` widgets inside it (fetched).
|
||||
- Camera and bounds: `NCameraUpdate.fitBounds(bounds, padding)`, `controller.getContentBounds()`, `onCameraIdle`, `onMapTapped`, `onSymbolTapped` (fetched).
|
||||
- Map language: `NLocale` doc comment says "현재 네이버 지도 SDK는 한국어, 영어, 중국어, 일본어만을 지원합니다". The `NaverMapViewOptions.locale` comment says "지도의 언어를 설정합니다. (한국어, 영어, 일어, 중국어 지원)" and defaults to the system locale (fetched).
|
||||
- Brand styling: `customStyle` (Map Style Editor ID) since 1.4.0. Source: [CHANGELOG](https://github.com/note11g/flutter_naver_map/blob/main/CHANGELOG.md) (fetched).
|
||||
- Authentication: `FlutterNaverMap().init(clientId:, onAuthFailed:)` uses the new NCP auth (NCP console > Maps > Application > "Dynamic Map") (fetched).
|
||||
|
||||
**Open issues that matter** — [issues](https://github.com/note11g/flutter_naver_map/issues) (fetched)
|
||||
- #349 (2025-08-26): `NClusterableMarker` makes the whole marker set flicker, on both iOS and Android, with an Android crash log. A fix was tried on `dev/1.4.5` but is unreleased.
|
||||
- #363 (2026-05-20): after clustering, markers revert to the icon they were created with, so custom icons are lost.
|
||||
- #342 (2025-07-28): on iOS, `clusterMarkerBuilder` stops firing after `clearOverlays()`.
|
||||
- #321 (2025-06-05): gestures misbehave when maps are used on two screens.
|
||||
- #365 (2026-08-27): on Android API 30–32 only, each map screen open and close leaks the MapView tree plus about 18 MB of native heap (39 → 267 MB after 12 cycles).
|
||||
- #347 (2025-08-04): iOS memory leak.
|
||||
- #283 (2024-12): an Impeller crash on one device.
|
||||
- #368 (2026-10-05): iOS crash on a zero-area polygon.
|
||||
- #364 and #366: `forceGLSurfaceView` is broken in 1.4.4.
|
||||
- #367: an open PR for AGP 9. We use AGP 8.11.1, so this doesn't affect us yet.
|
||||
|
||||
**SDK-level docs**
|
||||
- Locale: `NaverMap#setLocale(Locale)`, `NaverMapOptions#locale(Locale)`, and iOS `NMFMapView.locale` all say "지도의 로캘을 지정합니다. 기본값은 시스템 로캘". The supported-language list appears only in the Flutter plugin's comment above, not in the native reference. Sources: [Android NaverMap ref](https://navermaps.github.io/android-map-sdk/reference/com/naver/maps/map/NaverMap.html), [iOS NMFMapView ref](https://navermaps.github.io/ios-map-sdk/reference/Classes/NMFMapView.html) (fetched).
|
||||
- Paths: "PathOverlay 는 경로선을 나타내는 데 특화된 오버레이… 테두리와 패턴 이미지… 진척률… 경로선과 겹치는 마커 및 심벌을 숨길 수도 있습니다." Source: [guide 5-7](https://navermaps.github.io/android-map-sdk/guide-ko/5-7.html) (fetched).
|
||||
- Clustering: native marker clustering via `ClusteringKey`. Source: [guide 5-8](https://navermaps.github.io/android-map-sdk/guide-ko/5-8.html) (fetched).
|
||||
|
||||
**NCP Maps pricing**
|
||||
- Product page pricing table: "Maps 이용요금은 요청된 호출수 기준으로 부과됩니다."
|
||||
- Dynamic Map: "6,000,000건 이하 무료 … ※ 대표 계정 1개에 한해 월 6,000,000건의 무료 이용량을 제공합니다."
|
||||
- Static Map, Geocoding, Reverse Geocoding: 3,000,000/month each.
|
||||
- Directions 5: 60,000/month. Directions 15: 3,000/month.
|
||||
- The over-quota price cells show only **"-"**.
|
||||
- "AI NAVER API 내 지도 API 상품은 무료 이용량을 제공하지 않습니다."
|
||||
- The feature table marks Dynamic Map as available on **Web JS, Android SDK and iOS SDK (O/O/O)**, so the 6M free tier covers the mobile SDK.
|
||||
- Source: [ncloud.com/product/applicationService/maps](https://www.ncloud.com/product/applicationService/maps) (fetched as raw HTML on 2026-10-29; the page is JS-rendered, so I extracted the table text).
|
||||
- "Maps API는 대표 계정에 한하여 무료 이용량을 제공합니다. 대표 계정이 아닐 경우에는 과금이 되므로 주의". The 대표 계정 is the account that used the Maps API first. Default call limits per application: Dynamic Map 6,000,000 (maximum 15M/day, 45M/month). Daily and monthly limits and alerts can be set. Source: [Maps Application guide, updated 2026-10-15](https://guide.ncloud-docs.com/docs/application-maps-app-vpc) (fetched).
|
||||
- The older [Maps 개요](https://guide.ncloud-docs.com/docs/maps-overview) page lists free usage only for Web Dynamic Map, Static Map and Geocoding. **The newer pages above supersede it** (inference).
|
||||
- Over-quota unit price: 0.1원/건 for Dynamic Map, from the 2025 change notice (snippet, earlier notes §2). It's **not shown on the current product page, so it's unconfirmed** for the new Maps product.
|
||||
- Billing unit: "Mobile Dynamic Map의 경우 지도 뷰가 1회 생성될 때 1건" (snippet, NCP forum FAQ).
|
||||
|
||||
### Q2. The Kakao Flutter packages
|
||||
|
||||
**`kakao_maps_flutter`**
|
||||
- 0.2.2 published 2026-08-24, after 0.2.1 (2026-07-01) and 0.2.0 (2026-06-29). Requires **Dart ^3.12.0 and Flutter >=3.44.0**, which conflicts with our 3.41.4. 351 downloads in 30 days, 9 likes. Repo: 4 stars, 2 open PRs. Sources: [pub.dev API](https://pub.dev/api/packages/kakao_maps_flutter), [GitHub](https://github.com/seunghwanly/kakao_maps_flutter) (fetched).
|
||||
- Native dependencies: Android `com.kakao.maps.open:android:2.15.1` (minSdk 23); iOS `KakaoMapsSDK ~> 2.12.19` (iOS 13). Source: build.gradle and podspec (fetched).
|
||||
- `KakaoMapController` methods include markers, marker styles from bytes, InfoWindows, camera (`CameraUpdate.fromBounds`), `getViewportBounds`, POI visibility, logo and compass, and LOD marker layers. **There is no polyline, shape or route-line method.** `addLodMarkerLayer` is "Mobile only" and maps to native `LodLabelLayer`, which uses competition and hiding rather than count clusters. `addWebMarkerClusterer` is "Web only". There is **no language method**. Source: [controller source](https://github.com/seunghwanly/kakao_maps_flutter/blob/main/lib/src/controller/kakao_map_controller.dart) (fetched).
|
||||
- The README says "Separate agreement to Kakao Maps SDK Terms of Use required" and "Quota limits may apply for commercial use". Source: [pub.dev](https://pub.dev/packages/kakao_maps_flutter) (fetched).
|
||||
|
||||
**`kakao_map_plugin`**
|
||||
- 1.0.0 published 2026-09-11, after 0.4.0 (2026-01-20). Requires Dart >=3.3 and Flutter >=3.19. 2,192 downloads in 30 days, 48 likes. One open issue, #72 (2026-10-23): "Android build fails with Gradle 9 / AGP 9". Sources: [pub.dev API](https://pub.dev/api/packages/kakao_map_plugin), [GitHub](https://github.com/johyunchol/kakao_map_plugin) (fetched).
|
||||
- README: "네이티브 라이브러리를 사용한 것이 아닌 Javascript 라이브러리를 이용하여 제작… Android, iOS 는 `webview_flutter` 로". Support: Android SDK 19/20+, iOS 9.0+. Requires `usesCleartextTraffic="true"`. Source: [README](https://github.com/johyunchol/kakao_map_plugin/blob/main/README.md) (fetched).
|
||||
- Supported features:
|
||||
- `Polyline` set, `onPolylineTap`, `getPolylineLength`
|
||||
- `Clusterer(markers, styles: [ClustererStyle.material(...)])`
|
||||
- `MarkerIcon.fromWidget(...)`, plus `KakaoMapWidgetOverlay`: real Flutter widgets that follow the map once per frame. The README advises using `CustomOverlay` beyond a few hundred.
|
||||
- `fitBounds(points, padding: 48)`, `panToBounds`
|
||||
- Limitation: iOS `reload()` is unsupported
|
||||
- Source: README (fetched).
|
||||
- Kakao JS API documentation: the full doc page (2.1 MB) contains no `language`, `locale`, 영문 or 다국어 option. So labels are **Korean only** (fetched; absence-based inference). Source: [apis.map.kakao.com/web/documentation](https://apis.map.kakao.com/web/documentation/).
|
||||
|
||||
### Q3. Multilingual labels
|
||||
|
||||
- **Naver:** ko, en, ja and zh, set per map at runtime (see Q1). How completely POIs are translated is **not verified**, so the spike should check it.
|
||||
- **Kakao Maps SDK v2 (native Android):** `boolean setPoiLanguage(String language)` is documented as "지도의 POI 언어를 변경한다. 한국어는 "ko", 영어는 "en"", alongside `String[] getSupportedLanguages()`. Whether ja and zh are supported is **unconfirmed**; the docs name only ko and en. The iOS reference page wasn't reachable, so iOS parity is unconfirmed. Source: [KakaoMap reference](https://apis.map.kakao.com/android_v2/reference/com/kakao/vectormap/KakaoMap.html) (fetched). Neither Flutter package wraps this method (fetched, Q2).
|
||||
- **Google:**
|
||||
- Supported languages include ko, ja, en, zh-CN and zh-TW. "By default the API will attempt to load the most appropriate language based on the users location or browser settings." Source: [Google Maps FAQ](https://developers.google.com/maps/faq) (fetched).
|
||||
- On Android, map text labels "are displayed in the appropriate language based on the user's device settings and location". Source: [Configure a map](https://developers.google.com/maps/documentation/android-sdk/configure-map) (snippet).
|
||||
- `google_maps_flutter` has no per-map language parameter, so you **can't force English on a Korean-language phone** (inference).
|
||||
- **Google data limits in Korea:** the coverage table row for South Korea shows Map Tiles 2D/3D "⬤", Geocoding "⬤", and Traffic Layer, Driving Directions/Snap to Roads, Biking Directions and Walking Directions all "—" ("not available … or low data quality"). Source: [Google coverage](https://developers.google.com/maps/coverage) (fetched).
|
||||
- The 1:5,000 map-data export was conditionally approved on 2026-02-27, but no navigation launch had been reported as of Aug 2026 (earlier notes §3, snippet). I found no newer launch news (snippet search, 2026-10-29).
|
||||
|
||||
### Q4. Terms
|
||||
|
||||
**TourAPI**
|
||||
- 한국관광공사_국문 관광정보 서비스_GW: "**이용허락범위 제한 없음**". It offers only Visitkorea content "저작권 등에 구애 없이 자유롭게 활용 가능한 정보만을 선별". Photo restrictions: no defamatory use and no corporate CI/BI use; images are 공공누리 Type 1 and Type 3. Development accounts get 1,000 calls/day, and production accounts can raise that by registering a use case. Source: [data.go.kr 15101578](https://www.data.go.kr/data/15101578/openapi.do) (fetched).
|
||||
- So TourAPI coordinates can be stored in our DB and shown on any map (inference). Credit photos according to their 공공누리 type.
|
||||
|
||||
**Kakao Local results on a Naver map: confirmed, nothing newer contradicts it**
|
||||
- 2026-06-29, reply by "Map": "말씀하신 형태로 타사 지도SDK와 혼용하여 사용하셔도 약관 상 이슈는 없습니다. 다만… 실시간 호출 기반의 사용만 가능하며, 데이터 저장 등의 목적으로는 호출이 불가". Source: [DevTalk 150397](https://devtalk.kakao.com/t/local-api-sdk/150397) (fetched).
|
||||
- 2026-08-18: "다른 지도 API 와 조합하여 사용하시는 것을 제한하지는 않습니다만…". The reply has no staff badge, but the answer is official in style. Source: [DevTalk 151190](https://devtalk.kakao.com/t/local-api/151190) (fetched).
|
||||
- **Newest (2026-10-19 and 10-20), reply by "Map":**
|
||||
- "좌표와 주소 정보를 저장하여 활용하는 형태는 허용하지 않습니다".
|
||||
- Publishing data as a static JSON file is not allowed.
|
||||
- "장소ID, URL은 저장하여 카카오맵으로 랜딩하는 구조로 활용할 수 있습니다".
|
||||
- "장소ID 및 URL만 저장하고 별도 확보한 주소를 공공기관 API로 변환한 좌표로 저장하여 지도에 표시하는 방식은 가능합니다".
|
||||
- This doesn't contradict the earlier answers; it **adds a storable-coordinate path** through public geocoding.
|
||||
- Source: [DevTalk 152228](https://devtalk.kakao.com/t/api-id/152228) (fetched).
|
||||
|
||||
**Logo and attribution**
|
||||
- **Naver SDK:** "네이버 로고는 비활성화할 수 없으나, 위치를 조정하거나 클릭을 비활성화할 수는 있습니다. 네이버 지도 SDK를 사용하는 앱은 반드시 네이버 로고가 앱의 UI 요소에 가려지지 않도록 해야 합니다." If logo click is disabled, the app must provide a menu that opens the legal notice and open-source license screens. Source: [guide 4-1](https://navermaps.github.io/android-map-sdk/guide-ko/4-1.html) (fetched).
|
||||
- The Flutter plugin exposes `logoAlign`, `logoMargin`, `logoClickEnable`, `openLegalNotice()` and `openMapOpenSourceLicense()` (fetched).
|
||||
- NCP also requires that Maps feature names stay unchanged (for example, 거리뷰 can't be called 로드뷰), and treats calls outside the official path as abuse. Source: [maps-spec](https://guide.ncloud-docs.com/docs/maps-spec) (fetched).
|
||||
- **Kakao SDK v2:** the logo is bottom-right by default. "이에 대한 변경이나 가려짐은 허용되지 않습니다". Repositioning with `getLogo().setPosition()` is allowed when your UI covers it, and brief temporary covering is OK. Source: [precautions](https://apis.map.kakao.com/android_v2/docs/getting-started/precautions/) (fetched). Note that `kakao_maps_flutter` lists "Logo Visibility ❌ on Android" (fetched).
|
||||
- **Google:** Places content must be shown on a Google map, and only place_id may be stored (earlier notes §3/§7, fetched). Showing our own or TourAPI data on a Google map is not restricted by that rule (inference).
|
||||
- I did **not** find a Naver rule against showing third-party POIs (Kakao or TourAPI) on a Naver map. No clause-level Naver terms were read, so this is **unconfirmed**. The SDK is a general overlay API (inference).
|
||||
|
||||
---
|
||||
|
||||
## Recommendation + fallback
|
||||
|
||||
**MVP: Naver Maps via `flutter_naver_map` 1.4.4, with an NCP "Maps" (new product) subscription on the company's 대표 계정.**
|
||||
|
||||
Why:
|
||||
- It's the only option that is native, mature (about 29k downloads/month), compatible with our Flutter 3.41 and AGP 8.11 today, and covers all four map needs. It also lets us set label language per map (ko/en, with ja/zh later), independent of the device locale.
|
||||
- Cost at 10k MAU is 0원 (about 180k of the 6M/month free calls).
|
||||
- Pair it with:
|
||||
- Kakao Local REST through the NestJS proxy (no caching; store only place_id and place_url)
|
||||
- TourAPI and public-geocoded coordinates in our own DB
|
||||
- Kakao or TMAP for route geometry, drawn as `NPathOverlay`
|
||||
- Apply our brand style with the Map Style Editor (`customStyle`).
|
||||
|
||||
**Fallback: `google_maps_flutter`.** Use 2.18.1 on the current Flutter, or 2.19+ after upgrading to Flutter ≥3.47.
|
||||
- Upside: native and best-maintained, labels in ko/en/ja/zh, free map loads, and clustering and polylines are standard.
|
||||
- Downsides:
|
||||
- Labels follow the **device** language only.
|
||||
- No Google routing or traffic in Korea, so we'd keep Kakao or TMAP routes.
|
||||
- Korean base-map detail is reported to be thinner (inference).
|
||||
- Google Places must not be mixed in (we don't plan to use them anyway).
|
||||
- **Korean-only last resort:** `kakao_map_plugin` 1.0.0 (WebView). It has full features but carries a WebView performance risk, Korean-only labels, and an AGP 9 build issue.
|
||||
- **Don't choose `kakao_maps_flutter` now.** It has no polylines, needs Flutter ≥3.44, and has about 350 downloads/month. Revisit if it adds RouteLine and language support.
|
||||
|
||||
**Risk list**
|
||||
1. **Single maintainer and stale release.** No release since 2025-12-20; the plugin pins Naver SDK 3.23.0 while native is at 3.24.0, and v2 is in progress on a branch. Mitigation: be ready to fork; the license is BSD-3.
|
||||
2. **Clustering bugs** #349 (flicker) and #363 (custom icon reverts) hit our map tab directly. Mitigation: test in the spike; if they reproduce, cluster on the server or in Dart and draw plain `NMarker`s.
|
||||
3. **Multiple map instances.** #321 (two-map gestures), #365 (Android 30–32 leak), and #347 (iOS leak) affect us, since the course map, map tab and co-edit screen each hold a map. Mitigation: reuse one map per screen and avoid stacking map routes.
|
||||
4. **The NCP free tier depends on the 대표 계정.** A non-대표 account is billed from the first call, and the over-quota price isn't shown on the product page. Mitigation: register on the account that will own production, and set NCP usage limits and alerts.
|
||||
5. **Label translation coverage** in en/ja/zh isn't verified. POIs we add ourselves need our own i18n names whatever the base map.
|
||||
6. **AGP 9 / Gradle 9** will break both Naver (PR #367 open) and `kakao_map_plugin` (#72) when we upgrade. Hold AGP at 8.x until they're fixed.
|
||||
|
||||
---
|
||||
|
||||
## 1-day spike checklist (go/no-go for `flutter_naver_map`)
|
||||
|
||||
**Setup (about 1h)**
|
||||
- [ ] On the account that will own production: NCP console > Maps > subscribe to the new Maps product > Application with "Dynamic Map". Confirm the 대표 계정 check passes, write down the over-quota price the console shows, and set daily and monthly limits plus an alert.
|
||||
- [ ] Add `flutter_naver_map: 1.4.4` to `flutter/`. `flutter build apk` and `flutter build ios --no-codesign` must pass with Flutter 3.41.4, AGP 8.11.1 and iOS 13. Also run on an Android device with Impeller on (default).
|
||||
|
||||
**Course map (about 2h)**
|
||||
- [ ] Draw 6 numbered #FF5A60 circle markers via `NOverlayImage.fromWidget`, with tap → bottom sheet.
|
||||
- [ ] Draw an `NPathOverlay` from real Kakao or TMAP walking-route coordinates.
|
||||
- [ ] Use `NCameraUpdate.fitBounds` with bottom padding sized to the sheet height.
|
||||
- [ ] Check that the Naver logo stays visible above the sheet (`logoAlign`/`logoMargin`).
|
||||
|
||||
**Map tab (about 2h)**
|
||||
- [ ] Add 1,000 `NClusterableMarker`s with a custom `clusterMarkerBuilder`. Pan and zoom for 2 minutes on iOS and Android, and **watch for flicker (#349) and icon reverts (#363)**.
|
||||
- [ ] Wire `onCameraIdle` + `getContentBounds()` → "이 지역 검색" → NestJS proxy → Kakao Local (not cached) → replace markers.
|
||||
|
||||
**Language (about 1h)**
|
||||
- [ ] Switch `locale` to `NLocale('en')`, then `ja`, then `zh` at runtime.
|
||||
- [ ] Take screenshots of Myeongdong, Hongdae, Gyeongbokgung, Haeundae and Jeju airport, and count untranslated labels.
|
||||
- [ ] Compare with Google on an en-US device (about 30 min).
|
||||
|
||||
**Stability (about 1.5h)**
|
||||
- [ ] Open and close the course map 20 times while the map tab stays alive. Watch memory on an Android 11/12 (API 30–32) emulator for #365 and on iOS for #347.
|
||||
- [ ] Test gestures on the second map (#321).
|
||||
- [ ] Co-edit simulation: two devices; one adds or moves markers once a second over a mock WebSocket. Check that the other device updates within 300 ms and doesn't crash after 5 minutes.
|
||||
|
||||
**Data (about 0.5h)**
|
||||
- [ ] Load TourAPI WGS84 coordinates from our DB, and coordinates geocoded through a public geocoder, onto the Naver map. Check alignment against the base map (target: under 5 m offset).
|
||||
|
||||
**Go/no-go**
|
||||
- Go if: no crash, flicker that is absent or mitigable, an acceptable memory trend, and readable English labels.
|
||||
- Otherwise: switch the map layer to `google_maps_flutter`. Data and routing stay the same.
|
||||
Reference in New Issue
Block a user