Commit Graph
53 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 9da3bce1bf fix(B06): 횡단 카드 버튼이 서버에 바로 저장하던 것을 캐시로 바꿈
사용자 확정(2026-09-06): 조작은 캐시에 쌓이고 [저장]·[확정]에서만 영구저장소에
나간다. 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈)은 누를 때마다
POST cross-design 이 나가 서버가 계산하고 바로 저장하고 있었다.

- 세션 초안 crossdesign 신설(B06_Section_Cross_Design_Session) — 선택값만 담는다.
- 계산은 브라우저 재계산 창구 하나로 돌린다(B05·B06 공용).
- 재계산 때 세션 선택이 정본보다 우선 — 새로고침 뒤에도 고른 값이 남는다.
- [저장]·[확정] patch 에 선택값 + 전 측점 면적을 실어 보낸다. 카드 버튼을 바꾸면
  구조물이 없는 측점 면적도 달라지므로 구조물 측점만 보내면 수량이 어긋난다.
- 구조물 목록 주석 정정(이미 초안 방식인데 옛 주석만 남아 있었다).

검증: tsc --noEmit 통과, pytest 389 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 15:14:44 +09:00
eomsangdonandClaude Opus 5 1bfc9ee12c fix(B06): 등록표에 extraspan 이 빠져 B06 화면이 통째로 안 뜨던 회귀
캐시·세션 일원화에서 조정창 값 8종을 옮기며 다단 구간값(`extraspan`)을 등록표에
빠뜨렸다. 표에 없는 이름을 꺼내다 예외가 나 페이지 렌더가 통째로 실패했고 화면에는
「준비 중인 페이지입니다」만 떴다(화면 확인으로 발견).

- `extraspan` 을 등록표에 넣음.
- 표에 없는 이름은 이제 **예외 대신 저장 건너뛰기** — 그 값만 안 남고 화면은 선다.
  콘솔에 한 번 알려 표에 줄을 넣게 한다.
- B06 이 키를 만들 때 쓰던 형변환을 없앰 — 앞으로 등록표에 없는 이름은 컴파일에서
  걸린다. 같은 사고가 화면까지 가지 않는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 12:21:32 +09:00
eomsangdonandClaude Opus 5 6d9c7087e9 fix(B05,B06): 3D 에서 고른 구조물이 B06 횡단도에 안 뜨던 문제 — 세 자리 수리
2026-09-05 사용자 지시 건. 넘김 자체는 서 있었고 값이 중간에 지워지거나 대조에서
떨어지고 있었다.

- 부재키가 지워지던 길 — 3D 로 고른 뒤 선택 동기화가 **측점만** 다시 적어 부재키를
  덮었다. 같은 측점이면 이미 적힌 부재키를 지키게 함(모든 호출자에 함께 적용).
- 측점 대조 허용오차 0.01m → 0.05m. 같은 화면의 다른 대조와 같은 값이며, 3D 가 준
  누가거리가 소수점 아래에서 조금만 달라도 측점을 못 찾고 조용히 끝나던 원인.
- 「진입당 한 번」 빗장을 넘김값 서명 비교로 교체 — 자료가 늦게 와도 다시 서고,
  같은 값이면 재렌더에도 스크롤이 안 튄다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 11:50:00 +09:00
eomsangdonandClaude Opus 5 a126df25bb refactor(B05,B06): 설계 초안·계산 결과도 등록표로 — 이동할 때 다시 부르지 않게
캐시·세션 일원화 2단계 (2026-09-06 사용자 지시).

- ② 설계 초안 이관 — 구조물 미저장분, 상단측 변경분, 페이지 간 넘김값(구조물 선택),
  표준횡단 편집값, 조정창 4축·단수·연동값 8종, 암 경계선, 표시 반폭. 넘김값은 별도
  임시 키를 없애고 초안 한 자리로 흡수.
- ④ 계산 결과 이관 — 최신 노선 응답, 서버가 준 규격 횡단·암 경계 기본값. 횡단 상세는
  메모리 캐시에 더해 세션에도 한 벌 얹어 새로고침 뒤 첫 화면이 서버를 안 기다림
  (용량을 넘으면 조용히 건너뛰고 예전대로 다시 받음).
- B05 진입의 강제 새로읽기를 걷어냄 — 캐시로 먼저 그리고 노선번호·지표면 서명으로
  뒤에서 신선도만 확인, 달라졌을 때만 다시 그림.
