Commit Graph
86 Commits
Author SHA1 Message Date
eomsangdon 9f35ecd2d8 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 17:49:45 +09:00
eomsangdonandClaude Opus 5 72075563e3 feat(B03·B04): 지형 라이다 여러 장 입력·병합 전처리
- 지형 파일 개수 제한 해제(정확히 1개 → 1장 이상), 한 카드에 여러 장 담기
  (화면 표시 「용화_서편.las 외 1장」, 업로드는 한 장씩 차례로 전송)
- 구조화 엔진이 여러 파일을 합친 범위로 한 벌 생성 — WF1 자동 전처리·B04 재분석 모두
  프로젝트 지형 파일 전부를 대상으로 실행
- 점이 1억 개를 넘으면 씨닝 — 지면 분류점은 전부 남기고 나머지만 0.5m 칸 최저점으로 축소
  (용화 실측: 4,900만점 → 249만점, 지면점 1,140,716개 그대로, 1m 지면격자 표고차 0.0000m)
- 머리글만 읽어 5km 넘게 떨어진 파일은 업로드 거부 (임도는 길어도 2~3km)
- 화면 조립부 700줄 준수를 위해 terrainCoverage 를 판정 모듈로 이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 17:45:59 +09:00
eomsangdonandClaude Opus 5 2d0895d975 fix(B03): LAS 없이 설계 업로드가 지형 PRJ·TFW 필수 검사에 막히던 것 해소
- 「LAS 없이 설계」면 지형 한 벌(포인트클라우드·지형 PRJ·TFW)을 필수에서 면제
- 업로드 요청 검사도 완료 검사와 같은 기준으로 노선 PRJ 와 지형 PRJ 를 갈라 셈
  (종전에는 확장자만 봐서 노선 PRJ 를 지형 PRJ 로 오인)
- 업로드 현황의 「필수 충족」은 stage 0 완료를 우선 근거로 판정 — B04 이동 버튼 복구

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 17:45:43 +09:00
eomsangdon 1f3b30e698 @
feat(B06): 구조물 면적·유토곡선 서버 계산 자리 마련 + 상단측 저장 누락 수정

계산 자리 일원화(CLAUDE.md 5장) — 브라우저에서만 돌던 두 계산을 서버가 같은 TS 로
한 번 더 돌려 정본에 얹음. 파이썬 포팅 금지(기하가 두 벌이 되면 그림과 수량이 갈림).

- B06_Section_Server_Calc_Node.ts 신설 — 구조물 폐회로 면적 계산 후 그 위에서
  유토곡선을 쌓음(화면과 같은 순서). balloon 위치는 서버가 만들지 않음.
- B06_Section_Structure_Layouts.ts 신설 — 정본만 읽는 제어기 흉내를 B07 도면에서
  떼어 공용화. B07·서버가 같은 한 벌을 씀.
- common_util_node_bundle.py 신설 — 번들 빌드·실행 배관 공용화(코리도도 이걸 씀).
- 전처리 체인(초기값 스냅샷 앞)·[저장]·[확정]에서 서버 재계산 호출.
- 상단측(측구 방향) 변경이 B05 [임시저장]에만 실리던 것을 B06 [저장]·[확정]에도
  실음 — flushUphillOverrides.
- 죽은 세션 등록 항목 pipes 제거(읽는 곳도 쓰는 곳도 없었음).

검증: tsc --noEmit 통과, pytest 386 passed, tmp/tests/test_b06_server_calc_node.mjs 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@
2026-09-06 14:20:54 +09:00
eomsangdonandClaude Opus 5 0ea75e512f style(B03): 계획노선 미리보기 — 범위 점선 상자 제거, 실선 녹색
- 계획노선처럼 그릴 선이 있는 자료에는 범위 점선 상자를 그리지 않음.
  점구름·래스터는 그대로 상자를 그림.
- 노선 선 색을 녹색으로. 지형 범위를 벗어나면 붉은 경고색으로 덮어쓰는
  규칙은 유지.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 22:58:45 +09:00
eomsangdonandClaude Opus 5 5666086c6e fix(B03): 파일 교체 후 다시 업로드할 수 있게 — 끝난 카드 [파일 선택] + 확정 대기 관문
- 완료 카드에서도 [파일 선택]을 보임. 올리는 중에만 감춤. 교체 확인 모달과
  교체 업로드 규칙은 이미 있던 것을 그대로 씀.
- 업로드 관문이 전처리 1단계 IN_PROGRESS 를 무조건 「분석 중」으로 읽어,
  자동 확정이 보류된 프로젝트는 영영 새 자료를 받지 못했음. 전처리 진행 파일이
  awaiting_confirmation·completed·failed 로 끝나 있으면 받도록 고침.
  실제로 도는 중(analyzing)이면 그대로 막음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 22:42:57 +09:00
eomsangdon 057ba34f32 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-04 22:18:36 +09:00
eomsangdonandClaude Opus 5 41c1771fad feat(B03): 부속 파일 카드에 파일 속 값 표시·래스터 썸네일 점선 테두리
개수만 보이던 부속 파일 카드에 파일 안의 중요한 값을 함께 보임.

- .shx — 도형 종류(폴리라인 등)와 범위 크기를 머리글에서 읽음.
- .dbf — 속성 이름 목록을 머리글 서술자에서 읽음(앞 4개).
- .cpg — 같은 세트 .dbf 의 첫 글자 속성을 그 인코딩으로 읽어 견본으로 보임.
- .prj — 중앙자오선(투영 매개변수)과 길이 단위. proj 문자열 변환을 쓰지 않아
  정보 손실 경고가 나지 않음.
- 카드 표시 줄 수를 2 → 3 으로 늘리고, 길이 단위 표기를 m 으로 통일.
- GeoTIFF 썸네일에 다른 미리보기와 같은 점선 테두리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 22:16:14 +09:00
eomsangdonandClaude Opus 5 c322f53845 feat(B05): 코리도를 전처리 체인이 미리 만들어 영구저장 + 초기값 편입
사용자 확정(2026-09-04) — 「다른 로직과 동일하게: 전처리 계산 마지막에 연산 후
영구저장, 진입 시 로딩, 조작은 캐시, 저장·확정 때 저장」. 예전에는 사용자가 B05에
처음 들어간 그 순간 브라우저가 17MB 규모를 만들어 첫 진입이 느렸음.

계산은 **재구현하지 않음** — 브라우저가 쓰는 TS 빌더(8,209줄)를 Node 로 그대로 돌림.
- `B05_Profile_UI_Corridor_Envelope.ts` 신설 — 저장 형식·버전 해시·직렬화를
  `_UI_Corridor.ts` 에서 그대로 떼어 브라우저·서버 공용으로 둠(내용 불변).
- `B05_Profile_Corridor_Node.ts` 신설 — 입력 JSON 을 받아 저장본을 내놓는 진입점.
  `npm run build:corridor` 로 번들(335kB), `npm run build` 에 물림.
- `B05_Profile_Corridor_Prebuild.py` 신설 — 상세·노선점을 모아 Node 실행 후 저장.
  번들이 TS 원본보다 낡으면 스스로 다시 만듦(두 그림이 갈라지는 것을 막는 장치).
- 체인 마지막(스냅샷 직전)에 호출. 실패는 비치명적 — 저장본이 없으면 브라우저 폴백.
- 초기값 — 스냅샷이 코리도를 `initial_corridor.json` 으로 함께 뜨고, [초기화] 복원 때
  **새 route id** 이름으로 되돌림(복원이 새 번호를 만들기 때문).
- `window.__corridorSource` 디버그 훅 — 저장본을 썼는지 다시 만들었는지 화면 밖 확인용.

