- 교각점 고정 단추: 켜면 그 꺾임점이 노드·손잡이 어느 쪽으로도 안 끌림(`apexLock`)
- 계획 횡단선을 절·성토 교차점에서 끊음 — 그 밖은 원지반이라 지반선과 겹쳐 그려지던 것.
교차점은 B06 이 쓰는 `toeOffsets` 를 열어 함께 씀
- 횡단 판을 캔버스에서 SVG 로 바꾸고 휠 줌·가운데 끌기 팬·더블클릭 원복을 붙임
- 줌·팬 본문을 `A00_Common/b_svg_zoom_pan.ts` 공용 조각으로 빼고 B06 은 감싸개만 남김
- 「이전 횡단」 판은 계획 평면선이 바뀔 때만 채움(같은 측점 두 번 누르기로는 안 채움)
- 「거리 재기」 단추의 눌린 꼴 추가 · 등고선 높이 라벨을 맨 위로 올리고 더 촘촘히
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
B05 는 관 목록 전체를 세션 스냅샷으로, B06 은 바뀐 것만 따로 담고 있어 담는 꼴이 둘이었음.
저장 순서를 맞춰 결과는 같게 했으나 자리가 둘인 한 같은 사고가 다시 남.
B06 의 추가·삭제·이동을 모두 B05 가 쓰는 스냅샷(pipes)에 쓰도록 바꾸고, B06 전용 예약
경로(culvertedit 세션·queueAdd·queueRemove·queueMove)를 걷어 냄. 옛 세션에 남아 있던
이동 예약만 저장 때 한 번 흘려보내게 읽기를 남김.
이제 관을 넣고 빼고 옮기는 길이 좌측 폼·목록·종단 우클릭·측점선 끌기 모두 한 함수이고,
담기는 자리도 한 곳임.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
B05 와 B06 은 한 페이지인데 구조물을 넣고 빼는 자리가 B05 뿐이라 화면을 오가야 했음.
종단 그래프 렌더러·알약 레인·좌측 배치 폼은 이미 공용이었으므로, 빠져 있던 조작층만
B05 와 같은 부품(mountStructureMenu)으로 B06 에도 붙임.
관 추가·삭제는 이동과 같은 예약 경로를 씀 — 세션에 쌓고 [저장]·[확정]에서 정본
(pipe_points.json)으로 나가며, 세부 배수유역 재분할은 그때 서버가 처리함. 넣었다 바로
빼거나 뺐다 다시 넣으면 예약만 걷어 내 정본이 흔들리지 않음.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
사용자 지시(2026-09-07): 「대신 경고부분은 삭제해주고 대신 각도를 사용자가 넣을수 있게 반영.
전체 공통으로 변경하는 경우에는 기본값 지정으로 하면 되지만 횡단도 하나만 변경하는 폼은
가져야함 / 개별 횡단도에는 암 절토 각도의 개별 수정 가능해야함」
**화면** — 암 측점 카드 아래에 「암 절토 68.2° ↺」 칸이 섬. 값을 넣으면 그 측점만 사면이
새 경사로 다시 그려지고 절토량도 따라 바뀜. ↺ 는 표준값으로 되돌림. 전체를 바꾸는 자리는
종전대로 좌측 [표준 횡단면 설정]임.
**계산에 넣는 자리는 한 곳씩** — 파이썬 `compute_cross_design(cut_slope_ratio=…)` ·
TS `computeCrossDesign({cutSlopeRatio})` 의 **그룹을 만든 바로 뒤**에서 경사비만 갈아 끼움.
부르는 쪽 9곳에서 표준값을 측점마다 복제하는 방식은 안 씀(한 곳만 빠져도 값이 조용히
사라지는 실패군). 기하·소단 코드는 한 줄도 안 건드림 — 25 확인대로 소단이 그 값을 읽어
서므로 **위치·개수가 새 경사를 저절로 따라옴**.
⚠ **경사는 나르는 값이 아니라 기하 입력임** — 계산 뒤에 키만 베껴 붙이면 설계선은 옛 경사로
그려지고 숫자만 새것이 됨(소단에서 겪은 자리). 그래서 재계산 세 경로(포장 강제·세월교 하강·
선형 재계산)와 브라우저 재계산·서버 프리뷰 **모두 계산 인자로** 넘김.
**되돌리기는 0 을 남김** — 세션에서 지우기만 하면 정본에 남은 옛 사용자 값이 되살아나
표준으로 못 돌아감. 0 = 「표준값을 씀」.
값의 길 — 세션 `cutslope`(등록표 한 줄) → 카드 입력 → [저장]·[확정]에서 `cross_patches`
(`design.cut_slope_ratio_user`) → 정본. `USER_TOUCHED_KEYS` 양쪽에 넣어 **표준을 바꿔도
개별로 고친 측점은 그대로** 둠(사용자 원문 끝줄).
시험 — 새 7건(넣은 경사가 실제로 그려짐 · 무릎 위 토사 경사는 그대로 · 0 은 되돌림 ·
재계산에도 남음 · **계산 전에 넘어감** · 각도↔경사비 · 칸은 암 측점에만),
거울 시험에 「암 절토 경사를 측점에서 바꿈」 한 갈래 추가, 7-3 회귀 한 줄 추가.
전체 **483 passed · 17 skipped**.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계단이 값에만 있던 것을 화면까지 연결함.
배선 — 세션 열쇠 `berm`(측점키 → 폭·간격·기울기)을 등록표에 두고,
`readBermSession` 으로 읽어 ① 브라우저 재계산(`refreshCrossDesigns`)과
② 서버 미리보기(`cross-design/preview` 의 `berms`) 양쪽에 실음.
암 경계선 오프셋과 같은 길이라 「계획선을 고치면 계단이 사라지는」 일이 없음.
실화면 확인(8001·5174, `/api/health` `stale:false`) — 측점 4120.0m 에 소단을 놓고
계획고를 한 칸 올렸다 내려 전 구간 재계산을 태움.
· 폭 0.5m · 간격 3.0m → 절토 6.84 → 8.10㎡ (토사 2.42→3.24 · 암 4.42→4.86)
· 폭 1.0m · 간격 2.0m → 절토 6.84 → 12.96㎡, 횡단도에 **계단이 눈으로 보임**
· 소단을 안 놓은 옆 측점(4100.0m)은 3.77㎡ 그대로 — 놓은 곳만 달라짐
· 되돌린 뒤 6.84㎡ 로 복귀. [저장]·[확정] 안 눌렀으므로 정본은 그대로.
`cut_slope_segments` 신설 — 절토 사면을 경사 구간별로 쪼갠 목록(파이썬·TS 짝).
법정 경사 검사가 읽을 값임(다른 창 요청). 소단이 서면 사면 전체를 하나로 재는
「실효 경사」가 완만해져 **위반이 사라진 것처럼** 보이므로(폭 1.0·간격 2 이면 설계 1:1 이
실효 1:1.71), 검사는 소단을 뺀 구간 자체를 봐야 함. 실측 — 소단을 놓아도 구간별 경사비는
1.0 그대로 나옴. 평탄부(소단)와 지반 만난 뒤 구간은 싣지 않음.
자체검증 — 거울 시험에 사면 구간 대조를 더해 파이썬·TS 일치 확인.
전체 539 passed · 18 skipped. TS 타입 검사 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 승인(2026-09-07). 앞서 취향을 localStorage 로 옮겨 **탭·재시작** 문제는 풀었고,
이 변경은 그 위에 **다른 PC 에서도 같은 배치**를 얹음. 사용자가 노트북·데스크톱 두 대를 오감.
- `db_management/018_user_ui_prefs.sql` — 사용자당 한 줄, `prefs` JSON 한 칸.
칸을 나누면 취향이 늘 때마다 마이그레이션이 또 필요해 한 칸에 담음.
- `GET/PUT /api/dashboard/me/ui-prefs` — 배치 값만. **설계값은 안 담음**(문자열만 받음).
- 로그인이 확인된 첫 순간에 한 번 받아 로컬 위에 얹고, 취향이 바뀌면 1.5초 모아 올림.
서버가 없거나 못 읽으면 **로컬 값으로 그대로 돔**(계획서 원문).
⚠ 같은 함정을 또 밟을 뻔했음 — 키만 아는 자리가 저장소를 직접 고르면 **올려보내기도 안 걸림**.
그래서 `storageOf` 를 없애고 **읽기·쓰기 창구 하나**(`readByKey`/`writeByKey`)로 모음.
저장소 선택과 서버 올려보내기가 그 한 곳에만 있음. 그물도 그 이름으로 갱신.
**DB 는 아직 적용하지 않았음** — 표가 없으면 API 가 실패하고 화면은 로컬 값으로 도는 것이
정상 동작임. 적용 시점은 다른 창들과 맞춘 뒤.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 취향까지 sessionStorage 에 있어 **탭을 새로 열거나 브라우저를 껐다 켜면** 패널 높이·
접힘·유토곡선 열림이 매번 초기화됐음. 계획서에는 「PC 를 바꾸면」으로 적혀 있었으나 실제
불편은 훨씬 잦았음(사용자 승인 뒤 조사에서 드러남).
- 저장소를 통(bucket)으로 가름 — **`pref` 만 localStorage**, 초안·결과는 세션 그대로.
설계 데이터가 아니므로 CLAUDE.md 5장 「캐시=세션」에 걸리지 않음.
- 키만 들고 저장소를 직접 만지던 화면 공용 부품 셋(`ui_template_resizer`·`_overlay`·
`_overlay_drag`)이 같은 판단(`storageOf`)을 쓰게 함 — 안 그러면 높이 값만 세션에 남아
절반만 옮겨졌음(실측: 접힘 4개는 옮겨지고 높이 3개는 안 옮겨짐).
- 첫 로드 때 세션에 남은 옛 취향을 한 번 쓸어 옮김 — 이 변경으로 쓰던 크기가 초기화되지 않게.
실측(공용 브라우저) — 옮긴 뒤 취향 8개 전부 localStorage, 세션 0개, 높이 보존
(종단 438px · 표 204px). **새 탭에서도 8개 그대로**(같은 값). 검증 탭은 닫음.
시험 `tmp/tests/test_prefs_persist_across_tabs.py` 4건 — 취향만 갈리는지 · 초안·결과는
세션인지 · 공용 부품이 같은 판단을 쓰는지 · 옛 값을 한 번 옮기는지.
이 조각은 DB 없이 되는 몫임. 계정 저장(`018_user_ui_prefs`)은 다음 단계.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
노선을 다시 계산하면 세션의 옛 노선치가 그대로 쌓였음. 용화(5601e828)에 145·161·169
세 노선치가 남아 있는 것을 실측함.
원인은 「안 지웠다」가 아니라 **못 지웠다** — 노선 변경 자리는 새 번호를 아직 모르니
`clearDrafts(projectId)` 로 부르는데, `stateKey` 가 노선 번호 없이는 `null` 을 내어
route 범위 키가 한 개도 안 나갔음. 부르는 쪽 주석은 「남기지 않는다」였고 실제로는 다 남았음.
`clearState` 한 곳에서, 노선 범위인데 노선 번호가 없으면
`aislo:<통>:<이름>:<프로젝트>:` 로 시작하는 키를 모두 쓸어 내게 함.
`clearDrafts` 와 `clearResults` 가 함께 나음. 노선 번호를 주면 종전대로 그 한 벌만 나감.
안전 확인 — 옛 노선치를 읽는 자리 없음(`readState` 호출 8곳 전부 전역·프로젝트 범위).
노선 복원도 새 route id 를 발급하므로 옛 키는 다시 안 불림.
자체검증 — `tmp/tests/test_page_state_route_sweep.py` 3건 신설.
옛 코드로 같은 시험을 돌리면 세 벌이 그대로 남아 깨지는 것까지 확인(헛도는 시험 아님).
전체 511 passed · 18 skipped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`std-cross` 가 [저장] 뒤에도 안 비는 것이 실수인지 의도인지 갈렸음 — **의도로 확정.**
다른 초안과 달리 이 값은 브라우저가 가진 **유일한** 사용자 표준단면임:
`sections/context` 가 주는 `standard_cross_section` 은 저장분이 아니라 config 기본값이고
(`B06_Section_Router.py:132`), 저장분은 서버 안에서만 쓰임
(`stored_standard_cross_section`). 비우면 브라우저 횡단 계산이 그 순간 config 기본값으로
되돌아감. [초기화]에서만 버림.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
손 안 댄 프로젝트를 열면 저장본 열쇠가 맞아 매번 16.9MB 를 받았고, 브라우저 보관이
모듈 Map 이라 새로고침 한 번에 날아가 또 받았음(보조 창 실측: 첫 로그인~B05 도달 29MB
중 16.9MB 가 이것). 해시 질의(0b30f5b0)는 낡았을 때만 막았지 맞을 때는 그대로였음.
- b_asset_cache 에 readCachedBytes / writeCachedBytes / purgeAssetsWithPrefix 추가.
앞 둘은 네트워크를 안 타는 순수 보관함 접근이고, 마지막은 주소 앞머리가 같은 옛
보관본을 지움 — 코리도는 주소에 열쇠가 박혀 정본이 바뀌면 새 주소가 되므로 17MB 짜리가
쌓이지 않게 담기 전에 치움.
- 코리도 조회가 보관함을 먼저 봄. 주소에 열쇠가 있어 정본이 바뀌면 저절로 다른 주소가
되므로 옛 보관본을 잘못 쓸 일이 없음.
자체검증(공용 브라우저) — 담기·읽기 왕복 정상(44바이트 왕복, 해시 보존), 열쇠만 다른 두 벌을
담은 뒤 앞머리 지우기로 둘 다 제거 확인. typecheck 통과.
※ 실제 16.9MB 절감은 저장본이 최신인 프로젝트에서 확인해야 함 — 이 프로젝트는 검증 중
계획고를 만져 저장본이 낡은 상태라 코리도 자체가 안 실림(__corridorSource null).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
관 추가·이동·삭제가 B05 패널 메모리에만 있어, B06 으로 넘어가 [저장]·[확정]하면 그
편집이 사라졌음(대응표 조사에서 드러남).
- 등록표에 `pipes` 초안(프로젝트 범위)을 되살림
- 배치가 바뀌는 순간 목록을 초안에 담고, 내보내기는 `flushPendingPipes` 한 창구로 모음
- B05 [임시저장]·B06 [저장]·[확정] 모두 이 창구를 지남 (자동저장 없음)
검증: 초안으로 관 11 → 10개 저장·초안 비움, 되돌려 11개 복구. 테스트 390 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 프로젝트명 조합기를 글자 단위 소유 추적으로 다시 만듦(`B02_ProjRegister_UI_Name.ts`) —
자동 글자 사이에 글을 끼워 넣어도 사업연도·사업지역·임도종류 연동이 끊기지 않음
(실측: 「울진군 금강송면」의 「금강송면」 앞 삽입 후에도 지역·종류·연도 변경이 반영)
- 비고 칸을 맨 마지막으로 이동
- 제목·여백·버튼 줄을 공용 템플릿(`createGeneralLayout` · `ui-general-block__actions`)으로 전환,
화면 전용 제목 스타일 제거
- 헤더의 사용자명·로그아웃(로그인·회원가입) 버튼이 붙어 보이던 것 간격 부여
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실측(B05 진입): auth/session 4회, workflow-state 2회, 구조물 이관 POST 가 진입할
때마다 나갔다.
- auth/session: 라우터 가드·상단 바·워크플로 확인이 각각 부르던 것을 5초 캐시로
묶음. 로그인·로그아웃에서 즉시 버린다.
- workflow-state: 공용 창구 하나로 모으고 같은 방식으로 캐시. 상단 오버레이가
따로 부르던 경로를 그 창구로 돌림. 단계 이동에서 캐시를 버린다.
- 구 구조물 측점 이관 POST: 탭 수명 동안 노선마다 한 번만.
실측 결과: B05 첫 진입 20 → 18건(핵심 API 10건), B06→B05 이동 7건.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(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>
- 확정 지표면: 목록(surface/models)으로 id 를 찾고 3D 단계에서 surface/confirmed
를 또 부르던 것을 확정 응답 한 번으로 합침. 모델 id·범위가 그 응답에 다 있다.
- 종횡단 설정값(sections/context): ④ 계산 결과로 보고 세션에 담음. B05·B06 을
오갈 때마다 다시 묻지 않는다. 노선 캐시를 버리는 자리에서 함께 버린다.
검증: tsc --noEmit 통과, pytest 389 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>
@
캐시·세션 일원화에서 조정창 값 8종을 옮기며 다단 구간값(`extraspan`)을 등록표에
빠뜨렸다. 표에 없는 이름을 꺼내다 예외가 나 페이지 렌더가 통째로 실패했고 화면에는
「준비 중인 페이지입니다」만 떴다(화면 확인으로 발견).
- `extraspan` 을 등록표에 넣음.
- 표에 없는 이름은 이제 **예외 대신 저장 건너뛰기** — 그 값만 안 남고 화면은 선다.
콘솔에 한 번 알려 표에 줄을 넣게 한다.
- B06 이 키를 만들 때 쓰던 형변환을 없앰 — 앞으로 등록표에 없는 이름은 컴파일에서
걸린다. 같은 사고가 화면까지 가지 않는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
캐시·세션 일원화 2단계 (2026-09-06 사용자 지시).
- ② 설계 초안 이관 — 구조물 미저장분, 상단측 변경분, 페이지 간 넘김값(구조물 선택),
표준횡단 편집값, 조정창 4축·단수·연동값 8종, 암 경계선, 표시 반폭. 넘김값은 별도
임시 키를 없애고 초안 한 자리로 흡수.
- ④ 계산 결과 이관 — 최신 노선 응답, 서버가 준 규격 횡단·암 경계 기본값. 횡단 상세는
메모리 캐시에 더해 세션에도 한 벌 얹어 새로고침 뒤 첫 화면이 서버를 안 기다림
(용량을 넘으면 조용히 건너뛰고 예전대로 다시 받음).
- B05 진입의 강제 새로읽기를 걷어냄 — 캐시로 먼저 그리고 노선번호·지표면 서명으로
뒤에서 신선도만 확인, 달라졌을 때만 다시 그림.
- [초기화]의 초안 비우기를 `clearDrafts` 한 곳으로 모음(예전에는 파일마다 따로).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 지시(캐시·세션 일원화 1단계). 세션 접근이 19개 파일 64곳에
흩어져 있고 키 이름이 네 갈래라 같은 설계값인데 두 화면이 서로의 값을 못 보는
자리가 있었다.
- `A00_Common/b_page_state.ts` 신설 — 값마다 통(① 취향 · ② 초안 · ④ 계산 결과)과
범위(전역·프로젝트·노선)를 한 줄로 적는 등록표. 키 형식은
`aislo:{통}:{이름}:{프로젝트}[:{노선}]` 하나이고 **페이지 이름을 키에 넣지 않는다**.
- 옛 키는 처음 읽을 때 새 키로 한 번 옮기고 지운다(사용자가 쓰던 배치 유지).
- 초안 비우기(`clearDrafts`)·결과 버리기(`clearResults`)를 그 한 곳에 둠.
- 이번 커밋은 ① 취향값 11개를 이관 — 패널 접힘·높이, 유토곡선 펼침·높이·범례,
테이블 펼침·높이, 배수유역 접힘·폭, B06 패널 접힘·높이.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 워크플로 상태 응답에 project_name 추가. 좌측 제목 패널 같은 행 오른쪽 끝에
프로젝트 이름 표기(길면 말줄임, 전체는 툴팁). 이름표를 오버레이 쪽에 두어
레이아웃을 직접 조립하는 B03 까지 여섯 화면이 한 곳으로 반영됨.
- fetchProjectWorkflowState 가 {status, workflow_state} 껍데기를 벗기도록 수정.
- 계획노선을 「업로드한 CSV」로 적은 주석을 「계획노선(정본)」으로 정리.
업로드 판정이 .csv 개수만 세어 shapefile 을 막던 것도 .shp 포함으로 맞춤.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05_Profile_UI_Style.css 1379줄 -> 592줄. 규칙을 값·순서 그대로 옮겨 두 조각으로 나눔.
- B05_Profile_UI_Style_Table.css (515줄) — 도면 테이블·값 열 오버레이·우클릭 메뉴·
계획고 편집 버튼·줌 조작구
- B05_Profile_UI_Style_Drainage.css (289줄) — 배수유역도 패널
진입 TS 두 곳(B05_Profile_UI_Page.ts, A00_Common/b_structures_section.ts)에서
본체 다음에 순서대로 불러 캐스케이드 순서 유지.
검증: tsc --noEmit 통과, prettier 서식 유지, 공용 브라우저(5174)에서 계산 스타일 확인
(표 이름표 sticky 78px, 구배 블록 absolute, 편집 버튼 21x17, 줌 22x22, 배수유역 flex).
종단 패널 캡처가 분리 전과 **바이트 단위로 동일**(md5 ee6bc8b52adb).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
다른 브랜치(feat/B05B06-구조물패널-일원화)의 B05·B06 구조물 배치 폼 일원화
결과를 받는다. 충돌 없음 — 그쪽은 B05/B06만, 이쪽은 B07/B08만 건드렸다.
그쪽 브랜치에 남아 있던 옛 폴더(B08_DesignDetail, B07_Quantity)는 이쪽 삭제가
반영돼 사라진다. main.py·라우트·척도 등 B07 작업물은 이쪽 것이 유지된다.
파일을 올리면 지표면 확정 직후 "노선 설계로 이동하세요"를 적고 그 뒤에 초기 설계
체인이 돈다. 그 사이 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(기슭막이 이관 때 생긴 기존 실패, 변경 전 동일).
업로드 잠금(결함 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>
파일을 아직 올리지 않은 새 프로젝트에서 대시보드 -> 파일 입력으로 이동하면
준비 화면(B11)이 확정 지표면을 찾다 실패해 "담당자에게 연락" 장애 안내를 띄웠다.
파일 입력 화면은 3D 지표면을 쓰지 않으므로 준비 자체가 필요 없다.
- goToWorkflowStage: 담아 둔 지표면을 실제로 쓰는 B04/B05로 갈 때만 준비 화면 경유,
나머지(B03/B06~B09)는 바로 이동
- 확정 지표면이 없을 때는 장애가 아니라 순서 문제이므로 전용 표식(PRELOAD_NO_SURFACE)을
던지고, 준비 화면은 안내 문구 + [파일 입력 화면으로] 버튼을 보여 준다
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
도엽 표시용 사본을 철회했지만, 이미 그 사본을 받아 둔 브라우저는 계속 그것을 쓴다
(보관함 키가 주소 기준이라 서버 파일을 지워도 남는다). DB_VERSION 1 -> 2로 올리고
업그레이드 시 기존 저장소를 버리도록 해 다음 접속에서 원본을 새로 받게 한다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 도엽 병합본의 화면 표시용 사본 생성(B04_wf1_Surface_Engine_SheetView):
프로젝트 + 500m로 잘라내고 좌표를 소수 7자리로 줄여 등고선 37.3MB -> 0.97MB.
분석용 원본은 그대로 둔다(배수유역은 상류까지 넓은 범위가 필요).
- /geojson의 도엽 레이어를 파일 그대로 + ETag로 전송 — 매 요청 2.0초 재직렬화 제거(0.008초).
- /vworld-map도 ETag 전송으로 바꾸고, 프론트가 붙이던 `&_t=` 시간꼬리표 제거.
- 도엽 레이어를 브라우저 보관함 경유로 조회하고 준비화면에서 미리 담는다.
- 배경 지도 범위 = 라이다 범위 + 계획노선 범위 + 여유 300m(SURFACE_MAP_MARGIN_M).
- 도엽 기준 좌표 = 계획노선 시점·종점(없으면 라이다 중심). 같은 도엽이면 9매,
이웃 도엽에 걸치면 12매. 표본 프로젝트는 기존 9매와 동일(회귀 없음).
- 선정에서 빠진 도엽 zip 정리(prune_sheets) — 표본에서 30매 중 21매가 다른 지역 잔재.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- GET /surface/confirmed 추가: 확정 구성(모델·필터·표현·평활·등고선간격)과
지형 가장자리만 반환(수 KB, 0.02s). 진입 판정·준비화면·B05의 단일 출처.
- B05 진입이 받던 포인트클라우드 JSON 23.8MB 제거 — 실제로 쓰던 값은 bounds뿐.
- 준비 표식을 프로젝트 ID에서 확정 signature로 변경: B04에서 다시 확정하면
대시보드 복귀·새 브라우저·B그룹 단계 이동 어느 경로로 들어와도 최신본을 담는다.
- preloadSurfaceAssets가 평활 여부를 추측하던 부분 제거(확정 저장값 사용) —
추측이 어긋나면 같은 지형을 두 번 내려받았다.
- B04 진입 시 필터·표현·평활·등고선간격을 확정본 값으로 초기화(확정 없으면 기존 기본값).
- 모델 확정 직후 준비 표식과 B05 세션 캐시를 비워 옛 지형이 남지 않게 함.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- B11_Status_UI_Loading + 라우트 b11-loading: 공통 프로그레스 서클로 단계·진행률 표시,
끝나면 원래 가려던 화면으로 자동 이동
- goToWorkflowStage: 아직 준비하지 않은 프로젝트면 준비 화면 경유, 같은 프로젝트로
다시 들어오면 건너뜀(탭 단위 기억). 다른 프로젝트면 보관분 교체
- 선적재 범위: 확정 지표면 3D + 그 등고선만 (종단·횡단은 0.86MB·0.06초로 이미 즉시라 제외,
배수유역·포인트클라우드도 제외)
- 실패 시 자동 이동하지 않고 담당자 연락 안내 + [그래도 이동]/[대시보드로]
- B04 등고선 간격 시작값을 B05 저장값과 공유(B04 변경은 DB에 쓰지 않음)
- 새 문구는 ui_locales에 한국어·영어 등록
- 휠 위 = 축소로 반전, 커서 지점을 축으로 한 dolly를 공용 유틸에서 직접 처리
- 회전 중심을 작은 구로 표시(돌리는 동안만, 화면상 크기 일정, 항상 위에 그림)
- 등고선 렌더 비용 감소: 폴리라인을 주곡선·보조곡선 2덩어리로 병합(드로우콜 424 → 2),
라벨은 카메라가 움직였을 때만 재배치
- common_util_http_cache: 파일 mtime+크기 ETag, If-None-Match 일치 시 304
(preview·contour 적용, 파일이 바뀌면 자동 무효화)
- A00_Common/b_asset_cache: IndexedDB 보관함(키 = projectId|url, 값 = 바이트+ETag).
보관본 즉시 사용 후 백그라운드 재검증, 3D는 보관 바이트를 직접 파싱
- 프로젝트 전환 시 타 프로젝트 보관분 삭제, 대시보드→B그룹 이동 시 확정 모델의
3D 프리뷰·등고선(1.0m) 미리 받기(포인트클라우드 제외)