Commit Graph
850 Commits
Author SHA1 Message Date
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 b5de29679f feat(B04): 방위 표시를 지면에 누운 나침반 링으로
시안 3종 비교 뒤 사용자 선택(2026-09-03) — TerriaJS·cesium-navigation 계열 표기.
링·눈금·도북 화살을 지면 평면 도형으로 두고 카메라에 투영하므로, 링이 눌린 정도가
곧 시점 기울기이고 도북은 늘 화면의 실제 북쪽을 가리킴.

- 15° 눈금(90°마다 긴 눈금), N·E·S·W 라벨(뒤로 넘어가면 흐림).
- 표고축 침은 내려다볼수록 짧아지고, 점으로 눌리면 Z 라벨을 감춤.
- 위젯 56 → 84px — 라벨이 읽히는 최소 크기.

검증: typecheck·prettier 통과. 리로드 실측 — 위젯 84×84, 링 경로 `M0.00 −33.98…`,
도북 화살 `M0.00 −33.30 L−4.28 −17.14 L4.28 −17.14Z` 로 기본 시점 계산값과 일치.
회전 중 거동은 사용자 화면 검증 대기.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 20:07:29 +09:00
eomsangdonandClaude Opus 5 dcabce147e feat(B04): 지표면 3D 방위 표시를 3축 트라이어드로 교체
옛 콤파스는 방위각(`atan2(ox, oz)`)만 써서 경사에 따른 남북 압축이 빠졌음 —
사시도 프리셋(오프셋 120·95·135, 앙각 27.7°)에서 바늘 41.6°, 화면 실제 북쪽 62.4°로
20.8° 어긋났음(2026-09-03 사용자 지적).

세계 축 N(−z)·E(+x)·Z(+y)를 카메라 화면 기저(오른쪽 r, 위 u)에 투영해 선과 글자를
그림. 기저는 카메라 오프셋만으로 구함(up = +y 고정). 뒤로 누운 축(깊이 > 0.25)과
정면으로 와 짧아진 축은 흐리게 그려 겹침을 줄임.

검증: typecheck 통과. 기본 시점에서 DOM 좌표가 해석값과 일치 —
N (28.0, 11.0) · E (45.0, 28.0) · Z (28.0, 27.4). 회전 중 거동은 사용자 화면 검증 대기.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 19:54:13 +09:00
eomsangdonandClaude Opus 5 b908a0b10d feat(B06): 종단면도 구조물 라벨도 배수관 표기로 통일
관종·관경(`파형강관 D1200`) 대신 `배수관` 을 적음 — 횡단 카드와 같은 규칙.
판정을 `structureDisplayName()`(`_UI_Section_Common`) 한 곳으로 모아 두 렌더러가
같은 문자열을 쓰게 함. 저장 라벨은 그대로 — 재진입 이관이 라벨로 종류를 되짚음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 19:35:21 +09:00
eomsangdonandClaude Opus 5 f772401b06 feat(B06): 횡단 카드 구조물 pill 을 배수관 표기로 통일
관종·관경(`파형강관 D1200`) 대신 표시 이름 `배수관` 하나만 적음 —
2026-08-17 확정한 `PIPE_DISPLAY_NAME` 규칙과 같은 표기. 관종·관경은 툴팁에 남김.
판정은 `PIPE_TYPES` 목록으로 하고 저장 라벨은 손대지 않음 — 재진입 이관이
라벨 문자열로 구조물 종류를 되짚기 때문임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 19:28:10 +09:00
eomsangdon c21b68f2ce @
feat(B06): 횡단 카드 제목행에 성토사면 본래 경사길이 표기

사면 미교차 경고가 붙는 제목행 우측 끝에 성토사면 경사길이를 표기함.
값은 정본 설계선(`design_line`) 기준이라 기슭막이·집수정이 사면을 끊기 전
**본래 길이**이고, 양측 성토는 좌·우 두 값을 다 냄.

- `fillSlopeLengths()` 신설 — 기존 `protectedSpan`·`meetOffset` 재사용,
  성토측만 노견 끝(측구가 있으면 측구 바깥)에서 사면 끝까지 `run × √(1+1/n²)`.
- 미교차 측점은 `≥` 하한값 — 추세 외삽은 지반이 사면과 나란한 자리에서
  수십 m 씩 튀어(740m 측점 101.53m) 길이 표기에 못 씀.
- `meetOffset` 교차점을 두 걸음 사이 선형보간으로 냄 — 반폭 맞춤(1m 올림)에는
  영향이 없고 길이 표기가 탐색 간격만큼 튀는 것만 막음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@
2026-09-03 19:16:46 +09:00
eomsangdon 0f5b4e4df7 auto: 2026-09-03 18:31 (ESD_LAPTOP) 2026-09-03 18:31:54 +09:00
eomsangdonandClaude Opus 5 4fdbcaf09c fix(B07): 장 확정 수량표 결함 3건 — 측점 구분·계획고·확정 해제
장 단위 확정 흐름을 실측하다 드러난 것들이다(2026-09-03, 용화 검증본 3장).