자체검증: 전체 시험 381 통과·17 건너뜀(옛 테스트 2건은 이름·경로 변경에 맞춰 갱신).
실경로 — 용화 프로젝트(route 139)로 사전 생성 성공, 브라우저가 그 저장본을
`source: "stored"`, 해시 `377c2a84` 로 **그대로 채택**(재빌드 0회, 전송 278ms).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 21:22:27 +09:00
eomsangdonandClaude Opus 5 9019ca28ef feat(B03): 파일 카드 미리보기 확대 — 전폭·고정 높이, 라이다 점 그림·GeoTIFF 썸네일
- 미리보기를 카드 한 행 전폭·높이 120px 고정으로 키움.
- 라이다: 분류 통계를 훑는 그 길에 XY 를 성기게 주워 탑뷰 점 그림(상한 5천 점,
  파일 재열람 없음). 분류가 없는 파일은 앞 3청크만 봄.
- GeoTIFF: 오버뷰가 있을 때만 128px 흑백 썸네일(2~98 백분위 대비), 없으면 종전 범위 사각형.
- 부속 파일(.shx·.dbf·.cpg·.prj·.tfw)은 그림 대신 구분되는 값 표시 — 머리글만 읽는
  가벼운 분석기 추가.
- 값이 없는 완료 카드는 「보여 줄 값이 없음」 한 줄.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 19:17:00 +09:00
eomsangdonandClaude Opus 5 4e4bfa2354 feat(B02/B03/B04/B05): 계획노선 사용 범위 · 절단 여유 3m · 배수유역도 줌·측점 표기
- 계획노선 사용 범위: B02 등록에 시작·종료 누가거리 두 칸 추가, B01 수정 모달에서도
  변경. projects.route_start_m·route_end_m 신설(015_route_range.sql).
  load_design_route 가 범위 절단 → 서피스 트림 순서로 적용. 시작 >= 종료는 화면·서버
  양쪽에서 차단. 비우면 전 구간으로 종전과 같음.
- 서피스 절단 여유 기본값 30m → 3m (SURFACE_ROUTE_EDGE_TRIM_M).
- B04 지도·B05 배수유역도 줌 상한을 「화면 폭 20m」 기준으로 계산(고정 8배·16배 폐지).
  4배를 넘으면 배경 그림 흐림 보간 해제.
- 계획선 위 측점 눈금·번호 표기(측점번호+잔여거리). 관 마커와 겹치면 반대쪽으로 밀고,
  되꺾임 구간에서 라벨이 겹치면 건너뜀. 그리기 코드는 두 화면 공용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 19:08:11 +09:00
eomsangdonandClaude Opus 5 cc15a83f67 feat(B03~B08): 제목 줄 프로젝트 이름 + 계획노선 CSV 문구 정리
- 워크플로 상태 응답에 project_name 추가. 좌측 제목 패널 같은 행 오른쪽 끝에
  프로젝트 이름 표기(길면 말줄임, 전체는 툴팁). 이름표를 오버레이 쪽에 두어
  레이아웃을 직접 조립하는 B03 까지 여섯 화면이 한 곳으로 반영됨.
- fetchProjectWorkflowState 가 {status, workflow_state} 껍데기를 벗기도록 수정.
- 계획노선을 「업로드한 CSV」로 적은 주석을 「계획노선(정본)」으로 정리.
  업로드 판정이 .csv 개수만 세어 shapefile 을 막던 것도 .shp 포함으로 맞춤.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 18:26:17 +09:00
eomsangdonandClaude Opus 5 f541ab4480 refactor(B03): 파일 입력 화면 700줄 초과 분리 — 판정 규칙·업로드 흐름
925줄 한 파일을 셋으로 나눔 (동작 불변).
- `B03_FileInput_UI_Page.ts` 692줄 — 화면 조립·카드 렌더·현황 표시
- `B03_FileInput_UI_Page_Flow.ts` 262줄 — 중단 세션 이어올리기·보관함 이관·청크 업로드·
  초기 계산 중 재잠금·서비스워커. 화면 상태는 `UploadFlowContext` 창구로만 받음
- `B03_FileInput_UI_Page_Rules.ts` 107줄 — 필수 카드 판정·파일 적합성·업로드 가능 판정·
  서버 파일의 카드 매핑 (상태를 가두지 않는 순수 함수)

검증: 공용 브라우저에서 새 프로젝트 만들어 노선 5종 실제 선택·업로드 —
카드 5장 선택 후 [파일 업로드] 비활성, [LAS 없이 설계] 켜면 활성(판정 규칙 정상),
업로드 후 4장 완료 표시(20초). 남은 `route_prj` 오류·400 은 지형 자료가 없어
분리 전에도 같던 것. `tsc --noEmit` 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 11:19:04 +09:00
eomsangdonandClaude Opus 5 fbbedc7230 fix(700줄분리): 진입 파일에서 분리 전 이름 전부 재노출
laptop-sub 가 쓴 AST 대조법(분리 전 커밋의 모듈 정의 이름 ↔ 지금 모듈 `dir()`)을
내 4개에도 적용해 누락 26개를 찾아 되살림.

- `B03_FileInput_Router.py` 누락 17 → 0 (헬퍼 13 + 청크 엔드포인트 4)
- `B03_FileInput_Router_Temp.py` 누락 5 → 0 (`_total_chunks` + 청크 엔드포인트 4)
- `B07_DesignDetail_Router_Support.py` 누락 3 → 0 (`_BASIN_MAX_DISTANCE_M` ·
  `_clip_segment` · `_geometry_lines`)
- `config/config_system.py` 누락 1 → 0 (`_SCS_SOIL` — `import *` 가 밑줄 이름을 안 실음)

검증: 네 파일 모두 **정의 이름 누락 0**(28·19·36·246개 대조), 라우트 수 유지
(B03 7 · temp 9+attach 1 · B07 7), ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 10:53:37 +09:00
eomsangdonandClaude Opus 5 3ec6527cc2 refactor(B03): 임시 보관함 라우터 700줄 초과 분리 — 청크·보조
749줄 한 파일을 셋으로 나눔 (동작 불변, 순수 이동).
- `B03_FileInput_Router_Temp.py` 478줄 — 묶음 생성·목록·삭제·파일 업로드·프로젝트 연결
- `B03_FileInput_Router_Temp_Chunks.py` 294줄 — 세션·조각·진행·마무리 (prefix 없는
  APIRouter 를 본체가 `include_router` 로 붙여 `/api/temp-uploads/...` 경로 불변)
- `B03_FileInput_Router_Temp_Support.py` 46줄 — 조각 수·묶음 폴더·상태 갱신 (순환 방지)

검증: 라우트 10개(temp 9 + attach 1) 경로·메서드 동일, 공용 브라우저에서 실제 청크 흐름
create 200 → upload-sessions 200 → chunks 200 → finalize 200 → delete 200,
ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 10:34:01 +09:00
eomsangdonandClaude Opus 5 c4aac6f299 refactor(B03): 파일 입력 라우터 700줄 초과 분리 — 보조·청크 업로드
872줄 한 파일을 셋으로 나눔 (동작 불변, 순수 분리).
- `B03_FileInput_Router.py` 309줄 — 파일 업로드·현황·워크플로 엔드포인트
- `B03_FileInput_Router_Chunks.py` 390줄 — 세션 생성·조각 전송·마무리·진행 조회
  (자체 APIRouter 를 본체가 `include_router` 로 붙여 경로 문자열 불변)
- `B03_FileInput_Router_Helpers.py` 268줄 — 필수 파일 판정·중복 지문 판별·단계 기록·알림