- [초기화]의 초안 비우기를 `clearDrafts` 한 곳으로 모음(예전에는 파일마다 따로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 11:48:40 +09:00
eomsangdonandClaude Fable 5 738e09e7b1 feat(B05/B06): 구조물 선택 화면 전체 활성화 + 세션 상시 공유
- 바깥 선택이 폼에 실릴 때 접힌 좌측 패널 자동 펼침(onReveal 창구)
- 계곡 통과 시설 목록 행도 보이는 자리로 스크롤(rAF)
- 종단 테이블 구조물 구간 판정을 허용오차 비교로 교체 + 병합 측점 포함(강조 0건→6건)
- 구조물 선택 세션을 소비형에서 유지형으로 — B06 카드·목록·부재 선택도 같은 칸에 기록,
  양쪽 진입 시 복원(목록 지연 로드 대비 이중 복원)
- 조정창 닫기가 세션 선택까지 지우던 결함 수정(부재 해제와 측점 해제 분리)
- B05 페이지 700줄 유지 위해 상단측 세션 보관을 Page_Helpers로 이동(동작 불변)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-04 16:27:35 +09:00
eomsangdonandClaude Opus 5 ebef874e5f feat(B05): 부재키 일원화 — 세월교·BOX암거까지
- 이름표를 횡단도 이름으로 통일 — 세월교 유입·유출, BOX 좌·우, 본체는 body
- 조정창 하나가 여러 부재를 다루므로 `측이름:부재` 꼴 — 강조는 전체 키, 조정창은 앞칸만
- B06 갈래 태우기 신규 모듈 — 세월교/BOX/기슭막이 조정창으로 각각 보냄
- 저장 코리도 만료(BUILD_VERSION 91→92) — 재계산 비용 실측 차이 없음(5.1초 vs 4.7초)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 15:32:10 +09:00
eomsangdonandClaude Opus 5 2878ab9617 feat(B05): 3D 코리도 구조물 개별 선택
- 구조물 솔리드에 부재키(key) 부여 — B06과 같은 이름(inlet·outlet·extra{i}·bextra{i}·own·basin·pipe)
- 구조물 메쉬에 신원표(userData) — 이름 규칙은 그대로 유지
- 신규 모듈 두 개 — 3D 클릭·강조(Viewer_Structure_Pick), 좌측 패널 연결·B06 넘김(Structure_Pick_Session)
- 좌측 패널·종단에서 고른 것도 3D가 따라오도록 선택 동기화에 포트 추가
- B06 진입 시 세션 넘김값으로 그 측점 카드 선택·스크롤 + 기슭막이 조정창 열기
- 저장 코리도 만료(BUILD_VERSION 90→91) — 옛 저장본엔 부재키가 없음
- 뷰어 700줄 여유 — 검증용 요약을 Viewer_Debug로 분리(동작 불변)
- 검증 수단 — __corridorScene에 camera·project 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 15:04:38 +09:00
eomsangdonandClaude Opus 5 bc7b9e3a48 fix(B06): 유토곡선 영역 누락 — 재계산 결과와 계획선 정본이 어긋나던 것
두 곳이 같은 뿌리였음. 브라우저 재계산은 **편집이 반영된 계획고**로 횡단 설계를 만드는데
`design_profiles` 는 저장분 그대로라 두 값의 기준이 갈렸음.

1. 재계산 창구가 방금 푼 계획선을 **공유 캐시에도 얹도록** 함
   (`detail.longitudinal.design_profiles`). 이게 없으면 낡음 판정이 영원히 참이 되어
   B06 유토곡선이 통째로 빈 채로 남았음(사용자 보고). `profile_alignment`(base_pvi)는
   건드리지 않음 — 편집 델타의 기준선이라 편집분을 구워 넣으면 이중 적용됨.

2. B06 진입 정합이 **미저장 세션 편집을 못 보고 건너뛰던** 것. 서버에서 갓 받은 저장분
   끼리는 늘 일치해 「낡지 않음」이 되는데, B05가 세션에 남긴 편집은 그 안에 없음.
   세션 초안이 있으면 판정을 건너뛰고 무조건 맞추도록 함 — 재계산은 브라우저 안에서
   끝나 값이 쌈.

화면 검증(5174, 같은 시점 비교):
  수정 전 — B05 절토 4,774.1㎥ / 성토 16,715.5㎥, B06 절토 4,515.0㎥ / 성토 14,857.5㎥
  수정 후 — 양쪽 모두 절토 4,774.1㎥ / 성토 16,690.7㎥ (일치)
B06 유토곡선 영역도 곡선이 다시 그려짐(문구 없음).

전체 테스트 183건 통과, `tsc --noEmit` 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:49:25 +09:00
eomsangdonandClaude Opus 5 a35c8ff356 feat(B05,B06): 계획선 편집 중 횡단 재계산을 브라우저에서 수행 — 서버 왕복 제거
사용자 조작 중의 계산은 브라우저 안에서 끝나야 함(2026-09-03 사용자 확정). 계획고가
바뀔 때마다 전 측점 횡단 계산이 `POST …/cross-design/preview` 로 나가 왕복이 조작
속도를 지배했음.

- `refreshCrossDesigns` 를 로컬 계산으로 교체. 계획고는 저장 선형(`base_pvi`)에 편집
  델타를 얹어 TS `buildAlignment` 로 여기서 풂 — 호출부(B05·B06) 시그니처는 그대로라
  단일 창구가 유지됨. 서버 프리뷰는 선형 저장분이 없는 옛 데이터 폴백으로만 남음.
- 표준단면 config 기본값·암 경계 기본 오프셋을 `sections/context` 응답에서 세션에 기억
  (`rememberStandardDefaults`·`rememberRockBoundaryDefault`). 프론트에 config 수치를
  복제하지 않으면서 패널 없는 B05 도 같은 값으로 계산함.
- 디바운스 250 → 60ms — 왕복이 사라져 손을 떼는 즉시 유토곡선이 따라옴.
- 낡음 판정을 `hasStaleDesigns` 로 바꿔 첫 건에서 중단하고, 계획선 유효 샘플을
  샘플 배열당 한 번만 걸러 이진탐색(그리기 프레임당 2.33ms → 0.07ms 실측).
- 파이썬 엔진 2파일·프리뷰 라우터에 「TS 짝 파일과 한 벌」 경고 블록 추가.

검증: `tmp/tests/test_b06_cross_design_mirror.py` 10건 — 토사/암 2단계/L형 측구/포장/
세월교 하강/사면 미닫힘 등에서 파이썬과 TS 결과가 면적·설계선까지 일치. 전체 183건 통과.
`tsc --noEmit` 통과. 실측: route 127(측점 128) 전 측점 로컬 재계산 7.5ms.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 19:58:09 +09:00
eomsangdonandClaude Opus 5 9b4abecf9d refactor(B05/B06): 유토곡선 일원화 — 보는 노선·횡단 재계산 창구·낡음 판정 통합
같은 데이터를 두 화면에 보여 주는 기능인데 세 곳이 갈려 값이 달랐다(실측: 절토(자연)
B06 3,704.6㎥ ↔ B05 4,526.8㎥).

① 보는 노선 — B05는 최신 경로, B06은 최신 **확정** 경로를 열어 노선을 다시 탐색한
   프로젝트에서 서로 다른 노선을 봤다(route 126 DRAFT ↔ 125 CONFIRMED, 같은 20m
   측점 성토 4.82㎡ ↔ 85.9㎡). `get_workflow_route_context()`(최신 경로) 신설해 B06
   화면 context가 그것을 쓴다. 납품 도면(B07)이 쓰는 확정 전용 창구는 그대로 둔다.

② 횡단 재계산 — 호출이 두 벌이라 인자가 갈렸다(B06만 표준 단면값·암 경계 오프셋 전달,
   보존하는 사용자 부속값도 2개 ↔ 7개). `B06_Section_Cross_Refresh.refreshCrossDesigns()`
   한 창구로 모으고 세션 편집값은 저장소에서 직접 읽어 패널 없는 B05도 같은 값을 보낸다.

③ 낡음 판정 — 「옛 암 2단계 필드 누락」 조건이 B06 페이지에만 있어 B05는 재계산을
   건너뛰었다. 공용 `staleDesignChainages()` 안으로 옮겨 두 화면이 같은 시점에 같은
   조치를 한다.

검증 — 공용 브라우저 실측: 두 화면 모두 route 126, 요약줄 문자열 완전 일치
(`절토(자연) 4,526.8㎥ · 성토 14,881.8㎥ · 토취 10,213.3㎥ · 최종 누가토량 −10,213.3㎥`).
pytest 370 passed·17 skipped(일원화 검사 4건 신설), typecheck·prettier·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 09:50:14 +09:00
eomsangdon cc2c788122 refactor(B06): 횡단 페이지 저장 흐름·관 옵션 반영 분리 (926→680줄)
- `B06_Section_UI_Page_Persist.ts`(231줄) 신설 — 암 경계선 세션 저장소
  (`createRockBoundaryStore`), 편집분 수집, [저장]·[확정].
- `B06_Section_UI_Page_Pipe_Options.ts`(130줄) 신설 — 폼에서 바꾼 관 옵션을
  횡단 캐시·조정창 제어기에 얹는 경로.
- 페이지는 상태 창구(`SectionPersistContext`·`PipeOptionsContext`)만 넘김.
- 화면 검증: B06 진입 카드 280장·암 버튼 69개·콘솔 오류 0. 암 경계선 ▲ 조작으로
  표시 -0.5m → -0.4m + 세션키 기록, ↺ 로 -0.5m 복귀. [저장] 클릭 시
  `POST /sections/111/save` 200.
- `tsc --noEmit` 0, prettier 적용, pytest 359 passed.
2026-09-02 16:37:48 +09:00
eomsangdonandClaude Opus 5 1c9ff90dfd feat(B06): BOX암거 좌측 폼을 세월교와 같은 규칙으로 연결한다
세월교와 같은 문제가 BOX암거에도 있었다 — 좌측 「구조물 배치」의 본체 규격·날개벽을
바꿔도 도면이 그대로였고, 폼 기본값이 스펙에서 오지 않았으며, 구체를 골라도 좌측
칸이 서지 않았다. `applyPipeOptionsToCache`가 `section.box`를 모르고 즉시 return하던
것이 뿌리다(세월교와 동일).

- `applyBoxFormOptions()` — 폼 옵션(`body_*`·`wing_*`)을 제어기로 보낸다.
  `BoxControl`에 `setBody`·`setWing`을 더했다: 캐시(`section.box`)를 먼저 고치고
  (`span_m`은 백엔드 `_box_set`과 같은 식으로 다시 잡는다) 정본 예약 + 카드 갱신.
- 날개벽 옵션 조립·해석을 `wingOptions()`·`wingPatchFrom()`으로 묶어 세월교와 나눠
  쓴다 — 세월교 쪽 중복 코드가 사라졌다.
- `withBoxSpec()` — 폼 기본값을 `section.box`(내공 폭·높이, 날개벽)에서 읽는다.
- 좌·우 끝을 고르면 폼의 **날개벽(유입)/(유출)** 칸이 선다. 좌·우 ↔ 유입/유출
  매핑은 기하가 날개벽을 고르는 기준(`uphill_side`)과 같다. 조정창은 결국 지우고
  폼 이름(유입/유출)만 쓰기로 한 사용자 확정(2026-08-30)을 따랐다.

구체 길이·표고는 폼에 대응 칸이 없어 조정창 축으로 남는다(본체 높이는 규격이 이미
정한다 — 2026-08-30 사용자).

자체검증(공용 브라우저 5174 + 워크트리 백엔드 8001, 측점 10+0.9 BOX암거):
- tsc --noEmit 통과.
- 구체 선택 시 좌측 `날개벽(유입) (BOX암거)` 칸 강조(수정 전 강조 없음).
- 본체 규격 2.0×2.0 → 3.0×3.0 → 도면 라벨 `BOX 3.0×3.0`, 다시 2.0×2.0 → `BOX
  2.0×2.0`. 한 번 고른 상태에서 연속 조작도 그대로 먹는다. 수정 전에는 라벨이
  5.34m 구체와 함께 전혀 움직이지 않았다.
- 회귀: 세월교 날개 길이 2→4→2에서 조정창 표시가 4.0m→2.0m로 따라온다
  (`wingOptions`/`wingPatchFrom` 공용화 뒤에도 동일).
- 조작값은 원래대로(BOX 2.0×2.0 · 세월교 날개 길이 2m) 되돌려 놓았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 13:37:43 +09:00
eomsangdonandClaude Opus 5 03840ff3d6 feat(B06): 세월교 좌측 「구조물 배치」 폼을 조정창 로직에 연결한다
좌측 폼의 세월교 상세 항목(관종·관경·수량·월류 폭·날개벽 유입/유출)이 도면에
전혀 반영되지 않았다. `applyPipeOptionsToCache`가 `section.culvert`만 보고
세월교 측점(`section.ford`)에서는 즉시 return했기 때문이다.

프론트는 구조물 배치의 상세 UI를 쓰고 로직은 조정창 제어기 것을 쓴다
(2026-08-30 사용자 확정).

- `applyFordFormOptions()` 신설 — 폼 옵션 키를 `FordControl.setPipe`/`setWing`
  인자로 옮긴다. 캐시 반영·바닥판 연장 재계산·정본 예약·카드 갱신은 제어기에
  이미 있어 새로 만들지 않았다.
- `FordControl.setPipe` 확장 — `pipe_kind`(관종)·`ford_width_m`(월류 폭 =
  `span_m`) 추가. 두 값은 조정창에 칸이 없고 폼만 보낸다.
- `withFordSpec()` — 폼 기본값을 `section.ford` 스펙에서 읽는다. 두 창이 같은
  스펙을 보므로 어느 쪽에서 만졌든 값이 갈리지 않는다(수량(련) 빈 칸 해소).

월류 높이(`ford_height_m`)는 백엔드 `_ford_set`이 읽지 않는다 — 세월교는 구체
위 노면이라 파임이 없고, 물넘이포장 전용 값이다. 폼에는 남되 도면 반영처는 없다.

자체검증(공용 브라우저 5174, 측점 7+9.7 세월교):
- tsc --noEmit 통과.
- 폼 날개 길이(유입) 2→4 → 조정창 「날개 길이 4.0m」, 바닥판 7.63m→9.04m
  (= +2×cos45°). 수정 전에는 둘 다 그대로였다.
- 폼 수량 3 → 조정창 「3련」, 폼 관경 Ø1200 → 조정창 select 1200.
- 재선택 왕복: 월류폭 12·수량 3·관경 1200·날개길이 4 그대로 되읽힘(스펙 정본).
- 진입 시 수량(련) 칸 = 1(수정 전 빈 칸), 관종 파형강관.
- 조작값은 원래 값(10/1/1000/2)으로 되돌려 놓았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 11:44:54 +09:00
eomsangdon e6ac071f58 merge: 구조물 패널 후속 수정 4건을 통합한다 2026-08-29 19:29:39 +09:00
eomsangdonandClaude Opus 5 2ee71eff19 fix(B05,B06): 독립 기슭막이 폼에서 단 수를 뺀다
조정창에서 옮겨 오는 [추가 기슭막이(단)] 행과 같은 값이라 두 벌이었다.
단 수 정본은 횡단 설계 patch(extra_wall_counts)이고 조작은 그 행이 한다 —
폼 칸과 그 값을 나르던 배선(tierCount·setTierCount)을 함께 걷어낸다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 19:17:07 +09:00
eomsangdon 184afa6e89 merge: B05·B06 구조물 패널 일원화 작업을 B07 작업 브랜치로 가져온다
다른 브랜치(feat/B05B06-구조물패널-일원화)의 B05·B06 구조물 배치 폼 일원화
결과를 받는다. 충돌 없음 — 그쪽은 B05/B06만, 이쪽은 B07/B08만 건드렸다.

그쪽 브랜치에 남아 있던 옛 폴더(B08_DesignDetail, B07_Quantity)는 이쪽 삭제가
반영돼 사라진다. main.py·라우트·척도 등 B07 작업물은 이쪽 것이 유지된다.
2026-08-29 19:13:03 +09:00
eomsangdonandClaude Opus 5 091a30286e fix(B05,B06): 독립 기슭막이 단 수를 좌·우로 나누고 그 칸을 강조한다
- 단 수를 바깥 행에서 좌·우 칸 안으로 옮긴다. 저장 키도 좌·우 각각
  (inlet_revet_tiers·outlet_revet_tiers, 옛 tiers는 폴백·호환 기록).
  폼 값은 다단 채널(extra·bextra)로 가고, 폼은 그 채널 값을 되읽는다.
- 좌·우 칸에도 조정창 행 이식 자리를 두어, 벽을 고르면 배관 유입구·유출구와
  같이 그 칸이 강조되고 조정 항목이 옮겨 온다. 칸 이름표는 좌·우 그대로 둔다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 19:09:42 +09:00
eomsangdonandClaude Opus 5 1165c657e7 feat(B05,B06): 독립 기슭막이를 좌·우 칸으로 나누고 단 수를 도면에 잇는다
- 설치 측·단 수를 컨테이너 밖 한 행으로 빼고, 벽 제원은 [기슭막이 (좌)]·
  [기슭막이 (우)] 두 칸으로 나눈다. 설치 측이 한쪽이면 그 칸만 뜬다.
  좌·우 이름표는 그 측점 오르막 방향(uphill_side)이 정한다.
- 두 칸은 배관 유출구와 같은 양식이다 — [구조][형태] + 길이·높이·전/후.
  구조 선택지는 기슭막이 하나뿐이지만 레이아웃을 맞추려 그대로 둔다.
- 값은 유입/유출 키로 좌·우 따로 저장한다(옛 한 벌 저장분은 양쪽으로 펼쳐 읽는다).
- 단 수에 [-][값][+] 조정칸을 붙이고, 폼 단 수를 다단 채널(extra·bextra)로
  보낸다 — 배수관 측점처럼 횡단도에 단이 선다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 19:05:07 +09:00
eomsangdonandClaude Opus 5 f7ec239625 fix(B06): 폼 형태·높이를 지금 그려진 값으로 맞춘다
배관 유출구 기슭막이가 폼과 다른 형태로 그려졌다. 폼은 저장된 옵션을,
그림은 조정값(m·h)을 쓰는데 둘이 어긋나도 맞추는 자리가 없었다.
조작이 정본이므로 폼이 그려진 값을 따라간다 — wallForm 의존성을 추가하고
형태·높이는 빈칸 채우기가 아니라 덮어쓰기로 바꾼다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 18:42:33 +09:00
eomsangdon b3e6f01eb4 fix(B06): 폼 높이·형태가 실제로 벽을 제어하게 한다
원인 추적 결과 두 겹이었다.
① 배관 벽 높이는 spec.revet_height_m을 쓰지 않는다 — revetWallSpec이 관경 기준
   하한과 조정값(adjust.h)만 본다. 폼 값을 스펙에만 넣어 그림이 안 바뀌었다.
   이제 폼의 높이·형태를 조정창과 같은 채널(revetOffset.update)로 보낸다.
② 형태마다 높이 한계가 있다(돌쌓기(메) 2.0m). 한계를 넘겨 입력하면 그림은 그대로인데
   폼 숫자만 커져 '제어가 안 된다'로 보였다. 기하가 적용한 값을 폼에 되돌리고
   한계를 토스트로 알린다.

폼 기본 높이도 스펙이 아니라 지금 그려진 순수 높이(조정창 표시값)를 쓴다.
2026-08-29 17:09:20 +09:00
eomsangdon 510731dd17 fix(B06): 폼의 높이·길이·전/후가 횡단도를 따라오게 하고 기본값을 조정창과 맞춘다
2026-08-29 사용자 지적 2건:
① 폼에서 높이·길이·기준측점 전/후를 고쳐도 도면이 그대로였다 — 조정창 조작값
   (revet_adjust.h·m)이 폼 값보다 우선이라 그림이 옛 값을 유지했다. 폼이 높이·
   형태를 정하면 그 벽의 조정값을 비워 폼 값이 이기게 했다.
② 폼 기본값은 예전 조정창이 보여주던 값이 기준이다 — 관 옵션이 비어 있으면
   횡단 스펙(culvert 스펙: 형태·높이·길이·전/후·집수정 구간값·관종·관경)에서
   채워 폼과 조정창이 같은 원천을 보게 했다. 저장된 옵션이 있으면 그쪽이 이긴다.
2026-08-29 16:56:37 +09:00
eomsangdon 45c6f9aa07 feat(B06): 기준 측점 이동을 B06 구조물 배치에서도 한다
2026-08-29 사용자: 구조물 배치 컨테이너를 B06으로 가져온 이유가 이것이다 —
폼의 기준 측점 숫자를 바꾸면 관이 옮겨져야 한다.

- 관 저장기에 이동 예약(queueMove)을 더했다. 세션 키 b06:culvertmove에 담고,
  [저장]·[확정]의 flush가 옵션 병합과 함께 pipe_points에 반영한다. 세부 배수유역
  재분할은 서버가 관 목록을 다시 받아 처리한다.
- 폼에서 측점을 옮기면 목록·폼 캐시가 즉시 새 자리를 따르고, 옵션은 옮기기 전
  자리로 예약한다(저장 시점 관 목록이 그 자리 기준).
- 이동 안내는 차단 문구에서 '저장 뒤 다시 계산' 알림으로 바꿨다.
2026-08-29 16:53:17 +09:00
eomsangdon 936def3755 fix(B06): 폼에서 바꾼 관 제원이 횡단도에 바로 반영되게 한다
원인: 좌측 폼의 실시간 반영이 세션 예약(culvertopt)과 목록 캐시까지만 갱신하고,
횡단 캐시(section.culvert 스펙)를 건드리지 않아 카드가 옛 값으로 남았다.

- 폼 옵션 키를 culvert 스펙 자리로 옮기는 applyPipeOptionsToCache 추가
  (관종·관경, 유입·유출 기슭막이 형태·높이·길이·전/후, 집수정 구간값, 구조).
- 연장이 덮는 범위의 카드만 다시 그린다 — 조정창 조작과 같은 흐름.
- 화면 캐시만 고친다. 영구저장은 [저장]·[확정] 그대로.
2026-08-29 16:45:52 +09:00
eomsangdon a485e22851 fix(B06): 측점만 골랐을 때 기슭막이 조정창이 뜨지 않게 한다
원인: 앞선 커밋에서 넣은 '대표 벽 자동 선택'(selectDefaultWall)이 카드를 고를
때마다 벽을 골라 조정창까지 띄웠다(2026-08-29 사용자 보고: 기슭막이(유출) 창이
계속 떠 있음).

- selectDefaultWall과 그에 딸린 자동 선택 표시(withAutoAdopt 등)를 걷어냈다.
- 카드·목록 선택 리스너에서 남아 있는 벽 선택을 비운다. 벽을 찍어 카드가 딸려
  선택된 경우는 건드리지 않는다(isWallSelecting 가드).

부작용: 단 수·옵션 행은 도면에서 벽을 고른 뒤에만 유입구·유출구에 붙는다
(사용자 확인: 측점 선택 시 자동 구조물 선택은 필요 없음).

검증: 목록 선택·카드 선택 시 조정창 0개·강조 없음, 벽 클릭 시 기슭막이(유출) 창
+ 유출구 강조 + 단 수·옵션 행 표시.
2026-08-29 16:28:11 +09:00
eomsangdonandClaude Fable 5 6e195afb69 feat(B07,B08): 워크플로 순서 교환 — 상세설계를 수량산출 앞으로
횡단설계(B06) 다음을 상세설계 → 수량산출 → 설계도서 순으로 재배열하고,
폴더 번호가 흐름과 일치하도록 이름을 맞바꾼다.

- B08_DesignDetail → B07_DesignDetail, B07_Quantity → B08_Quantity
  (파일 접두어·식별자·라우트·locale 키 전량 스왑)
- STAGE_KEYS 4=DESIGN_DETAIL, 5=QUANTITY 스왑 + 라우터 stage 리터럴 교체
- CAD 마운트 /b08-cad → /b07-cad (main.py·vite proxy·iframe URL),
  openwebcad Toolbar 라벨 B07로 수정 후 재빌드
- 유지: openwebcad postMessage 프로토콜 aislo:b08:*·패키지명(내부 식별자)
- 기존 프로젝트 storage 폴더 rename + project_manifest 갱신,
  DB project_workflow_stages stage_no 4↔5 행 스왑 완료

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 16:16:46 +09:00
eomsangdon 5d0d2f0918 feat(B05,B06): 구조물 배치를 실시간 반영으로 바꾸고 이식 행·강조를 정리한다
2026-08-29 사용자 지시 3건:
1. 유입구·유출구로 옮겨 온 단 수·옵션 행을 폼 양식(라벨+한 덩어리 컨트롤)으로
   맞추고 2열 격자로 세운다.
2. 이미 고른 항목은 값이 바뀔 때마다 곧바로 반영한다([수정] 버튼 불필요).
   버튼은 visibility만 꺼 자리를 남겨 삭제·리셋의 위치·크기가 흔들리지 않게 했다.
   정본 주입이 되먹임으로 돌아와도 편집 중인 폼은 닫지 않는다.
3. 도면에서 구조물을 고르면 그쪽 그룹(유입구/유출구)을 붉은 계열로 강조한다.
   카드만 고른 경우는 강조하지 않는다 — 대표 벽은 조용히 딸려 오고, 그 벽을
   다시 눌러 선택을 풀면 강조만 꺼지고 행은 남는다.

검증: 슬롯 grid 2열, 카드 선택 시 강조 없음·행 2개, 다른 벽 클릭 시 유입구 그룹
붉은 테두리(rgb(192,57,43)), 재클릭 시 강조 해제·행 복귀. 길이 + 즉시 캐시
반영(11) 후 - 원복(10), 폼 유지. typecheck 통과.
2026-08-29 16:00:04 +09:00
eomsangdon 889f746a61 fix(B06): 폼에서 관 옵션을 고칠 수 있게 하고 단 수·옵션 행을 되살린다
2026-08-29 사용자 보고 두 건:
① 값을 고치고 [수정]하면 '추가·이동·삭제는 B05에서' 안내만 떴다 — B06에서 관
   옵션 저장 경로가 없었다. 조정창 구간값과 같은 저장기(culvertOptions.queue)로
   보내 캐시에 예약하고 [저장]·[확정]이 정본에 쓴다. 기준점 이동만 배수유역
   재분할이 걸려 B05 몫으로 남기고, 안내 문구도 추가·삭제/이동으로 나눴다.
② 연동·경사 옵션과 단 수 행이 구조물 배치에서 사라졌다 — 그 행들은 고른 벽에
   딸린 것이라 도면에서 벽을 찍기 전에는 이식될 창 자체가 없었다. 시설을 폼에
   올릴 때 대표 벽(유출 기준벽, 없으면 유입)을 함께 골라 행이 서게 한다.

검증: 목록에서 배수관 선택 → 유출구 그룹에 [추가 기슭막이(단)]·[옵션] 표시.
길이 + 후 [수정] → '수정한 값은 [저장]·[확정] 때 반영됩니다' + 세션
b06:culvertopt에 inlet_revet_length_m 11 예약 확인. typecheck 통과.
2026-08-29 15:45:15 +09:00
eomsangdon 8e8849e4ac feat(B05,B06): 배관 조정 항목을 유입구·유출구 폼으로 모은다
2026-08-29 사용자 지시(좌측 패널 항목 정리 — 배관 자리):
- 길이·높이·기준측점 전/후 입력칸에 [-][+] 묶음 추가(stepper). 눈금은 조정창과
  같다(길이 1m·전후 0.5m·높이 0.1m). 래퍼 여백 0이라 2열 격자는 그대로다.
- 형태·구조물 형식 행은 [횡단 조정] 사본에서 숨김 — 폼의 형태·구조와 중복.
- 단 수·옵션 행은 고른 벽 쪽(유입구/유출구) 그룹으로 DOM 이식. 배선을 옮기지 않아
  값·동기는 그대로고, 사본이 갈릴 때마다 다시 이식한다.
- 유입구 '구조' 드롭다운에 조정창 형식(자동·집수정 I/ㄴ/ㄷ)을 병합. 고른 값이
  정본 둘(inlet_type·inlet_structure)을 함께 정하고, B06에서는 유입측 형식 제어와
  양방향으로 맞춘다. 형태·형식 연결은 미연결 상태 그대로 둔다.

검증(공용 브라우저): 유입구 스텝 5·유출구 4개, 구조 목록 6종 병합, 벽 선택 시
단 수·옵션이 유출구 그룹으로 이동(dock에는 높이·구간값만 남음). B05도 동일 폼이
정상 표시되고 [횡단 조정]은 뜨지 않음. typecheck 통과.
2026-08-29 15:30:55 +09:00
eomsangdon 56ecc08891 feat(B06): 횡단도를 고르면 그 측점 구조물을 좌측 폼에 올린다
- SectionView.setStationSelectListener 신설 — 카드(측점) 선택 변경 알림
- 좌측 패널 showAtChainage: 계곡 통과 시설(pipe_points) 우선, 없으면 그 측점을
  덮는 구조물 정본 항목(점형 근사·구간형 범위), 둘 다 없으면 선택 해제
- 연동 링크 카드는 structureSpan.ownerOf로 소유 측점 시설을 보여 준다

검증(공용 브라우저): 4+4.3 배수관·7+9.7 세월교·10+0.9 BOX암거 카드 클릭 시
종류·기준 측점·목록 강조 일치. 링크 카드 4+0.0→4+4.3, 14+0.0→13+15.7 소유
측점 표시. 구조물 없는 0+0.0 카드는 폼 해제. typecheck 통과.
2026-08-29 14:47:44 +09:00
eomsangdon 2d6d66a389 fix(B06): 구조물 배치를 좌측 최상단으로 올리고 상단 여백을 B05와 맞춘다
- 좌측 패널 순서: 구조물 배치 → 횡단 보기 설정 → 표준 횡단면 설정
  (2026-08-29 사용자 지시 — B05와 같은 첫 컨테이너)
- .b06-profile__form .ui-sidebar-scroll 상단 패딩 8px — B05
  .b05-route__panel .ui-sidebar-scroll과 같은 값으로 구분선과의 갭 일치

검증: 공용 브라우저 실측 — B06/B05 모두 첫 컨테이너 '구조물 배치',
scroll padding-top 8px, 상단 갭 8.0px 동일. typecheck 통과.
2026-08-29 14:27:34 +09:00
eomsangdon 2e28af6e86 feat(B05,B06): 구조물 배치 컨테이너를 B06에 장착하고 [횡단 조정] 사본을 세운다
B05/B06 인터페이스 일원화 1차 (2026-08-29 사용자 확정 계획):
- A00_Common/b_structures_section.ts: B05 구조물 배치 폼·목록 공용 진입점
  (재수출 + 스타일 동봉)
- B06 좌측 패널에 [구조물 배치] 섹션 + 하단 dock [목록][구분선][저장버튼]
  (B05 동일 템플릿). 구조물 조작은 세션 pending으로 쌓여 기존
  flushPendingStructures([임시저장]·[확정])로 정본 반영
- 선택 연동: 목록·폼 → 최근접 카드 focusStation, 횡단도 벽·세월교·BOX →
  좌측 폼에 소유 측점 시설 로드(wireStructureSelection)
- [횡단 조정] 하위 컨테이너(Adjust_Dock): 오버레이 조정창을 같은 deps로
  사본 인스턴스 생성해 세움 — 로직 이동 0, 카드 재렌더로 자동 동기.
  9키·십자 행은 사본에서 숨김(사용자 지시 7), 방향키 이중 입력 방지
- A군 시설 추가·이동·삭제는 B06에서 안내 토스트(배수유역 체인은 B05 몫)

검증: 공용 브라우저 — 구간값 길이 사본 + 10.0→11.0m 양측 동기,
오버레이 - 원복, ✕ 닫기 시 사본 해제. B05 회귀 없음. typecheck 통과.
2026-08-29 14:20:49 +09:00
eomsangdon cb8cf2c9d2 fix(B05,B06): 구조물 저장 실패가 횡단 저장까지 막던 것을 고친다
화면 실측에서 나왔다. 세션에 남은 미저장 구조물이 서버에 거절되자(등록되지 않은
타입 400) 예외가 B06 [저장] 전체를 중단시켜 sections/save가 아예 나가지 않았다.

flushPendingStructures를 .catch()로 감싸 토스트만 띄우고 횡단 저장은 계속한다.
미저장분은 세션에 그대로 남아 다음 [저장]에서 다시 시도된다.
2026-08-29 11:39:03 +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 1e55322f2f feat(B06): 다단 기슭막이 구간값을 단별로 손수 잡는다
다단은 소유 벽 연장에 종속이라 길이·전/후를 따로 못 잡았다. 계곡부·능선부에서는
아래 단일수록 연장이 달라져 자동 규칙으로 못 잡으므로 수동 입력으로 간다.
조정창 UI는 기준벽 것을 그대로 쓴다(길이·기준측점 전·후 세 행).

- Const: EXTRA_SPAN_DEFAULT(10m·5/5) + applySpanPatch()로 길이↔전/후 산식을
  기준벽과 공용화
- Station_Controls: StructureSpanControl에 tierValuesFor/updateTier 추가. 값은
  세션(b06:extraspan)에 담고 캐시(design.extra_spans)에도 얹는다. 단 수를 줄이면
  그 단의 구간값도 지운다
- View_Structure: 다단 키면 단별 제어기로, 기준벽은 종전 경로
- Wire: culvertReach에 단별 연장을 더하고, 링크 카드에서 각 단을 자기 구간값으로
  판정한다(tierSpanOf)
- Corridor_Structures: 3D 스윕 범위를 단별 구간값으로
- 저장: CrossSectionPatch.extra_spans(프론트 payload + WallSpanPatch 스키마 +
  확정 병합) — [저장]·[확정] 때 정본에 남는다

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 10:54:03 +09:00
eomsangdonandClaude Opus 5 a87182496e feat(B06·B05): BOX암거 조정창 · 구체 기울기 · 3D 벽 구간 정리
조정창에서 좌·우 끝을 따로 잡는다 — ◀▶는 구체 길이, ▲▼는 그 끝의 구체 표고를
0.1m씩 움직인다. 좌·우 표고가 달라지면 구체가 기울고, 날개벽 구간 바닥(에이프런)은
각 끝 표고에서 수평을 지킨다(2026-08-25 사용자).

- `computeBoxLayout`이 좌·우를 따로 푼다: 끝 표고·길이·성토선·에이프런
- 성토선은 그쪽 표고 기준으로 물매 1:1.2를 지키므로 표고를 내리면 구체가 길어진다
- 조정창 `_Cross_Box_Panel.ts` + 제어 `createBoxControls` + `design.box_adjust` 저장
  (세션 → 캐시 → 확정 payload, 세월교와 같은 체계)
- 3D: 구체 밖(날개벽 구간)에 서 있던 벽을 없앴다 — 천장 없는 통로가 생기던 자리는
  날개벽 몫이다. 이제 상판·구체 저판·측벽 2매·에이프런 2매 + 날개벽 4매로 나뉜다
- 카드 렌더러의 구체 배선(선택 토글·강조·조정창)을 `_Cross_View_Bodies.ts`로 분리,
  연동 플래그 세션은 `_Page_Link_Session.ts`로 분리(700줄 제한)

검증(10+0.9): 구체 5.34m·수평 → ◀ 1회 5.44m → ▼ 2회 표고 −0.2m·물매 1:28.4,
에이프런 두 장 모두 수평 유지, ↺ 원복. 3D 솔리드 10개(측벽 링 0.2m).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 15:03:53 +09:00
eomsangdonandClaude Opus 5 81bb505cc4 feat(B05·B06): 세월교 횡단 구체·조정창·3D 예상형상
B05 세월교 옵션에 BOX암거 날개벽 한 벌(설치·짧은쪽 높이 1m·길이 2m·각도 45°)을
그대로 붙이고, B06 횡단도에 세월교 구체를 그린다. 구체는 양측 ㄴ형 집수정 측벽 +
그 사이를 잇는 바닥판 + 바닥판 상면에 안힌 관 + 관 위 성토(노체) 채움이다.

- 바닥판 편측 연장 = 날개벽 길이 × cos(각도) — 각도는 관축 기준 벌어짐각
- 측벽은 buildBasin 재사용이라 1:0.3 기움·좌우·상하 대각 이동·계류측 성토부선이
  집수정과 같은 규칙으로 따라온다 (기슭막이 다단·재질과는 연계하지 않음)
- 구체는 월류 폭만큼 도로 방향으로 이어져 기준 측점 전후 절반까지 붙는다
- 조정창: 측벽 높이·좌우·상하, 관경·수량(정본 pipe_points 되쓰기).
  높이·좌우·상하는 세션 + design.ford_adjust에 저장
- 3D 예상형상: 구체 부재는 월류 폭 구간 스윕, 관은 련수만큼 폭 안 등간격
- 부재 두께: 바닥판 0.3m(교본 물넘이 물받이 최소 30cm), 측벽 0.2m(집수정 승계)

700줄 제한으로 카드 렌더러·측점 제어기·페이지에서 배선을 분리했다
(_Cross_View_Ford, _Page_Ford_Controls, _Page_Patches, Culvert_Const 구간값 헬퍼).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:05:42 +09:00
eomsangdonandClaude Opus 5 cd8d14f105 feat(B05·B06): 기슭막이 구간값 조정창 · 연동 기슭막이 옵션 · 가림 구간 선 정리
기슭막이 범위(길이·기준측점 전/후)를 B06 횡단도 조정창에서 지정하게 하고, 그
범위가 덮는 옆 측점의 기슭막이를 "연동" 파생물로 다루도록 체계를 세웠다.
값의 원천은 배수관 옵션(pipe_points) 하나다 — 같은 숫자를 B06 정본에 따로 담으면
B05 배수관 카드와 갈려 어느 쪽이 참인지 알 수 없다.

① 집수정 전/후 필드 신설 — inlet_basin_before_m·after_m(기본 각 1m), 길이 2m 유지.
   종방향 구간 계산을 revetSpanOfSpec·basinSpanOfSpec 한 곳으로 모아 2D 링크 판정과
   3D 스윕이 같은 값을 쓰게 했다.
② B06 조정창에 길이·전·후 행 — 기슭막이(유입·유출)·집수정 모두. 캐시를 고쳐 즉시
   보여주고 저장은 조작이 멎으면 한 번만 나간다(세부유역 재계산이 매번 돌지 않게).
   길이를 바꾸면 늘어난 몫만 지금 비율대로 나눠 담는다 — 총길이에서 비율로 다시
   계산하면 0.1m 반올림이 쌓여 5.0/5.0이 5.6/5.4로 어긋난다.
③ 링크 카드 선택 허용 — "소유 측점 통째 복사"에서 "위치 4축만 물려받고 원지반
   접합은 이 측점 지형으로 재계산"으로 바꿨다. 구조물 형식은 언제나 소유 측점 값이다.
   손대기 전에도 어긋나지 않게 소유 측점이 실제로 적용한 4축(revetShift)을 명시값으로
   물려준다.
④ 연동(측점별)·경사(전체 공통) 토글 — 연동 조작은 소유 측점 키에 실리고 그 연장이
   덮는 측점을 함께 다시 그린다. 경사는 3D 전용 스위치다(끄면 스윕 프레임 dz=0).
   횡단도까지 -dz로 밀면 노견에서 출발하는 성토선까지 내려가 노견과 벌어진다.
⑤ 가림 구간 선 정리 — 유입부 접속선과 유출부 접지 후 절토선을 2D·3D 모두에서
   빼되 기하는 남긴다. 면적·수량 계산은 건드리지 않았다(전면 개편 대상).
⑥ 집수정은 소유 측점 횡단도 하나에만 — 링크 카드에서 집수정·계류측 다단을 뺀다.
⑦ 3D 구간 겹침 정리 — 측점 간격이 구조물 연장보다 좁으면 두 구간 제어점이 번갈아
   서서 짧은 쪽(집수정 2m)이 잘려 보였다. 두 소유 측점의 중간에서 끊는다.
⑧ 조정창 정리 — 십자·9키를 맨 아래로, 창을 위쪽 기준 오버레이로(낮은 횡단도에서
   제목이 잘리던 문제), 연동·경사를 1행 토글 버튼으로, 스크롤 자리 유지.

파일 분리: B06_Section_UI_Cross_View_Structure.ts(조정창 배선),
B06_Section_Api_Culvert_Options.ts(구간값 저장) — 700줄 제한.
BUILD_VERSION 14 → 17(저장 코리도 만료).
tsc/ruff/prettier 통과, pytest 196 passed(기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-9.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:26:35 +09:00
eomsangdonandClaude Opus 5 83eb58a251 feat(B05·B06): 배수관 측점 정본화 · 코리도 단차 제거 · 인접 측점 기슭막이 링크
3D 예상형상은 종단·횡단 확정 뒤의 최종 산출물이고 3D 쪽 편집 경로는 없다
(2026-08-24 사용자 확정). 그런데 구조물(비정규) 측점은 횡단 정본 자체가 없어
조회할 때마다 프리뷰 기본값이 재계산됐고, 조정창 조작값은 세션에서 사라졌다.
정본 경로를 열고, 그 위에서 코리도 단차를 걷어냈다.

① 구조물 측점 정본화 — 확정·임시저장이 종단 정본 stations 중 DB 행이 없는
   측점을 대상에 넣어 upsert. cross_sections 19 → 23행.
② 조정창 조작값 정본화 — 기슭막이 4축(x·d·h·m)·다단 단 수를 design.revet_adjust
   / extra_wall_counts로 저장하고, 3D culvertLayoutOf가 그 값을 기하 입력으로 쓴다.
   카드 우선순위는 세션 → 정본 → 자동.
③ 노폭 연장의 노견 편입 — PIECE_COLS.shoulder 2→3으로 원 노견 끝 꺾임을 남기고,
   조기 return을 없애 확폭이 구조물 구간 내내 유지되게 했다.
④ 종단 기울기 반영 — 구조물 구간 복사 단면에 계획고 차이를 전량 얹는다.
   노견 표고 단차 0.49~0.61m 제거.
⑤ 접속 테이퍼 — 구간 경계를 제어점으로 세워 "복사 vs 보간" 두 규칙을 하나로
   통합. 노폭 3.0m·성토비탈 8.1m 단차 제거. 접속 길이 = 인접 측점까지.
   제어점 생성은 B05_Profile_UI_Corridor_Frames.ts로 분리(Build 699 → 635줄).
⑥ 인접 측점 링크 — 기슭막이 연장(기본 10m)이 덮는 옆 측점 횡단도에도 소유 측점
   단면을 계획고 차이만 얹어 그린다. 요소별 연장 판정(관·집수정 제외), 표시 전용.

BUILD_VERSION 11 → 14 (저장 코리도 만료).
tsc/ruff/prettier 통과, pytest 192 passed (기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 17:11:21 +09:00
eomsangdonandClaude Opus 5 eb41202bf4 fix(B06): 교차점 자동 줌아웃이 5m 사면 규칙에 잘리던 문제
자동 줌아웃 판정이 배수관용 slopeToeOffset(성토사면 5m에서 컷오프)을 써서, 사면이
5m를 넘는 측점은 필요 폭을 과소 산정했고 교차점이 화면 밖에 남았다(2026-08-23
사용자 보고).

- _UI_Cross_Fit 재작성: 설계선(design_line)과 지반선의 **실제 교차점**을 0.1m
  간격으로 훑어 찾는다(노면·노견·측구 구간은 건너뜀). 설계선이 만나기 전에 끝나면
  끝단 기울기 차로 외삽하고 1m 올림.
- 카드 자동 줌아웃(effectiveHalfWidth)이 이 값을 쓴다. 보유 샘플 밖으로는 넓히지
  않는다(지반이 없어 빈 화면이 될 뿐).
- [적용]은 전 측점 중 필요한 최대 폭까지 함께 넓힌다 — 20m를 넘으면 그 값으로
  재생성해 각 카드가 자동 줌아웃할 지반을 확보한다.

자체검증: node tmp/tests/test_toe_extrapolate.mjs (사면 18m 교차점을 5m 컷오프
없이 탐색, 설계선이 15m에서 끊겨도 외삽으로 같은 자리), tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:54:38 +09:00
eomsangdonandClaude Opus 5 dff1e3aff9 feat(B06): 횡단 보기 반폭을 별도 컨테이너로 분리 + 사이드 양식 B05 정렬
- 「횡단 보기 설정」 컨테이너 신설: 반폭 입력 + [적용] 버튼 한 줄. 표준 횡단면
  설정의 [전체 측점 반영]에 물려 있던 반폭 적용을 떼어냈다 — 보유 샘플(20m) 안이면
  전 측점 설계 재계산 없이 즉시 반영된다.
- 표준 횡단면 설정 컨테이너는 기본 접힘.
- 사이드 컨테이너 양식(여백·글자 크기·색)을 B05 .b05-route__panel-section 값으로
  맞춤. 접힘 토글·외곽선은 이미 공용(ui-collapsible / ui-sidebar-section)이었다.
  표준단면 「변수 위치 안내」 모식도 스타일은 현행 유지.
- 표준패널의 미사용 extraControl 인자 제거.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:47:36 +09:00
eomsangdonandClaude Opus 5 f2ad5508f5 feat(B06): 횡단 줌 조작 일원화 + 교차점 맞춤 자동 확대
- 카드 하단 ◀/▶/↺(개별 표시 반폭) 삭제. 조작구는 우측 상단 줌 버튼 하나로.
- 줌 버튼 역할 확장(원배율에서만 반폭 조작):
  − 배율>1이면 축소, 원배율이면 표시 반폭 +1m
  + 배율>1이면 확대, 원배율이면 표시 반폭 −1m(하한 2m)
  ⤢ 배율 원복 + 절·성토 교차점이 다 보이는 폭으로 맞춤
- 교차점 맞춤(_UI_Cross_Fit): 보유 샘플(계산 반폭 20m) 안에서 교차점을 찾고,
  샘플 끝까지 안 만나면 끝단 사면·지반 기울기 차로 만나는 자리를 추세 외삽해
  올림 +1m을 요청 반폭으로 쓴다(상한 60m).
- 요청 반폭 > 보유 샘플이면 그 폭으로 재생성(regenerate) 후 해당 측점만 세션
  반폭으로 넓게 표시. 계산 기본 20m·캐시는 그대로, 확정 시 기존 경로대로
  display_half_width_m에 영구 저장.
- 재생성 로직을 _UI_Page_Common.createSampleWidener로 분리(700줄 제한),
  [전체 측점 반영]도 같은 경로 사용. 연타 중복 요청 차단.

자체검증: node tmp/tests/test_toe_extrapolate.mjs (외삽 좌/우·발산 지형·+1m 올림),
tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:16:31 +09:00
eomsangdonandClaude Fable 5 76df1e9335 fix(B05): 종단 계획고 변경을 횡단 설계에 자동 반영 - B05 진입 시에도 재계산
2026-08-23 사용자 보고: 종단 그래프의 계획고 변화가 B06 횡단도에 반영 안 됨.

원인: 횡단 설계는 계산 당시 계획고(design.design_elevation_m) 기준으로 설계선
좌표를 굳혀 둔다. 계획선이 뒤에 바뀌면(사용자 편집·확정, 배수 최소고 같은
백엔드 규칙 도입) 설계선은 옛 자리에 남는데, 화면의 계획고 십자선과 3D
예상형상은 최신 계획선을 쓴다 - 두 기준이 어긋난다. 실측으로 한 노선에서
최대 2.21m 어긋남 확인. 지금까지 이 보정은 B06 진입 때만 돌아서, B05의 횡단
기준 유토곡선과 3D는 옛 설계선을 계속 썼다.

- staleDesignChainages() 신설(B06_Section_UI_Section_Common) - 계획선 보간값과
  계산 기준의 차이로 재계산 대상을 판정하는 B05·B06 공용 규칙.
- B05 Profile_Panel: 진입 렌더에서 어긋남이 있으면 프리뷰 1회로 맞춘다.
- B06 Page: 같은 공용 규칙을 쓰도록 통일(옛 암 2단계 필드 누락 조건은 유지).

검증: tsc 통과 · pytest 191 passed(신규 stale 판정 6건) · 공용 브라우저 실측 -
계획고·지반고 배치 대조(전 측점 일치, 렌더 역산 RMS 0.004~0.03m), 측점 중심
좌표가 노선 폴리라인과 거리 0, 인위 stale 1건을 B05 진입으로 자동 복구(stale
1 to 0, 계획고 540.895 복원).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 17:40:48 +09:00
eomsangdonandClaude Opus 5 2a247184fd feat(B06): 집수정 좌우·상하 이동 및 내공 조정 + 설계선 스냅 급경사 제거
- 집수정 조정값(BasinAdjust: 내공 폭·높이, 좌우 lateralM, 상하 slopeM) 신설.
  측점별 세션 보관 + 백엔드 design.basin_adjust 저장 경로(Schema·Router) 연동
- 조정창에 집수정 조정 항목 추가, I형 관 시작점을 벽 안쪽 변과 원지반의
  교차점으로 산출(이분법), 집수정 성토(되메움)선 5° → 성토 비탈 1:1.2로 통일
- 설계선 트림 수정: 배수관 레이아웃이 사면 폴리라인을 준 쪽은 그 시작점(노견)에서
  설계선을 끊는다 — 종전에는 트림 경계에서 끝점 표고를 벽 상단으로 강제 스냅해
  집수정을 좌우로 옮기면 마지막 구간이 수직으로 튀는 선이 남았다(사용자 지적)
- basinApproachPoints의 길이 0 중복 꼭짓점 제거

검증: 4+4.3(집수정 I형 좌우 2.9m 이동)·13+15.7·5+0.0·2+0.0에서 급경사
세그먼트 0건 · tsc --noEmit 통과 · ruff check 통과 · prettier 적용 ·
pytest tmp/tests/ 148 passed, 7 skipped · B06_Section 700줄 초과 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 17:50:45 +09:00
eomsangdonandClaude Opus 5 e54da341ea refactor(B06): 700줄 초과 파일 분리 — Router·Cross_View·Section_View·Style
- B06_Section_Router.py(824) → Router_Design.py(139) 분리
- Cross_View → Cross_View_Metrics.ts(75) 분리
- Cross_Design → Cross_Design_Surface.ts(54) 분리
- Section_View → Section_View_Panel.ts(53) 분리
- Page → Page_Common.ts(15) 분리
- Style_Cross.css → Style_Cross_Controls.css(174) 분리
- B06_Section/ 전체 700줄 초과 0건

검증: tsc --noEmit 통과 · ruff check 통과(import 정렬·포맷 적용) ·
prettier 적용 · pytest tmp/tests/ 148 passed, 7 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 17:04:08 +09:00
eomsangdonandClaude Opus 5 9a58e3b1bd feat(B06): 유출부 보호공 삭제·성토부선 전환 + 추가 기슭막이(계단식)
- 보호공(돌붙임) 띠 삭제, 윗면 선만 성토부선(계획선)으로 유지 — 구간별
  사면길이·5m 초과 여부 툴팁 표기
- 성토부 5m 이상이면 조정창 +로 추가 기슭막이(배관 없는 동일 형상 벽)
  계단식 추가 — 자동 자리는 배관용과 같은 규칙(1:1.2 최소 자리)
- 추가 벽도 ◀/▶/↺ 이동(안쪽 한계 = 앞 구조물), 마지막 벽 - 삭제
- 개수·이동량 세션 보관(b06:extrawall / revetx extra{n} 키)
- 700줄 제한: Extra(성토부선·추가 벽)·Wire(카드 배선) 분리 신설

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 13:24:47 +09:00
eomsangdonandClaude Opus 5 1774d61101 feat(B06): 집수정 관 끝선·두께 0.2·구조물 형식 드롭다운
2026-08-22 사용자 요청 3건:
- 관 끝선 = I형 벽의 안쪽(물받는 쪽) 변 복사(기슭막이와 동일 방식).
  관 시작점(하단): ㄴ·ㄷ형은 측벽 안쪽 변×바닥 윗면 교차점, I형은
  내공 1.0m 유지.
- 집수정 부재(벽·바닥판) 두께 0.2m(BASIN_MEMBER_THICKNESS_M).
- 유입 구조물 형식 드롭다운: 자동(규칙)/기슭막이+배관/집수정 I·ㄴ·ㄷ형.
  집수정 클릭 선택 가능, 선택 시 조정창에 드롭다운(집수정은 ◀▶ 숨김).
  세션 보관(inletstruct)·revet 선택 시 양측성토 로직 복귀·manual 사유.
- 집수정 구성을 _Cross_Culvert_Basin.ts로 분리(700줄 제한 — Geom 690줄).
  I형 바닥판 제거(벽뿐 — 정의 정합).
- 검증: 13+15.7 모듈(auto/revet/I/L/U 전부 기대 형상·관유입 자리 일치)
  + UI 실조작(집수정 클릭→드롭다운 revet/U/auto 전환, 부재 수 2→0→3→2,
  세션 왕복) + 스크린샷 대조.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 11:04:40 +09:00
eomsangdonandClaude Opus 5 6a3c991b5a feat(B06): 기슭막이 선택·X 자리 조절 화살표
- 기슭막이 폴리곤을 눌러 고르면 강조되고 카드 하단에 ◀/▶/↺가 뜬다. 0.1m씩
  화면 좌우로 민다(좌우 벽에서 뜻이 뒤집히지 않게 outward 부호는 내부 환산).
- 구조물 선택이 절·성토 면적 강조보다 우선한다. 벽 클릭은 벽에서 멈춰 밴드·카드
  선택으로 번지지 않고, 한쪽을 고르면 다른 쪽 강조는 꺼진다.
- computeCulvertLayout에 revetShift 인자 추가. 손으로 민 자리는 고정되어 관 길이
  정수 맞춤이 벽을 다시 옮기지 않고 폭으로만 흡수한다(폭 상한 0.45×2).
- 값은 세션 보관(b06:revetx), 이동 범위 ±3m.
- 700줄 정리: Page 751→690(_UI_Page_Station_Controls 분리),
  Cross_View 765→629(_UI_Cross_View_Zoom 분리).

검증: 이동 5케이스 접점 오차 0.00e+00, 계획고 스윕 24케이스 회귀 문제 0,
tsc 통과, pytest 148 pass. 화면 조작 확인은 다음 단계.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 16:14:17 +09:00
eomsangdonandClaude Fable 5 a6197cdc46 fix(B06): 횡단 반폭 표시 기본값 12가 20으로 되돌아오던 문제
원인: 진입 로직이 data.options.cross_half_width_m을 '사용자가 확정한 표시 반폭'으로
보고 입력칸을 덮었다. 그 값은 종·횡단을 만들 때 쓴 **샘플링(계산) 반폭**이고
백엔드 기본이 20m라, 표시 기본값 12를 넣어도 진입할 때마다 20으로 돌아왔다.

수정: 계산 범위(백엔드 20m)는 그대로 두고, 입력칸은 사용자가 실제로 고른 표시
폭만 되살린다 — 측점 개별 표시 반폭 저장값(design.display_half_width_m)의 최대값,
그다음 세션에 남은 마지막 조절값 순. 둘 다 없으면 표시 기본 12m.

검증: tsc, pytest 125 통과, 헤드 브라우저 B06 탭에서 반폭 12·횡단면도 X축 12~-12 확인.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 19:52:20 +09:00
eomsangdonandClaude Fable 5 0b1a66b8d1 feat(B05/B06): 입력 흐름·알약 번호·초기화 모달·전후 분할·표시 반폭 정비
- 위치 마지막 칸 Tab → 상세 옵션 첫 칸(잠금 해제보다 탭 계산이 빨라 메모로
  건너뛰던 문제). 화면 순서(위→아래) 그대로 이동.
- [초기선 복원] → "저장선 복원"으로 문구 교정 — 복원 목표는 마지막 저장선이다
  (임시저장 시 편집이 정본에 반영). 최초 자동 계산 복귀는 [초기화] 안내.
- 종단 알약에 좌측 목록과 같은 중복 번호("옹벽 1/2") — 라벨·툴팁·벌룬 동일 표기.
- [초기화] 무동작 수정: 원인은 playwright 연결 브라우저의 네이티브 confirm 자동
  취소. 공용 showConfirmDialog 모달(ui_template_elements) 신설로 교체.
- C군 옵션: 전길이 → "기준측점 전" + "기준측점 후" 신설(기본 10/5/5). 나중에
  입력한 쪽이 살아남고 반대쪽 = 길이 − 그 값. 저장은 before_m 기준(후는 파생).
- B06 횡단 반폭 표시 기본 20 → 12 (계산·보유 샘플 폭은 백엔드 20m 유지 — 표시
  범위만 좁힘, 저장·세션값 있으면 그 값 우선).
- 측점 범위 표기 폰트 = 기준 측점 입력 칸과 동일(13.33px), 볼드 유지.
- 검증: pytest 112 통과, tsc, 헤드 브라우저 — Tab 포커스 '높이', 전7→후3·후2→전8
  연동, 범위 2+12.0~3+2.0, 알약 '옹벽 1/2', 초기화 모달 표시, 저장 왕복·원복.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 18:56:06 +09:00
eomsangdonandClaude Opus 5 431791c257 feat(B03,B05,B06): 초기 계산 끝까지 업로드 잠금 + 자료 없으면 대시보드로 (결함 3·6 화면측)
업로드 잠금(결함 3)
- 종전에는 전처리(B04)만 끝나면 버튼이 풀려, 노선·횡단이 도는 동안 자료를 또 올릴 수
  있었다. isInitialPipelineRunning()/pollInitialPipeline()을 두어 **횡단 단계가 열릴
  때까지**(3단계가 NOT_STARTED를 벗어날 때까지) 잠근다.
- relockWhileInitialPipelineRuns(): 새로고침·재진입해도 계산이 도는 중이면 다시 잠그고
  스피너를 붙인다. 잠금이 화면 상태로만 있으면 새로고침 한 번에 풀렸다.
- 보관함 연결 경로도 같은 대기 흐름을 탄다.

자료 없으면 대시보드(결함 6)
- b_missing_data_guard 신설 — 근거 자료가 없으면 한 줄 안내 후 B01로 보낸다. 새 자료가
  올라오면 서버가 옛 산출물을 지우므로, 열어 둔 뒷단계 화면은 빈 화면이 아니라
  대시보드로 나가야 한다(2026-08-08 사용자 지시).
- B05: 확정 지표면이 없으면 이동. B06: 노선 또는 종단면이 없으면 이동.

검증: 자료가 없는 신규 프로젝트로 B05 진입 → 안내 후 #/b01-account 로 이동함을
헤드리스 크롬으로 확인. typecheck·prettier 통과, 정적 번들 재빌드.

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