실무 탭이 「위 치수조서 + 아래 수량산출서」인데 1단계에서 아래 표가 섰고 이번이 위 그림.
그림이 붙으면서 한 면에 넉 장을 쌓을 수 없게 돼 **장 나눔(㉢)도 같이** 했음.
장 나눔 — 계획평면도가 쓰는 본 그대로
`standard_sheet` / `standard_sheet_2` … 제원 조합 하나가 한 장.
좌측 목록은 `idPrefix` 묶음(계획평면도와 같은 짜임)이고 kind 는 새로 `standard`.
구조물이 없어도 한 장은 남김 — 단추가 사라지면 「없어진 것」처럼 보이고 사유를 읽을
자리도 없어짐.
그림 — `B07_DesignDetail_Engine_Cad_StandardFigure.py`
⚠ **기울기를 값으로 받음. 0.3 을 그림에 박지 않았음.** `face_slope_ratio` 가 오면 그
값으로 기울고, 비어 있으면 교본 7-3 기본 0.3 으로 그리되 **「자동 판정 전」이라고 그림에
적음**. 자동 판정이 붙는 대로 그림이 따라감.
⚠ 치수는 수량이 쓰는 그 상수(`STONE_MASONRY`)를 직접 읽음 — 여기서 다시 적으면 그림과
표가 갈림. 상부 0.45+0.10H · 하부 0.45+0.40H · 터파기 폭 평균두께+0.2 · 되메우기 0.2.
ⓘ 그 상수는 **뒷면이 수직인 1:0.3 벽**을 뜻함(하부−상부 = 0.30H = 전면이 기우는 양).
기울기가 0.3 이 아니면 그 차이만큼 뒷면이 기욺 — 상수에서 따라 나오는 결과라 그대로 그림.
⚠ 치수가 없는 것은 그리되 치수를 안 적음 — 막자갈은 「입적 − 몸통 − 고임돌」이라 폭·높이로
정의된 도형이 아님. 자리만 보이고 값은 표를 가리킴.
죽은 길 걷어냄 — `BLANK_DRAWINGS` 가 「표준도」 하나뿐이었는데 그것이 내용 있는 장이 되어
빈 도각 경로가 통째로 안 쓰이게 됨. 상수·목록 루프·분기·import 를 지움(700줄 제한도 걸렸음).
자체검증 — 회귀 573 통과 · 0 실패, `tsc --noEmit` 0.
⚠ 병합 뒤 깨진 시험 둘을 고침(내 폴더 `tmp/tests`, 랩탑 메인 `11394d40` 의 여파)
· `stone_supply='채집'` 기본값을 확정 ② 근거와 함께 허용 목록에 등록
· 바닥막이 「모든 옵션이 b05」 단정 → 조달이 detail 로 들어와 B05 셋만 보게 좁힘
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「표준도」를 누르면 도각만 실린 빈 장이 뜨던 것을, 제원 조합마다 표 한 벌을
CAD 표 객체로 그려 낸다. 도각은 두르지 않음(2026-09-08 사용자 지시).
값은 여기서 셈하지 않음 — `build_standard_sheets` 가 낸 것을 글자로 옮길 뿐임.
셈이 두 벌이 되면 도면과 수량서가 갈림(CLAUDE.md 5장).
실화면 확인 (프로젝트 936be972, 구조물 5기를 심고 확인)
장 4개 · 개소 5 — ①③ 이 같은 제원이라 한 장에 2개소로 모임(장 나눔 실물 증명)
돌쌓기(찰) H=2.5 뒷길이 45㎝ 깬돌 12줄 2개소·합 20.00m
돌쌓기(메) H=2.0 뒷길이 35㎝ 야면석 10줄 1개소
옹벽 H=2.0 7줄 1개소 (관측 원단위 사유 1줄)
큰돌쌓기 H=2.5 5줄 1개소 (막힌 사유 4줄이 표에 그대로 뜸)
⚠ 만들다 잡은 것 — 표 폭을 176㎜ 로 냈더니 단서가 붙은 근거 문구(물구멍관·버림
콘크리트)가 칸을 넘어 수량 칸을 덮었음. 표는 글자를 안 접음. A1 작도 영역
739 × 499㎜ 에 맞춰 735㎜ 로 넓히고 줄 높이 9㎜ 로 잡음 —
**네 장까지** 한 면에 듦(47줄 × 9 + 간격 = 465㎜). 더 늘면 장 나눔(㉢)이 필요함.
⚠ 못 낸 값은 0 이 아니라 「-」 로 적음. 도면에 0 이 찍히면 「없다」로 읽힘.
⚠ 구조물이 없으면 빈 격자 대신 사유 한 줄이 뜸 — 빈 표는 「만들다 만 것」으로 보임.
자체검증 — 회귀 573 통과 · 0 실패. 공용 브라우저에서 표준도를 눌러 실제로 열고
확대해 글자·수치를 읽어 확인함(스크린샷 `tmp/browser/shots/standard_fit.png`).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 메인이 측구를 갈라 냈으므로(`6a7c339f`) 그 값을 그대로 옮김.
여기서 다시 가르지 않음 — 근거가 없는 측점은 B06 이 나누지 않고 사유를 함께 냄.
`split_basis()` 를 함께 둠 — `ditch_split_basis` 를 사람이 읽는 말로 바꿔 준다.
⚠ 표 칸은 숫자만 담으므로 이 말은 표 밖(주기·화면)에 실어야 함.
「전량 암」이 경계선을 못 찾아서인지 정말 암 지반이어서인지 숫자만으로는 구별 안 됨.
⚠ 층따기 밑수가 바뀐 것이 이 표에도 그대로 왔음 — 랩탑 메인이 「성토 사면길이」에서
「B06 이 낸 원지반 깎는 길이(`bench_cut_length_m`)」로 고쳤고, 이 모듈이 B08 `_length_of`
를 빌려 쓰므로 **같이 움직였음**. 값이 없는 옛 저장분에서는 0 으로 섬 —
성토 사면길이로 대신 채우지 않는 것이 맞음(다른 면을 세게 됨).
실측(936be972, 옛 저장분) — 여전히 **14칸**. `ditch_split_basis`·`bench_cut_length_m`
둘 다 저장된 설계에 없음(B06 확정 전 자료). 새 키가 있는 자료에서 16칸이 되는 것은
시험으로 확인함.
자체검증 — 시험 11건(측구 두 칸 · 못 가른 측점 사유 · 층따기 밑수 따라가기 추가),
회귀 573 통과 · 0 실패.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
별표2 Ⅰ.1.나.(5) 가 요구하는 여덟(지반고·계획고·절토고·성토고·단면적·지장목 제거·
측구터파기 단면적·사면보호공) 중 뒤 넷이 빈칸으로 나가던 자리.
빈칸의 까닭은 「값이 없어서」가 아니라 **통로가 없어서**였음 — 표가 `source["quantities"]`
를 보는데 그 키가 원본 파일에 아예 없음(실측: 횡단 원본 15키에 `samples`·`center_z`·
`chainage_m` 은 있고 `quantities` 는 없음). 반면 저장된 설계에는 단면적이 그대로 있고
사면길이도 설계선에서 유도됨.
⚠ 계산을 새로 짜지 않음 — 단면적은 B06 저장값을 그대로 읽고, 사면 계열은 B08 이 쓰는
`station_slope` 를 그대로 부름. 계열 이름·어느 면을 쓰나도 `SlopeArea` 정의를 빌림
(거기서 밑수가 바뀌면 이 표도 같이 움직여야 함).
채운 열 칸
단면적 3 깍기 토사 · 깍기 암석 · 쌓기
사면 7 층따기 · 면고르기(성·절) · 지장목제거(성·절) · 성토파종 · 절토살포
⚠ 사면 칸의 단위 — B08 은 측점 사이를 적분해 ㎡ 를 내나 그것은 두 측점이 있어야 나옴.
한 장짜리 횡단도에 들어가는 것은 그 측점의 **사면길이(m)** 이고 1m 폭 조각의 ㎡/m 와
수치가 같음. 표기를 m 로 볼지 ㎡/m 로 볼지는 표기 문제이고 값은 하나임.
안 채운 칸 — 근거가 없어 임의로 안 넣음
측구 토사/암석(저장값이 `ditch_area_m2` 한 값뿐) · 표토제거(두께 칸 없음) ·
편책(별도 일위대가 제작 뒤 연결로 확정) · 제근(입목 본수 안 듦) · 노면다짐
자체검증 — 새 시험 8건(사면길이는 손으로 잰 √5 · √(2.4²+2²) 와 대조, `is not None`
만 보면 0 이어도 통과하므로 실수치로 맞춤), 회귀 570 통과 · 0 실패.
실프로젝트 936be972 세 측점에서 **21칸 중 14칸**에 값이 찍힘(앞서 4칸).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 5번(2026-09-09 「진행해줘」)의 1단계. 실무 원본 `07-구조도-소광리.xlsx`
53탭을 펴서 표 짜임을 확정한 뒤, B08 원단위 전개를 그 모양으로 접는 통로를 냄.
⚠ 계산은 새로 만들지 않음 — `build_unit_table` 결과를 제원 조합으로 묶고 단위당으로
나눌 뿐임(계산 자리는 한 곳, CLAUDE.md 5장).
장 나눔 축 = 제원 조합(`type_id` + 높이 + 제원 전부). 확정 ⑨ 대로 기울기가 바뀌면 장이
갈림 — 기울기가 제원의 한 칸이라 저절로 지켜짐. 측점·방향처럼 개소마다 다를 뿐인 칸은
장을 안 가름(`PER_PLACE_OPTION_KEYS`).
선행 확인 두 건도 끝냄
· 8-3 틈메우기돌 — 53탭 전수에서 `틈메우기`·`틈막이`·`사춤` 0건 ⇒ 넣지 않음
· 8-2 버림 콘크리트 — 실무에 있음(「바닥 10㎝ 이상 콘크리트(버림)」 · 옹벽 버림CON'C),
KDS 44 90 00 의 100㎜ 와 같음
⚠ 만들다 잡음 — `billing_unit` 이 비어 있으면 「단위 미정」이 아니라 「m·연장」이라는
계약이 있었음(`StructureQuantity`). 미정으로 읽어 돌쌓기가 전부 단위 없는 장이 됐음.
⚠ 실무 시트와 어긋나는 줄 일곱은 PLAN 4-12 에 표로 남기고 확정 대기로 둠 —
임의로 맞추지 않음(터파기 0.35 대 2.30 이 가장 큼).
자체검증 — 새 시험 11건 통과, 회귀 562 통과 · 0 실패.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
공용 오버레이가 좁은 폭에서 좌측 패널을 320 에서 280·227·182 로 물리면서(ef4cdb66)
2열 칸이 128.8 에서 108.8·82.4·60px 까지 줄어 도면 이름이 말줄임으로 잘렸음.
문서 넘침은 0 이라 수치로는 안 잡히는 자리 — 잘린 것이 `overflow: hidden` 안이라서.
실측 (도면 31장, 잘린 이름 수 · 고치기 전 → 뒤)
1400·1000 0 → 0 (2열 128.8px 그대로 — 넓은 폭 배치 안 건드림)
860·760·620 1 → 0 (1열 221.6px)
560 16 → 0 (1열 168.8px)
500 19 → 2 (1열 124px)
남은 2건은 횡단도 격자 밖(「계획평면도(노선배치도)」 등)이고 폭 500 에서만 남음 —
그 폭에서 패널이 182px 까지 물러난 결과라 공용 오버레이 몫.
`repeat(auto-fit, minmax(120px, 1fr))` — 가장 긴 이름 107px + 단추 안여백·테두리
20px 를 문턱으로 잡음. 넓은 폭에서는 두 칸이 들어가 배치가 그대로임.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
무한 로딩으로 보이던 자리가 둘이었음.
1) 미리받기가 클릭 앞을 막음 (진짜 원인)
진입 직후 도면 31 장을 순서대로 미리 받는데, 한 장이 0.3~1.0초라
그 사이 클릭한 도면이 앞의 여러 장 뒤에 줄을 서서 30초 넘게 안 열렸음.
화면은 「불러오는 중」 그대로였음.
- 클릭이 도는 동안 미리받기가 쉬게 함
- 클릭이 이미 받아 둔 장은 건너뜀
2) CAD 가 아무 말도 안 하면 끝이 없었음
끝을 알리는 것이 drawing-loaded · drawing-error 두 통지뿐이라,
iframe 이 안 뜨거나(ready 없음) 도면을 여는 중에 멈추면 영원히 돎.
- 지켜보는 시계 추가 (ready 20초 · 도면 15초)
- iframe 자체가 못 뜨면 기다리지 않고 바로 끊음
- 화면 표시만 끊고 요청은 살려 둠 — 늦게 오면 그대로 받음
곁들여 B07 의 「모든 도면 확정 뒤에 이동」 가드를 개발환경에서만 품
(B09 로 가는 길. 운영에서는 그대로 막음).
확인: 단계 표시줄 B08·B09 가 눌리고 B07 → B08 이동됨. tsc 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 칸이 있는 글자와 그림에 모서리 그립 추가, 모서리를 끌어 칸 크기를 바꾸는 조작 신설 (다른 도면 요소에도 동일 적용)
- 기본 도각(00_template_A1)의 글자 24개에 표제란 칸을 계산해 부여 — 칸 기준 가로·세로 가운데 정렬
- 도각 편집 시 도면명·도면번호도 보던 도면 값으로 미리보기 제공
- 복제 시 미리보기 값 유지 (그립 편집 후 자리표가 토큰으로 되돌아가던 문제)
- CAD index.html 을 캐시하지 않도록 처리 — 빌드 후에도 옛 화면이 남던 문제 해소
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 텍스트 자리표에 칸 크기(boxWidth/boxHeight) 도입 — basePoint 를 칸 중심으로 두고 가로·세로 가운데 정렬, 선택 시 칸 테두리 표시, DXF 내보내기도 중앙 정렬로 반영
- 그림은 칸 안에서 비율을 유지하며 맞춤(letterbox) — 칸을 늘려도 로고·서명이 찌그러지지 않음
- 자리표 패널에 선택 항목 칸 크기(가로·세로 mm) 입력 추가
- 도각 편집 중 자리표에 실제 값 미리보기 — 서버가 표제란 값(공사명·회사·담당자·로고·서명)을 함께 내려주고 화면만 값으로 표시, 저장값은 {{키}} 토큰 유지
- title_block_fields 공개화 및 frame-template 응답에 fields 추가
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 저장소에 LibreDWG 0.14.8594 Windows 실행 파일 동봉 (dwg2dxf/dxf2dwg + 필요한 DLL 4개, 약 33MB)
실제 파일은 메인 워크트리 B07_DesignDetail/openwebcad/tools/libredwg 에 두고 보조 워크트리는 junction 으로 연결
- 파이썬 바인딩 미포함 (import 시 GPL 이 본 프로그램까지 확산) — 별도 프로세스 호출 방식 유지
- GPL v3 전문(COPYING)과 원본 출처·구성·교체 방법 README 동봉
- 변환기 탐색 순서: .env 경로 → 동봉본 → PATH
- 옛 DXF 의 유니코드 escape 를 복원해 DWG 왕복 시 한글 깨짐 해결, DWG 출력용 DXF 는 R2004 로 생성
- DWG 왕복 검증 테스트 추가 (tmp/tests, git 추적 제외)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 내보내기 엔진 신설 — 캐드 도면(JSON)을 ezdxf 로 DXF 작성(선·폴리선·글자·점·원·호, 도면층 유지), DWG 는 LibreDWG dxf2dwg 를 별도 프로세스로 호출
- POST /{project_id}/drawing-export 신설, 한글 파일명은 RFC 5987 방식으로 전달, 담지 못한 그림 수는 X-Aislo-Skipped 헤더로 통지
- CAD 출력 리본에 「DXF 내보내기」·「DWG 내보내기」 추가 — 캐드가 부모에 요청하면 부모가 서버 파일을 받아 내려받기
- 도각·내보내기 엔드포인트를 B07_DesignDetail_Router_Frame 으로 분리 (700줄 제한)
- 그림(Image)은 DXF 외부 참조 방식이라 제외하고 개수를 안내
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>
@
- ODA File Converter 제거 — 비회원 무료 사용이 비상업 용도로 제한되어 상용 서비스에 부적합
- LibreDWG dwg2dxf 를 별도 프로세스로 호출 (GPL 의무가 본 프로그램에 미치지 않는 방식), 경로는 .env LIBREDWG_DWG2DXF_PATH 또는 PATH 자동 탐색
- DWG 머리글로 형식 판정 — R2018 이후·미지원 형식은 변환 시도 없이 「2018 DWG 또는 DXF 로 저장」 안내
- 변환 실패·변환기 미설치도 같은 안내로 통일
- 형식 판정·안내 경로 테스트 추가 (tmp/tests, git 추적 제외)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 부모 사이드바 팔레트(B07_DesignDetail_UI_FramePlaceholders.ts) 제거, CAD 앱에 FramePlaceholderPanel 신설
- 도면 로드 메시지에 frameEdit 플래그 추가 — 도각 편집으로 실은 도면에서만 패널 표시
- 자리표를 화면 중앙에 직접 생성 (부모 왕복 없이 CAD 상태에 추가, 실행취소 스택 반영)
- 그림 자리표는 값이 없어도 테두리와 이름을 그려 배치 위치가 보이게 함
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- DXF -> 도각 JSON 변환 엔진 신설 (ezdxf) — 선·폴리선·원/호/타원/스플라인 평탄화·글자·점 변환, 블록·치수는 분해, 해치 등 미지원 요소는 제외
- DWG 는 ODA File Converter(.env ODA_CONVERTER_PATH) 경유 변환, 미설치 시 DXF 저장 안내로 폴백
- POST /{project_id}/frame-template/import 신설 — 파일을 편집 화면용 도면으로 반환(저장은 기존 [완료] 경로 유지), 20MB·2만 도형 상한
- 도각 편집 띠에 「파일 불러오기」 추가, 자리표 팔레트 신설 (글자 14종·그림 4종을 도면 중앙에 배치 후 이동)
- CAD 텍스트 선택 시 회색 점선 외곽선 표시 (출력물에는 미포함)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 확정. 별표2 Ⅰ.2.나.(4) 확폭표(R 10~45m → 2.25~0.25m)를 측점별
평면 곡선반경에 물려 차도 폭을 넓힌다.
- 확폭 방향은 **곡선 바깥쪽 편측** — 노선 폴리라인의 외적 부호로 회전 방향을 보고
바깥쪽을 정한다(좌회전이면 우측). 측점 기록에 `curve_outer_side` 로 실린다.
- 차도 반폭을 좌·우로 나눠 들어 한쪽만 넓어지게 함. 확폭이 0이면 예전과 같은 대칭
단면이다. 노견·측구·사면은 그 바깥으로 그대로 밀린다.
- 확폭을 더한 유효너비는 법정 상한 5m 에서 자른다(규격 3.0m 면 최대 2.0m 까지).
- 계산 짝을 함께 고침 — 파이썬 `compute_cross_design` 과 브라우저 `computeCrossDesign`,
표는 양쪽에 두되 짝임을 주석으로 못 박음. 확폭 입력은 측점 기록에서 뽑는 헬퍼
하나로 9개 호출부(횡단·확정·B07 도면)에 같은 값이 가게 함.
- 횡단도에 노폭 라벨 — 확폭이 걸리면 「노폭 4.5m (규격 3.0 + 확폭 1.5)」로 적는다.
- 확인: 표 경계·편측 적용·5m 상한·회전 방향 판정 5건(pytest) + 브라우저 표 15건 일치.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 횡단면도 장 배치의 칸 여백 8mm → 0mm — 이웃 박스 테두리가 맞닿음.
- CAD 리본 높이 116px → 122px — 내용(85px)이 보이는 높이(81px)를 넘어 생기던
세로 스크롤바 제거. 캔버스 상단이 6px 내려감.
- 장 라벨을 누가거리 범위 「1060~1070m」에서 시작 측점 「No.53」으로 교체.
- 좌측 패널 2열 격자 단추의 최소폭을 풀어 패널을 14px 넘어가던 것을 막고,
이름이 길면 `…` 로 잘리게 함.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 표준 횡단면도를 실제 도면으로 만듦.
- 본 그림: B06 좌측 패널 모식도와 같은 배치를 실치수로 그림(1/50). 노폭·노견·
측구 상단폭·노면 전폭에 치수선(눈금+치수값)을 붙이고, 절토·성토 경사비와
횡단경사를 표기. 값은 B06 표준 횡단면 설정을 그대로 읽고 없으면 config 기본값.
- 측구 부분 확대도(1/10): 상단폭·저폭·깊이 치수 + 확대 축척 표기.
- 암반 2단 절토: 아래는 암반 경사(1:0.4), 위는 토사 경사(1:1), 갈리는 높이에
암반선을 파선으로 긋고 각도를 함께 적음.
- 암 L형 측구·포장 횡단경사는 주기(※)로 적음 — 본 그림은 토사 기준.
곁들여: Router_Support 가 700줄을 넘어 재수출 import 를 한 문장으로 합쳐 681줄로
줄임(기능 변화 없음).
검증: 치수값이 STANDARD_CROSS_SECTION 과 일치(500·3000·500·900·4000), 확대도
900·300·300 + S=1/10, 2단 절토선 꺾임점 1개, 콘텐츠 358.2x172.6 mm ≤ A1 작도영역.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 라이다 계획평면도에 지표면 탑뷰 그림을 얹음.
- 확정 DTM 격자를 도곽 범위로 잘라 음영기복 PNG 를 만들고 Image 엔티티로 실음
(북서 315도·고도 45도, 한 변 최대 1,600 px). 점구름 4,900만 점을 그대로
그리지 않음.
- 어느 지표면을 쓸지는 1단계 확정값을 따름 — DrainageContext 에 surface_params
를 실어 전달.
- 축척·도곽·장 나눔은 계획평면도와 같음(1/1,200) — 노선이 같은 자리에 섬.
- entities_bbox 가 꼭짓점 배열(points)을 세도록 고침. 세지 않으면 그림이 도곽
계산에서 통째로 빠짐.
검증(용화_LAS): 콘텐츠 726.1x487.2 mm ≤ A1 작도영역, 그림 범위 안에 노선이
완전히 들어감, 음영기복 준비 0.4초·자료 214 KB. 능선·계곡이 눈으로 구분됨.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 용지도를 실제 도면으로 만듦. 축척·도곽·장 나눔은 계획평면도와
같고(1/1,200) 배경도 같은 창구(map_background)를 씀.
- 연속지적도 필지 경계 + 지번(jibun) 표기. 작은 필지는 솎고(종이 6x3 mm 미만),
도곽을 통째로 감싸는 임야 대필지는 도곽 중심에 지번만 적음 — 그러지 않으면
노선이 대필지 안에 들어앉을 때 지번이 통째로 사라짐.
- 시군구·읍면동/리 경계를 파선·일점쇄선으로 구분. 지적·행정 경계는 도곽 범위로
절취 — 자르지 않으면 산지 대필지 하나가 도면을 10 km 로 벌림(실측 8,368 mm).
- 도면용 색을 화면용과 따로 정함(등고선을 가장 옅게, 행정 경계를 굵고 진하게).
- 범례를 유역도 정보표 자리(오른쪽 칸 방위표 아래)에 넣음.
- _geometry_lines 가 MultiPolygon 을 편다 — 지적·행정구역이 그 형식임.
검증(용화_LAS): 콘텐츠 734.3x489.2 mm ≤ A1 작도영역, 지번 「산77-15임」이 지적
속성과 일치, 도면 목록에 landuse 가 실림. 이 노선은 임야 대필지 한 곳에 통째로
들어가 경계선이 도곽 안에 없음 — 자료대로의 정상 결과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 계획평면도(지형·노선배치도·배치도)를 실제 도면으로 만듦.
- 배경 공용화: map_background() 한 창구로 도엽 등고선·세류선 읽기·좌표 환산·
도곽 절취를 모음. 유역도와 계획평면도가 같은 것을 부르고, 환산 결과는
파일 mtime 을 키로 캐시(_metric_lines_cached).
- 축척 1/1,200 고정(DRAWING_SCALE_PLAN) — 지식DB 「설계제원_총괄」 측량·도면
기준. 횡단면도와 같은 원칙으로 줄이지 않고 안 들어가면 장을 나눔(plan_chunks,
종단 측점 기준·경계 측점 1개 중복).
- 세 장이 같은 배경·같은 도곽 배치를 쓰고 주제만 다름. 측점 눈금은 종단 측점
좌표로 찍고, 구조물은 pipe_points.json 정본을 읽어 마름모+이름으로 표기.
- 도면 목록·단건 조회에 kind="plan" 추가. 화면 목록은 id 접두어로 묶어 장이
나뉘어도 한 그룹으로 보임.
검증(용화_LAS): 콘텐츠 734.3x489.2 mm ≤ A1 작도영역 739.2x499.2, 노선 실거리
630.1x214.2 m → 종이 525.12x178.46 mm(실측 0.83333 mm/m = 1/1,200 일치),
배경 등고선 180줄이 세 장 동일, 유역도 8.5초 → 계획평면도 1.3초(캐시 적중,
파일 재읽기 없음).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실측 결과 축척은 문제가 아니었음. 실거리 3 m 가 모든 단면에서 30.0 mm
(mm/m = 10.0 단일값). 뒤죽박죽으로 보인 원인은 칸 크기 — 한 장 안에서
폭 116~218 mm, 높이 29~178 mm 로 제각각이었음.
- 장별 완전 통일: 한 장 안 모든 칸을 그 장 최대 블록 크기로 통일(_grid_for).
테두리는 build_cross_drawing(cell_frame=...) 로 칸에 맞춰 그림.
- 장 경계는 전체 최소 장수가 되도록 동적계획으로 선택(_sheet_breaks).
앞에서부터 채우면 바로 뒤의 큰 단면이 칸을 키워 6칸짜리 장에 1개만
실리는 낭비가 있었음.
- 축척은 지식DB 「설계제원_총괄」 기준 1/100 고정 — 어떤 경우에도 줄이지 않고
안 들어가면 장을 나눔. 장수는 세트마다 달라짐(2026-09-04 사용자 확정).
검증(용화_LAS): 장 21개 전부 칸 크기 단일값, mm/m = 10 단일, 측점 65개
누락 0, 칸 밖 이탈 0.000 mm. 실서버 API 로도 동일 확인.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
732줄 한 파일을 둘로 나눔 (동작 불변, 순수 이동).
- `B07_DesignDetail_UI_Page.ts` 517줄 — CAD 임베드·postMessage 교신·저장/확정 흐름
- `B07_DesignDetail_UI_Panels.ts` 234줄 — 도면 목록 12분류(`DRAWING_GROUPS`)와
측점 설계 정보 카드. DOM 만 만들고 고르기 동작은 콜백으로 받음
검증: 공용 브라우저 B07 화면 실측 — 도면 목록 패널 1개·항목 54개(「설계 도면 49건」),
CAD iframe 1개 로드, 콘솔 오류 0. `tsc --noEmit` 통과, tmp/tests 378 passed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`_Support_Basin.py` 로 옮긴 뒤 `CONTOUR_FILE` · `STREAM_FILE` · `_basins_crs` ·
`_geojson_payload` · `_geojson_features` · `_too_far_from_route` 가 진입 파일에서
사라져, 옛 이름을 참조하던 다른 워크트리의 테스트가 ImportError·AttributeError 로
깨졌음(laptop-sub 보고 2건). 프로덕션 호출부는 새 모듈을 직접 봐 동작에는 영향 없었음.
`as` 형태로 다시 내보내 분리 전 이름 14개가 진입 파일에서 모두 보이게 함.
검증: 진입 파일 속성 14개 전부 확인, 라우트 7개 유지, ruff check 통과,
tmp/tests 378 passed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
장 단위 확정 흐름을 실측하다 드러난 것들이다(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>
토적도만 납품 표기(`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>
장(여러 측점을 담은 횡단 도면)에는 측점 단위 지반·계획 값이 없는데도 제목이
「측점 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>
해칭 — 수확기가 `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 사용자 결정).
후보는 도면 관행 축척(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>
- 서명: `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>
- 편집 띠를 CAD 위 절대배치에서 도면 목록 하단 액션 칸으로 옮김 —
1행 편집 띠, 2행 [도각 편집]·[현재 도면 확정] (리본과 겹쳐 문구·버튼이 찌그러지던 문제)
- `drawImage` 가 'broken' 상태 그림에서 던지던 예외로 렌더 루프가 끊겨
이후 모든 도면이 백지로 남던 결함 해소 — 못 읽은 그림은 건너뜀
- `ImageEntity` 가 자리표시자(`{{회사로고}}`)를 절대 URL 로 굳히던 저장 경로 수정 —
원본 주소를 보관해 그대로 돌려주고, 자리표시자는 요청조차 하지 않음
- 버튼 줌(ZOOMIN·ZOOMOUT)이 배율만 바꿔 도면이 화면 밖으로 밀리던 것을
화면 중심 고정으로 수정
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 상태막대 `명령행` 토글의 초기 상태를 `useState(true)` → `useState(false)` 로 변경
- 진입 시 `--cad-command-height` 가 `0px` 로 잡혀 캔버스 세로 공간 확보
- 토글 동작·명령행 구현 자체는 불변
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- screenCanvas.drawController.drawImage 가 worldToTarget 결과를 그대로 써서 그림이
거울상 자리(캔버스 밖)에 놓였음. 선·글자처럼 canvasSize.y - y 로 뒤집고 회전 부호도 반대로
- vitest 추가: 그림 중심의 뒤집힌 y 자리, 회전 부호·원상 복구
- 검증(공용 브라우저, 종단면도): 로고 상자 비배경 픽셀 0 → 14708(파랑 11661),
서명 상자 498 → 2810(빨강 852). 뷰는 187% 로 정확히 복귀
- B01 프로젝트 수정: 과업책임자·분야별책임자·설계자를 회사 구성원 목록(select)에서
지정. 회사 로고·설계자 서명 칸은 누르면 등록 목록 모달(선택·삭제·신규 추가 업로드).
- 백엔드: `company_assets`(013) CRUD 라우트 신설 — 목록·업로드(Form+File, 2MB·확장자
검사)·수정·소프트 삭제·파일 서빙. `_scope_company` 로 SYSTEM_ADMIN 만 타 회사 지정,
`_check_project_refs` 로 담당자·자산이 같은 회사·같은 종류인지 검사(400).
- projects 조회·수정에 pm/field_lead/designer/logo_asset/signature_asset 5칸 합류.
중복 3곳을 `_project_rows` 로 묶어 700줄 제한 유지.
- B07 표제란: 로고·서명 출처를 `companies.logo_path`/`users.signature_path` 에서
프로젝트가 고른 `company_assets` 로 전환(삭제된 자산은 그림째 제외).
- 검증: pytest 143 통과(신규 4), tsc·ruff·prettier 통과. 공용 브라우저 사용자 경로
(업로드→선택→저장→재열기) 및 종단도 API 표제란 글자 4건·그림 2건 수치 확인.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-02): 설계일자는 확정일 자동이 아니라 **사용자가 넣는다**. 도면번호는
Claude 판단으로 목록 순번을 쓴다.
설계일자
- `013_company_assets.sql` 로 `projects.design_date DATE` 추가(같은 마이그레이션에
로고·서명 공유 테이블 자리도 함께 만들었음 — 배선은 다음 커밋).
- B01 프로젝트 수정 모달에 날짜 칸. 공용 `createInputField` 가 `type="date"` 를 받게 넓힘.
- 표제란에는 도면 표기 관행대로 `2026. 09. 02.` 꼴로 적는다.
도면번호
- 단건 조회는 목록 순서를 모른다 — 알려면 횡단 장 계획을 다시 계산해야 하고 도면을 열
때마다 그러면 비싸다. **목록이 매긴 번호를 manifest 에 적어 두고** 단건 조회가 읽는다.
목록은 화면 진입 때 늘 먼저 뜨므로 성립하고, 목록이 바뀌면 다음 조회에서 다시 적힌다.
- `add_title_fields()` 신설 — 도면을 읽는 도중에 아는 값을 문맥에 얹는 창구.
검증: `pytest tmp/tests/ -q` 139 passed / 0 failed, 루트 `tsc --noEmit` 통과.
실사용자 경로(5174, wdw) — 대시보드 [수정] 모달 라벨 10개(설계일자 칸 추가 확인) →
`2026-09-02` 입력 → [확인] → 종단면도 표제란에 `2026. 09. 02.`.
도면번호는 목록 13건 기준 종단 1 · 유역도 6 · 용지도 13 이 도각에 그대로 실림
(표지는 도각을 두르지 않아 번호 칸이 없다).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표제란에 남아 있던 빈칸 중 연도·기번과 사업량은 프로그램이 지어낼 수 없는 값이라
입력 자리를 만든다. 값의 출처를 정하지 않고 받을 칸만 세운다.
DB (`012_title_block_inputs.sql`, ADD COLUMN·NULL 허용)
- `projects.project_number` — 표지 연도·기번(실무문서 폴더명 관행:
`2024년 간선임도(기번3-울진.대흥)`)
- `projects.work_amount` — 표지 사업량. 단위·표기가 사업 종류마다 달라 자유 문자열.
B01 프로젝트 수정
- 수정 모달에 시행청·연도기번·사업량 3칸 추가. 011 로 만든 시행청도 여기서 처음 입력
가능해짐(그전에는 스크립트로만 넣었음).
- 목록·단건 조회 4곳과 UPDATE 에 세 칸을 함께 실음. USER 권한은 다른 칸과 같이 잠금.
B07
- `_title_block_fields` 가 연도기번·사업량도 실어 보냄. 비어 있으면 종전대로 빈칸.
검증: `pytest tmp/tests/ -q` 139 passed / 0 failed(표지 값 1건 신규), 루트 `tsc --noEmit`
통과. 실사용자 경로 실측(5174) — 대시보드 wdw 행 [수정] 클릭 → 모달 라벨 9개에 새 3칸
확인 → 연도기번·사업량 입력 → [확인] 저장 → 표지 도면 Text 7개 **빈칸 0 · `{{` 잔존 0**,
화면에도 연도기번·`wdw 설계도`·위치·사업량·시행청이 모두 그려짐.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도면 7종이 도각만 두르는데도 경고를 냈음 — `build_blank_drawing()` 이 콘텐츠
bbox 로 작도 영역(`_A1_INNER`, 770×520mm)을 그대로 넘겼고, 검사 기준은 여백을 뺀
수용 한도(739×499mm)라 담을 내용이 없는데도 넘친 것으로 잡혔음.
- `usable_bbox()` 신설 — 작도 영역 한가운데의 수용 한도 크기 bbox. 중심이 같아
도각 배치(이동량 0)는 그대로.
- 한도와 **같은** 크기는 넘친 것이 아니므로 비교에 부동소수 여유(1e-6)를 둠.
한도를 그대로 넘기면 마지막 자리 오차로 경고가 났음.
검증: `pytest tmp/tests/ -q` 138 passed / 0 failed(경고 없음을 잠그는 1건 신규).
백엔드 재시작 뒤 화면 실측(5174, wdw): 빈 도면 7종 전부 200, 새 서버 로그의
"작도 영역을 넘습니다" **0건**.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
축척은 지어내는 값이 아니라 이미 정해져 있던 것 — `config_system` 의 도면별 축척
상수를 그대로 표제란에 싣는다. 도각이 `A1 = 1 :` 를 이미 찍으므로 **분모만** 낸다.
- `scale_fields()` 신설 — A3 는 A1 도면을 절반으로 뽑는 종이라 분모가 2배. 가로·세로가
다른 도면(종단·토적)은 이름표를 붙여 함께 적는다.
- 종단면도 `1000(H) · 200(V)` / 횡단면도 `100` / 유역도 `6000` / 토적도 `2000(H)`.
A3 는 각각 2배. 담을 내용이 없는 빈 도면·표지는 축척이 없어 빈칸 그대로.
검증: `pytest tmp/tests/ -q` 135 passed / 0 failed(축척 2건 신규 — 상수 유래·A3 2배,
호출부가 넘긴 값이 도각에 실림). 백엔드 재시작 뒤 화면 실측(5174, wdw): 종단
`1000(H) · 200(V)`/`2000(H) · 400(V)`, 횡단 `100`/`200`, 유역도 `6000`/`12000`,
토적도 `2000(H)`/`4000(H)`, 표준도 빈칸.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
도각의 로고·서명 자리에 흰 사각형이 남던 것 — `ImageEntity.draw()` 가 폴리곤 네 변을
선택·강조 여부와 무관하게 늘 그렸음. 출력·내보내기가 같은 `draw()` 를 다른
DrawController 로 타므로 화면만의 문제가 아니라 산출물에도 실렸음.
- 도각층만 특례로 두지 않고 `ImageEntity` 전체에서 뺌. 일반 CAD 관행대로 **집었을
때만**(강조·선택) 테두리를 보임 — 앞으로 붙일 그림(현황사진 등)에도 같은 규칙.
- 자리 표시가 필요하면 도각 편집 화면에서 집으면 보임.
검증: `ImageEntity.test.ts` 신규 2건 — 안 집은 그림은 `drawLine` 0회·`drawImage` 1회,
집은 그림은 4회·1회. `npx vitest run` 89 passed / 0 failed, check-types·build 통과.
화면 실측(5174, wdw 표준도): 두 슬롯 사각형 안 흰 픽셀(RGB>200) **0**,
그림 픽셀은 그대로(로고 56 · 서명 106).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-02) — 로고·서명을 임의로 만들어 표제란에 넣고, 위치·크기는
도각을 고치면 따라오게 하며, 시행청·과업책임자 등은 DB를 넓혀 채울 것.
도각(표제란)
- `00_template_A1.json` 에 그림 자리 2개 추가 — 회사 로고는 용역회사 칸 왼쪽
(316~348 × 20~36mm), 설계자 서명은 설계 칸 아래(638~680 × 17.5~25.5mm).
자리·크기가 **템플릿 좌표로만** 정해지므로 도각을 고치면 그대로 따라옴.
- `_fill_placeholders` 가 그림 자리(`imageData`)의 `{{키}}` 도 채움. 값을 못 구하면
빈 문자열을 남기지 않고 **엔티티째 제거** — 빈 값은 CAD 가 깨진 그림으로 그림.
- `_transform_entity` 가 `points` 배열도 옮김. 그림(로고·서명)과 띠(Hatch)가 이 키를
쓰는데 여태 변환 대상이 아니라 도각을 옮기면 제자리에 남았음.
DB (`011_title_block.sql`, 전부 ADD COLUMN·NULL 허용)
- `projects` — `client_org`(시행청), `pm_user_id`·`field_lead_user_id`·`designer_user_id`
- `companies.logo_path` · `users.signature_path` — 그림은 파일로 두고 경로만 담음
(기존 `storage_path`·`input_files` 와 같은 방식)
- FK 는 걸지 않음 — 사유를 파일 머리말에 적음(소프트 삭제·LEFT JOIN·4환경 공유).
배선
- `_title_block_fields` 가 시행청·과업책임자·분야별책임자·설계자(배정 없으면 소유자)와
로고·서명 data URL 까지 실어 보냄.
- `read_stored_asset()` 신설 — `storage/` 기준 상대 경로의 **파일**을 읽음.
`resolve_stored_project_path()` 는 폴더를 만드는 프로젝트 루트용이라 파일에 못 씀.
CAD 결함 1건 (이번 작업에서 드러남)
- `screenCanvas.drawController.drawImage` 가 `(width, height)` 를 좌표처럼 변환해
화면 오프셋과 y 뒤집기가 섞여 들어갔음 — 그림이 제 자리를 벗어나고 비율이 무너짐.
크기는 배율만 곱하고 자리는 세계 중심으로 잡도록 고침(SVG 컨트롤러와 같은 방식).
- 검증 창구 `__aisloCad.screen(x, y)` 추가 — 세계→화면 좌표. 그림·글자가 제 자리에
그려졌는지 픽셀로 판정할 때 씀.
검증: `pytest tmp/tests/ -q` 135 passed / 0 failed(그림 자리 3건 신규),
`npx vitest run` 87 passed / 0 failed, `check-types`·`build` 통과.
화면 실측(5174, wdw): 표준도 API Text 24개 `{{` 잔존 0, Image 2개가 도각 좌표
(316,20)-(348,36)·(638,18)-(680,26)에 실림. 캔버스 픽셀 판정 — 두 자리 모두 배경색
외 픽셀이 그려짐(로고 88px·서명 64px), 로고 파랑(20,70,140)이 슬롯 안에서만 검출.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
교차검증에서 표지만 빈칸으로 나갔음 — 문맥값을 합치는 자리가 `frame_entities` 안에
있어, 도각을 두르지 않는 표지 경로(`build_cover_drawing`)가 비껴갔음.
- 합치는 자리를 치환 함수 `_fill_placeholders` 한 곳으로 옮김. 도각을 쓰든 안 쓰든
`{{키}}` 를 치환하는 모든 경로가 같은 값을 받음 — 앞으로 생길 경로도 자동으로 닿음.
- 표지 docstring 의 "값 공급은 다음 판 몫" 문구 정정.
검증: `tmp/tests/test_b07_title_block_fields.py` 에 표지 케이스 추가(공사명·위치가
표지에 실리고 `{{` 잔존 0). `pytest tmp/tests/ -q` 132 passed / 0 failed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표제란(도각) 값 공급
- `use_title_fields()` 문맥 변수 신설 — 회사 도각 폴더와 같은 방식이라 작도 엔진
6개의 서명을 고치지 않음. `frame_entities` 가 문맥값 위에 호출부 값(도면명)을 얹음.
- 라우터가 도면 한 건을 그리기 전에 DB 값을 세움: 공사명·위치(projects),
용역회사(companies), 설계자(users). 못 채운 자리는 빈칸 — 도각 원본의 남의 값이
도면으로 나가지 않음.
- 미공급 항목과 사유를 `_title_block_fields` 주석에 명시: 시행청·과업책임자·
분야별책임자는 DB 칸 부재(B02 마이그레이션 대기), 축척·사업량·연도기번은 임의 수치
금지, 설계일자는 채울 시점 정의 미결.
CAD 회귀 6건 (87건 중 81 passed → 87 passed)
- `window` 부재 5건: `notifyWindow()` 한 곳으로 모으고 `window` 없는 Node 시험에서는
통지를 건너뜀. `triggerReactUpdate` 가 이미 같은 이유로 시험을 건너뛰던 것과 같은 결.
- `find-closest-entity`: 목의 호가 90°까지만 돌아 클릭점에서 147px 떨어져 있었음 —
시험 의도(호가 가장 가깝다)대로 3/4바퀴로 되돌림.
- 선색 기대값 4건: 앱 기본 선색이 흰 종이 배경에 맞춰 검정으로 바뀐 뒤 상류 기대값
`#fff` 가 남아 있었음 — `getActiveLineColor()` 대조로 교체.
- 좌표 NaN: 없어진 `TOOLBAR_WIDTH` 를 시험 보조가 아직 참조 — 입력 컨트롤러가 캔버스
bounding rect 를 쓰도록 바뀐 현행에 맞춤.
- 호 각도 비교: 같은 각의 음수·2π 표기 차이라 [0, 2π) 정규화 후 대조.
검증: `npx vitest run` 87 passed / 0 failed, `npm run check-types`·`npm run build` 통과,
`pytest tmp/tests/ -q` 131 passed / 0 failed(신규 `test_b07_title_block_fields.py` 4건 포함).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
파일마다 포맷 폭이 달라(≈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>
- `groupId` 를 도면 JSON 에 실어 [저장] 뒤 다시 연 도면에서도 묶음 유지.
엔티티 13종의 `toJson` 대신 직렬화 한 곳(export/import)에서 붙이고,
복원은 순번이 아니라 id 로 — `compact` 가 null 을 걷어 index 가 어긋남.
- `setScreenScale` 의 매 호출 `console.log` 제거 — 줌·팬마다 콘솔을 덮었음.
- 검증: `group-id-roundtrip.test.ts` 신규, `npx vitest run` 87건 중 81 passed,
실패 6건은 작업 전과 동일한 기존 결함. `npm run build` 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>