digitie

SKILL — kor-travel-geo 에이전트 매뉴얼

- [ ] DTO/스키마 변경이면 `scripts/export_openapi.py` 재실행 → 프론트엔드 `gen:types`

digitie 0 Updated 1mo ago

Resources

17
GitHub

Install

npx skillscat add digitie/kor-travel-geo

Install via the SkillsCat registry.

SKILL.md

SKILL — kor-travel-geo 에이전트 매뉴얼

이 파일은 당신(AI 에이전트)이 작업을 시작하기 전 반드시 읽어야 한다.
1회만 읽으면 30분 이상의 디버깅을 줄일 수 있다.

1. 정체성

이 저장소(GitHub 이름 kor-travel-geo, Python 패키지 kortravelgeo)는 도로명주소 전자지도(PDF 사양)를 PostGIS에 적재해 제공하는 한국 주소 지오코딩 라이브러리·REST API다. vworld API의 응답 형식을 호환하면서 자체 확장(x_extension)을 더한다. kor-travel-geo-ui는 같은 저장소 안에서 관리하는 별도 Node.js 패키지이며, 디버그/관리 UI로 백엔드 REST API만 호출한다.

이전 SpatiaLite/SQLite 기반 구현은 같은 kortravelgeo 패키지였으나 v1 브랜치에 보존되어 있다. main 브랜치는 PostgreSQL + PostGIS 기반 새 사양으로 재시작한다.

식별자 매핑

항목
GitHub 저장소 kor-travel-geo
Python import from kortravelgeo import ...
CLI 명령 ktgctl
환경변수 prefix KTG_*
PostgreSQL DB 이름 kor_travel_geo
프론트엔드 패키지 kor-travel-geo-ui

개발 환경 (PC, WSL)

  • Git source of truth는 NTFS /mnt/f/dev/kor-travel-geo 계열 checkout이다. 코드 편집, branch, commit, PR은 NTFS 에이전트 worktree에서 수행한다.
  • 테스트와 장기 실행은 WSL ext4 테스트 미러에서 수행한다. NTFS worktree를 rsync --delete~/dev/kor-travel-geo-<agent>-test/에 복사한 뒤 pip/npm/pytest/uvicorn을 실행한다. ext4 미러에서는 commit/push하지 않는다.
  • Git 명령은 Windows Git 기준이다. NTFS worktree의 .git/gitdirF:/dev/...를 가리키게 두고, WSL 미러에서 Git commit/branch를 수집하는 스크립트는 Windows git.exeF:/dev/kor-travel-geo-* 경로를 사용한다. WSL git 편의를 위해 포인터를 /mnt/f/...로 바꾸지 않는다.
  • DB/RustFS 검증은 접속 설정 기준이다. 이 저장소는 PostgreSQL/PostGIS와 RustFS를 직접 구동하지 않는다. 이미 동작 중인 DB와 bucket에 KTG_PG_DSN, KTG_RUSTFS_* 설정으로 접속해 사용한다.
  • 데이터(data/)는 NTFS main repo 아래 /mnt/f/dev/kor-travel-geo/data/를 기준으로 둔다. ext4 테스트 미러에서는 절대경로 또는 심볼릭 링크로 참조한다.
  • 로컬 secret/env 파일(.env, kor-travel-geo-ui/.env.local, .claude/settings.local.json 등)은 각 NTFS worktree에 복사하되 Git에 커밋하지 않는다. .env*, .claude/, .codegraph/는 ignore 대상이다.
  • 프론트엔드 실행은 WSL ext4 테스트 미러의 Linux Node/npm 기준이다. kor-travel-geo-ui 의존성 설치, next dev/next start, lint, type-check, unit test, build, React Doctor는 WSL에서 실행한다.
  • Playwright e2e는 Windows Node/브라우저 전용이다. WSL Playwright는 실행하지 않고, Windows Playwright를 WSL UI 서버(--hostname 0.0.0.0)에 붙인다.
  • 반복되는 작업 실패 패턴은 먼저 docs/agent-failure-patterns.md를 본다. 특히 NTFS worktree에서는 WSL git을 쓰지 않고, exec_commandCreateProcess ... os error 2는 저장소 버그가 아니라 런처/quoting 문제로 먼저 분류한다.

