# 폴더 임포트 v2.0 데이터 형상 전환

**소요 시간**: 약 16분 (기능개발 에이전트 기준)
**Context 사용량**: input ~추정 / output ~107k tokens (기능개발 에이전트 subagent_tokens 106,989 기준)

## 작업 개요

폴더 선택 시 로딩하는 지리정보 데이터를 v1.0 형상에서 v2.0 형상으로 전환했다.
v1.0(POI_위경도값/측점_위경도값/타원체고/center.csv 의존)을 더 이상 지원하지 않고,
실측 납품 폴더 구조(드론 base.csv + building/ 하위 번호 CSV + route.json 보정)에 맞춘 v2.0 전용 파서로 전면 재작성했다.

### 작업 배경 (v1.0 → v2.0)
- v1.0은 별도 가공 산출물(`POI_위경도값`, `측점_위경도값`, `center.csv`, 타원체고 컬럼)에 의존 → 실제 납품 폴더와 컬럼/인코딩이 불일치
- v2.0 실데이터는 한 폴더에 드론 CSV(UTF-8)와 측량 CSV(EUC-KR)가 혼재하고, 중심선(center.csv)이 없음
- 따라서 인코딩 자동 감지 + 번호 CSV 직접 파싱 + 측점 기반 중심선 생성으로 구조를 단순화

## 변경 파일과 핵심 내용

### client/src/types/geo.ts
- `DirectionChange` 타입 신설: `{ station, from, to, atSeconds }`
- `RouteStructure` 에 `lengthM?`, `category?` 추가 (type 유니온 `bridge|tunnel|station` 유지, 구교 → `bridge`)
- `FolderGeoData` 에 `structures: RouteStructure[]`, `directionChanges: DirectionChange[]` 추가

### client/src/utils/geoData.ts (전면 재작성, v2.0 전용)
- 인코딩 자동 감지 `decodeBytes(buf)`: 앞 3바이트 `EF BB BF` → UTF-8, 아니면 EUC-KR, 잔여 `U+FEFF` 제거
- `readCsv(file)` 시그니처 단순화 (인코딩 인자 제거)
- `makeFieldIndexer`: 헤더명 `indexOf` 실패 시 위치 인덱스 폴백
- 신규 파서: `parseStations` / `parsePois` / `parseStructures` / `buildCenterlineFromStations` / `mergeStructures`
- v1.0 코드 제거: `POI_위경도값`/`측점_위경도값`/타원체고 식별, `center.csv` 로더, 인코딩 하드코딩 분기

### client/src/store/geoStore.ts
- `structures`, `directionChanges` 적재

### client/src/stationbar/StationBar.tsx
- 구조물 마커 소스를 `routeMeta.structures` → `geoStore.structures`(CSV 유래) 우선으로 전환
- 위치 로직(station → lat/lon → 이름매칭 → mileage)은 lat/lon 지원으로 그대로 활용

## 컬럼 매핑 (실파일 검증)

| 구분 | 파일 | 인코딩 | 매핑 |
|------|------|--------|------|
| 드론 | `<base>.csv` | UTF-8 | frame_cnt/latitude/longitude/altitude/yaw/pitch/roll/focal_len — 변경 없음 |
| 측점 | building/`01)측점.csv` | EUC-KR | title←측점, z←Z좌표, lat, lon, type=station; 비고에서 DirectionChange 추출(mm:ss→초) |
| POI(1) | 루트 `<base>_POI.csv` | UTF-8 | title / category_clean / lat / lon, z=0 |
| POI(2) | building/`02)지장물.csv` | EUC-KR | 명칭 / category='지장물' / lat / lon / z←Z좌표 |
| 구조물 | `03)교량`(bridge) + `04)터널`(tunnel) + `06)구교`(bridge, category='구교') | — | name / lengthM←연장(m) / lat / lon; 위경도 범위(33~39 / 124~132) 밖 깨진 행 필터 |
| 중심선 | center.csv 없음 | — | 측점 mileage 정렬 폴리라인으로 생성 |
| 보정 | route.json | — | `mergeStructures` 가 name 매칭으로 offset/station/좌표 override + 미존재 항목 추가 (선택적 보정) |

## 결정 사항
- **v2.0 전용화**: v1.0 지원 코드를 제거하고 v2.0 형상만 로딩
- **구조물 = CSV 자동 + route.json 보정**: 03/04/06 CSV에서 자동 수집하고 route.json은 선택적 override/augment 레이어로만 사용
- **측점 중심선**: center.csv 부재 → 측점 mileage 정렬 폴리라인을 중심선으로 사용
- **비고 방향전환**: 측점 비고 텍스트에서 상/하행 전환 + 시각(mm:ss)을 정규식으로 추출하여 `DirectionChange` 생성

## 실데이터 검증값 (하행)회덕-대전조차장 데이터, v2.0)
- 인코딩: 드론/POI/05)출입문/06)구교 = UTF-8(BOM), 01~04 = EUC-KR (BOM 자동감지로 일괄 처리)
- directionChanges 2건: 157K930 상행→하행 @125s, 158K340 하행→상행 @75s
- 측점 47개
- POI 137개 (`<base>_POI` 114 + 지장물 23)
- 구조물: 교량 12 (깨진 1행 필터) + 터널 2 + 구교 9

## 미구현 / 후속 과제
- **05)출입문번호.csv 파싱 스킵**: 운영데이터로 재생바 아이콘이 과도해져 기본 표시 제외. 파싱 자체를 생략(Timeline 렌더는 bridge/tunnel/station만). 추후 필요 시 `parseDoors` 추가.
- **directionChanges 와이어링**: 타입/스토어까지 적재 완료. StationBar `barSegments` 의 방향전환은 현재 연속 체이니지(chain) 자동 판정 로직을 유지하고, `directionChanges` 강제 분할은 미적용. 자동 판정이 영상과 일치하므로 회귀 위험 회피 목적의 후속 과제로 둠.

## 검수 포인트
- 한글 인코딩 깨짐 없음 (BOM 자동감지)
- 깨진 행 마커 제외 (위경도 범위 밖 필터)
- route.json 보정 동작
- RoutePanel / RouteInfoOverlay 는 POI category로 교량·터널을 필터 → v2.0에서는 structures가 분리되어 해당 목록이 비어 보일 수 있음(정상, 구조물은 StationBar로 표시)

## 빌드 결과
- `nvm use 20` → `npm run build -w client` → `tsc && vite build`
- ✓ built (215 modules), 에러 0
- chunk > 500kB 경고는 기존 video.js 특성 (정상)