① **측점 구분 없이 역추출** — `_table_values_from_cells()` 가 도면의 표를 전부 훑어
   마지막 값을 모든 측점에 넣었다(실측: 4개 측점 전부 지반고 837.21, 도면에는
   840.87·840.33·836.45·837.21 로 제대로 그려져 있었음). 표 엔티티 id 가
   `uuid5("{도면id}:qtable")` 이라 측점을 되짚을 수 있어 그 표만 읽는다. 옛 도면은
   id 가 안 맞으므로 종전처럼 전부 훑는 폴백을 남긴다.

② **계획고가 빈 채로 나감** — 장 배치 입력의 원본에는 계획고가 없어 계획고·절토고·성토고
   세 칸이 통째로 비었다(21개 항목 중 지반고 하나만 채워짐). `_quantity_table()` 이
   횡단 설계(`design.design_elevation_m`)도 보게 했다.

③ **확정 해제가 404** — [수정]이 도면 목록을 **설계값 없이** 만들어 장 나눔이 달라졌고,
   방금 확정한 장 id 가 목록에 없어 되돌릴 수 없었다. 목록 조회·확정과 같은 인자를 쓴다.

검증(공용 브라우저·실동작) — 확정 해제 404 → **200**, 표 값 `planned=840.87 fill=0.00` 등
측점마다 다름, manifest 수량표가 측점별로 갈림(220 · 240 · 260 · 264 · 280 각각 4/21 항목
채움 — 나머지 17칸은 사용자가 CAD 에서 채우는 자리). 시험 뒤 확정은 모두 해제해 원상복구.
pytest 383 passed·17 skipped, ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 16:43:35 +09:00
eomsangdonandClaude Opus 5 e29e3cab67 feat(B07): 유역도 정보표 측점 표기도 n+ 0.0 으로 통일
토적도만 납품 표기(`120+ 0.0`)로 바꿔 두어 유역도 정보표는 `No.6` 으로 남아 있었다
(2026-09-03 사용자 지시로 통일). `station_plus_label()` 을 토적도 전용 모듈에서 공용
`_Engine_Cad` 로 올려 두 도면이 같은 함수를 쓴다. 종단도 표·횡단도 제목의 `No.n` 표기는
그대로 둔다 — 이번 지시 범위가 아니다.

검증 — 유역도 정보표 첫 줄 `(1) No.6` → `(1) 6+ 0.0`. pytest 383 passed·17 skipped,
ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 16:09:14 +09:00
eomsangdon 95fdd34351 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-03 15:50:22 +09:00
eomsangdonandClaude Opus 5 090442bb00 fix(B04): 유역 경계 단순화 허용오차 2.0m → 1.0m (격자 한 칸)
유역 격자가 1m(DRAINAGE_GRID_SIZE_M)라 경계는 1m 계단이다. 허용오차를 격자 한 칸에
맞추면 형상 손실이 격자 오차 안으로 들어가고, 유역별로 따로 단순화해 생기던 공유 경계
어긋남도 줄어든다.

실측(min_area=0 상태, 용화/S자):
- 좌표점        622·829   → 1,749·1,987
- 면적오차      1.86%·1.42% → 1.01%·0.67%
- 유역끼리 중첩 1,043㎡·1,373㎡ → 243㎡·373㎡
- 틈            1,184㎡·2,579㎡ → 369㎡·668㎡
0.5m 이하는 1m 계단 점을 지우지 못해 좌표점만 6배(10,215)로 튄다.

브라우저 실측도 같은 값(API 좌표점 1,750·1,987, 경계 없는 유역 0개)이고 확대해도 계단이
도드라지지 않는다. 테스트 159 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 15:50:12 +09:00
eomsangdonandClaude Opus 5 5331167439 refactor(B05): 구조물 배치 폼 뼈대를 전용 조립기로 분리 (700줄 제한 1차)
`_UI_Structures_Panel` 1,078줄 → 1,024줄. 화면 요소를 세우는 몫만 `_UI_Structures_Form`
으로 옮기고 패널은 값·검증·저장·목록을 맡는다. 배치 규칙(행 순서·구분선·버튼 묶음)은
사용자 지시로 굳은 것이라 그대로 옮겼다.

아직 제한을 넘는다 — 남은 큰 덩어리는 `commit()` 약 200줄과 옵션 필드 렌더·시설 폼
로드 약 170줄이다. 둘 다 폼 상태를 깊게 만지므로 [추가]·[삭제] 실동작 검증을 붙여
따로 옮긴다.

검증 — 공용 브라우저 B05 「구조물 배치」 실측: 제목·측점 행·메모 칸·목록 1개,
버튼 [추가]·[삭제]·[리셋], 구조물군 7항목 그대로. pytest 383 passed·17 skipped,
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 15:47:16 +09:00
eomsangdonandClaude Opus 5 754e00de19 fix(B07): 장 선택 시 정보 패널을 장 단위로 표기
장(여러 측점을 담은 횡단 도면)에는 측점 단위 지반·계획 값이 없는데도 제목이
「측점 3장 (220~264m)」으로 달려 어느 측점 값인지 오해됐다. 장이면 제목을 「장」으로 바꾸고
「이 장은 측점 여러 개를 담습니다. 지반·계획 정보는 측점 도면에서 봅니다」로 안내한다.