에이전트별 worktree / CodeGraph

  • ChatGPT Codex는 /mnt/f/dev/kor-travel-geo-codex, Claude Code는 /mnt/f/dev/kor-travel-geo-claude, Google Antigravity 2.0은 /mnt/f/dev/kor-travel-geo-antigravity worktree를 고정으로 사용한다.
  • geo-codex, geo-claude, geo-antigravity 이름은 더 이상 새 작업에 쓰지 않는다.
  • worktree는 에이전트별로 유지하고 작업마다 새 branch만 만든다. 새 작업 시작 예시는 git fetch origin main && git switch -c agent/codex-next origin/main이다.
  • CodeGraph는 worktree마다 최초 1회 codegraph init -i로 초기화한다. .codegraph/가 이미 있으면 codegraph init을 반복하지 말고 codegraph sync로 증분 갱신한다. NTFS /mnt에서는 live watch가 비활성화될 수 있으므로 branch 전환·pull·merge 뒤 수동 sync가 필수다.
  • 현재 인덱스 상태는 codegraph status로 확인한다.
  • Codex MCP 설정은 프로젝트 루트 .codex/config.toml에 둔다. Codex Desktop을 재시작한 뒤 CodeGraph MCP 도구가 노출된다.
  • kor-travel-geo-ui의 React 컴포넌트, 지도 wrapper, 공용 UI primitive를 수정하기 전에는 CodeGraph MCP의 codegraph_explore로 영향도를 먼저 평가한다. 확인 대상은 호출자, import 경로, 관련 테스트, maplibre-vworld-js 경계다.
  • .codegraph/는 로컬 SQLite 인덱스이므로 커밋하지 않는다.

2. 빠른 시작

cd /mnt/f/dev/kor-travel-geo-codex              # NTFS Codex worktree
git fetch origin main && git switch -c agent/codex-next origin/main
rsync -a --delete --exclude .git --exclude .codegraph --exclude .venv --exclude node_modules --exclude kor-travel-geo-ui/.next --exclude data ./ ~/dev/kor-travel-geo-codex-test/
cd ~/dev/kor-travel-geo-codex-test                 # WSL ext4 테스트 미러
sudo apt install -y libgdal-dev gdal-bin              # loaders extra용 (ADR-008)
uv venv && uv pip install -e ".[api,dev]"
uv pip install "gdal==$(gdal-config --version)"        # 시스템 GDAL과 버전 매치
uv pip install -e ".[loaders]"                         # 이제 안전하게 빌드
test -f .env || cp .env.example .env                  # KTG_PG_DSN, KTG_RUSTFS_* 채우기
test -e data || ln -s /mnt/f/dev/kor-travel-geo/data data # NTFS data를 참조
# PostgreSQL/PostGIS와 RustFS는 이미 동작 중인 외부 인프라에 접속한다.
alembic upgrade head
ktgctl load all-sidos \
  --juso "./data/juso/도로명주소 한글_전체분" \
  --jibun "./data/juso/도로명주소 한글_전체분" \
  --locsum "./data/juso/위치정보요약DB" \
  --navi "./data/juso/내비게이션용DB" \
  --shp-root "./data/jusoMap/202605" \
  --yyyymm 202605
uvicorn kortravelgeo.api.app:app --reload

자세한 환경 셋업과 conda/Docker 대안은 docs/dev-environment.md.

3. 디렉토리 지도

src/kortravelgeo/
  dto/       — pydantic v2 입력/출력 (DB·FastAPI 의존성 없음)
  core/      — 비즈니스 로직 (Protocol에만 의존)
  infra/     — DB 어댑터 (SQLAlchemy 2 async, raw SQL)
  loaders/   — 파일 적재 (일반 쿼리 경로와 완전 분리)
  client.py  — AsyncAddressClient (라이브러리 API 진입점)
  api/       — FastAPI 라우터 (client.py를 호출)
  cli/       — typer CLI

