k-skill/packages/parking-lot-search/README.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

2.3 KiB

parking-lot-search

Korean parking-lot lookup backed first by the official Data.go.kr 전국주차장정보표준데이터 Open API.

Usage principles

  • Do not infer or track the user's location automatically.
  • Ask for the current location first, then use a neighborhood/station/landmark or latitude, longitude pair.
  • The default result set is public (공영) parking lots only.
  • The package resolves text locations through Kakao Map place search, then searches the official parking dataset near the resolved coordinates.
  • Live occupancy and reservation are not provided by the official standard data.

Official surfaces

  • Data.go.kr standard dataset: https://www.data.go.kr/data/15012896/standard.do
  • Data.go.kr Open API docs: https://www.data.go.kr/data/15012896/openapi.do
  • Open API endpoint: https://api.data.go.kr/openapi/tn_pubr_prkplce_info_api
  • Kakao Map mobile search: https://m.map.kakao.com/actions/searchView?q=<query>
  • Kakao Map place panel JSON: https://place-api.map.kakao.com/places/panel3/<confirmId>

Proxy-first usage

By default, the package calls the shared k-skill proxy:

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;
});

Set KSKILL_PROXY_BASE_URL or pass proxyBaseUrl to use a local proxy.

Direct Data.go.kr usage

For direct official API calls, pass apiKey or set DATA_GO_KR_API_KEY and useDirectApi: true.

const result = await searchNearbyParkingLotsByLocationQuery("광화문", {
  apiKey: process.env.DATA_GO_KR_API_KEY,
  limit: 5,
  radius: 2000
});

Public API

  • parseCoordinateQuery(locationQuery)
  • normalizeParkingLotRows(payload, origin, options)
  • buildOfficialParkingLotApiUrl(options)
  • searchNearbyParkingLotsByCoordinates(options)
  • searchNearbyParkingLotsByLocationQuery(locationQuery, options)

Modu Parking status

Issue #135 mentioned connecting 모두의주차장 if possible. This package does not scrape or call an unofficial Modu Parking surface. Add it later only if there is an approved, stable, and legally usable API contract.