| name | ipzitalk-subway-proximity |
| description | 주소 또는 단지명을 입력받아, 가장 가까운 지하철/전철역까지의 직선거리를 기준으로 역세권 신호 배지(🟢역세권/🟡준역세권/🟠다소 이격/⬜역 이격)를 카드 + 지도로 생성한다. "역세권", "역세권이야?", "지하철 가까워", "역까지 거리", "지하철 도보", "전철역 근처", "역까지 몇 분", "다중노선", "환승 편해?" 등의 표현이 있을 때 이 스킬을 사용한다. 사용자가 특정 주소/단지의 지하철 접근성을 물으면 즉시 트리거한다.
|
| version | 1.0.1 |
| license | proprietary |
역세권 진단
주소/단지명 하나로 최근접 역까지 거리를 재서 역세권 신호 배지 + 지도를 만든다.
※ "참고 신호"다. 역 직선거리 기준이며 실제 도보거리·환승·출구 위치는 미반영.
입력
| 파라미터 | 필수 | 기본 | 설명 |
|---|
address 또는 complex_query | ✅(택1) | - | 주소 또는 단지명 |
반경 고정(배지 공통). X세권 배지는 가벼운 단일지표 도구라 사용자 반경을 받지 않는다.
수집 2,000m · 판정 밴드 최대 1,200m · 다중노선 판정창 1,000m · 지도 원 500m(밴드 1구간) 모두 스킬 고정값.
반경을 조절하려는 요청은 교통 환경 분석 스킬로 넘긴다(거기는 radius_m을 받는다).
워크플로우 (검증된 실제 도구·파라미터)
- 표준번들 확보 (1단계) —
resolve-site로 단지명/주소 → 좌표·region_code·bjd·전용면적 기준을 한 번에 확보.
- 예)
resolve-site → lat / lng / region_code / bjd 를 한 번에 받는다.
- 역 조회 —
search_by_nearby_category(center=좌표, categories=['subway'], radius_m=2000)
→ 반경 내 역을 sort=distance로 받아 최근접 역 + 거리 산출. 같은 역의 복수 노선은 각각 표기(사당 4호선/2호선 등).
- 배지 판정(아래 밴드) → 다중노선 가점(아래) → 지도 생성.
밴드(역 직선거리 m): ≤500 🟢 역세권 / 500–800 🟡 준역세권 / 800–1200 🟠 다소 이격 / >1200 ⬜ 역 이격
더블 · 트리플 역세권 라벨 (노선 기준)
판정창 1,000m 안에서 이용 가능한 서로 다른 노선 수로 라벨을 붙인다.
| 1km 내 노선 수 | 라벨 |
|---|
| 1 | 역세권 |
| 2 | 더블 역세권 |
| 3 | 트리플 역세권 |
| 4+ | 쿼드러플 역세권 |
- 세는 단위는 노선이다. 역 개수도, 카카오 레코드 수도 아니다.
- 카카오는 환승역을 노선별로 쪼개 준다(
사당역 4호선 / 사당역 2호선 = 레코드 2건, 역 1곳, 노선 2개).
- 역명이 달라도 같은 역사인 경우가 있다(
이수역=7호선, 총신대입구역=4호선 → 동일 역사 환승). 역명 dedupe로는 못 걸러진다.
- 노선 추출:
kakao_category_name의 말단 세그먼트(… > 수도권7호선). 경전철·신분당선 등도 같은 자리에서 얻는다.
- 등급은 올리지 않는다. 배지 등급은 최근접 거리 밴드가 단독으로 정한다. 라벨은
signal.label과 hedge 본문에만 반영.
- 개통예정 노선(GTX 등)은 세지 않는다 → 수기 편집 영역.
- 판정창 경계(1,000m)는 엄격 적용하되, 경계에 걸친 역이 이미 산입된 노선이면 결과가 바뀌지 않으므로 hedge에 한 줄로 밝힌다.
- 예) 내방역 1,002m 탈락 → 7호선은 이수역으로 이미 산입 → 트리플 유지.
출력 = 공통 카드 템플릿
출력물 레이아웃 기준은 templates/result.html이다. 이 구조를 그대로 두고 ipzi-data 비실행 JSON 블록만 교체한다(self-contained, CDN·이모지 금지, SVG 인라인, 라이트/다크 대응). 역세권 배지 설정:
iconId:"i-subway" (SVG 심볼: i-subway·i-map·i-info 포함), badgeTitle:"역세권 진단"
axisMax:1500, radiusDefault:1000, metric:"distance", unit:"m"
bands:[{max:500,cls:"g",label:"≤500 역세권"},{max:800,cls:"a",label:"500–800 준역세권"},{max:1200,cls:"o",label:"800–1200 다소 이격"},{max:Infinity,cls:"x",label:">1200 역 이격"}]
signal:{label:"<라벨>",cls:"<밴드>"} — label은 노선 수에 따라 역세권/더블/트리플/쿼드러플, cls는 최근접 밴드
stat:[{n:"<최근접>m",l:"최근접(<역명>)",cls:"<밴드>"},{n:"<노선수>",l:"1km 내 노선 (7·4·2)",cls:"g"},{n:"__COUNT__",l:"슬라이더 반경 내 역"}]
- ⚠️
__COUNT__는 카드 스크립트가 슬라이더 반경 내 POI 레코드 수로 치환한다. 노선 수가 아니다. 라벨을 "N km 내 역"으로 쓰면 radiusDefault와 어긋나니 "슬라이더 반경 내 역"으로 적는다.
pois: 역명(노선) + d(거리 m) 배열, 거리 오름차순
hedge.verify: null (공식 확인처 없음)
지도 호출 규칙 (배지 공통 · 서버 렌더 버그 회피)
/map?d= 페이지는 fitBounds로 마커만 감싸고 반경 원을 무시한다. 원이 마커 bounds를 벗어나면 잘린다.
정확한 조건: SITE(center)에서 마커 bounds의 북·남·동·서 여유가 각각 radius_m 이상이어야 원이 온전히 보인다. "마커 최대 이격의 절반" 같은 근사는 틀린다 — POI는 한쪽으로 쏠리기 마련이라, 실측하면 방배 데모 10개 지도의 원이 전부 잘려 있었다(병세권·숲세권·쇼세권은 여유 0m).
- 🚨 반경 눈금 마커를 넣지 않는다. 예전엔
fitBounds가 반경 원을 무시해 원이 잘리는 걸 막으려고
정북·남·동·서에 회색 더미 마커 4개를 심었다. 사용자에게는 정체를 알 수 없는 점으로 보여 혼란만 준다.
원이 잘리더라도 마커는 실제 장소만 찍는다. (근본 해결은 render.ts가 원을 bounds에 포함하도록 고치는 것 — 발견사항 6번)
dLat = r×1.05 / 111320 · dLng = r×1.05 / (111320 × cos(lat))
- 대안은
radius_m을 아예 안 넘겨 원을 포기하는 것뿐이다.
get_map_embed_url에 center와 radius_m을 항상 함께 넘긴다.
- 마커는 2개 이상(SITE + 역). 1개면 서버가
zoom:15로 고정하고 반경을 무시한다.
- 역 마커는 노선색으로: 2호선
#00A84D · 4호선 #00A5DE · 7호선 #747F00 · 판정창 밖 #94a3b8.
- 좁은 화면 최소줌(한반도) 회피:
/map 페이지는 사이드바가 280px 고정이고 반응형 규칙이 없다. 안쪽 지도 영역이 좁으면 fitBounds가 최소 줌으로 떨어진다. 카드 CSS에서 iframe에 min-width:720px를 주고 .map{overflow-x:auto}로 감싸면 안쪽 뷰포트가 720px로 확보돼 정상 줌이 나온다(좁은 화면에서는 카드가 가로 스크롤). templates/result.html에 반영됨.
- ⚠️
/map 페이지를 단독 탭에서 좁은 폭(모바일)으로 열면 여전히 최소줌으로 뜬다. 이건 서버 렌더 문제이며 스킬로 회피할 수 없다 → "지도 크게 열기"는 데스크톱 기준.
필수 단서 · 금지 표현
- 필수(hedge): 역 직선거리 기준 · 실제 도보거리/환승/출구 위치 미반영.
- 금지: "도보 N분 확정", "환승 X분", "개통예정 노선(GTX 등) 반영" — 개통예정 노선은 수기 편집 영역.
엣지
- 지오코딩 실패/
NOT_FOUND → 재입력 요청 · 후보 다수/AMBIGUOUS → 후보 나열
- 반경 내 역 0건 → ⬜ 역 이격(데이터 부족) 배지
검증된 사항 (방배롯데캐슬아르떼)
resolve-site + search_by_nearby_category(categories=['subway'], radius_m=2000) 조합으로 실데이터 산출 확인(2026-07-08 최초, 2026-07-09 재호출로 동일 값 재확인).
- 반경 2km 내 역 8건: 이수(7호선) 279m · 총신대입구(4호선) 406m · 사당(4호선) 659m · 사당(2호선) 772m · 내방(7호선) 1002m · 남성(7호선) 1139m · 방배(2호선) 1246m · 낙성대(2호선) 1910m. 캡 미도달.
- 최근접 이수역 279m → 🟢 역세권 판정.
- 1km 판정창 내 노선 = {7, 4, 2} → 트리플 역세권. 판정창을 1.2km로 넓혀도 남성(7)·방배(2)가 추가될 뿐 노선 집합은 불변 → 노선 기준은 경계값에 둔감하다는 것을 실데이터로 확인.
- 환승역 함정 실증:
이수역 7호선과 총신대입구역 4호선은 동일 역사인데 역명이 달라 dedupe로 안 걸러진다. 사당역은 4·2호선이 레코드 2건. → 역 개수로 세면 3곳, 실제 역사는 2곳, 노선은 3개.
- hedge/금지표현·
verify:null·밴드표가 카드 푸터에 정상 렌더됨.
섹션마다 출처를 작게 단다
데이터 블록 하단에 .src 한 줄. 도구·API 이름은 쓰지 않는다. 사용자가 아는 기관명만.
| 블록 | 출처 표기 |
|---|
| 단지 개요·세대수·준공·주차·연차 | 공동주택관리정보시스템(K-apt) |
| 매매·전세·평당가·거래량 | 국토교통부 실거래가 |
| 학교·교통·생활·상권 등 장소 | 카카오맵 |
| 분양공고·분양가·주택형·입주월 | 청약홈 |
| 지도 (장소 마커) | 네이버 지도 · 카카오맵 |
| 지도 (분양공고 마커) | 네이버 지도 · 청약홈 |
- 🚨 출처 문자열은
ipzi-data JSON으로 받지 않고 템플릿 마크업에 직접 박는다.
어느 블록이 어디서 왔는지는 실행마다 달라지지 않는다. 데이터로 받으면 채우는 걸 잊거나 틀리게 쓸 여지만 생긴다.
- 🚨 한 블록에 두 출처가 섞이면 병기한다. 예:
세대수·주차 — 공동주택관리정보시스템(K-apt) · 위치 — 카카오맵.
하나로 뭉뚱그리면 어느 숫자가 어디서 왔는지 사용자가 알 수 없다.
- 🚨 쓰지 않은 기관을 출처로 적지 않는다. 우리가 부르는 곳은 위 다섯 곳뿐이다.
- 히어로·유의사항·푸터에는 달지 않는다. 데이터 블록에만.
디자인 정본
스킬 폴더 밖 문서에 의존하지 않도록 규칙을 여기 인라인으로 둔다.
- CDN·외부 폰트·이모지 금지. 아이콘은
<symbol> 인라인 + <use> 참조로 self-contained.
- 라이트/다크 양쪽.
prefers-color-scheme + :root[data-theme] 모두 대응.
- 토큰만 사용:
--g/--y/--o/--r/--x/--brand/--up/--down/--zebra (+ -s 배경 변형).
- 예외 상태:
null은 "정보없음"(0 아님) · 표본 부족은 판정 유보 · 45건 캡 도달은 "목록 불완전" 표기.
★·☆는 활자 기호이며 이모지가 아니다. 등급 표기에 사용 가능.
- 지도 카드 CSS:
.map{overflow-x:auto; overflow-y:hidden} + .map iframe{display:block; min-width:720px}.
overflow:hidden만 주면 iframe이 카드 폭에 짓눌려 지도가 최소 줌(한반도)으로 떨어진다.
- 🚨 지도 링크는 발급 후 7일 만료. 산출물 지도 캡션에 유효기간·재발급 필요를 반드시 적는다.
만료 시 iframe이 빈 화면이 되는데, 원인 표기가 없으면 리포트가 고장난 것처럼 보인다.
🚨 개통 예정 역이 장소명에 섞인다 (실측 2026-07-09)
카카오는 개통 예정 역을 장소명 문자열로 표기하고, 카테고리도 지하철로 준다.
"위례호수공원역 (2026년12월예정)" 215m category_name: 교통,수송 > 지하철,전철
다행히 search_by_nearby_category(categories=['subway']) 는 이것을 반환하지 않는다. 실측:
반경 500m · categories:['subway'] → 0건 (215m 예정역이 있는데도)
반경 1000m · query="공원"(키워드) → 예정역이 나옴
- 🚨 지하철은 반드시 카테고리 검색을 쓴다. 키워드 검색으로 바꾸면 미개통 역이 최근접이 되어 등급이 통째로 뒤집힌다.
- 키워드 검색을 쓰는 축(철도
query="기차역", 터미널 query="버스터미널")은 장소명에
예정·개통·(20NN년 이 포함되면 판정에서 제외하고 목록에만 꼬리표를 단다. 연도를 지어내지 말 것.
- 학교도 같은 함정이다(
"산빛초등학교 (2027년 3월 예정)"). 운영 중인 시설로만 판정한다.
🚨 화면 문구는 일반인 언어로 (2026-07-10 결정)
진단 시리즈(초품아·역세권·병세권·쇼세권·숲세권)의 독자는 부동산 전문가가 아니다.
내부 용어를 그대로 화면에 쓰지 않는다. 임계값·색(cls)은 그대로 두고 라벨만 바꾼다.
| 쓰지 않는 말 | 대신 |
|---|
| 최근접 · (최근접·판정 기준) | 제일 가까운 곳 · (제일 가까움) |
| 판정 밴드 · 판정 기준 | 등급 기준 |
| 신호 등급 | 등급 |
| 인접 / 근접 | 아주 가까움 / 가까움 |
| 다소 이격 | 조금 먼 편 |
| 이격 · 역 이격 | 먼 편 · 역이 먼 편 |
| 보도권 | 가까움 |
| 판정 유보 | 자료 부족 |
| 판정창 | 기준 범위 |
| 참고 신호(진단 아님) | 참고용이며 확정 판단이 아닙니다 |
| 1km 내 · 슬라이더 반경 내 | 1km 안 · 선택한 반경 안 |
| 미확인 | 확인되지 않음 |
| 판정에서 제외 | 등급에서 제외 |
거리도 읽기 쉽게: 1313m → 1.3km.
문장도 사람 말로
✕ SITE(파랑) · 반경 3km 원 · 판정 기준 경찰병원(주황, 2.3km) · 서울세계로병원(회색)은 등급에 미반영
✓ 파란 점이 우리 집, 주황 점이 등급 기준이 된 경찰병원(2.3km)입니다.
회색 서울세계로병원(645m)은 종합병원이 아니라 등급에 넣지 않았습니다.
- 🚨 부드럽게 쓰되 사실은 그대로. "가까움"이 "좋음"이 되면 안 된다. 등급은 거리 밴드가 정한다.
- 🚨 숫자는 화면 전체에서 일치해야 한다.
aux 항목을 개수에서 뺐으면 본문 문장의 개수도 함께 고친다.
실제로 목록은 5곳인데 본문이 6곳이라고 적힌 적이 있다.
- 익숙한 말은 남긴다:
역세권·준역세권·초품아·상권.
MCP 도구 네임스페이스와 출처
ipzitalk MCP 도구의 네임스페이스는 실행 환경(Codex, Claude Code, Hermes, claude.ai 커넥터 등)에 따라 다르다.
이 문서에 적힌 도구 이름(search_announcement_info, get_geocode, get_map_embed_url 등)은 접두사 없는 기본 도구명(base tool name) 이다.
- 먼저 연결된 도구 목록에서 같은 기본 도구명을 찾는다.
- 그중
ipzitalk-remote 플러그인의 ipzitalk 서버 provenance가 확인되는 도구만 우선 사용한다. Codex에서는 실제 도구 호출 이벤트의 server: ipzitalk과 기본 도구명을 기준으로 확인한다.
presale-mcp 또는 다른 로컬 MCP provenance의 동명 도구는 Remote Skill의 대체 수단으로 사용하지 않는다.
- provenance를 확인할 수 없거나 같은 기본 도구명이 여러 서버에 있어 모호하면 임의 선택하지 말고 중단하여 필요한 Remote 도구명을 안내한다.
클라이언트가 연결 도구 목록에 plugin/server provenance를 구조적으로 제공하지 않을 때만 다음 명시적 fallback을 사용한다.
mcp__plugin_ipzitalk-remote_ipzitalk__<도구명>
mcp__ipzitalk_mcp__<도구명>
mcp__ipzitalk__<도구명>
mcp__claude_ai_ipzitalk__<도구명>
fallback으로도 Remote 출처를 유일하게 확인할 수 없으면 값을 추정하지 말고, 사용자에게 ipzitalk Remote MCP 연결 상태를 확인하도록 안내한 뒤 중단한다.