판정은 도면 id(`cross_s…` = 장) 로 한다 — `chainage_m` 은 장에도 첫 측점 값이 실려 와
그것으로는 갈리지 않는다(실측).

검증 — 공용 브라우저 B07: 3장(220~264m) 선택 시 `장 3장 (220~264m) · 잠정 · 이 장은 측점
여러 개를 담습니다…`, 종단도 선택 시 패널 없음(종전과 같음). typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 14:06:11 +09:00
eomsangdonandClaude Opus 5 15c2d81b49 refactor(B06): 횡단 카드 껍데기·반폭 계산 분리 (700줄 제한)
`_UI_Cross_View` 784줄 → 698줄. 도면과 무관한 제목행·하단 정보행을 `_UI_Cross_Card_Chrome`
으로 옮기고, 실효 표시 반폭 계산은 순수 계산이라 `_UI_Cross_View_Metrics` 로, 측점별 줌·팬
상태 맵은 임자인 `_UI_Cross_View_Zoom` 으로 옮겼다. 계산·판정 규칙은 그대로다.

검증 — 공용 브라우저 B06 실측: 카드 65·제목행 65·하단행 65·단면유형 pill 65·사면 미교차
경고 13, 첫 카드 제목행 `0+0.0 / 0.0m / 토사·리핑암·발파암 / 편측 성토 / BP` 로 종전과 동일.
pytest 383 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:56:01 +09:00
eomsangdonandClaude Opus 5 d6d211ef61 refactor(B06): 유토곡선 패널 조립을 전용 모듈로 분리 (700줄 제한)
`_UI_Section_View` 751줄 → 689줄. 곡선 계산 → 차트 → 범례 → 요약줄까지 한 덩어리를
`_UI_Section_View_MassHaul` 로 옮기고, 뷰 컨트롤러는 **붙일 자리**만 정한다(차트는 종단면도와
같은 부모의 형제, 범례는 스크롤 컨테이너 밖). 낡음 판정·계산은 옮긴 자리에서도 공용 모듈
그대로라 동작이 바뀌지 않는다.

검증 — 공용 브라우저 B06 실측: 요약줄 문자열 동일
(`절토(자연) 4,526.8㎥ … 최종 누가토량 −10,213.3㎥`), 범례 1·차트 1·카드 65·상태줄 빈 문자열.
pytest 383 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:50:53 +09:00
eomsangdonandClaude Opus 5 451ed97279 feat(B07): 돌쌓기 해칭 CAD 반영 + 표제란 SVG 서명 벡터 변환
해칭 — 수확기가 `g[clip-path]` 를 통째로 건너뛰어 기슭막이 형태 해칭(돌쌓기·콘크리트·
돌망태·통나무·바자)이 CAD 도면에 하나도 실리지 않았다. 클립을 쓰는 대신 **경계로 잘라서**
싣는다(2026-09-03 사용자 결정). 선분–폴리곤 교차로 안쪽 조각만 남기고, 클립 안 원(통나무
마구리)은 36각 폴리선으로 펴서 같은 방식으로 자른다. 문자는 중심점이 안일 때만 싣는다.

서명 — SVG 로 올라온 자산만 CAD 폴리선으로 바꾼다(2026-09-03 사용자 결정). DXF 로 나가도
선으로 남고 확대해도 깨지지 않는다. `B07_DesignDetail_Engine_Cad_Svg` 신설(path M·L·H·V·
C·Q·S·T·Z 지원, 곡선은 16분할, viewBox 비율 유지·y 뒤집기). PNG·JPG 는 그릴 선이 없으므로
종전대로 ImageEntity, 읽기 실패도 원래 그림을 그대로 둔다.

검증 — `tmp/tests/test_b07_signature_vector.py` 5건 신설(파싱·비율·엔티티 교체·래스터 유지·
손상 SVG), 전체 383 passed·17 skipped. typecheck·prettier·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:46:54 +09:00
eomsangdonandClaude Opus 5 ce4fcc1f13 feat(B07): 토적도 길이별 자동 축척 + 납품 도면 표기 8행 반영
축척 — 노선 연장에 맞춰 **한 장에 들어가는 가장 큰 그림**을 고른다(2026-09-03 사용자 결정).
후보는 도면 관행 축척(1:500~1:6,000, `DRAWING_SCALE_MASSHAUL_H_CANDIDATES`)이고 A1 작도영역
가용 폭 700mm 를 기준으로 판정한다. 실측 — 40m 노선 1:500 · 용화 1,106m 1:2,000 ·
3,465m 1:5,000. 세로는 종이 1mm=50㎥ 고정(도면끼리 비교하려면 같아야 한다).

