finally 에서 await fileManager.deleteFile(...) 가 catch 의 return 을 게이팅해,
정리용 네트워크 호출이 행되면 500 응답조차 클라이언트로 송신되지 않던 문제를 해소한다.
- deleteFile 을 await 하지 않고 fire-and-forget + .catch 로 분리해 응답을 정리 완료에 묶지 않음
- 상주 Node 서버(PM2 next start)이므로 응답 후에도 detached 삭제가 정상 완료되며,
미삭제 시에도 Gemini 측에서 자동 만료
- 클라이언트 120s 타임아웃과 짝을 이뤄 한쪽이 행되어도 스피너에 갇히지 않음
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PDF 분석 요청 실패/행(hang) 시 전역 스피너가 영구히 멈춰 화면 복귀가
불가능하던 문제를 해소한다.
- 네트워크 구간을 try/finally 로 감싸 성공·실패·타임아웃 어떤 경로든
스피너(pdfAnalyzing·isGlobalLoading)를 반드시 해제하도록 보장
- AbortController + 120s 타임아웃으로 무한 행 차단
- alert 은 스피너 해제 후 표시(스피너 z-index 가 alert 보다 높아 가려지는 것 방지)
- pdf.import.error.timeout 메시지 키 추가(ko/ja)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- analyzePdfAndApply에서 confidence < 0.6이면 반영 전 useSwal confirm으로 사용자 확인
- pdf.import.confirm.low.confidence 메시지 키 ko/ja 추가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit introduces a new HTML document detailing the functionality of the PDF 도면 to 외벽선 자동작성 feature, including styles and layout for improved presentation.
2026-05-29 18:24:04 +09:00
6 changed files with 525 additions and 30 deletions
<p>요청하신 <strong>“PDF 도면 업로드 → AI 분석 → 외벽선 자동 그리기”</strong> 기능은 <strong>새로 만들 필요가 없습니다.</strong> 이미 <strong>완전히 구현되어 동작 중</strong>입니다.</p>
<p>커밋 <spanclass="hash">849f7a1d</span>(2026-05-20)에서 Google <strong>Gemini</strong> 기반으로 전체 구현 → <spanclass="hash">f8641079</span>에서 일시 비활성화 → 현재 HEAD <spanclass="hash">0187b234</span>에서 <strong>다시 활성화</strong>되어 있습니다.</p>
<p>따라서 이번 작업의 실제 성격은 <strong>“신규 개발”이 아니라 “기존 구현의 검증 · 정합성 보완 · 품질 개선”</strong>입니다. 아래에서 구현 위치, 데이터 흐름, 그리고 보강이 필요한 갭/리스크를 정리합니다.</p>
<li><b>환경변수</b>: <code>GEMINI_API_KEY</code>, <code>GEMINI_MODEL</code> — <code>.env.development / .env.local.dev / .env.localhost / .env.production</code> 4개 파일 모두 존재. <spanstyle="color:var(--muted)">(값은 본 리포트에 미기재)</span></li>
<li><b>로케일</b>: <code>ko.json</code>(L19-45) / <code>ja.json</code> 각 30개 메시지 — <code>pdf.import.*</code>(동작/에러) + <code>modal.placement.initial.setting.size.pdf.*</code>(UI 라벨/안내).</li>
</ul>
<!-- ================= 5. 계획 대비 실제 ================= -->
<h2><spanclass="num">05</span>계획서 대비 실제 구현 차이</h2>
<p>구현 과정에서 초기 계획(<spanclass="path">docs/…구현 계획.md</span>)과 달라진 설계 결정들입니다. 대부분 <b>더 나은 통합 방향</b>으로 수렴했습니다.</p>
<tr><td>UI 진입점</td><td>floor-plan 상단 툴바 + 신규 PDF 아이콘</td><td>배치면 초기설정 모달의 치수 입력방법 라디오 옵션</td><td><spanclass="tag diff">변경</span> 기존 흐름과 자연스럽게 통합</td></tr>
<p>기능은 동작하지만, “외벽선을 도면 그대로 정확히” 재현하려는 목표 관점에서 다음 항목들의 검증/보완을 권장합니다.</p>
<divclass="risk high">
<h4>R1 · 실측 치수가 캔버스에 보존되지 않을 수 있음<spanclass="sev high">HIGH</span></h4>
<p><code>fitAndCenter()</code>가 외벽선을 <b>캔버스 60%(≈840 canvas unit, 약 8.4m)에 맞춰 추가 스케일링</b>합니다. 도면이 그보다 크면 <code>scale < 1</code>이 곱해져 <b>실제 치수 ↔ 캔버스 길이 정합이 깨집니다.</b> 수동 입력 흐름은 <code>실측/10</code>을 그대로 좌표로 쓰므로, PDF 경로만 길이가 달라질 위험이 있습니다.</p>
<pclass="fix"><b>권장:</b> 일반 주택(외곽 8.4m 초과 흔함) 기준으로 <b>실측 비율을 보존하는 변환</b>으로 재검토. 화면 맞춤이 필요하면 좌표 자체가 아니라 canvas <b>viewport zoom/pan</b>으로 처리하거나, 그리드 축척과 동일한 mm/unit 비율을 강제할 것.</p>
</div>
<divclass="risk mid">
<h4>R2 · 자기교차(self-intersection) 폴리곤 통과 가능<spanclass="sev mid">MID</span></h4>
<h4>R3 · 지붕면(ROOF) 자동 생성 부재 — 안내 문구와 동작 갭<spanclass="sev mid">MID</span></h4>
<p>로케일 <code>…pdf.file.info</code>는 “외벽선과 <b>지붕형상</b>이 함께 생성”된다고 안내하지만, <code>usePdfImport</code>는 <b>외벽선(QLine) + WALL 폴리곤</b>까지만 만든다. 수동 흐름의 <code>ccwCheck → RoofShapeSetting 자동 오픈 → drawRoofPolygon</code> 단계가 PDF 경로에선 호출되지 않아 <b>지붕면은 수동 작성</b>이 필요하다.</p>
<pclass="fix"><b>권장:</b> ①요청 목표(외벽선 그리기)만 보면 충족이므로 문구를 동작에 맞게 정정하거나, ②PDF 적용 후 기존 <code>useRoofShapeSetting</code> 자산을 재사용해 지붕 자동화를 확장. (요청 범위 명확화 필요)</p>
<p>CLAUDE.md는 “feature code에서 env 직접 읽지 말고 <code>src/config</code>에서 import”를 규정한다. route는 <code>process.env</code>를 직접 읽는다. <b>다만 서버 시크릿은 클라이언트 config로 노출하면 안 되므로</b> 서버 라우트에서의 직접 사용은 정당화 가능한 회색지대다.</p>
<pclass="fix"><b>권장:</b> 현행 유지 가능. 일관성을 원하면 서버 전용 config 헬퍼로 묶되 클라이언트 번들 유입이 없도록 주의.</p>
</div>
<divclass="risk low">
<h4>R5 · 비결정적 분석 · 검증 자동화 부재<spanclass="sev low">LOW</span></h4>
<p>프로젝트에 테스트 러너가 없고(CLAUDE.md), Gemini 출력은 비결정적이다. 회귀 검증은 수동 의존. 분석 소요(최대 60s 타임아웃)에 비해 진행률 UX가 약하다.</p>
<pclass="fix"><b>권장:</b> 좌표 변환부(<code>toCanvasUnits</code>/<code>fitAndCenter</code>/<code>ensureCounterClockwise</code>)는 순수 함수이므로 <b>단위 테스트로 분리 검증</b> 가능. 분석 중 스피너/단계 표시 추가 검토.</p>
</div>
<!-- ================= 7. 파일 인벤토리 ================= -->
<h2><spanclass="num">07</span>파일 인벤토리</h2>
<tableclass="file-list">
<thead><tr><thstyle="width:46%">경로</th><thstyle="width:14%">구분</th><th>역할 / 핵심 라인</th></tr></thead>
<tbody>
<tr><td>src/app/api/gemini/floor-plan/route.js</td><td><spanclass="tag done">신규</span></td><td>Gemini 분석 서버 라우트 · POST(L111) · validate(L64) · finally 폐기(L202)</td></tr>
<!-- ================= 8. 다음 단계 제안 ================= -->
<h2><spanclass="num">08</span>다음 단계 제안</h2>
<p>“새 기능 개발”이 아니라 <b>기존 구현의 검증·보완</b>으로 방향을 잡는 것을 권합니다. 우선순위 순:</p>
<ulclass="clean">
<li><b>1. 실측 정합성 검증 (R1)</b> — 실제 PDF 한두 건으로 “도면 치수 vs 캔버스 외벽선 길이”를 측정. 어긋나면 <code>fitAndCenter</code> 스케일 전략부터 재설계.</li>
<li><b>2. 요구 범위 확정 (R3)</b> — “외벽선만”인지 “지붕면까지”인지 결정. 결정에 따라 안내 문구 정정 또는 지붕 자동화 확장.</li>
<li><b>3. 자기교차/단순화 가드 (R2)</b> — 꼬인 폴리곤·과다 정점에 대한 방어 추가.</li>
<li><b>4. 좌표 변환 단위 테스트</b> — 순수 함수부를 분리해 회귀 안전망 마련.</li>
<li><b>5. lint/build 점검</b> — 보완 작업 시 CLAUDE.md 규약(no-semicolon, single-quote, <code>yarn lint</code>)에 맞춰 마무리.</li>
</ul>
<pstyle="color:var(--muted);font-size:13.5px;">실제 코드 보완에 착수하기 전, 위 R1·R3는 제품 의사결정이 필요하므로 먼저 합의하는 것을 권합니다. 합의되면 brainstorming → 구현 → 검증 순으로 진행하겠습니다.</p>
<footer>
생성: Claude Code · 코드베이스 정적 분석 기반 (Gemini 실호출/런타임 검증은 미포함) · 라인 번호는 분석 시점(HEAD <spanclass="hash">0187b234</span>) 기준<br/>
저장 위치: <spanclass="path">docs/PDF 도면 외벽선 자동작성 - 코드베이스 현황 분석.html</span>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.