Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 53 additions & 34 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,58 @@
# AGENTS.md

이 저장소는 `pykma`, `pyopinet`과 같은 작업 형태를 따른다.
## 목표

이 저장소(GitHub/PyPI 이름 `python-krex-api`, import 패키지 이름 `krex`)는 한국도로공사 OpenAPI
(`data.ex.co.kr`, `data.go.kr`)를 Python 환경에서 쉽게 사용할 수 있도록 제공하는 **OpenAPI
클라이언트 라이브러리**다. API 명세 변환, 데이터 정규화, 로컬 유효성 검사 및 에러 매핑을
핵심 가치로 삼으며, Streamlit 등 시각화나 도메인 가시 레이어는 라이브러리 소비자 앱이
담당한다. `pykma`, `pyopinet`과 같은 작업 형태를 따른다.

## Think Before Coding

- 새 endpoint를 추가하기 전 `endpoints.md`에 명세가 있는지, `API_COVERAGE.md`에 구현/미구현
상태가 이미 표시돼 있는지 먼저 확인한다.
- 응답 shape이 실제 fixture로 검증되지 않았다면 Pydantic 모델을 성급하게 고정하지 말고
`Page[dict]`로 시작한다(`CONTRIBUTING.md`의 방침과 동일).
- `pykma`, `pyopinet` 같은 sibling 라이브러리에 이미 검증된 provider 연동이 있는지 먼저
찾아본다.

## Simplicity First

- 새 기능은 `codes.py` → `models.py` → `client.py` 순으로 필요한 계층만 추가한다.
- 검증된 provider endpoint 구현이 sibling library에 있으면 독립 wrapper를 새로 만들지 않고
기존 `KrexClient` namespace로 포팅한다.
- Streamlit 등 도메인 시각화·디버그 UI 로직은 이 라이브러리에 넣지 않고 소비자 앱에 맡긴다.

## Surgical Changes

- 한 patch는 관련된 module과 문서만 건드린다. 예를 들어 `src/krex/client.py`를 고치면 같은
patch에서 `endpoints.md`/`API_COVERAGE.md`도 함께 갱신한다.
- `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.coverage`, `.venv` 같은 산출물은 diff에
포함하지 않는다.
- 기존 enum/모델 필드 이름을 바꿀 때는 하위 호환이 필요한지 확인하고 `CHANGELOG.md`에 남긴다.

## Goal-Driven Execution

- 지시 우선순위는 사용자 요청 > 이 `AGENTS.md` > `README.md`/기존 테스트 순이다.
- 완료 기준은 관련 pytest가 통과하고, 변경된 동작이 `README.md`/`endpoints.md`/
`API_COVERAGE.md`에 반영된 상태다.
- 애매한 요구사항은 최소한의, 되돌릴 수 있는 가정으로 진행하고 그 가정을 커밋/PR에 남긴다.

## Practical Bias

- 실제 provider 응답(fixture)이 없는 필드는 무리해서 타입을 좁히지 않고 raw로 남긴다.
- Live 검증은 opt-in(`KEX_LIVE=1`)으로 유지하고, 기본 test suite는 항상 네트워크 없이
통과해야 한다.
- 문서와 코드가 어긋나면 코드를 기준으로 문서를 먼저 고친다.

## 문서 언어 정책

이 저장소의 **모든 Markdown/RST 문서는 한글로 작성한다**. 공식 API 필드명, 코드 식별자, 명령어, URL, provider 원문처럼 그대로 보존해야 하는 값만 영어를 유지한다.

설명 문장, 절제목, 표 column 헤더, 빠른 시작 가이드, 일지 항목은 한글로 적는다. 새 문서를 만들 때 영문 초안을 두지 않는다 — 처음부터 한글로 쓴다.

## 역할

이 저장소(GitHub/PyPI 이름 `python-krex-api`, import 패키지 이름 `krex`)는 한국도로공사 OpenAPI (`data.ex.co.kr`, `data.go.kr`)를 Python 환경에서 쉽게 사용할 수 있도록 제공하는 **OpenAPI 클라이언트 라이브러리**다. API 명세 변환, 데이터 정규화, 로컬 유효성 검사 및 에러 매핑을 핵심 가치로 삼으며, Streamlit 등 시각화나 도메인 가시 레이어는 라이브러리 소비자 앱이 담당한다.