표기 8행(사용자 확정) — ① 장비명 무대→종무대 ② 값 표기 `Q= 162.41M3`(등호 뒤 한 칸)
③ 지시선 계단형·balloon 모서리 접점 ④ 평형선·띠 경계현 빨강 ⑤ 측점 `120+ 0.0`
⑥ 표 눈금 신설(정규 빨강·추가 회색) ⑦ 행 이름 3.2mm·자간 벌림 ⑧ M.N 소수 2자리 `0+16.90`.

`MM_H` 상수를 없애고 `mm_h` 를 그리기 함수에 넘긴다 — 축척이 노선마다 달라졌기 때문.

검증 — `tmp/tests/test_b07_masshaul_basin.py` 갱신·신설(축척 3건·표기 8행·지시선·눈금),
전체 378 passed·17 skipped, ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:37:05 +09:00
eomsangdonandClaude Opus 5 2aaa0c594d feat(B05): 세월교 접근선 구간을 3D 패치 리본에 포함
노견 → 벽 상단 접근선 구간이 패치에서 빠져 있어 좁은 좌측 패치 사이로 원지반이 드러나
보였다(2026-09-03 사용자 확정: 「패치로 덮기」). 접근선은 벽보다 위라 덮어도 관 구멍·L자
통로를 막지 않는다 — 벽 전면·유로는 종전대로 리본에 담지 않는다(2026-08-25 사용자 ②).

접근선 줄을 `patchPoints` 앞에 담고 `fillRuns` 에 한 장으로 실어 「구간 1줄 = 리본 1장」
규칙을 그대로 따른다.

검증 — typecheck·prettier 통과. 3D 육안 확인은 카메라 조작이 필요해 다음 화면 검증
묶음에서 함께 수행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:29:29 +09:00
eomsangdonandClaude Opus 5 e83171b2b3 refactor(공통): 작업 좌표계 폴백을 창구 하나로 통합 + 트림 실패 진단
같은 폴백 사다리가 네 곳에 서로 다른 모양으로 흩어져 있었고, 그중 배수유역 라우터
`_route_center_lonlat` 은 노선 CSV 의 `crs_epsg` **라벨**을 그대로 변환에 썼다(라벨과
실좌표계가 다른 사례 실측 — 2026-09-01 용화 라벨 5179 / 실제 5176).

`common_util_crs.resolve_project_crs()` 신설 — 사다리는 ① 노선 crs_input ② 파일 라벨
(원본 좌표를 읽는 자리만) ③ 지형 PRJ(작업 좌표계 정본) ④ DB epsg ⑤ EPSG:5186.
작업 좌표계는 **지형 PRJ 우선으로 확정**(2026-09-03 사용자 결정 — 서피스 격자가 모델좌표의
주인이라 현행 유지). `project_epsg_from_prj()` 도 이 창구로 위임.

더해 지표면 트림이 노선을 통째로 지울 때 노선·지표면 bbox 를 함께 로그에 남긴다 —
"겹치지 않습니다" 만으로는 좌표계 문제인지 측량 범위 문제인지 갈리지 않았다.

검증 — `tmp/tests/test_project_crs_resolution.py` 5건 신설(사다리 4·진단 1),
전체 375 passed·17 skipped, ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:25:20 +09:00
eomsangdon f91d589ed4 Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-03 13:16:14 +09:00
eomsangdonandClaude Opus 5 8393dfd619 fix(B04): 세부유역 최소면적 필터 제거 — 작은 유역이 통째로 안 그려지던 문제
100㎡ 미만 유역은 `polygonize_labels` 의 최소면적 필터에 걸려 폴리곤이 아예 만들어지지
않았다. 유역 목록에는 있는데 지도에는 없는 상태 — 실측에서 용화 22개 중 1개(64㎡),
S자 48개 중 1개가 그랬다. 링 목록이 조각을 싣게 된 뒤로는 버릴 이유가 없다.

실측: 폴리곤 면적 오차(셀 면적 대비 평균) 용화 5.76%→1.86%, S자 3.56%→1.42%,
경계 없는 유역 1개→0개. 좌표점은 583→622 · 806→829 로 거의 그대로다.
1차 전체 배수유역 등 다른 호출부의 기본값(100㎡)은 그대로 둔다.

S자 실사례 검증: 용화 지형 위에 스위치백 3구간 합성 노선(정점 439·연장 4,528m)으로
신규 프로젝트를 만들어 자동 체인까지 완주 — 관 48개·세부유역 48개, 경계 없는 유역 0개.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:13:00 +09:00
eomsangdonandClaude Opus 5 f1bcee7857 feat(B04): 세부유역 경계를 링 목록(외곽+구멍)으로 넓혀 중첩·빈공간 해소
단일 링 자료형이 곧 중첩·빈공간이었다. 아래 유역이 위 유역을 감싸면 구멍이 사라져 위
유역을 통째로 덮고(합성 실측 256㎡ 전량), 한 관의 유역이 두 조각이면 작은 쪽이 사라져
빈공간이 됐다(144㎡).