검증: 라우트 7개 경로·메서드 동일(`GET upload-overview|upload-status|workflow-state`,
`POST files|upload-sessions|chunks|finalize`), 공용 브라우저에서 노선 5종 실제 업로드 성공
(shp metadata preview_path 포함), ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 10:15:19 +09:00
eomsangdonandClaude Opus 5 98db2731b9 style(B03): 미리보기 범위 사각형 옅은 점선 처리
어두운 테마에서 채움 35%가 회색 덩어리로 보여 범위인지 안 읽힘 — 채움 12% +
점선 테두리로 「범위」임이 드러나게 함(실측 스크린샷 확인).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 07:06:32 +09:00
eomsangdonandClaude Opus 5 ab16361125 feat(B03): 업로드 자료 카드 그래픽 미리보기 — 범위 사각형·노선 형상·범위 대조
- 계획노선 shapefile 분석에 `preview_path`(200점 안팎 솎은 좌표열) 추가 — 이미
  메모리에 있는 정점을 쓰므로 파일 재열람 0회(솎기 0.136ms)
- LAS·GeoTIFF 는 사용자 확정대로 **bbox 사각형만** (점구름·래스터 렌더 안 함)
- `upload-overview` 응답에 분석 `metadata` 동봉 — 재접속해도 같은 그림
- 카드에 SVG 미리보기 렌더(신규 `B03_FileInput_UI_Preview.ts`), 값 없으면 미표시
- 계획노선 카드는 지형 자료 범위와 대조 — 벗어나면 경고색·안내, 좌표계가 다르면
  대조 생략(재투영 안 함). shapefile 은 좌표계가 없어 같은 세트 `.prj` 값을 씀

검증: 공용 브라우저 실측(노선 선 121점·범위 안/밖·좌표계 상이 3갈래),
tmp/tests/test_b03_preview_path.py 2건, tsc --noEmit 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 07:04:33 +09:00
eomsangdonandClaude Opus 5 db91109b5a fix(B03): 입력 버튼 3칸 1:1:1·높이 통일, 토글 아래 빈 자리 제거
사용자 지시(2026-09-03).

- 고르는 자리를 flex 에서 **격자 3칸**으로 바꿈. flex 로는 내용 폭이 배분에 섞여
  288·254·288 로 어긋났고 버튼 높이도 달랐다. 격자는 칸을 먼저 나누므로 1:1:1 이고,
  칸을 꽉 채우게 해 세 칸 높이가 같아진다(실측 277×47 셋 다 동일).
- 빈 오류 줄이 자리를 잡아 토글 아래가 비어 보이던 것 제거 — 글자가 있을 때만 자리를
  차지한다(`:empty { display: none }`, min-height·마진 제거).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 21:06:48 +09:00
eomsangdonandClaude Opus 5 7c3a65e814 feat(B03): 선택 영역 설명 이관 · 임시 보관함 이름·테두리 정리 · 계획노선은 shapefile만
사용자 지시 4건(2026-09-03).

- 선택 영역의 설명 문구를 좌측 안내 패널로 옮기고 본문에는 「입력 파일 선택」만 남김.
- [임시 보관함에서 불러오기] → [임시 보관함]. 버튼을 감싸던 점선 테두리 삭제 —
  버튼 자신의 테두리와 이중이었음.
- 계획노선 도형 카드는 `.shp` 만 받음. CSV 는 내부 계산이 만드는 파일이라 사용자가 넣는
  자료가 아님(사용자 확인). 컨테이너의 CSV 안내 문구도 삭제.
- 이미 `.csv` 로 올라간 옛 프로젝트가 「미등록」으로 보이지 않도록 **서버 파일 매핑에만**
  `.csv → 계획노선 도형` 예외를 둠. 새로 받는 확장자와 이미 받은 것을 갈라 둔다.

좌측 안내 문구도 함께 갱신 — CSV 언급 제거, 버튼 새 이름 반영.

검증: 실측 — 선택 영역 텍스트 「입력 파일 선택」, 보관함 테두리 none·라벨 「임시 보관함」,
계획노선 안내 문구 없음, 카드 확장자 `.shp`, 옛 CSV 는 「완료 · 용화_계획노선.csv」 유지.
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 21:02:19 +09:00
eomsangdonandClaude Opus 5 b9e6a2b6a8 feat(B03): LAS 없이 설계 토글을 입력 컨테이너로 · 켜면 지형 자료 전체 차단
사용자 지시(2026-09-03).

- 토글을 지형 컨테이너에서 **파일 입력 컨테이너**로 옮김 — 무엇을 받을지 정하는
  스위치라 고르는 자리 옆에 선다. 서식도 입혔음(공용 체크 줄 + 켜짐 강조).
- 켜면 지형 자료를 **통째로** 받지 않음: 포인트클라우드·좌표계·래스터 카드를 모두 잠그고
  컨테이너를 흐림. 필수 판정에서도 지형 슬롯 전체가 빠진다.
- 파일 거르기를 확장자가 아니라 **배정된 카드** 기준으로 바꿈 — `.prj` 는 노선·지형이 같은
  확장자라 확장자로 거르면 노선 좌표계까지 함께 떨어졌다.
- 이미 올라간 자료(재입력)는 지우지 않고 **조작만 잠금** — 로컬로 고른 파일만 내린다.

좌측 안내 패널의 글자 크기도 공용 양식에 맞춤 — 본문 `--text-body-sm`·`--color-text-body`
(B04 `b04-surface__check` 와 같음), 제목 `--text-caption`.

검증: 실측 — 토글이 입력 컨테이너 안에 있고, 켜면 지형 카드 4장이 모두 disabled +
[파일 선택] 잠김, 기존 업로드분은 「완료」·파일명 유지. 끄면 원복. 패널 글자 14px/12px.
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:55:29 +09:00
eomsangdonandClaude Opus 5 a00c7497c1 feat(B03): 보관함 선택 요약·「업로드할 파일을 선택하세요」 경고 제거
사용자 지시 2건(2026-09-03).

- 임시 보관함 선택 요약(「선택된 보관 자료 없음」·묶음 이름·파일 수)을 없앰. 불러온 자료는
  카드가 곧바로 보여 주고, 고르기 전 상태는 [파일 업로드]가 잠긴 것으로 이미 드러남.
  쓰이지 않게 된 `.b03-file__temp-summary` 규칙과 로케일 2건도 함께 제거.
- 입력 컨테이너의 「업로드할 파일을 선택하세요」 경고를 띄우지 않음 — 아직 아무것도 고르지
  않은 상태를 붉은 글씨로 알릴 이유가 없음. 확장자·개수·필수 슬롯 같은 나머지 사유와
  [파일 업로드]를 눌렀을 때의 검사 결과는 그대로 표시.

검증: 실측 — 보관함 자리에 버튼 하나만 남음(요약 span 없음), 오류 줄 빈 문자열,
한 줄 배치 선택 518px · 보관함 210px · 업로드 102px. typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:47:02 +09:00
eomsangdonandClaude Opus 5 d9fcfa3b96 refactor(B03): 좌측 안내 패널을 B04~B07 공용양식으로 맞춤
처음엔 B03 전용 스타일로 문단을 만들었으나, 좌측 패널 양식은 다른 단계와 같아야 한다는
사용자 지시(2026-09-03). 공용 조립으로 교체함.

- 패널 루트 `b03-file__form`, 문단은 `ui-collapsible ui-sidebar-section`,
  제목은 `ui-collapsible__title` — 외곽선·캐럿·접힘 동작이 전부 공용 CSS·동작이다.
- 값도 `b04-surface__form`·`__group`·`__group-legend` 와 같게 맞춤
  (gap·padding 16, 배경 `--color-surface-raised`, legend `--text-caption`).

검증: 실측 — 문단 클래스 `b03-file__guide-group ui-collapsible ui-sidebar-section`,
패딩 16px, 배경 `rgb(37,31,56)`, 제목 클릭 시 `is-collapsed` 토글·복귀 확인.
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:42:50 +09:00
eomsangdonandClaude Opus 5 68e0a1c67f feat(B03): 고르는 자리 한 줄 · 완료 안내는 좌측 패널 · 결과 목록 제거
사용자 지시 3건(2026-09-03).

