k-skill/docs/features/fine-dust-location.md
Jeffrey (Dongkyu) Kim ef2c69b81c Replace sops+age encryption with plain dotenv and agent-native credential resolution
Agent environments (OpenClaw, Claude Code, Codex) assume users delegate
credentials to the agent. sops+age added setup friction without real
security benefit since the agent decrypts on every call anyway.

New model: skills declare required env var names; how they are supplied
is up to the agent (own vault, shell env, or ~/.config/k-skill/secrets.env
as the default fallback with 0600 permissions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:12:04 +09:00

4.9 KiB

사용자 위치 미세먼지 조회 가이드

이 기능으로 할 수 있는 일

  • 지역명/행정구역 힌트로 측정소 후보 찾기
  • 단일 측정소 확정이 어려우면 후보 측정소 목록 반환
  • 정확한 측정소명으로 재조회
  • PM10, PM2.5, 등급, 조회 시각 요약

먼저 필요한 것

필요한 환경변수

클라이언트 기본값:

  • 기본 external proxy URL: https://k-skill-proxy.nomadamas.org
  • KSKILL_PROXY_BASE_URL 는 override 가 필요할 때만 사용

프록시 없이 direct fallback 으로 쓸 때만:

  • AIR_KOREA_OPEN_API_KEY

Credential resolution order

  1. 이미 환경변수에 있으면 그대로 사용한다.
  2. 에이전트가 자체 secret vault(1Password CLI, Bitwarden CLI, macOS Keychain 등)를 사용 중이면 거기서 꺼내 환경변수로 주입해도 된다.
  3. ~/.config/k-skill/secrets.env (기본 fallback) — plain dotenv 파일, 퍼미션 0600.
  4. 아무것도 없으면 유저에게 물어서 2 또는 3에 저장한다.

입력값

  • 기본: 지역명/행정구역 힌트(regionHint)
  • 재조회: 정확한 측정소명(stationName)

기본 흐름

  1. KSKILL_PROXY_BASE_URL 가 있으면 먼저 k-skill-proxy/v1/fine-dust/report endpoint 를 호출합니다.
  2. regionHint 가 들어오면 프록시는 먼저 시도명을 추출하고, getCtprvnRltmMesureDnsty 로 해당 시도 측정소 목록을 확보합니다.
  3. region token 이 시도 내 실제 측정소명과 유일하게 대응하면 그 측정소로 getMsrstnAcctoRltmMesureDnsty 를 호출합니다.
  4. 단일 측정소 확정이 어려우면 ambiguous_locationcandidate_stations 를 반환합니다.
  5. 클라이언트/사용자는 후보 중 정확한 측정소명으로 다시 /v1/fine-dust/report?stationName=... 를 호출합니다.
  6. PM10, PM2.5, 등급, 조회 시점/조회 시각을 함께 요약합니다.

프록시 예시:

python3 scripts/fine_dust.py report --region-hint "서울 강남구" --json

후보 반환 예시:

curl -fsS --get 'https://k-skill-proxy.nomadamas.org/v1/fine-dust/report' \
  --data-urlencode 'regionHint=광주 광산구'

정확한 측정소명 재조회:

curl -fsS --get 'https://k-skill-proxy.nomadamas.org/v1/fine-dust/report' \
  --data-urlencode 'stationName=우산동(광주)'

원본 AirKorea endpoint 형태를 거의 그대로 쓰고 싶으면 passthrough endpoint 도 사용할 수 있습니다. 별도 client API 는 불필요하고, 프록시가 serviceKey 만 서버에서 주입합니다.

curl -fsS --get 'https://k-skill-proxy.nomadamas.org/B552584/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty' \
  --data-urlencode 'returnType=json' \
  --data-urlencode 'numOfRows=1' \
  --data-urlencode 'pageNo=1' \
  --data-urlencode 'stationName=강남구' \
  --data-urlencode 'dataTerm=DAILY' \
  --data-urlencode 'ver=1.4'

예시

지역 기반 direct fallback:

curl -sG "http://apis.data.go.kr/B552584/MsrstnInfoInqireSvc/getMsrstnList" \
  --data-urlencode "serviceKey=${AIR_KOREA_OPEN_API_KEY}" \
  --data-urlencode "returnType=json" \
  --data-urlencode "numOfRows=50" \
  --data-urlencode "pageNo=1" \
  --data-urlencode "addr=서울 강남구"

실시간 측정값:

curl -sG "http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty" \
  --data-urlencode "serviceKey=${AIR_KOREA_OPEN_API_KEY}" \
  --data-urlencode "returnType=json" \
  --data-urlencode "numOfRows=100" \
  --data-urlencode "pageNo=1" \
  --data-urlencode "stationName=중구" \
  --data-urlencode "dataTerm=DAILY" \
  --data-urlencode "ver=1.4"

helper script 반복 검증:

python3 scripts/fine_dust.py report \
  --station-file scripts/fixtures/fine-dust-stations.json \
  --measurement-file scripts/fixtures/fine-dust-measurements.json \
  --region-hint "서울 강남구"

fallback / 대체 흐름

  • 지역명/행정구역을 먼저 받습니다
  • 단일 측정소를 확정하지 못하면 후보 측정소 목록을 돌려줍니다
  • 사용자는 후보 중 하나를 선택해 stationName 으로 다시 조회합니다
  • 측정소 목록 API가 403 이어도 getCtprvnRltmMesureDnsty 와 측정소별 실측 API 조합으로 우회합니다

주의할 점

  • 실시간 수치라 조회 시각을 같이 적어야 합니다
  • PM10/PM2.5 값이 - 이거나 비정상이면 등급도 함께 재확인합니다
  • API 가 khaiGrade 를 비워 보내면 통합대기등급은 정보없음 으로 표시합니다
  • regionHint 는 자연어이므로 단일 측정소가 안 잡히는 경우가 자주 있습니다
  • hosted 모드에서는 upstream AirKorea key 를 클라이언트에 배포하지 않고 proxy 에만 둡니다