## 식별자 (혼동 방지)
## 식별자 표

| 항목 | 값 |
|------|----|
Expand All @@ -24,35 +64,19 @@

## 개발 환경 정책

PC 개발은 Windows 호스트에서 직접 진행한다.
- **Git 사용**: 이 저장소의 git 작업은 항상 Windows용 `git.exe` 기준으로 수행한다. WSL 셸 안에서도 필요하면 `"/mnt/c/Program Files/Git/cmd/git.exe"`처럼 Windows git을 직접 호출한다.
- **Python 버전**: Python 3.11+
- **Git 사용**: 이 저장소의 git 작업은 항상 Windows용 `git.exe` 기준으로 수행한다. WSL 셸 안에서도 필요하면 `"/mnt/c/Program Files/Git/cmd/git.exe"`처럼 Windows git을 직접 호출한다.
- **Unit test**: 네트워크를 절대 직접 호출하지 않는다. Fake session 또는 JSON fixture를 사용한다.
- **의존성 관리**: `pyproject.toml`을 기준으로 하며, 개발 및 디버그용 의존성은 명시된 optional-dependencies에 격리한다.
- **에이전트별 고정 worktree**: ChatGPT Codex는 `F:\dev\python-krex-api-codex`, Claude Code는 `F:\dev\python-krex-api-claude`, Google Antigravity는 `F:\dev\python-krex-api-antigravity`를 사용한다. 작업마다 브랜치만 새로 만들고, CodeGraph는 worktree마다 1회 `codegraph init -i` 후 `codegraph sync`로 유지한다.

## 지시 우선순위

1. 사용자 요청
2. 이 `AGENTS.md`
3. `SKILL.md`
4. `API_COVERAGE.md`, `endpoints.md`
5. `codes.md`, `error-codes.md`
6. 기존 코드와 테스트
7. 최소한의, 되돌릴 수 있는 가정

## 절대 하지 말 것 (DO NOT)

1. **`main` 직접 푸시 금지**: 반드시 feature 브랜치 + PR 머지 과정을 거친다.
2. **API key 평문 커밋 금지**: `.env`에 키를 관리하되 절대 커밋하지 않는다. `data.ex.co.kr`에는 `KEX_EX_API_KEY`, `data.go.kr`에는 `DATA_GO_KR_SERVICE_KEY` 환경 변수를 사용한다. `KrexClient` 인스턴스 표현식(`__repr__`)이나 실패 메시지, 문서 등에 API 키가 노출되지 않도록 처리한다.
2. **API key 평문 커밋 및 노출 금지**: `.env`에 키를 관리하되 절대 커밋하지 않는다. `data.ex.co.kr`에는 `KEX_EX_API_KEY`, `data.go.kr`에는 `DATA_GO_KR_SERVICE_KEY` 환경 변수를 사용한다. `KrexClient` 인스턴스 표현식(`__repr__`)이나 실패 메시지, 문서 등에 API 키가 노출되지 않도록 처리한다.
3. **Unit test에서 network 호출 금지**: 가짜 세션(Fake Session)이나 fixture 파일(JSON 등)을 사용한다.
4. **Stable 의미가 있는 반환값을 raw string으로 노출 금지**: raw string보다는 typed Pydantic model 또는 enum을 제공한다.
5. **모호한 raw 주소 데이터에서 법정동 코드 추측 금지**: 공개 주소 데이터는 provider 원문 문자열 그대로 보존한다.
6. **`routeNo`, `unitCode`, branch code, office code 등의 leading zero 제거 금지**: 0이 앞에 붙는 코드는 반드시 문자열 타입으로 보존한다.
7. **Debug UI 의존성을 이 library에 포함 금지**: Streamlit 등의 디버그 UI 도구는 배포 패키지 코어 의존성에서 철저히 제외한다.
8. **임시/캐시 파일 커밋 금지**: `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.coverage`, `.venv` 및 가상환경 관련 파일은 절대 커밋하지 않는다.
9. **독립된 wrapper 신규 작성 남발 금지**: sibling library에 검증된 provider endpoint 구현이 있으면 기존 `KrexClient` namespace로 포팅하여 재사용성을 극대화한다.
10. **`.codegraph/` 커밋 금지**: CodeGraph 인덱스는 worktree 로컬 산출물이다. 이미 초기화된 worktree에서는 `codegraph init` 재실행 대신 `codegraph sync`를 사용한다.
5. **주소·코드 원문 임의 가공 금지**: 모호한 raw 주소 데이터에서 법정동 코드를 추측하지 않고 provider 원문 문자열 그대로 보존한다. `routeNo`, `unitCode`, branch code, office code 등 앞에 0이 붙는 코드는 반드시 문자열 타입으로 보존하고 leading zero를 제거하지 않는다.
6. **Debug UI 의존성을 이 library에 포함 금지**: Streamlit 등의 디버그 UI 도구는 배포 패키지 코어 의존성에서 철저히 제외한다.