- 재접속 현황 배너(「…모두 완료된 프로젝트입니다」)를 좌측 안내 패널 「고르는 방법」
  안으로 옮김 — 고르기 전에 읽을 것과 같은 자리.
- [입력 파일 선택]·[임시 보관함에서 불러오기]·[파일 업로드]를 한 줄(`b03-file__pick-row`)로
  묶음. 좁아지면 접히되 선택 영역이 남는 폭을 먹음.
- 업로드 완료 항목 목록 삭제 — 같은 내용을 카드가 완료 상태로 이미 보여 줌.
  쓰이지 않게 된 `renderUploadResults`와 `.b03-file__results` 규칙도 제거.

곁들여 고친 것 — 카드 격자를 2열 고정에서 `auto-fill minmax(260px, 1fr)` 로 바꿈.
안내 패널을 연 상태에서 카드 폭이 210px 로 눌려 제목이 글자 단위로 접혔음(실측).
제목은 한 줄 말줄임으로 둠.

검증: 한 줄 배치 실측 — 선택 397px · 보관함 331px · 업로드 102px, 높이 76px 로 정렬.
카드 66px(빈 칸)/117px(파일 있음), 제목 줄 높이 21px(한 줄). typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:39:52 +09:00
eomsangdonandClaude Opus 5 c2b3c56664 fix(B03): 컨테이너 패딩 복구 — 테마에 없는 --spacing-20 사용
`padding: var(--spacing-20)` 은 정의되지 않은 토큰이라 선언째 무효가 되어 카드
컨테이너의 패딩이 통째로 사라졌음(2026-09-03 사용자 보고). 16px 토큰으로 교체.

검증: 실측 계산값 — 컨테이너 16px, 카드 12/16px, 선택 바 12/16px, 안내 문단 12px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:35:29 +09:00
eomsangdonandClaude Opus 5 a059c5f152 feat(B03): 파일 입력 양식 정리 — 안내는 좌측 패널, 본문은 고르는 자리만
사용자 지적(2026-09-03) — 선택 항목이 너무 크고 대중없이 놓임. 안내는 B04·B05 와 같은
공용 좌측 패널로 빼고 본문은 고르는 자리만 남김.

- `B03_FileInput_UI_Guide.ts` 신설 — 필요한 파일 / 고르는 방법 / 알아 둘 것 3묶음을
  공용 오버레이 `optionsContent` 에 실음. 문단 구획은 공용 `ui-sidebar-section`.
- 선택 영역 160px 블록 → 한 줄 바. 긴 문구는 패널로 옮기고 힌트는 한 줄로 교체.
- 카드 `min-height: 220px` 폐지, [선택]을 제목 줄 오른쪽 끝 작은 버튼으로 이동,
  빈 칸은 제목 줄만 남김. 진행바·속도·예상완료는 올라가는 동안만 표시.
- 여백 정리 — 컨테이너 패딩 32 → 20, 그룹 제목 24 → 16px, 격자 간격 24 → 12.
- 좌측 패널이 열리면 본문을 밀어내는 규칙 추가 — B03 은 일반 레이아웃이라 공용
  워크플로 레이아웃의 padding 규칙이 없어 패널이 카드를 덮었음.

검증: 카드 높이 232 → 66px(빈 칸)·117px(파일 있음), 선택 영역 160 → 47px,
문서 높이 1408px 로 한 화면 남짓. typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:31:00 +09:00
eomsangdonandClaude Opus 5 d140d04766 fix(B03): [LAS 없이 설계] 토글이 업로드 버튼 판정을 다시 돌리게 수정
이 토글은 LAS 카드의 필수 여부를 바꾸는데(isSlotRequired) change 핸들러가
updateUploadButton() 을 부르지 않아, 파일을 먼저 고르고 토글을 나중에 켜면 필수 조건이
채워졌는데도 [파일 업로드] 가 잠긴 채 남았다. 새로고침하거나 파일을 하나 더 골라야
풀렸다.

검증: 공용 브라우저에서 저장된 토글 표시를 지워 첫 진입 상태로 재현 — 파일 7개만 고른
상태는 비활성(안내: LAS/LAZ 필요), 토글을 켠 직후 즉시 활성, 다시 끄면 즉시 비활성.
typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 10:29:09 +09:00
eomsangdonandClaude Opus 5 56b9bf5280 feat(B03): 계획노선 shapefile 의 CSV 정본화 + LAS 없는 도엽 서피스 좌표계 교정
- 자동설계 체인이 초기값 스냅샷에 `planned_route.csv` 를 함께 남김. 값은 체인이
  이미 만든 정점(사업지 좌표계·트림·조밀화 후)이라 재계산 없음.
- `load_design_route()` 는 surface_params 가 주어진 호출에 한해 그 CSV 정본을 읽음.
  트림 전 원본이 필요한 호출(도엽 범위)은 종전 경로 유지. 지표면·노선이 바뀌면
  `discard_initial_snapshot()` 이 폴더째 지워 경로가 저절로 닫힘.
- `run_sheet_surface_analysis()` 가 노선을 원본 좌표계로 읽어 도엽 서피스를 딴 자리에
  만들던 문제 교정 — `load_design_route()` 로 창구 통일, 도엽 확보 PRJ 탐색도 지형
  PRJ 폴더로 교정. shapefile 노선(5179) + 지형 PRJ(5176) 조합에서 트림이 노선을
  통째로 지우던 원인.

검증: tmp/tests 158 passed(신규 4건 포함), 공용 브라우저 실사용 경로로 용화 shapefile
한 벌 업로드 → 자동 체인 완주 → CSV 정본 643점, 원본 경로와 최대 좌표차 0.00007m.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 08:17:21 +09:00
eomsangdonandClaude Opus 5 3651ad9875 feat(B05): 종단 계획선 전체 측점 폴리라인 전환 + 직선화·쉬프트·undo/redo 신설
2026-09-02 사용자 지시 9건 반영. 화면 실조작 검증은 다음 세션 몫 (사용자 지시로
코딩까지만 진행).

1. 초기 계획선 = 전체 측점 폴리라인 — `design_ground_following_profile()` 신설.
   모든 측점을 변화점으로 잡고 계획고 = 원지반고, 라운드는 R을 지정한 자리에만
   (`build_curves(only_explicit=)`·`build_alignment(only_explicit_curves=)`).
   basis `ground_polyline`. 관 정착 선형은 폴백으로 내림.
2. 구간 쉬프트(⬆⬇) 삭제.
3. [직선화] 신설 — `B05_Profile_UI_Profile_Straighten.ts`. 두 측점의 라운드에 탄젠트한
   직선으로 대체하고 사이 라운드 삭제. 직선 틸팅 시 가운데 라운드 + 양측 탄젠트 재구성.
4. [쉬프트] 신설 — 직선 구간을 기하에서 되읽어(`detectStraightRun`) 복수 선택,
   최외곽 라운드 중심 기준 상·하 평행이동.
5. 방향키 조작 — 상하 0.1m 계획고, 좌우 0.1m 누가거리(구조물·비정규 측점 한정).
6. undo/redo 신설 — B05·B06 조작 세션 키 묶음 스냅샷(`_Profile_History.ts`).
   버튼은 요약줄 맨 앞(최대 기울기 좌측), 21x17px. Ctrl+Z / Ctrl+Shift+Z.
7. 종단 요약줄의 횡단배수 최소고 표시 삭제(산식·편집 차단은 유지).
8. [편집 되돌리기] 버튼 삭제 — undo/redo로 대체.
9. 지형 구분 기본값 특수지형 — 패널 셀렉트와 백엔드 기본값(스키마·체인 폴백) 일치.