- `polygon_parts()` 신설 — 조각마다 [외곽 링, 구멍 링...], 넓은 조각부터.
- `WatershedBasin.boundary_parts` 로 교체. `boundary_xy`(가장 넓은 조각의 외곽)와
  `boundary_rings`(편 링 목록)는 파생 속성이라 옛 소비처는 그대로 동작한다.
- API 에 `polygon_rings_lonlat` 추가. 저장 GeoJSON 은 구멍을 가진 Polygon, 조각이
  여럿이면 MultiPolygon.
- 캔버스 4곳(B04 유역화면 채움·선택, B05 배수유역도 채움·선택)은 even-odd 로 한 번에
  채우고 `pointInRings()` 로 판정 — 구멍 안을 눌러도 바깥 유역이 잡히지 않는다.
  중복이던 지역 `pointInRing` 은 삭제하고 공용 것으로 통일.

검증: 단위 5건 신규(도넛 구멍 보존·조각 2개 보존·파생 속성·빈 경계·조립 경로 전체에서
링 2개), 전체 168 passed, typecheck 통과. 브라우저 — API 가 유역 22개에 링 목록을 실어
보내고, 캔버스 even-odd 실측(가운데 알파 0 / 고리 255)으로 구멍이 실제로 뚫린다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:40:21 +09:00
eomsangdonandClaude Opus 5 a7f6232c01 fix(B06): I형 집수정 관 하단을 벽면 안으로 제한 — 관이 벽을 관통하게
관 하단 자리는 벽 계류측 변과 원지반의 교점인데, 원지반이 벽 상단보다 높은 자리에서는
교점이 벽 상단으로 밀려 관이 벽 위에 얹혔다(측벽과 배관이 만나지 않음). ㄴ·ㄷ형은 관이
바닥판 윗면에서 시작해 벽 안에 물리는 것과 대비된다.

교점을 벽 상단에서 관경+여유(0.5m)만큼 아래로 제한한다. 원지반이 그보다 낮으면 종전대로
교점을 그대로 쓴다. 벽을 키우는 방향은 벽이 1:0.3으로 기울어 base가 계류측으로 밀리며
지반 교점이 함께 올라가 벽이 7.5m까지 자라 폐기했다.

검증 — 공용 브라우저 B06 I형 8개 단면 실측: 관 유입측 끝단과 벽의 세로 겹침
18.1~56.4px(수정 전 0 — 벽 위로 이탈). ㄴ형 대조(13+4.1을 조정창에서 ㄴ형으로 바꿔 확인)
겹침 유지, 확인 후 세션값 원복. pytest 370 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 10:32:20 +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 16a24ace3d feat(B04): 지표면 3D 뷰어에 방위 콤파스 추가
뷰어 좌표 규약이 `x, 높이, -y` 라 세계 북쪽은 -z 다. 카메라 오프셋(카메라 − 타깃)의
수평 성분으로 도북이 화면에서 몇 도 돌아갔는지 계산해(atan2(offset.x, offset.z)) 바늘을
돌린다. 뷰어 우하단 — 축척 막대(좌하단)의 반대편에 둔다.

뷰어 파일이 이미 946줄이라 콤파스는 별도 모듈로 분리(700줄 제한). 애니메이션 루프에서
0.5° 이상 움직였을 때만 transform 을 다시 쓴다.

검증: typecheck 통과. 공용 브라우저 실측 — [상단] 시점 0°(바늘이 북쪽=화면 위),
[사시도] 41.6°, 캔버스 220px 드래그 시 218.6° 로 카메라와 함께 회전.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 10:02:15 +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
eomsangdonandClaude Opus 5 6bca521516 fix(B04): 세부 배수유역 배정을 종단 마루 분수령 기준으로 교체
옛 방식은 한 칸 이웃만 보는 국소 하강이라 1m 간격 계획고의 미세 요철에 걸려 멈췄다.
용화 실측: 측점 2,138개 중 1,898개(88.8%)가 저점에 갇혀 흐름이 아니라 누가거리
최근접으로 관에 붙었고, 그 결과 도로 셀 43.2%가 자기보다 높은 관에 배정됐다
(최대 6.82m 오르막).

이웃한 두 관 사이의 최고점(마루)을 분수령으로 삼아 왼쪽은 앞 관, 오른쪽은 뒤 관이
받게 바꿈. 1차원에서 물은 마루를 넘지 못하므로 물리적으로 정확하고 미세 요철에 면역.
첫 관 앞·마지막 관 뒤는 그 관이 받는다. 관 순서는 호출자가 준 그대로 보존.