## Module ownership

Expand All @@ -78,22 +102,17 @@ PC 개발은 Windows 호스트에서 직접 진행한다.
- coverage/support 상태: `API_COVERAGE.md`
- enum 변경: `codes.md`
- exception/provider error mapping: `error-codes.md`
- 구조적 결정(뒤집힐 수 있는, 재론쟁될 만한 결정): `docs/decisions.md`
- agent workflow/repeated mistakes: `SKILL.md`와 이 파일
- 문서 스타일 규칙: `CONTRIBUTING.md`, `SKILL.md`, 이 파일을 함께 갱신

## 작업 후 체크리스트

- [ ] `python -m compileall src/krex tests` 통과
- [ ] `python -m pytest` 통과
- [ ] `python -m mypy src/krex` 통과 (설치되어 있는 경우)
- [ ] `ruff check .` 통과 (설치되어 있는 경우)
- [ ] `.pytest_cache`, `.mypy_cache`, `.ruff_cache` 등이 커밋 대상에서 제외되었는지 확인

## 검증

```bash
python -m compileall src/krex tests
python -m pytest
python -m mypy src/krex
ruff check .
```

실제 `data.ex.co.kr` 및 `data.go.kr` 검증은 의도적으로 할 때만 다음 명령어를 사용한다:
Expand Down
111 changes: 66 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
# python-krex-api