700줄 제한 — 패널을 `_Profile_Panel_Tools` · `_Profile_Preview` 로 분리하고 측점↔구조물
짝짓기를 `_Profile_Structures` 로 이관(842줄 → 696줄).

검증: tsc --noEmit 오류 0, ruff format/check 통과,
pytest tmp/tests/ -q → 366 passed / 14 skipped / 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:30:16 +09:00
eomsangdonandClaude Opus 5 2e57d29156 fix(B05,B03): 초기 설계 실패 시 초기값 부재 처리 — 실패 마커·안내 메일·[초기화] 거부
증상: 파일 입력 직후 초기 계산값과 B05 [초기화] 결과가 다름.

원인
- 자동설계 체인이 5단계까지 전부 성공해야만 `save_initial_snapshot()` 호출.
  중간에 깨지면 `initial_snapshot/` 미생성 → [초기화]가 복원 대신 재계산 폴백.
- 재계산 폴백의 지표면 기준이 체인과 다름 — 체인은 stage 1 확정값
  (`get_surface_confirmation_params`), [초기화]는 config 기본값
  (`surface_confirmation_defaults`). 실측: 프로젝트 stage1 `classification`/5m 대
  config `csf`/1m.
- 체인이 깨져도 WF1 은 초기 분석 완료 메일을 그대로 발송.

수정 (2026-09-02 사용자 확정 — 부분 결과는 분석 안 됨과 다르지 않으므로 부분
스냅샷은 만들지 않음)
- `initial_design.failed` 마커 신설 — 프로젝트 루트(스냅샷 4트리 밖), 실패 사유 기록.
  체인 진입 시 옛 마커 제거, 실패 5지점 + 스냅샷 저장 실패에서 기록.
- WF1 이 마커를 읽어 완료 메일 대신 `send_initial_design_failed_email()` 발송
  (관리자 주소 `ADMIN_EMAIL`, 없으면 주소 없이 안내).
- B05 [초기화]: 스냅샷 있으면 복원, 실패 마커 있으면 409 `initial_design_failed`
  로 거부(DELETE 앞에서 반환 — 데이터 무변경), 옛 프로젝트만 종전 재계산 폴백.
- 재계산 폴백의 지표면 기준을 `get_surface_confirmation_params()` 로 통일.

자체검증: `pytest tmp/tests/ -q` 366 passed / 14 skipped / 0 failed (+4).
공용 브라우저 실측 — 실패 프로젝트 [초기화] 409 응답·`routes` 행 무변경 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:03:18 +09:00
eomsangdonandClaude Opus 5 4cb9b15939 style: 저장소 전체 포맷터 일괄 적용 (prettier·biome·ruff)
파일마다 포맷 폭이 달라(≈80 대 100) 한 줄만 고쳐도 포맷터가 무관한 줄을 대량
재포맷했음. 사용자 지시로 전체를 한 번에 맞춤. 코드 동작 변경 없음 — 포맷만.

- 프론트엔드 `.ts/.css/.html` → 저장소 prettier (`.prettierrc`, printWidth 100)
- `B07_DesignDetail/openwebcad/**` → 자체 biome (tab 들여쓰기·single quote·lineWidth 100).
  `biome format` 만 사용 — `biome lint --write` 는 포맷 아닌 코드 수정까지 하므로 제외
- 파이썬 → `ruff format` (엔진 코드는 이미 정합, resources·scratch 스크립트 24개만 변경)

두 포맷터가 서로 되돌리지 않도록 `.prettierignore` 신규 — openwebcad 와 빌드·산출물
폴더를 prettier 대상에서 뺌. `.prettierrc` 에 `endOfLine: "auto"` 추가 — 기본값 `lf` 가
`core.autocrlf=true` 로 받은 CRLF 파일을 매번 전부 다시 써서 `--list-different` 가
실제 포맷 차이를 가리고 있었음.

검증: `tsc --noEmit` 통과(루트·openwebcad 둘 다), pytest 349 passed / 17 skipped /
0 failed, CAD vitest 87건 중 81 passed / 6 failed(laptop-sub 기준선과 동일, 회귀 없음).
포맷터 재실행 시 prettier·biome 모두 변경 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 07:08:24 +09:00
eomsangdonandClaude Opus 5 b014c4c1ec fix(B05): 노선 원천을 한 곳으로 모으고 도엽 서피스를 기본 하나만 만든다
용화 자동 체인이 끝까지 돌았는데 종단 계획선이 PVI 3개 직선으로 나왔다. 관 22개
측점이 92.6~2044.9m 로 트림 전 원본(2,136m) 기준인데 확정 노선은 1,070.4m 라
21개가 노선 밖이었다. 좌표계도 갈려 있었다 — 관은 EPSG 5179(노선 파일), 노선은
5176(프로젝트)에 저장돼 누가거리만 우연히 맞물려 있었다.

원인은 계획노선을 읽는 곳이 흩어져 있는 것이다. 트림·조밀화를 체인 한 곳에만
넣었더니 배수유역·유입·도엽은 원본을 그대로 읽었다.

- load_design_route() 신규 — 읽기·좌표계 변환·트림·조밀화를 한 곳에서 끝낸다.
  설계 계통(체인·배수유역)은 전부 이 함수를 지난다.
- Router_Watershed 도 이 함수를 쓴다. 좌표계가 프로젝트 기준으로 통일돼 관과
  노선이 같은 공간에 놓인다.
- 도엽 서피스는 SHEET_SURFACE_AUTO_METHODS(기본 laplace 1종)만 자동 생성한다.
  여섯 방식을 매번 만들면 WF1 891초 중 655초를 여기서 쓴다. 나머지는 관리자가
  화면에서 고를 때 만든다.

Router_Inflow 는 노선을 EPSG 라벨용으로만 쓰고 기하를 안 써서 제외했다.
Engine_Extent(배경 지도 범위)도 제외 — 지도는 트림 전 전 구간을 덮어야 사용자가
측량 범위 밖을 볼 수 있다.

실측(용화 route 120):
  배수유역 노선   2,136m -> 1,070m   격자 889x1435 -> 545x831
  1차 영역        538,574㎡ -> 263,170㎡
  관 좌표계       EPSG 5179 -> 5176
  관              22개(10개가 노선 밖) -> 11개 전부 노선 안
  종단 PVI        3개 -> 13개, 종곡선 1 -> 11, 불균형 97.0% -> 86.2%
  PVI 측점이 관 측점과 일치한다(반올림 오차 제외).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 15:53:59 +09:00
eomsangdon e4b859766b Merge remote-tracking branch 'origin/feat/b03-route-shapefile' into feat/b07-cover-template
# Conflicts:
#	B03_FileInput/B03_FileInput_Service_Chain.py
2026-09-01 15:34:07 +09:00
eomsangdonandClaude Opus 5 cf14958ea5 fix(B05): 예정노선 정점을 직결 문턱 아래로 좁혀 계획선을 그대로 채택한다
용화 예정노선으로 자동 체인을 돌리자 B05가 400으로 끊겼다.
  세그먼트 1 (BP -> CP1) 경로 탐색 실패: 종단경사 한계(26%)로 통과 경로가 없습니다.

원인은 제어점 간격이다. Solver.py:394 는 제어점 쌍이 direct_link_max_m
(ROUTE_DIRECT_LINK_CELL_FACTOR 2.0 x ROUTE_GRID_RES_M 2.0 = 4.0m) 이하면 격자 탐색
없이 직결해 원청 계획노선을 그대로 보존하고, 경사·곡선 위반은 경고로만 남긴다.

  샘플 CSV  350m / 135점 = 간격 2.6m  -> 대부분 직결   -> 통과(곡선 위반 9건은 경고)
  용화 예정  2136m / 121점 = 간격 17.6m -> 전부 탐색     -> 첫 구간 44.6%에서 실패