검증: 단위 5건 신규(전체 163 passed), 실측 오르막 배정 43.2% → 17.6%(최대 4.15m),
잔여 1,993셀은 전부 사그 저류 후 더 낮은 장벽으로 넘치는 경우(어긋남 0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 09:43:38 +09:00
eomsangdonandClaude Opus 5 23b1e7e5b0 feat(B05/B06): 옛 계획고 유토곡선 노출 차단 + 사면 미교차 측점 경고
① 저장된 횡단이 지금 계획선과 어긋나면(재계산 예약 상태) 유토곡선을 그리지 않고
「횡단을 지금 계획선에 맞춰 다시 계산하는 중입니다」만 띄움. 옛 계획고로 만든 면적이
2초간 보였다가 정본으로 갈아 끼워지던 것을 없앰(2026-09-03 사용자 확정 「새 값만
보여주기」). 용화 실측 — 65측점 중 56개가 낡음, 계획고 차 −9.36~+5.83m,
저장분 성토 42,050㎥ ↔ 정본 14,881㎥.

② 사면이 계산 반폭 끝까지 원지반과 만나지 않아 면적이 잘린 측점에 카드 경고 표기.
판정은 면적을 내는 엔진 한 곳(B06_Section_Engine_Design)에서 `slope_unclosed` 로
내려 화면·수량·도면이 같은 기준을 봄. 계산은 손대지 않음(2026-09-03 사용자 확정
「영원히 못 만나는 지형이 있을 수 있으니 경고로 대체」).

검증 — 공용 브라우저 B06 실측: 2.6초 재계산 안내만 표시(옛 값 미노출), 4.4초 정본
표시, 사면 미교차 경고 13/65측점. pytest 366 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 09:10:46 +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 698f8f0505 knowledge(임도): 유토곡선 토량배분 기술문서 신설 + 미결 20·21 등재
실무 유토곡선 원본 6건(.MASS · EARTH.DAT) 파싱 관측 수록 — 최종 누가토량 +49~+324㎥,
0선 교차 3~17회, 장비 한계거리 전 건 무대 20.0 / 도자 60.0 m. 평형선 자동 선정·극값
무시 임계·balloon 표기 관행은 현행 근거 공백임을 명시하고 미결 20 으로 등재. 도자
한계거리 60m(실무) vs 70m(현행 구현) 채택은 미결 21.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 07:53:32 +09:00
eomsangdonandClaude Opus 5 0e0dd74e92 feat(B05/B06): 유토곡선 요약줄에 최종 누가토량 칩 신설
평형선·장비 띠·물량 balloon 이 안 생기는 노선에서 그 이유를 화면에서 읽을 수 있게,
곡선 끝의 누가토량을 요약 칩으로 드러냄. 0에 가까울수록 절·성토 균형이며 곡선이
0선을 넘지 않으면 평형선이 서지 않는다는 설명을 툴팁에 담음. 판정·조정은 사용자
몫이라 자동 보정 로직은 두지 않음(2026-09-03 사용자 확정).

B05 종단 패널과 B06 횡단 화면이 같은 함수를 쓰므로 양쪽에 함께 반영됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 07:53:32 +09:00
eomsangdonandClaude Opus 5 8daadf2d4f fix(B06): I형 집수정 배관 끝단이 마감면에 접혀 삼각형이 되던 결함 수정
관 끝단 두 꼭짓점을 마감면(I형 벽 안쪽 변) 선분 안으로 자를 때, 원지반이 벽 상단
위라 관 시작점이 벽 상단에 붙으면 위·아래 교점이 같은 끝점으로 접혀 관 단면이
삼각형으로 그려짐. 비스듬히 자른 끝단 길이는 항상 관경 이상이므로, 그보다 짧으면
접힌 것으로 보고 축 직각 마감으로 되돌림.

검증 — 공용 브라우저 B06 단면 8개 실측: 유입측 끝단 길이 0.0px → 18.7~58.4px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 07:19:32 +09:00
eomsangdonandClaude Opus 5 e065e5701e fix(B05): 최소고 가드를 편집 단일 창구로 이관 + 되돌리기가 구조물 위치까지 복원
2026-09-02 화면 검증에서 나온 미해결 2건 처리.

- 최소고 가드: `blocksMinCover` 가 `_Profile_Render` 측점 끌기 한 곳에만 있어
  [직선화]·[쉬프트]·틸팅·방향키가 그냥 지나감. 판정 로직을
  `_Profile_MinCover.blocksMinCover()` 로 옮기고 모든 편집이 지나는
  `_Profile_Panel.applyEdits` 한 곳에서만 호출. 화면 모듈의 사본·죽은 배선
  (`enforceMinCover` ctx 필드, 미사용 import)은 제거.
- 되돌리기 범위: 이력이 `b05:`·`b05-`·`b06:`·`b06-` 세션 키만 스냅샷하는데
  구조물(관) 위치는 세션 밖이라 undo 가 계획선만 되돌림. `_Profile_Panel_Tools`
  가 기록 직전에 관 목록을 `b05:pipes` 로 흘리고 복원 뒤 되읽어 반영.
  사용자 확정 ⑥ 「범위는 B05 페이지 조작 전부」 충족.

검증(공용 브라우저, 용화 검증 프로젝트 route_id 126):
- 최소고 강제 켠 상태로 관 측점 264.060 방향키 ↓ → 편집 미적용 + 경고
  "배수관 Ø800 — 최소 계획고(지반 +1.3m) 아래로 내려갈 수 없습니다."
- 구조물 측점 264.060 → 263.960 이동 후 ↶ 1회 → 264.060 복귀,
  `b05:pipes` 목록도 264.06 으로 복귀.
- `tsc --noEmit` 0, prettier 통과, pytest 366 passed / 17 skipped / 0 failed.
- 파일 줄수: Panel 699 · Panel_Tools 197 · Render 350 · MinCover 188 (700줄 제한 준수).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 20:34:18 +09:00
eomsangdon 73a77a1376 Merge remote-tracking branch 'origin/sub_desktop_1' into main_desktop_1 2026-09-02 19:32:16 +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
eomsangdon 5e51343f16 Merge remote-tracking branch 'origin/sub_laptop_1' into sub_desktop_1 2026-09-02 19:25:15 +09:00
eomsangdonandClaude Opus 5 ac983cf0e1 feat(B02): 등록 폼에 표제란 8칸 반영
사용자 지시(2026-09-02) — 프로젝트 등록에서도 수정 모달과 같은 항목 수신.

- 시행청·연도기번·사업량·설계일자·과업책임자·분야별책임자·설계자·회사 로고 8칸 추가.
  담당자는 select + 「신규 등록…」(관리자만), 로고는 회사 대표 로고가 기본값
- 담당자·자산 회사 경계 검사를 check_project_refs(company_id, data) 로 옮겨 B01 수정과 공용
- GET /admin/members 문턱을 require_company 로 — 일반 사용자도 담당자 선택 필요.
  _scope_company 가 남의 회사를 막고 쓰기는 관리자 그대로
- fix: road_type 스키마가 옛 값(branch·stream)을 받고 화면 선택지 work 를 막아
  「작업임도」 등록이 422 로 떨어지던 것 수정 — ^(main|fire|work)$
- 검증(5174 실조작): 등록 칸 14개로 수정 모달과 동일, 등록된 행에 8칸 그대로 저장
  (road_type=work, logo_asset_id=1, designer=3), 해당 프로젝트 표제란 12칸 전부 채워짐.
  pytest 151 passed (신규 test_b02_register_schema.py 8건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:21:27 +09:00
eomsangdonandClaude Opus 5 3d0215f8d8 feat(B07): 표지에 회사 로고 자리 신설
- `00_template_cover.json` 에 Image 자리 추가 — `{{회사로고}}`,
  x 57.40~137.40 · y 64.06~104.06 (폭 80 · 높이 40)
- 자리는 오른쪽 아래 `{{시행청}}`(기준점 784.35, 84.06)과 좌우로 마주 보게 잡음.
  왼쪽 여백은 `{{연도기번}}`(x 57.4)과 맞추고 세로는 시행청 글자줄에 맞춤
- 값 공급은 도각과 같은 통로 — `build_cover_drawing` 이 이미 `_fill_placeholders` 를
  태우므로 로고를 못 구하면 종전대로 엔티티째 빠짐

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:19:57 +09:00
eomsangdonandClaude Opus 5 6e0c77d811 docs(B07): 94883733 내용 설명 — 도각 표제란 서명 자리 2개 신설
`94883733` 이 자동 폴백 커밋(`auto: …`)으로 묶여 나가 내용 설명이 빠짐. 이력 재작성
금지(CLAUDE.md 6장)라 amend 대신 이 빈 커밋으로 남김. 그 커밋의 실제 변경:

- `resources/template_2dDrawing/00_template_A1.json` — Image 자리 2개 추가.
  `{{과업책임자서명}}`(x 536.89~578.89) · `{{분야별책임자서명}}`(x 587.91~629.91),
  둘 다 y 17.5~25.5. 설계자 서명과 같은 폭 42·높이 8이고, 표제란 세로선
  (531.87 / 583.91 / 633.91) 이 만드는 칸 안에서 좌우 여백 4로 가운데 배치.
- `B07_DesignDetail_Router.py` `_title_block_fields` — 두 자리 값을
  `pm_user_id`·`field_lead_user_id` 계정의 `company_assets` SIGNATURE 자산에서 읽음
  (설계자와 같은 최신 1건 서브쿼리). 서명을 안 올린 사람 자리는 종전대로 엔티티째 빠짐.

자체검증: `frame-template` 응답이 Image 4건(회사로고+서명 3)으로 자리·좌표 확인,
`tmp/tests/test_b07_title_block_signatures.py` 3건 신설, `pytest tmp/tests/ -q` 15 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:09:43 +09:00
eomsangdon 94883733d5 auto: 2026-09-02 19:08 (EOMSANGDON-HOME) 2026-09-02 19:08:55 +09:00
eomsangdon f0dd4b08ef Merge remote-tracking branch 'origin/sub_desktop_1' into sub_laptop_1 2026-09-02 19:02:52 +09:00
eomsangdon aff882c2a0 Merge remote-tracking branch 'origin/main_desktop_1' into sub_laptop_1 2026-09-02 19:02:51 +09:00
eomsangdonandClaude Opus 5 dde40101bb fix(B07): 표제란 로고·서명 원천을 계정·회사 자산으로 이관
- 서명: `projects.signature_asset_id` 대신 설계자(`designer_user_id`, 없으면 소유자)
  계정의 `company_assets` SIGNATURE 자산을 따라감 (여러 벌이면 최신 1건)
- 로고: 프로젝트가 고른 것 우선, 없으면 `companies.logo_asset_id` (014) 로 폴백
- `projects.signature_asset_id` 는 컬럼만 남기고 더 읽지 않음 — B01 이 항상 null 저장

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:01:56 +09:00
eomsangdon a91262f110 Merge remote-tracking branch 'origin/sub_laptop_1' into sub_desktop_1 2026-09-02 18:57:57 +09:00
eomsangdon 85a478dd8a Merge remote-tracking branch 'origin/main_desktop_1' into sub_desktop_1 2026-09-02 18:57:56 +09:00
eomsangdonandClaude Opus 5 3a36af9a2c feat(B01): 서명은 사람 계정에, 회사 로고는 회사 등록 단계로 재배치
사용자 확정(2026-09-02) — 이름이 들어가는 자리는 서명도 받고, 담당자 선택에 신규 등록
항목을 두며, 회사 로고는 회사 등록 단계에서 받아 이후 변경.

- 014_company_logo.sql: companies.logo_asset_id 추가 (서명은 company_assets.user_id 로
  이미 표현되어 컬럼 없음). 공유 DB 적용 완료
- 사용자 수정 모달에 「서명 (도면 표제란)」 칸 — createAssetField 에 owner(주인 못박기)·
  onChange(즉시 반영) 추가로 재사용, 주인 고정 시 물리기 체크 잠금
- 담당자 select 3개에 「+ 신규 등록…」 — 계정 생성 모달 뒤 세 select 에 항목 삽입·자동 선택
- POST /admin/members 가 이름·직위·부서 수신, 계정 없으면 status=PENDING 으로 생성
  (로그인 불가 비밀번호). 700줄 제한으로 B01_Dashboard_Repository_Members.py 분리
- 회사 등록 모달에 로고 파일 칸, PUT /company/logo 신설, 회사 패널·회사 목록에서 변경
- 프로젝트 수정 모달의 「설계자 서명」 칸 제거 — signature_asset_id 는 null 로 고정 저장
- 검증(5174 실조작): 신규 등록 구성원 2→3(id 6 PENDING)·select 자동 선택, 서명 자산
  [4,'검증신규 서명',user_id 6] 생성, 회사 logo_asset_id None→1, 검증 자산·계정 정리.
  pytest 143 passed, tsc·ruff·prettier 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:57:16 +09:00
eomsangdonandClaude Opus 5 65d6fd261f fix(B07): 도각 편집 띠 사이드바 이관·깨진 그림에 렌더 루프 정지 해소
- 편집 띠를 CAD 위 절대배치에서 도면 목록 하단 액션 칸으로 옮김 —
  1행 편집 띠, 2행 [도각 편집]·[현재 도면 확정] (리본과 겹쳐 문구·버튼이 찌그러지던 문제)
- `drawImage` 가 'broken' 상태 그림에서 던지던 예외로 렌더 루프가 끊겨
  이후 모든 도면이 백지로 남던 결함 해소 — 못 읽은 그림은 건너뜀
- `ImageEntity` 가 자리표시자(`{{회사로고}}`)를 절대 URL 로 굳히던 저장 경로 수정 —
  원본 주소를 보관해 그대로 돌려주고, 자리표시자는 요청조차 하지 않음
- 버튼 줌(ZOOMIN·ZOOMOUT)이 배율만 바꿔 도면이 화면 밖으로 밀리던 것을
  화면 중심 고정으로 수정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:12:28 +09:00
eomsangdonandClaude Opus 5 5fc8009925 feat(B01): 서명 그리기 캔버스 추가
- 자산 모달 서명 칸에 마우스 그리기 판 신설 — pointer 이벤트 + setPointerCapture,
  getBoundingClientRect 로 CSS 크기 → 캔버스 픽셀 환산, [지우기] 1개
- 올릴 때 canvas.toBlob('image/png') → signature.png 로 기존 업로드 통로
  (POST /company/assets) 재사용 — 백엔드·DB 변경 없음
- 파일을 안 고르면 그린 서명을 대신 실어 보냄, 로고 칸에는 캔버스 없음
- 검증(5174 공용 브라우저): 좌표 환산 실측 x 98–381 · y 38–111(요청 100–380 · 40–110),
  [지우기] 후 잉크 0, 저장 PNG 480×160 RGBA 5,250 bytes,
  프로젝트 signature_asset_id 2→3 반영 확인 후 원복. pytest 143 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:04:44 +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