![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)
![GPL-3.0-or-later 라이선스](https://img.shields.io/badge/License-GPL--3.0--or--later-blue.svg)
![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)

한국도로공사(Korea Expressway Corporation, KEX) 공공데이터 OpenAPI를 Python에서 편하게 쓰기 위한 비공식 클라이언트 라이브러리입니다.

`python-krex-api`는 `data.ex.co.kr`와 `data.go.kr`에 흩어진 고속도로 교통량, 실시간 소통, 통행료, 영업소, 휴게소, 휴게소별 날씨, 기준정보 API를 한 인터페이스로 감싸고, 응답을 Pydantic 모델과 enum으로 변환합니다.

> 현재 저장소는 초기 구현 단계입니다. 세부 엔드포인트 명세는 [endpoints.md](endpoints.md), 지원 상태표는 [API_COVERAGE.md](API_COVERAGE.md), 코드표는 [codes.md](codes.md), 에러 매핑은 [error-codes.md](error-codes.md), 구현 규칙은 [SKILL.md](SKILL.md)와 [AGENTS.md](AGENTS.md)를 참고하세요.
현재 진행 중인 작업은 [CHANGELOG.md](CHANGELOG.md#unreleased)를 참고하세요.

## 먼저 읽을 문서

| 필요 정보 | 문서 |
|---|---|
| 엔드포인트 상세 명세 | [endpoints.md](endpoints.md) |
| 지원/live 검증 상태 | [API_COVERAGE.md](API_COVERAGE.md) |
| 공통 코드표 · enum | [codes.md](codes.md) |
| 에러 코드 매핑 | [error-codes.md](error-codes.md) |
| 에이전트 구현 규칙 | [SKILL.md](SKILL.md), [AGENTS.md](AGENTS.md) |
| 구조적 의사결정 기록 | [docs/decisions.md](docs/decisions.md) |
| 기여 가이드 | [CONTRIBUTING.md](CONTRIBUTING.md) |
| 변경 이력 | [CHANGELOG.md](CHANGELOG.md) |

---

Expand Down Expand Up @@ -65,47 +82,66 @@ pip install python-krex-api

### 3단계: 사용

`KrexClient`는 동기 클라이언트가 기본이고, `KrexClient.aio()`는 같은 namespace/메서드를 그대로 `await`할 수 있는 비동기 진입점입니다(`python-krheritage-api`와 같은 스타일). asyncio 애플리케이션이라면 이 방식을 대표 예제로 사용하세요.

```python
import asyncio

from krex import CarType, KrexClient


async def main() -> None:
async with KrexClient.aio() as client:
# 실시간 소통
flows = await client.traffic.flow(route_no="0010")
for item in flows.items[:5]:
print(item.route_name, item.conzone_name, item.speed, item.congestion_level)

# 영업소간 통행료
fees = await client.tollfee.between_tollgates(
start_unit_code="101",
end_unit_code="105",
car_type=CarType.LIGHT,
)
print(fees.items[0].toll_fee)

# 휴게소 표준데이터(data.go.kr)
areas = await client.restarea.list_all(route_name="경부고속도로")
print(areas.items[0].name, areas.items[0].has_ev_charger)

# 노선별 휴게시설과 휴게소 주유소 가격(data.ex.co.kr)
facilities = await client.restarea.route_facilities(route_code="0010")
fuel_prices = await client.restarea.fuel_prices(
service_area_code=facilities.items[0].service_area_code
)
print(facilities.items[0].service_area_name, fuel_prices.items[0].gasoline_price)

# 휴게소별 날씨(data.ex.co.kr)
weather = await client.restarea.latest_weather(lookback_hours=72)
if weather.first:
print(weather.first.unit_name, weather.first.weather, weather.first.temperature)


asyncio.run(main())
```

스크립트나 동기 코드베이스에서는 `from_env()`로 만든 동기 클라이언트를 그대로 사용할 수 있습니다.

```python
from krex import CarType, KrexClient

client = KrexClient.from_env()

# 실시간 소통
flows = client.traffic.flow(route_no="0010")
for item in flows.items[:5]:
print(item.route_name, item.conzone_name, item.speed, item.congestion_level)

# 영업소간 통행료
fees = client.tollfee.between_tollgates(
start_unit_code="101",
end_unit_code="105",
car_type=CarType.LIGHT,
)
print(fees.items[0].toll_fee)

# 휴게소 표준데이터(data.go.kr)
areas = client.restarea.list_all(route_name="경부고속도로")
print(areas.items[0].name, areas.items[0].has_ev_charger)

# 노선별 휴게시설과 휴게소 주유소 가격(data.ex.co.kr)
facilities = client.restarea.route_facilities(route_code="0010")
fuel_prices = client.restarea.fuel_prices(service_area_code=facilities.items[0].service_area_code)
print(facilities.items[0].service_area_name, fuel_prices.items[0].gasoline_price)

# 휴게소별 날씨(data.ex.co.kr)
weather = client.restarea.latest_weather(lookback_hours=72)
if weather.first:
print(weather.first.unit_name, weather.first.weather, weather.first.temperature)
```

비동기 코드에서는 `python-krheritage-api`와 같은 `aio()` 진입점을 사용할 수 있습니다.

```python
from krex import KrexClient

async with KrexClient.aio() as client:
flows = await client.traffic.flow(route_no="0010")
print(flows.first)
```

### 키를 직접 넘기는 방식
Expand Down Expand Up @@ -198,22 +234,7 @@ python -m streamlit run examples/streamlit_debug_ui.py --server.port 8504

## 구현 상태

현재 구현은 “공통 호출 기반 + 핵심 모델 우선” 단계입니다.

| 영역 | 상태 | 비고 |
|---|---|---|
| HTTP transport | 구현됨 | 5xx/네트워크 retry, 키 마스킹, JSON 파싱 |
| `data.ex.co.kr` envelope | 구현됨 | `SUCCESS`, `NO_DATA`, 인증/한도/서버 코드 매핑 |
| `data.go.kr` envelope | 구현됨 | `response.header.resultCode` 검사 |
| 교통 핵심 모델 | 부분 구현 | `TrafficByIc`, `TrafficFlow`, `Incident` |
| 통행료 핵심 모델 | 구현됨 | `TollFee`, `Tollgate` |
| 휴게소 핵심 모델 | 부분 구현 | 노선별 휴게시설, 표준 휴게소, 휴게소별 날씨, 주유소 가격, 음식가격 |
| 시설/행정 상세 모델 | 원시 dict 반환 | 경로 검증 후 Pydantic 모델 승격 예정 |
| 라이브 호출 테스트 | 미포함 | 기본 테스트는 네트워크를 쓰지 않음 |

검증되지 않은 포털 경로나 데이터셋은 무리해서 모델로 고정하지 않고 `Page[dict]`로 반환합니다. 실제 응답 fixture가 쌓이면 Pydantic 모델로 승격합니다.

전체 지원/미지원/실서버 검증 상태는 [API_COVERAGE.md](API_COVERAGE.md)를 기준으로 관리합니다.
영역별 구현/live 검증 상태는 [API_COVERAGE.md](API_COVERAGE.md)를 기준으로 관리합니다. 검증되지 않은 포털 경로나 데이터셋은 무리해서 모델로 고정하지 않고 `Page[dict]`로 반환하며, 실제 응답 fixture가 쌓이면 Pydantic 모델로 승격합니다.

---

Expand Down Expand Up @@ -493,6 +514,6 @@ tests/

## 라이선스

GPL-3.0-or-later. 자세한 조건은 [LICENSE](LICENSE)를 참고하세요.
GPL-3.0-or-later. 자세한 조건은 [LICENSE](LICENSE)를 참고하세요. 이 라이선스는 이 저장소의 코드에만 적용됩니다.

원천 데이터의 저작권과 이용조건은 한국도로공사, 공공데이터포털, 각 데이터 제공기관 정책을 따릅니다. 이 프로젝트는 비공식 라이브러리이며 한국도로공사와 무관합니다.
원천 데이터의 저작권과 이용조건은 한국도로공사, 공공데이터포털, 각 데이터 제공기관 정책을 따릅니다. 이 프로젝트는 비공식 라이브러리이며 한국도로공사와 무관합니다. 실제 이용 전에는 각 제공기관의 최신 이용약관을 직접 확인하세요 — 본 안내는 법적 자문이 아니며 법적 효력을 보장하지 않습니다.
18 changes: 17 additions & 1 deletion WSL_KRADDR_GEO_DEBUG_UI.md → WSL_KOR_TRAVEL_GEO_DEBUG_UI.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
# WSL kraddr.geo 디버그 UI 메모
# WSL kor-travel-geo 디버그 UI 메모

> **이름 변경**: 이 문서는 `python-kraddr-geo`/`kraddr_geo_api`/`pykraddr` 경로명으로 작성됐지만,
> 그 프로젝트는 `kor-travel-geo`(Python 패키지 `kortravelgeo`)로 리네임됐고 SpatiaLite/SQLite 기반
> 구현도 PostgreSQL + PostGIS로 재구현됐습니다. 아래의 옛 경로·모듈명·명령은 더 이상 유효하지
> 않습니다. 이 저장소(`python-krex-api`)는 `kor-travel-geo`를 import하지 않으므로 이 노트를
> 정본으로 유지하지 않습니다.
>
> `kor-travel-geo`의 로컬 디버그 UI를 WSL에서 띄우는 현재 방법은 그 저장소 자신의 문서
> (`docs/agent-guide.md`, `docs/adr/065-linux-only-development-environment.md` 등)를 확인하세요.
> 제공 표면은 README 기준으로 REST API `uvicorn kortravelgeo.api.app:app`, 관리 UI는 별도 Next.js
> 패키지 `kor-travel-geo-ui`입니다 — 정확한 포트/플래그는 그쪽 문서에서 확인해야 이 저장소가 다시
> 오래된 정보를 복제하지 않습니다.

---

아래는 리네임 이전에 작성된 원문(참고용, 유효하지 않음)입니다.

이 provider를 `python-kraddr-geo` 또는 `python-krtour-map`과 함께 검증할 때는 WSL에서 Linux 실행 파일을 사용하고 host binding을 명시해 로컬 지오코딩 디버그 스택을 실행한다.

Expand Down
Loading
Loading