# Plan History: B03 업로드 CRS 정상화 - **완료 일자**: 2026-07-18 - **수행 주체**: 개발 전문 AI - **검증 결과**: 합격 (PASS) --- ### B03 업로드 CRS 정상화 #### 목표 - 복합 CRS 전체의 `to_epsg() == None`을 수평 CRS 판별 실패로 오인하지 않는다. - GeoTIFF·PRJ·LAS에서 수평 CRS와 수직 CRS를 분리해 동일한 메타데이터 구조로 저장한다. - 기존 DB 연동 필드인 `epsg`에는 지도 좌표 변환에 사용할 수평 EPSG를 유지한다. - KNGeoid24처럼 공식 EPSG가 없는 수직 CRS는 오류나 임의의 EPSG로 치환하지 않고 사용자 정의 수직 CRS로 기록한다. - 실제로 알 수 없는 수평 CRS는 추측하지 않고 상태값으로 명확히 남긴다. #### 구현 원칙 - GeoTIFF는 파일 내부 CRS를 기준으로 분석하며, 영상 래스터의 수직 CRS를 억지로 합성하지 않는다. - LAS와 PRJ의 복합 CRS는 구성 요소를 분해하여 수평 EPSG와 수직 기준을 각각 판정한다. - `GTIFF_SRS_SOURCE=EPSG` 같은 전역 환경 설정과 WKT 이름 기반 임의 매칭은 실제 실패 자료가 확보되기 전까지 추가하지 않는다. - 알려진 CRS만 선택적으로 정상화하고, 예상하지 못한 CRS 오류나 경고를 전역으로 숨기지 않는다. - Rasterio와 Pyproj가 사용하는 PROJ 버전 차이는 이번 결함의 직접 원인이 아니므로 패키지 변경 없이 검증 결과만 남긴다. #### 구현 체크리스트 - [x] 공통 CRS 정상화 함수에서 수평·수직 CRS 구성 요소를 분리한다. - [x] 기존 `epsg` 필드가 복합 CRS에서도 수평 EPSG를 반환하도록 수정한다. - [x] `horizontal_crs`, `vertical_crs`, `crs_status` 상세 메타데이터를 추가한다. - [x] KNGeoid24 사설 코드가 `custom_vertical_crs` 상태로 정상 기록되는지 확인한다. - [x] 현재 영구저장소의 TIFF가 `EPSG:5187`, 영상 자료로 유지되는지 확인한다. - [x] 현재 영구저장소의 PRJ와 LAS가 수평 `EPSG:5187` 및 수직 `KNGeoid24`로 분리되는지 확인한다. - [x] Python 정적 검사와 포맷 검사를 통과한다. - [ ] Graphify, 위키 인제스트, 위키 린트는 담당 AI 작업으로 남긴다. #### 수행 결과 (2026-07-18) - `B03_FileInput_Engine_Analyze.py`에 `normalize_crs_metadata()`를 추가하여 GeoTIFF·PRJ·LAS가 동일한 CRS 메타데이터 구조를 사용하도록 변경했다. - 기존 `epsg` 필드는 복합 CRS 전체 코드가 아니라 수평 구성 요소의 EPSG를 반환한다. 따라서 KNGeoid24가 결합된 PRJ와 LAS도 `epsg=5187`로 DB에 저장할 수 있다. - 상세 판정 결과로 `horizontal_crs`, `vertical_crs`, `crs_status`를 추가했다. 상태는 `identified`, `custom_vertical_crs`, `unknown_horizontal_crs`, `missing_crs`로 구분한다. - KNGeoid24 WKT의 사설 `EPSG:9995/99999` 표식은 원문을 변경하지 않고 파싱용 WKT에서만 분리하며, `custom_authority_codes`에 원래 코드를 보존한다. - Rasterio가 GeoTIFF를 열 때 발생시키는 `EPSG:9995/99999 crs not found` 로그만 파일 오픈 구간에서 선택적으로 차단하고 B03 안내 로그로 변환했다. 다른 GDAL/PROJ 경고는 차단하지 않는다. - 동시 업로드 시 다른 작업의 로그를 잘못 차단하지 않도록 경고 필터를 생성한 스레드에서 발생한 메시지만 처리한다. - 실제 영구저장소 `result.tif` 검증 결과는 `EPSG:5187`, 4밴드 `uint8`, `likely_type=image`, `crs_status=identified`이며 수직 CRS를 영상 메타데이터에 합성하지 않았다. - 실제 `result.prj`와 `cloud_merged.las` 헤더 검증 결과는 수평 `EPSG:5187`, 수직 `Korean National Geoid Model (KNGeoid24)`, `crs_status=custom_vertical_crs`이다. - 등록되지 않은 임의 수평 투영 CRS는 `epsg=None`, `crs_status=unknown_horizontal_crs`로 유지하여 EPSG를 추측하지 않는 것을 확인했다. - 현재 런타임은 Rasterio 1.5.0/PROJ 9.7.1과 Pyproj 3.7.2/PROJ 9.5.1이며, 재현 결함이 없어 패키지나 전역 `GTIFF_SRS_SOURCE` 설정을 변경하지 않았다. - `ruff format`, `ruff check`, `python -m py_compile`, 실제 저장 파일 기반 회귀 assertion, JSON 직렬화 검증을 통과했다. - CRS 검증과 무관한 1.7GB LAS classification 전수 스캔은 다시 실행하지 않고 LAS 헤더만 검증했다. - 사용자 요청에 따라 Graphify, 위키 인제스트, 위키 린트는 실행하지 않았으며 담당 AI의 후속 작업으로 남겼다.