기존 프로젝트가 됐던 것은 제약을 만족해서가 아니라 탐색을 타지 않아서였다.

계획노선은 바꿀 수 없는 선이므로(사용자 확정), 같은 직선 위에 점을 더 찍어 간격만
좁힌다. densify_route()는 원래 정점을 모두 남기고 사이만 채운다 — 평면 형상도
연장도 끝점도 그대로다. 문턱과 정확히 같게 두면 부동소수 오차 한 번에 탐색으로
넘어가므로 ROUTE_PLANNED_DENSIFY_SAFETY(0.9)를 곱한다.

실측(용화, classification/dtm/smooth): 트림 후 63정점 -> 조밀화 323정점,
연장 1,070m 불변, 최대 간격 3.50m(문턱 4.0m), 시·종점 동일.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 14:30:56 +09:00
eomsangdonandClaude Opus 5 8ac892d97d feat(B04): 계획노선을 3D 최고 표고 평면에 그리고, 지표면 밖 구간은 잘라 낸다
실무 자료 용화.las가 계획노선 2,136m 중 일부만 덮는다. 좌표 문제가 아니라 측량
범위 자체다 — LAS(VLR EPSG 5176)와 정사영상 용화.tif 범위가 서로 일치하고, 위경도로
datum 보정까지 태워도 위도는 완전히 포함되며 경도만 동쪽 431m 초과한다.

노선 3D 표시
- 계획노선을 지표면에 드리우지 않고 데이터 최고 표고(bounds.z_max) 평면에 수평으로
  얹는다. 노선과 측량 범위가 평면상 어디서 어긋나는지 보려는 것이라 지형을 따라
  오르내리면 오히려 판단이 어렵다.
- 색은 2D 지도·B05 배수유역도가 쓰는 routeLineColor()를 그대로 쓴다. 같은 선을 두
  화면에서 다른 색으로 그리면 같은 것인지 알아볼 수 없다.

노선 트림
- trim_route_to_surface(): DtmGridSampler 의 valid_mask 로 판정한다. bounds 사각형이
  아니라 불규칙한 실제 외곽이다. 가장 긴 연속 유효 구간을 남긴다.
- 가장자리 여유 SURFACE_ROUTE_EDGE_TRIM_M(30m)은 잘라 낸 쪽 끝에만 적용한다. 노선
  본래 끝점이 지표면 안이면 깎지 않는다.
- 자르는 자리는 _planned_route_points_in_project_crs() 한 곳이다. 체인의 BP·EP·CP가
  전부 이 함수를 지나므로 여기서 한 번 자르면 하류가 모두 유효해진다.
- 지표면을 못 열면 자르지 않는다. 트림 실패가 설계를 막으면 안 된다.

실측(용화 노선 2,136m):
  csf/dtm/smooth            -> 1,310m (61%)
  classification/dtm/smooth -> 1,070m (50%)
bounds 사각형 기준 추정치 1,400m보다 짧다 — 실제 외곽이 사각형보다 작기 때문이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:46:48 +09:00
eomsangdonandClaude Opus 5 10a629973b feat(B04): 자동 전처리를 기본 조합만 만들고 나머지는 관리자 요청 시 만든다
지면 필터를 고쳐 지면점이 9~26배 늘자, 필터 전체 x 표현 전체를 미리 만드는
자동 전처리가 감당 못 할 만큼 길어졌다(용화 기준 15~20 모델). 산출물 대부분은
아무도 열어 보지 않는다.

- 자동 전처리는 기본 필터 1종 x SURFACE_AUTO_METHODS(dtm) 만 만든다. 스무딩
  유무 두 벌은 기존대로 같이 나온다.
- 기본 필터는 고정값이 아니라 입력 LAS를 보고 정한다 — 지면분류(class 2)가
  있으면 classification, 없으면 csf. csf는 분류 없는 LAS를 필터링하기 위한
  수단이므로 그때만 쓴다.
- 관리자가 B04 드롭다운을 바꾸면 그 조합이 이미 저장돼 있는지 보고, 없으면
  모달로 물은 뒤 그 조합만 계산해 영구 저장한다. 취소하면 드롭다운을 되돌린다.
  이미 있으면 묻지 않고 저장된 데이터를 그대로 쓴다.
- config_signature에서 source_filters·precompute를 뺀다. 이 둘은 "무엇을
  만들지"를 고르는 값이라 서명에 넣으면 조합을 바꿀 때마다 manifest가 통째로
  폐기돼 이전에 만들어 둔 조합이 사라진다.
- analyzeSurface가 API_ANALYSIS_TIMEOUT_MS를 쓴다 — 기본 30초로는 조합 하나를
  만드는 동안 abort 된다.

detect_extra_filters()는 resolve_auto_source_filters()로 대체했다. 필터를
말없이 덧붙이는 대신, 자동 경로의 기본값을 정하는 판정으로 쓴다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 12:26:43 +09:00
eomsangdonandClaude Opus 5 1eb5ad4a60 feat(B03): 입력 화면을 계획노선/지형 두 컨테이너로 나누고 파일마다 카드를 준다
노선 파일이 다섯이면 카드도 다섯이어야 어느 것이 왔는지 보인다(사용자 지시).
세트를 슬롯 하나에 몰아 담던 companions 구조를 걷어내고, 슬롯 하나가 파일 하나를
갖는 기존 구조로 되돌렸다 - 업로드 루프도 원래대로다.

- 왼쪽 컨테이너 계획노선 자료: csv(.csv/.shp) shx dbf cpg route_prj
- 오른쪽 컨테이너 지형 자료(LAS): las_laz prj(지형 좌표계) tfw tif + LAS 없는 설계 토글
- .prj만 확장자로 안 갈린다 - 노선 도형과 basename이 같으면 노선 좌표계 카드,
  아니면 지형 카드(planSlotAssignments). 재접속 현황은 저장 경로(input/shp/)로 가른다.
- 재접속 현황 응답에 relative_path 추가.
- 필수 판정이 노선 PRJ를 route_prj로 따로 센다 - 지형 PRJ 없이 통과하던 구멍을 막았다.
- 형제 카드(shx/dbf/route_prj)는 노선 도형이 shapefile일 때만 필수 - 확장자 줄의
  "선택" 꼬리표가 실시간으로 붙고 떨어진다.
- 카드가 좁아져 한글 제목이 글자 단위로 접히던 것을 word-break: keep-all과 헤더
  flex-wrap으로 고쳤다.

화면 검증(공용 브라우저): 실물 7파일을 한 번에 떨어뜨려 배정 실측 - route.prj는
노선 좌표계 카드, terrain.prj는 지형 카드로 갈렸고 카드 제목 9개 모두 한 줄.
tmp/tests/test_route_shapefile_input.py 9개 통과, tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 19:50:39 +09:00
eomsangdonandClaude Opus 5 36e4decf34 fix(B03): 노선 슬롯 카드에서 shapefile 세트를 한 번에 고르게 한다
카드의 파일 선택 버튼은 단일 선택이라 .shp 하나만 골라졌다. 형제 파일이 없으면
GDAL도 못 열고 필수 세트 판정도 막힌다. .shp를 받는 슬롯만 multiple로 연다.

화면 검증(공용 브라우저): 계획노선 카드 accept=".csv,.shp" multiple=true,
나머지 슬롯은 종전대로 단일 선택 유지.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 19:31:54 +09:00
eomsangdonandClaude Opus 5 fe72ea041b feat(B03): 계획노선 shapefile 입력과 PRJ 2개 분리를 지원한다
원청 정식 계획노선이 shapefile(UTM-K)로, 지형이 별도 PRJ(동부원점 Bessel)로
들어오는데 입력 경로가 shapefile 확장자를 막고 PRJ를 프로젝트당 1개로 전제했다.

