k-skill/parking-lot-search/SKILL.md
Jeffrey (Dongkyu) Kim e1656541a4
Fix parking lot lookups: force HTTPS, cache full dataset, normalize provider fields (#156)
Data.go.kr 이 tn_pubr_prkplce_info_api 를 HTTPS 로만 서비스하고 HTTP 요청은 301 로 리다이렉트하기 때문에 Node fetch 가 `response.ok=false` 로 떨어져 기능이 전체 실패하고 있었다. 이 커밋은 HTTPS 로 직접 호출하도록 수정하면서, 업스트림의 주소/지역 필터가 실제로는 동작하지 않고 페이지당 응답이 1000rows 기준 26s 에 달해 20s fetch timeout 에 꾸준히 걸리던 문제까지 함께 해결한다.

## What changed

- packages/k-skill-proxy/src/parking-lots.js
  - PARKING_LOT_API_URL 을 `http://` → `https://` 로 고정 (root cause).
  - 업스트림 address/geo 필터가 신뢰 불가하므로 full-dataset 을 한 번 로드해 프로세스 메모리에 6시간 TTL 로 캐시하고, 동시 호출자는 in-flight promise 를 공유하도록 한다. nearby 쿼리는 캐시된 행을 좌표 거리로 필터링해 서비스한다.
  - DATASET_PAGE_SIZE=300, fetch timeout 30s 로 페이지당 응답이 20s 를 넘기지 않도록 맞췄다.
- packages/k-skill-proxy/src/server.js
  - 더 이상 의미 없어진 numOfRows / maxPages 쿼리 파라미터를 라우트에서 제거하고, 응답 payload 의 query echo 도 정리했다.
- packages/k-skill-proxy/test/server.test.js
  - 새 캐시 기반 동작을 검증하는 테스트로 교체: (1) full dataset load + 좌표 필터 + 프록시 응답 캐시 재사용, (2) public_only 기본값 및 해제 시 동작, (3) 좌표 검증 실패 400, (4) 업스트림 키 미설정 시 503.
- packages/parking-lot-search/src/index.js
  - OFFICIAL_API_URL 도 HTTPS 로 맞춰 직접 호출 모드 사용자도 같은 버그를 밟지 않게 한다.
- packages/parking-lot-search/src/parse.js
  - 업스트림이 `insttCode` / `insttNm` (camelCase) 를 돌려주는데 parser 가 snake_case (`instt_code`, `instt_nm`) 만 인식해 providerCode/providerName 이 비어 있던 문제를 수정.
- packages/parking-lot-search/test/* 및 fixtures
  - HTTPS URL 매칭으로 업데이트하고, insttCode/insttNm 회귀 테스트를 fixture/assertion 에 추가.
- docs/features/parking-lot-search.md, parking-lot-search/SKILL.md, packages/parking-lot-search/README.md
  - 공식 endpoint 표기를 HTTPS 로 통일.
- .changeset/parking-lot-https-fix.md
  - parking-lot-search 패키지 patch 릴리즈 노트 추가.

## How it was verified

- `npm run ci` (lint + typecheck + tests + pack:dry-run) 통과.
- 로컬에서 실제 `DATA_GO_KR_API_KEY` 로 k-skill-proxy 를 기동해 live 호출 검증:
  - 광화문 (37.573713, 126.978338) cold cache: 30s 내 전체 18,868 rows 로드, 2km 내 47개 공영주차장 반환 (세종로 414m, 서린노외 456m 등).
  - 강남역 (37.497952, 127.027621) warm cache: 31ms 응답, 1.5km 내 13개 반환 (역삼문화공원 380m, 역삼푸른솔도서관 421m 등).
- 업스트림 직접 HTTPS 호출로 `resultCode=00 NORMAL_SERVICE` 정상 동작 확인.
2026-04-22 10:52:57 +09:00

3.9 KiB

name description license metadata
parking-lot-search Use when the user asks for nearby parking lots or 근처 주차장/공영주차장. Always ask the user's current location first, then use official Data.go.kr public parking data through k-skill-proxy or the parking-lot-search package. MIT
category locale phase
convenience ko-KR v1

Parking Lot Search

What this skill does

유저가 알려준 현재 위치를 기준으로 근처 공영주차장 을 찾는다.

  • 위치는 자동 추정하지 않는다.
  • 반드시 먼저 현재 위치를 질문한다.
  • 기본값은 공영 주차장만 보여준다.
  • 공식 전국주차장정보표준데이터 Open API를 사용한다.
  • 위치 문자열은 Kakao Map anchor 검색으로 좌표를 잡은 뒤, 공식 주차장 데이터에서 거리순으로 정리한다.
  • 실시간 만차/잔여면/예약 여부는 공식 표준데이터에 없으므로 확정해서 말하지 않는다.

When to use

  • "근처 주차장 찾아줘"
  • "광화문 주변 공영주차장 어디 있어?"
  • "서울역 근처 무료 주차장 있어?"
  • "지금 여기서 가까운 공영주차장 지도 링크 줘"

Mandatory first question

위치 정보 없이 바로 검색하지 말고 반드시 먼저 물어본다.

권장 질문:

현재 위치를 알려주세요. 동네/역명/랜드마크/위도·경도 중 편한 형식으로 보내주시면 근처 공영주차장을 찾아볼게요.

위치가 애매하면:

가까운 역명이나 동 이름으로 한 번만 더 알려주세요.

Official surfaces

  • 표준데이터 안내: https://www.data.go.kr/data/15012896/standard.do
  • Open API 안내: https://www.data.go.kr/data/15012896/openapi.do
  • Open API endpoint: https://api.data.go.kr/openapi/tn_pubr_prkplce_info_api
  • k-skill proxy: /v1/parking-lots/search
  • Kakao Map 모바일 검색: https://m.map.kakao.com/actions/searchView?q=<query>
  • Kakao Map 장소 패널 JSON: https://place-api.map.kakao.com/places/panel3/<confirmId>

Workflow

  1. 유저에게 반드시 현재 위치를 묻는다.
  2. 위치 문자열을 받으면 Kakao Map으로 anchor 후보를 고르고 좌표를 확보한다.
  3. anchor 주소에서 시도 + 시군구 address hint를 만든다.
  4. k-skill-proxy /v1/parking-lots/search 또는 parking-lot-search 패키지로 공식 주차장 데이터를 조회한다.
  5. 보통 3~5개만 짧게 정리하고, 지도 링크를 같이 준다.
  6. 요금/운영시간은 데이터 기준일자와 함께 안내하고, 실시간 현황이 아님을 밝힌다.

Responding

결과는 보통 아래 필드를 포함해 짧게 정리한다.

  • 주차장명
  • 거리
  • 공영/민영 및 노상/노외/부설 유형
  • 주소
  • 운영요일/운영시간
  • 요금정보, 기본요금, 추가요금
  • 주차구획수
  • 전화번호/관리기관
  • 데이터기준일자
  • 지도 링크

Node.js example

const { searchNearbyParkingLotsByLocationQuery } = require("parking-lot-search");

async function main() {
  const result = await searchNearbyParkingLotsByLocationQuery("광화문", {
    limit: 3,
    radius: 1500
  });

  console.log(result.anchor);
  console.log(result.items);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

모두의주차장 status

Issue #135에서 모두의주차장 연동 가능성을 언급했지만, v1은 공식 공공데이터 기반으로 시작한다. 승인된 공식/파트너 API 계약이 확인되기 전에는 모두의주차장 비공식 API 호출이나 scraping을 하지 않는다.

Done when

  • 유저의 현재 위치를 먼저 확인했다.
  • 공식 데이터 기반으로 최소 1개 이상 nearby parking lot을 찾았거나, 못 찾은 이유와 다음 질문을 제시했다.
  • 가장 가까운 결과를 3~5개 이내로 정리했다.
  • 실시간 잔여면/예약 가능 여부가 아님을 필요한 경우 명확히 했다.