프론트엔드 작업은 kor-travel-geo-ui/에서 수행한다. 이 패키지는 Next.js 기반 내부 디버그/관리 UI이며, DB 드라이버를 직접 갖지 않고 /v1/* REST API만 호출한다.

의존 방향은 dto → core → infra → client → api/cli 한 방향. import-linter가 CI에서 강제한다.

4. 절대 하지 말 것 (DO NOT)

  1. 의존 방향 역행 금지: 위 계층 순서를 거스르는 import 금지. 역방향 import 시 import-linter가 CI에서 실패시킴.
  2. 동기 인터페이스 추가 금지: AsyncAddressClient만 둔다. 동기가 필요하면 호출자가 asyncio.run으로 감싼다.
  3. pg_trgm.similarity_threshold 전역 변경 금지: 항상 트랜잭션 내부에서 SET LOCAL.
  4. ORM에 비즈니스 로직 금지: infra/models.py는 매핑만. 쿼리는 infra/*_repo.py의 raw SQL에.
  5. 좌표 순서 혼동 금지: 모든 외부 인터페이스는 (lon, lat). 내부 PostGIS도 ST_MakePoint(lon, lat).
  6. MVM_RES_CD 매핑 하드코드 금지: settings 또는 DB load_codes 테이블에서 읽는다.
  7. 응답에 x_extension 외 자체 필드 추가 금지: vworld 호환성을 깬다.
  8. 외부 API 키 평문 커밋 금지: 모두 SecretStr. .env는 권한 600 또는 systemd EnvironmentFile/vault.
  9. ogr2ogr subprocess 호출 금지: GDAL Python binding(gdal.VectorTranslate) 사용. CP949 디코딩은 open_options=["ENCODING=CP949"]로 명시.
  10. 프론트엔드 패키지에 DB 드라이버 추가 금지: kor-travel-geo-ui는 백엔드 REST API만 호출. pg, prisma 같은 의존성 들어오면 ADR 위반.
  11. 공간 쿼리 술어에서 좌표 형변환 금지: 입력 좌표는 CTE/파라미터로 한 번만 ST_Transform해서 상수로 굳히고, 술어는 ST_DWithin(t.pt_5179, p.geom, :radius_m)처럼 컬럼은 그대로 둔다. ST_Transform(t.pt_5179, 4326)이 술어에 들어가면 GiST 인덱스를 못 타고 매 행 변환이 돌아간다. 반경 검색은 pt_5179(meter) 기준으로 한다 — pt_4326은 응답 직렬화 전용. MV의 pt_source 컬럼이 좌표 출처(entrance vs centroid)를 노출하므로 라우터는 centroid 결과의 confidence를 낮춰 반환(ADR-007, ADR-012, docs/data-model.md "공간 쿼리 가이드").
  12. SQLAlchemy bulk insert().values(rows) 파라미터 폭주 금지: PostgreSQL 프로토콜은 한 쿼리당 최대 65,535개 파라미터. row × column이 ~30,000 이상이면 psycopg.copy_* 또는 gdal.VectorTranslate(... PG_USE_COPY=YES)로 전환한다(ADR-005). 안전 마진은 한도의 절반(30k) 권장.
  13. 작업 큐 상태를 in-memory만 신뢰 금지: 적재 작업은 load_jobs 테이블로 영속화한다(ADR-011). lifespan startup에서 state IN ('queued','running') 잔존 행을 failed로 마크하고, 실행 직렬성은 advisory lock 또는 SELECT ... FOR UPDATE SKIP LOCKED로 DB 수준에서 보강.
  14. PostgreSQL/RustFS Docker 생명주기 직접 관리 금지: 이 저장소는 이미 동작 중인 DB와 bucket에 접속만 한다. 구동·정지·재시작 절차는 이 저장소의 문서나 스크립트에 두지 않는다.

5. 자주 묻는 작업

작업 시작 파일
새 엔드포인트 추가 dto/<name>.pycore/<name>.pyinfra/<name>_repo.pyapi/routers/<name>.py
새 SQL 쿼리 튜닝 infra/*_repo.py_SQL 상수. EXPLAIN은 /debug/explain UI
새 적재 소스 추가 loaders/<name>_loader.py, manifest.py 확장
응답 필드 추가 (자체 확장) dto/<name>.py*Extension 클래스
새 에러 코드 추가 exceptions.py + api/responses.py 매핑
외부 API 폴백 호출 httpx.AsyncClient + tenacity 재시도. 키는 Settings에서 SecretStr
PR 리뷰 반영 docs/agent-guide.md §B4.3. gh pr view comments만 보지 말고 reviews[].body, review_threads[], 마지막 conversation comment를 모두 확인

6. 도메인 어휘

약어 의미
BJD_CD 법정동코드 10자리 (시도2 + 시군구3 + 읍면동3 + 리2)
RNCODE_FULL 도로명코드 12자리 (SIG_CD 5 + RN_CD 7)
BD_MGT_SN 건물관리번호 25자리, 전국 unique
BSI_ZON_NO 건물의 기초구역번호 = 우편번호 5자리
BAS_ID TL_KODIS_BAS의 기초구역번호 = 우편번호
MV mv_geocode_target — 평면화된 머티리얼라이즈드 뷰
MVM_RES_CD 이동사유코드 (신규/수정/삭제)
MVMN_DE 이동일자 YYYYMMDD

7. 작업 후 체크리스트

  • pytest -q 통과
  • ruff check . / mypy / lint-imports 통과
  • 프론트엔드 작업이면 kor-travel-geo-ui에서 npx react-doctor@latest . --offline --verbose --json 실행 후 경고를 수정하고 재실행
  • docs/journal.md에 작업 항목 추가 (역시간순)
  • docs/resume.md의 진척도 갱신
  • 의사결정이 있었다면 docs/decisions.md에 ADR 추가
  • 사용자 가시 변경이면 CHANGELOG.md 갱신
  • DTO/스키마 변경이면 scripts/export_openapi.py 재실행 → 프론트엔드 gen:types