- 업로드 허용에 .shp/.shx/.dbf/.cpg 추가, 한 번에 보낼 파일 수 5 -> 10
- B03_FileInput_Engine_Shapefile: ESRI 규격 직접 파싱(GDAL 미사용). 형제 파일이
  아직 안 왔어도 .shp 하나로 기하를 읽는다. .cpg 내용이 949뿐인 실물을 CP949로
  정규화해 한글 속성을 살린다.
- 노선 판독을 read_planned_route로 일원화(CSV/shapefile), PlannedRoute에
  crs_input 추가 - 변환 입력은 EPSG 코드가 아니라 crs_input_from_prj가 주는
  값(EPSG:n 또는 원문 WKT)이다. 실물 PRJ 2종 모두 to_epsg가 None이다.
- shapefile 세트를 input/shp/ 한 폴더에 모은다(GDAL 요건). 노선 PRJ가 그 안에
  남으므로 지형 PRJ(input/prj/)와 파일명 정렬 운에 기대지 않고 갈린다.
  find_project_prj가 지형 PRJ를 프로젝트 좌표계로 고른다.
- 필수 세트를 노선 1종(csv 또는 shp) + prj + tfw로 완화, shp면 shx/dbf 동반 필수.
- UI: 확장자 단독 슬롯 매칭을 basename 그룹핑으로 바꿔 노선 PRJ와 지형 PRJ가
  같은 슬롯을 다투지 않게 하고, 노선 슬롯이 파일 한 벌을 담아 함께 전송한다.

자체검증: tmp/tests/test_route_shapefile_input.py 9개 통과, tsc --noEmit 통과,
ruff check/format 통과. 전체 스위트 잔여 실패 11건은 HEAD 사본(git archive)에서
동일하게 재현되는 기존 실패다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 19:28:34 +09:00
eomsangdonandClaude Opus 5 0d90595a40 fix(B03/B04): PRJ 좌표계 판별을 문자열 매칭에서 WKT 정본+EPSG 라벨로 바꾼다
get_epsg_from_prj()가 WKT에 항상 있는 false_easting 때문에 EAST 분기가
무조건 걸려 모든 PRJ를 EPSG:5187로 판정했다(표준 WKT 6종 실측). 새 원청
자료의 5176(비표준 TOWGS84)·5179(AUTHORITY 없는 ESRI WKT)가 이 경로로
들어오면 최대 100km 어긋난다.

- common_util/common_util_crs.py 신설: 판별 사다리(pyproj DB 대조 →
  AUTHORITY 태그 → 투영 파라미터 지문)와 변환 입력 정규화. 수평 성분에
  TOWGS84가 박힌 PRJ는 EPSG로 갈아타지 않고 원문 WKT로 변환해 지역 보정을
  보존한다. 수직 성분의 bound(KNGeoid)는 2D 변환에 무관하므로 무시.
- B04 get_epsg_from_prj: 죽은 문자열 분기 제거, 유틸 위임. 시그니처 불변 —
  기존 COMPD_CS 프로젝트는 예전과 같은 EPSG:5187 문자열이 나온다.
- B03 _component_metadata: to_epsg 실패 시 사다리 라벨 보강,
  normalize_crs_metadata: BoundCRS 벗김(TOWGS84 PRJ 수평 탐색 실패 수정).

검증: tmp/tests/test_common_util_crs.py 13건 포함 스위트 29 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 16:27:13 +09:00
eomsangdon 1d1b1c8c0b fix(B03): 자동 설계 체인이 확정된 지표면 선택값을 쓰게 한다
LAS 없이 설계한 프로젝트에서 WF1이 sheet_laplace로 자동 확정한 직후 체인이
config 기본값(csf/dtm)으로 B05 경로 계산을 걸어 404로 끊겼다.

  ERROR 자동 설계 체인 중단(B05 경로 계산 실패): status=404

stage 1 스냅샷(get_surface_confirmation_params)을 읽어 실제 확정값을 쓴다.
B05 초기화가 부르는 경로도 같은 함수라 함께 고쳐진다.

검증: 프로젝트 5d18ebe3(LAS 없이 도엽등고선으로 생성)에서 체인 재실행 —
B05 route_id=112 연장 354.84m, 횡단 19개, 배수유역 관 4개·세부유역 8개까지
완주. 확정 선택값 {"source_filter": "sheet_laplace", "method": "dtm",
"smooth": true} 그대로 사용.
2026-08-30 18:18:16 +09:00
eomsangdon 3ea6aa5b13 fix(B03): LAS 없이 설계를 켜면 LAS/LAZ를 아예 받지 않는다
사용자 보고(2026-08-30): 체크한 상태에서 실수로 넣은 LAS가 그대로 업로드됐다.
카드에 --disabled 클래스만 걸려 있어 회색으로 보일 뿐 선택 버튼과 input이
살아 있었고, 서버도 las_free일 때 LAS 1개를 정상 경로로 받아 줬다.

- 화면: 선택 버튼·file input을 실제로 잠그고, 켤 때 이미 고른 LAS는 내린다.
  파일 선택 영역·드롭으로 들어오는 것은 onFileSelected에서 걸러 낸다.
- 서버(신뢰 경계): /files는 las_free면 LAS 0개만 받는다. 큰 LAS가 타는
  청크 업로드 세션 생성도 같은 검사를 건다 — 여기서 막지 않으면 /files 검사를
  통째로 비켜 간다.
2026-08-30 18:11:19 +09:00
eomsangdon 37590b84d1 feat(B03): LAS 없는 설계도 스무딩 격자로 확정한다
2026-08-30 사용자 확정. 방식마다 dtm_sheet_*_smooth.npz를 같이 만들어 두므로
종·횡단이 LAS 경로와 같은 스무딩 격자를 샘플링한다.
2026-08-30 17:48:28 +09:00
eomsangdonandClaude Opus 5 b2d707f91d feat(B04): 등고선 보간 6종을 만들어 화면에서 비교하게 한다
문헌(ANUDEM Hutchinson 1988/89, DEM 보간 비교연구)은 지형에 따라 우열이
갈려 단일 최적해가 없다고 본다. 방식을 하나로 고르지 않고 전부 만들어 두고
사용자가 눈으로 비교해 정하도록 했다(2026-08-30 사용자 지시).

신규 B04_PreProcess_Engine_SheetMethods.py — 거리비례 / TPS(박판, 감쇠
최소곡률 LSMR) / 라플라스 / TIN 선형 / TIN 곡면(Clough-Tocher) / IDW.
방식마다 dtm_sheet_{key}.npz + 프리뷰를 만들어 surface_models에
source_filter=sheet_{key}로 등록하므로 기존 뷰어·등고선·프리뷰 경로가 그대로
돈다. 폐합 링 안쪽 처리는 방식과 무관하게 똑같이 적용한다.

화면: 도엽등고 3D 서피스 컨테이너에 방식 전환 버튼과 '라이다 겹쳐 보기'
토글(반투명 파랑)을 달았다. 라이다는 같은 좌표계라 같은 자리에 겹친다.

실측(c1bb453f, 6종 65s): 평탄 셀 TPS 0.003% / 거리비례 0.014% /
TIN 곡면 0.026% / 라플라스 0.235% / TIN 선형 10.4% / IDW 69.1%.
LAS 대비 노선 |dz| 평균은 2.59~3.00m로 방식 간 차이가 작다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 16:11:08 +09:00
eomsangdonandClaude Opus 5 3572694f73 feat(B03/B04): LAS 없이 도엽등고선으로 3D 서피스를 만들어 설계한다
- B03: 'LAS 없이 설계' 토글 — LAS 필수카드 비활성화, las_free 플래그로
  업로드·완료 검증 면제, 계획노선 CSV를 WF1 분석 입력으로 사용
