| name | ipzitalk-transit-environment |
| description | 주소 또는 단지명을 입력받아 교통 환경(지하철/전철 + 철도(KTX·기차역) + 고속·시외버스터미널)을 분석해 종합 등급 + 한줄평 + 인터랙티브 HTML 리포트와 지도를 생성한다. 개통예정 교통 호재 (GTX·연장·신설)는 자동 수집 대상이 아니라 "수기 편집 영역"으로 자리만 표시한다. "교통 환경", "교통 분석", "교통 좋아?", "버스터미널", "KTX", "대중교통 접근성", "서울 접근성" 등 종합 교통을 물을 때 사용한다. (단일 "역세권/지하철만" 질문은 역세권 진단 배지 스킬로 분리 — 트리거 겹치지 않게 할 것.)
|
| version | 1.0.1 |
| license | proprietary |
교통 환경 분석
주소/단지명 하나로 지하철·철도·버스터미널 접근성을 종합해 대표 보고용 교통 리포트를 만든다.
※ 모든 거리는 직선거리 기준. 실제 도보·차량 소요시간, 배차·운행, 환승은 미반영.
입력
| 파라미터 | 필수 | 기본 | 설명 |
|---|
address 또는 complex_query | ✅(택1) | - | 주소 또는 단지명 |
radius_m | ✕ | 1500 | 근린 축(지하철) 표시 반경. 최대 5,000m |
단지명이 브랜드면 후보가 여러 개면 자동 확정하지 말고 후보(지역 포함)를 사용자에게 제시해 선택받는다.
반경 처리 (R1~R3) — radius_m은 판정 파라미터가 아니라 관측 파라미터다
| 층위 | 값 | 사용자 radius_m |
|---|
| 밴드(등급 판정) | 축별 절대 거리, 불변 | 영향 없음 |
| 표시 반경(지도 원·목록) | 기본 1,500 · 사용자가 주면 그 값 | 그대로 반영 |
| 수집 반경(API 호출) | max(radius_m, 밴드최대 1200 × 1.25) | 하한만 보장 |
- R1. 밴드는 절대 기준. 반경을 5km로 넓혀도 1.4km 역은 여전히 "역 이격"이고, 300m로 좁혀도 279m 역은 여전히 "역세권"이다. 반경은 등급을 어느 쪽으로도 못 움직인다.
- R2. 수집 반경은 항상 밴드 최대 이상으로 자동 확장. 사용자가 300m를 줘도 1,500m까지 탐색한다. 안 그러면 900m 역을 놓치고 ">1200 이격"으로 오판한다. "반경 내 없음"과 "이격"은 다르다.
- R3. 요청 반경 밖이라도 최근접 1건은 항상 표시. 회색 + "요청 반경 밖 · 1.4km" 꼬리표. 판정은 나오는데 목록이 비어 보이는 상황을 막는다.
- cap 5,000m. 그 이상은 입지 분석 의미가 없다. 2,000m 초과 시 아래 45건 캡 경고를 강제 표기.
- 광역 축 격리. 철도(수집 12km)·버스터미널(수집 15km)은
radius_m을 적용하지 않는다. 1km를 줬다고 터미널을 1km 안에서 찾으면 3km 고속터미널을 놓쳐 "미흡"으로 오판한다.
- 수집 반경 내에도 지하철이 0건이면 "N km 내 지하철역 없음(미확인)"으로 명시하고 멈춘다. 추정 금지. 종합 등급은 철도·터미널로 대체 판정(아래 종합 등급 참조).
🚨 45건 캡 (카카오 카테고리 검색)
search_by_nearby_category는 쿼리당 최대 45건만 주고 grid 옵션이 없다(키워드 검색에만 있다). 반경을 넓히면 먼 역부터 조용히 잘린다.
- 다만 카카오는
sort=distance로 주므로 최근접 값은 정확 → 등급 판정은 안전, 목록·개수는 근사.
- 응답
metadata.truncated가 true면 리포트에 "목록 불완전" 경고를 단다.
- 실측:
subway r2000 = 8건, truncated:false(캡 미도달).
필수 도구
| 도구 | 용도 |
|---|
get_geocode / get_address | 좌표 확보(주거시설 후보 우선) |
search_by_nearby_category | 지하철 categories=['subway'] |
search_by_nearby_keyword | 철도 "기차역" · 버스터미널 "버스터미널" |
get_static_map / get_map_embed_url | 지도(지하철 근린 중심 + 크게 열기 링크) |
워크플로우
- 좌표 확보 — address→geocode / 단지명→get_address. 후보 다수 → 사용자 선택.
- 지하철(근린 축) —
search_by_nearby_category(center, radius_m=수집반경, categories=['subway']) → 노선·역명·직선거리. (깨끗함)
- 수집반경 =
max(radius_m, 1500) — R2. 사용자 미지정 시 1,500m. 도심 밀집지는 1,500m면 도보권 판정에 충분.
- 응답
metadata.truncated가 true면 목록 불완전 경고를 단다(45건 캡, grid 미지원).
- 철도(광역 축, 고정) —
search_by_nearby_keyword(center, radius_m=12000, query="기차역") → 폐역 제외(name/category_name에 "폐역" 포함 시 드롭). KTX정차역 표기 유지. radius_m 미적용.
- 버스터미널(광역 축, 고정) —
search_by_nearby_keyword(center, radius_m=15000, query="버스터미널", category_filter={include_contains:["터미널"]}) → ATM·비터미널 노이즈 제거. radius_m 미적용.
- 판정·등급 — 아래 밴드로 항목별 등급 → 종합 등급. 이어서 1km 판정창 내 지하철 노선 수로 더블/트리플 라벨 산출.
- 지도 —
get_map_embed_url(center, radius_m, markers≥2) (SITE + 노선색 지하철역 마커) → 리포트에 임베드 + "크게 열기" 링크. 아래 지도 호출 규칙 준수.
- 출력 — md 요약 먼저 → HTML 리포트(
templates/result.html).
0건이 나오면 재확인한다 (🚨 부재 단정 금지)
카테고리 검색의 45건 캡은 서버가 아니라 후처리 필터라, 밀집지역에서는 실제로 있는 시설이 0건으로 보일 수 있다.
0건이 나온 축은 ① metadata.truncated 확인 → ② 같은 축을 search_by_nearby_keyword 로 한 번 더 조회(반경 동일, center 재해소 금지) → ③ 둘 다 0건 + truncated:false 면 "반경 내 없음" 확정, 한쪽이라도 캡에 걸리거나 엇갈리면 "확인 불가(검색 한계)" 로 적는다. 없음과 확인 불가를 섞어 쓰지 않는다.
밴드 (직선거리)
| 항목 | 우수 | 양호 | 보통 | 미흡 | 축 구분 |
|---|
| 지하철 | ≤500m | 500–800 | 800–1200 | >1200 | 근린(radius_m 적용) |
| 철도(기차/KTX) | ≤2km | – | 2–5km | >5km | 광역(고정) |
| 버스터미널 | ≤3km | – | 3–7km | >7km | 광역(고정) |
더블 · 트리플 역세권 라벨 (지하철 축만)
판정창 1,000m 안에서 이용 가능한 서로 다른 지하철 노선 수로 라벨을 붙인다. 역세권은 통상 지하철을 뜻하므로 철도·버스터미널은 세지 않는다.
| 1km 내 지하철 노선 수 | 라벨 |
|---|
| 1 | 역세권 |
| 2 | 더블 역세권 |
| 3 | 트리플 역세권 |
| 4+ | 쿼드러플 역세권 |
- 세는 단위는 노선이다. 역 개수도, 카카오 레코드 수도 아니다.
- 카카오는 환승역을 노선별로 쪼갠다(
사당역 4호선 / 사당역 2호선 = 레코드 2, 역 1, 노선 2).
- 역명이 달라도 같은 역사인 경우가 있다(
이수역=7호선 / 총신대입구역=4호선 → 동일 역사). 역명 dedupe로는 못 걸러진다.
- 노선 추출:
kakao_category_name 말단 세그먼트(… > 수도권7호선).
- 종합 등급은 올리지 않는다. 등급은 최근접 거리 밴드가 단독 결정. 라벨은 상단 pill과 한줄평에만 붙는다.
- 개통예정 노선(GTX 등)은 세지 않는다 → 수기 편집 영역.
- 판정창 1,000m는
radius_m과 무관한 고정값이다(라벨은 판정이므로 R1 적용).
지도 호출 규칙 (서버 렌더 버그 회피)
/map?d= 페이지의 fitBounds는 마커만 감싸고 반경 원을 무시한다. 원이 마커 bounds를 벗어나면 잘린다.
정확한 조건: center에서 마커 bounds의 북·남·동·서 여유가 각각 radius_m 이상이어야 한다. "마커 이격의 절반" 근사는 틀린다.
- 🚨 반경 눈금 마커를 넣지 않는다. 예전엔
fitBounds가 반경 원을 무시해 원이 잘리는 걸 막으려고
정북·남·동·서에 회색 더미 마커 4개를 심었다. 사용자에게는 정체를 알 수 없는 점으로 보여 혼란만 준다.
원이 잘리더라도 마커는 실제 장소만 찍는다. (근본 해결은 render.ts가 원을 bounds에 포함하도록 고치는 것 — 발견사항 6번)
get_map_embed_url에 center + radius_m을 항상 함께 넘긴다. 마커는 2개 이상(1개면 서버가 zoom:15 고정).
- 원 반경은 1,000m(더블·트리플 판정창)로 그린다.
- 역 마커는 노선색으로: 2호선
#00A84D · 4호선 #00A5DE · 7호선 #747F00 · 판정창 밖 #94a3b8.
- 좁은 화면 최소줌(한반도) 회피:
/map은 사이드바 280px 고정 + 반응형 없음 → 카드 CSS에서 iframe에 min-width:720px, .map{overflow-x:auto}를 주면 정상화된다(좁은 화면은 가로 스크롤).
종합 등급 (★ 3단계)
- 지하철 접근성을 주 가중(대중교통 핵심), 철도·터미널은 보조.
- 지하철 최근접 ≤500m → ★★★ 우수 / 500–1200m → ★★☆ 양호 / >1200m → ★☆☆ 미흡.
- 지하철 0건(지방·철도중심 사업지): 지하철 대신 철도(≤2km 우수/2–5km 양호/>5km 미흡)·버스터미널 최근접으로 종합 등급 판정. 한줄평에 "지하철 없음 · 철도/버스 기준" 명시.
- 철도·터미널이 양호(≤기준)면 한줄평에 가점 서술.
- 더블/트리플 라벨은 등급에 반영하지 않는다. 상단 pill과 한줄평에만 붙는다.
- 도심 입지 보정: 철도가 원거리(>5km 미흡)여도 지하철이 도보권(≤500m)이면 종합은 지하철 위주로 ★★★ 유지 가능. 한줄평에 "철도 원거리이나 지하철 환승으로 대체" 명시.
- 한줄평: 노선 다양성·도보 역세권 여부·서울/광역 접근 수단을 1~2문장으로 정직하게.
출력 포맷
- 채팅(먼저): 종합 등급 + 한줄평 + 항목별(지하철/철도/터미널) 최근접·등급 요약(md 표).
- HTML 리포트(선택): 상단 제목+종합 등급 pill → 지도 히어로 → 종합 평가 박스 → 지하철/철도/버스터미널 3섹션 표 → 수기 편집 영역(개통예정 호재) → 출처·hedge 푸터.
- 레이아웃 기준:
templates/result.html
HTML 산출물 계약 🚨
- 렌더 데이터는
result.json에 저장하고, 사용자 전달 HTML은 고정 정본 templates/result.html의 ipzi-data 블록만 교체해 만든다. 새 HTML을 작성하거나 마크업·CSS·렌더 JS를 수정하지 않는다.
- 셸 사용이 허용된 환경에서는 스킬 기준
../../scripts/html_artifact_contract.mjs를 --file-name "<대상>_교통환경분석"과 함께 사용한다. 최종 사용자 파일명은 <대상>_교통환경분석.html이다.
- shell-free 환경에서는 같은 파일명으로 저장하고 교체 전후의 fixed template region이 원본과 같은지 비교한다.
- 내부 파일
result.json·audit.json은 고정 이름을 유지하되, 사용자 전달 HTML을 result.html이나 index.html이라는 고정 이름으로 내지 않는다.
수기 편집 영역 (자동 수집 X)
- 개통예정 교통망(GTX-D, 5호선 연장, 김포한강선 등)·택지지구 폴리곤·도로 신설은 자동수집 대상 아님.
- 리포트에 "수기 편집 영역" 박스로 자리만 두고, 담당자가 출처·추진 단계 명시해 기입.
필수 단서 · 금지 표현
- 필수: 직선거리 기준 · 소요시간/배차/환승 미반영 · 철도·터미널은 폐역·비터미널 제외 결과 · 출처·조회일 표기.
- 금지: "도보 N분 확정", "개통 확정"(호재는 수기·출처 필수), 근거 없는 종합 우열 단정.
엣지 · 실패 처리
| 상황 | 처리 |
|---|
지오코딩 실패 / NOT_FOUND | 재입력 요청 |
후보 다수 / AMBIGUOUS | 후보(지역) 나열 후 선택 |
| 지하철/철도/터미널 0건 | 해당 항목 "없음/원거리" 명시, 거리 지어내지 않음 |
| 키워드 45건 cap | 최근접만 사용(영향 적음) |
검증된 사항 (서울 서초구 방배동 사례 · 조회 2026-07-08)
실데이터로 도심 다중노선·우수 등급 케이스 검증. (region_code 11650)
- 지하철 (category subway, r2000,
truncated:false): 279m(7호선, 우수) · 406m(4호선, 우수) · 659m(4호선, 양호) · 772m(2호선, 양호) · 1,002m(7, 보통) · 1,246m(2, 미흡). 재호출로 동일 값 재확인.
- 트리플 역세권 확인: 1km 판정창 내 노선 = {7, 4, 2} → 3개. 판정창을 1.2km로 넓혀도 노선 집합 불변 → 노선 기준은 경계값에 둔감.
- 환승역 함정 실증:
이수역 7호선과 총신대입구역 4호선은 동일 역사(역명이 달라 dedupe 불가). 사당역은 4·2호선 레코드 2건. → 역 개수로 세면 3곳, 실제 역사 2곳, 노선 3개. 세는 단위는 노선이어야 함이 이 사례로 확정.
- 철도 (keyword "기차역", r12000, 폐역제외): 용산역 KTX 5.4km(미흡) · 영등포역 7.6km · 서울역 7.9km. → 직선상 원거리(>5km 미흡)이나 도심이라 지하철 환승 대체.
- 버스터미널 (keyword "버스터미널", r15000, include_contains["터미널"]): 남부터미널 2.8km(≤3km 우수) · 센트럴시티 3.0km · 고속터미널 3.3km.
- 종합: ★★★ 우수 — 지하철 다중노선 도보권(279m) + 남부터미널 근접(2.8km). → 도심 입지 보정 규칙(철도 미흡+지하철 우수 → ★★★ 유지)이 실제 케이스로 확인됨.
- 확인된 필터 효과: 폐역·비터미널(ATM 등) 노이즈 제거 정상 동작. 지하철은 category 조회로 잡음 없음(clean).
섹션마다 출처를 작게 단다
데이터 블록 하단에 .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일 만료. 산출물 지도 캡션에 유효기간·재발급 필요를 반드시 적는다.
🚨 개통 예정 역이 장소명에 섞인다 (실측 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월 예정)"). 운영 중인 시설로만 판정한다.
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 연결 상태를 확인하도록 안내한 뒤 중단한다.