- B04: 신규 Engine_SheetSurface — 도엽_등고선.geojson을 노선 bbox+300m
  직사각형으로 절취, 배수유역 엔진의 등고선 정점구름·Delaunay TIN 보간을
  재사용해 dtm_sheet.npz(1m 격자, LAS DTM과 동일 형식) + 프리뷰 glb 생성.
  build_surface_sampler('sheet','dtm')로 종·횡단·배수 하류 계산 무수정 동작
- WF1: las_free면 run_sheet_surface_analysis로 분기, sheet/dtm 자동 확정.
  VWorld·도엽 확보 블록을 download_geodata()로 추출해 두 경로가 공유
- LAS가 있어도 도엽 서피스를 함께 생성·등록(참고용), B04에
  '도엽등고 3D 서피스' 별도 컨테이너로 표시

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 14:27:41 +09:00
eomsangdon 60bbe89edb fix(B03): rerun analysis on reupload
Clear derived browser caches so B05 loads the newly generated route and section data.
2026-08-29 20:17:37 +09:00
eomsangdon 3640591c46 fix(B03): skip polling for unchanged uploads 2026-08-29 19:52:18 +09:00
eomsangdon f99f1f68d3 feat(B03,B04,B05): 초기 설계가 도는 동안 B05·B06 진입을 막는다
파일을 올리면 지표면 확정 직후 "노선 설계로 이동하세요"를 적고 그 뒤에 초기 설계
체인이 돈다. 그 사이 B05에 들어가 만지면 반쯤 계산된 값을 편집하게 되고, 그 편집이
섞인 채 초기값 스냅샷이 찍힌다. 계산이 끝날 때까지 준비 화면(B11)에서 기다리게 한다.

- initial_snapshot: 마커(initial_design.lock) 생성·해제·조회와 스냅샷 무효화,
  편집 정본 제거를 한곳에 둔다. 마커는 스냅샷 4트리 밖(프로젝트 루트)이라 복원에
  딸려 들어가지 않는다.
- 체인 두 곳(자동·재설계): 시작에 마커, finally에서 해제. 재설계 체인은 끝에 스냅샷을
  무효화한다 — 사용자 입력을 유지한 채 재계산하므로 그 결과를 찍으면 가짜 초기값이
  된다. 다음 [초기화]가 폴백을 타며 새 초기값을 만들고 그때 촬영한다.
- /surface/status: 마커가 있으면 in_progress + initial_design으로 답한다. stage 1이
  COMPLETE면 진행률 파일을 무시하는 기존 분기를 건드리지 않으려고 별도 확인이다.
- 진입 게이트(routeAfterPreloadCheck)와 B11이 그 상태를 보고 기다린다. 상태 조회가
  실패하면 막지 않고, B11 대기는 20분 상한을 둔다.
- [초기화] 폴백: 체인 전에 structures.json과 drainage/edits를 지운다. 남기면 구조물
  측점이 사용자 편집분에서 다시 파생돼 초기값이 오염된다(2026-08-29 실측).

테스트 4건 추가. 249 passed·8 failed(기슭막이 이관 때 생긴 기존 실패, 변경 전 동일).
2026-08-29 15:09:09 +09:00
eomsangdon 08c0dc3228 feat(B05,B06): 자동저장을 걷어내고 초기값 스냅샷으로 초기화한다
CLAUDE.md 5장(조작·데이터 흐름 정책)을 코드에 반영한다. 조작분은 세션에만 쌓고
영구저장은 [저장]·[확정]에서만 하며, [초기화]는 재계산이 아니라 초기값 복원이다.

자동저장 폐지
- B06 조정창 기준벽 구간값: 800ms 디바운스 PUT을 없애고 세션(b06:culvertopt)에
  담는다. flushCulvertOptions()를 B06 [저장]·[확정]과 B05 [저장]이 부른다.
- B05 구조물: 조작 즉시 PUT + 서버 재조회로 화면을 덮어쓰던 것을 세션
  (b05:structures) 적재로 바꾼다. 저장 전에도 고르고 지울 수 있도록 식별자를
  crypto.randomUUID()로 미리 발급한다(서버는 빈 값일 때만 새로 발급).
- B05에서 만지고 B06에서 확정하는 경로를 위해 flushPendingStructures()를 공용화.

초기값 스냅샷
- common_util_initial_snapshot: 자동설계 체인 성공 직후 정본 파일 4트리와
  routes+자식 4표를 initial_snapshot/에 뜬다. 이후 읽기 전용.
- reset_route_design: 스냅샷이 있으면 DELETE와 같은 트랜잭션에서 행을 되세우고
  파일을 되돌린다. 없으면 종전 재계산 폴백. 응답에 restored를 더한다.

조작 응답
- 등고선 재적용·B06 진입 정합·[모두 적용]에서 전체 화면 오버레이 제거.
- 재계산이 design을 갈아끼울 때 extra_spans를 보존한다(다른 조작값과 동일).

테스트: tmp/tests/test_initial_snapshot.py 5건 추가. 245 passed·8 failed(기존
실패 — 기슭막이 이관 때 placement가 interval→point로 바뀐 것을 테스트 미반영).
2026-08-29 11:15:29 +09:00
eomsangdonandClaude Opus 5 d935013ffa feat(B03): 같은 파일 재업로드는 전송 생략, 다른 내용이면 덮어쓰기 (E2E 결함 2)
사용자 결정(2026-08-08): 복수 파일을 허용하고 중복 기준은 파일명으로 둔다. 같은 이름으로
같은 내용이 다시 들어오면 덮어쓰지 말고 건너뛰고, 내용이 다르면 덮어쓴다.

파일 지문(부분 샘플링)
- B03_FileInput_Fingerprint.ts: 파일 크기 + 앞·중간·끝 8MB를 이어 SHA-256. 24MB만 읽어
  1~2초면 끝난다. 전체 읽기(1.7GB, 10~30초)와 견줘 실용적이고, 자리를 앞·중간·끝으로
  흩어 놓아 머리말만 같은 파일도 갈린다. 한계는 주석에 적었다.
- 화면이 업로드 세션 생성 요청에 지문을 실어 보내고, 서버가 같은 이름의 최신 입력 파일
  메타데이터에 적힌 지문과 견준다. 같으면 already_uploaded=true로 답해 **전송 자체를**
  건너뛴다(1.7GB면 3~5분 절약). 지문이 없거나 다르면 그냥 올린다 — 애매하면 올리는 쪽.
- 완료 요청에도 지문을 실어 input_files.metadata에 남긴다. upload_sessions에 컬럼을
  더하지 않으려는 선택이라 DB 스키마 변경이 없다.

옛 행 정리
- supersede_previous_input_files(): 같은 이름의 이전 행을 SUPERSEDED로 내린다. 조회는
  UPLOADED/PROCESSED만 보므로 목록·분석에서 자동으로 빠지고, 행은 이력으로 남는다.
- 직접 업로드 완료와 보관함 연결 양쪽에 적용.

검증(실서버 f45243b3)
- 같은 파일 재요청 → already_uploaded=true, 세션 미발급.
- 지문이 다르면 → 세션 발급(정상 업로드 경로).
- 옛 행이 SUPERSEDED로 내려가는 것 DB에서 확인.
- 화면 코드(B03_FileInput_Fingerprint.ts)를 그대로 실행해 만든 지문과 서버측 검증
  스크립트의 지문이 20MB 표본에서 완전히 일치(f281fd08…93e4).
typecheck·ruff·prettier 통과, 정적 번들 재빌드.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 20:11:23 +09:00