diff --git a/docs/PDF 도면 외벽선 자동작성 - 코드베이스 현황 분석.html b/docs/PDF 도면 외벽선 자동작성 - 코드베이스 현황 분석.html new file mode 100644 index 00000000..e0568d65 --- /dev/null +++ b/docs/PDF 도면 외벽선 자동작성 - 코드베이스 현황 분석.html @@ -0,0 +1,408 @@ + + +
+ + +배치면 초기설정 단계에서 PDF 도면을 업로드하면 AI(Gemini)가 외벽선을 추출해 캔버스에 그려주는 기능의 구현 현황
+ +요청하신 “PDF 도면 업로드 → AI 분석 → 외벽선 자동 그리기” 기능은 새로 만들 필요가 없습니다. 이미 완전히 구현되어 동작 중입니다.
+커밋 849f7a1d(2026-05-20)에서 Google Gemini 기반으로 전체 구현 → f8641079에서 일시 비활성화 → 현재 HEAD 0187b234에서 다시 활성화되어 있습니다.
+따라서 이번 작업의 실제 성격은 “신규 개발”이 아니라 “기존 구현의 검증 · 정합성 보완 · 품질 개선”입니다. 아래에서 구현 위치, 데이터 흐름, 그리고 보강이 필요한 갭/리스크를 정리합니다.
+gemini-3.1-pro-preview · @google/generative-ai ^0.24.1POST /api/gemini/floor-plan · 분석 후 파일 즉시 폐기QLine(outerLine) + QPolygon(WALL) 생성pdf.import.* / ...size.pdf.* 키usePdfImport 훅 + 배치면 초기설정 통합 + env/의존성/로케일. 총 12개 파일, +2137 라인.[클라이언트 · PlacementShapeSetting.jsx] + 배치면 초기설정 모달 열기 + │ + ▼ "도면 파일 업로드" 라디오 선택 (INPUT_MODE.PDF) + 파일 선택 handlePdfFileChange() # MIME=application/pdf, ≤20MB 검증 + │ + ▼ [저장] 버튼 → handleSaveBtn() → analyzePdfAndApply() + FormData(file, unitHint=mm, pageMode, facadePages?, floorPages?) + │ + ▼ POST +[서버 · /api/gemini/floor-plan/route.js] + ① MIME / 20MB 재검증 + ② GoogleAIFileManager.uploadFile() ──→ Gemini File API 업로드 + ③ waitForFileActive() # PROCESSING→ACTIVE, 60s 타임아웃 + ④ model.generateContent() # responseSchema 강제, temperature 0.1 + ⑤ validateOuterline() # 정점 3~500개, 면적≠0 검증 + ⑥ finally: deleteFile() # 성공/실패 무관 Gemini 파일 폐기 + │ + ▼ { outerline:[{x,y}…], unit:'mm', scale, confidence, notes } +[클라이언트 · usePdfImport.js] applyOuterline() + ⑦ toCanvasUnits() mm ÷ 10 → canvas unit + ⑧ 중복점 필터 인접거리 < 0.5 제거 + ⑨ fitAndCenter() 캔버스 60% / 최대 1500 내로 스케일 + 중앙정렬 + ⑩ ensureCounterClockwise() CCW 정규화 + ⑪ [기존 외벽선 존재 시] useSwal confirm "덮어쓰시겠습니까?" + ⑫ clearExistingCanvasState() → setOuterLinePoints() (Recoil) + ⑬ drawOuterLines() QLine(name='outerLine') 생성 + ⑭ addPolygonByLines() QPolygon(name=WALL) 생성 + ⑮ canvas.renderAll() + │ + ▼ roofSizeSet='1'(복시도)로 저장 → setSelectedMenu('outline') + 외벽선 메뉴로 자동 전환 (수동 입력 흐름과 동일 지점에 합류)+
POST 단일 핸들러)gemini-3.1-pro-preview (L9), 20MB (L7), 최대 500 정점 (L8).responseMimeType: 'application/json' + responseSchema(FLOOR_PLAN_SCHEMA, L11-31) + temperature: 0.1 (L156-160).validateOuterline() (L64-93) — 배열/정점수/숫자형/면적≠0(|area|<1 거부, L89). 빈 배열은 “평면도 아님”으로 정상 처리.finally에서 deleteFile()로 업로드 PDF 폐기 (L202-208) — 계획서 요구사항 “분석 후 폐기” 충족.process.env.GEMINI_API_KEY 직접 사용 (서버 전용, 클라이언트 미노출).MM_PER_CANVAS_UNIT = 10 (L11), MAX_DIM = 1500 (L12), MIN_CANVAS_UNIT_LENGTH = 0.5 (L13).toCanvasUnits(mm/10) → 중복점 필터 → fitAndCenter(화면 60% 맞춤·중앙정렬, L32-58) → ensureCounterClockwise(L27-30).drawOuterLines(L89-102)가 점 배열을 순회하며 QLine(stroke #000, width 3, name:'outerLine', idx) 생성 → canvas.add.addPolygonByLines(lines, { name: POLYGON_TYPE.WALL })로 WALL 폴리곤 생성(L148).clearExistingCanvasState로 관련 객체 정리.applyOuterline(mmPoints, { unit }), hasExistingOuterLine() 노출.INPUT_MODE = { SIZE_ROOF:'1', SIZE_ACTUAL:'2', PDF:'pdf' } (L34-38). 라디오 배열에 ra-pdf 항목 추가(L107-111).roofSizeSet은 ‘1’(복시도)로 저장(L113-121) → 저장 후 외벽선 메뉴로 자동 합류(L427-429).handlePdfFileChange(L128-142) — MIME/20MB 클라이언트 가드.analyzePdfAndApply(L144-198) — fetch → 에러/빈응답 분기 → applyOuterline 호출.package.json L23 — @google/generative-ai: ^0.24.1.GEMINI_API_KEY, GEMINI_MODEL — .env.development / .env.local.dev / .env.localhost / .env.production 4개 파일 모두 존재. (값은 본 리포트에 미기재)ko.json(L19-45) / ja.json 각 30개 메시지 — pdf.import.*(동작/에러) + modal.placement.initial.setting.size.pdf.*(UI 라벨/안내).구현 과정에서 초기 계획(docs/…구현 계획.md)과 달라진 설계 결정들입니다. 대부분 더 나은 통합 방향으로 수렴했습니다.
+| 항목 | 계획서 | 실제 구현 (HEAD) | 평가 |
|---|---|---|---|
| UI 진입점 | floor-plan 상단 툴바 + 신규 PDF 아이콘 | 배치면 초기설정 모달의 치수 입력방법 라디오 옵션 | 변경 기존 흐름과 자연스럽게 통합 |
| 업로드 모달 | 별도 PdfImportModal.jsx (상태머신) | 없음 — PlacementShapeSetting에 통합 | 변경 모달 중첩 회피 |
| 메뉴 등록 | menuAtom에 pdf-import 항목 | 미등록 (툴바 방식 폐기로 불필요) | 정합 |
| 페이지 지정 | (없음) | 전체/지정 + 입면도·평면도 페이지 입력 | 추가 분석 속도·정확도 개선 |
| config 매핑 | config.*.js에 GEMINI 추가 | 미적용 — route가 process.env 직접 사용 | 상이 아래 리스크 R3 참조 |
| 자기교차 검증 | turf 로 self-intersection 검출 | 미구현 — 정점수·면적만 검증, 나머지는 프롬프트+CCW 의존 | 미구현 리스크 R2 |
| 거대 폴리곤 | Douglas–Peucker 단순화 or 거부 | 500 정점 초과 시 거부만 (단순화 없음) | 미구현 |
| 파일 폐기 | finally에서 삭제 보장 | 동일 구현 | 정합 |
기능은 동작하지만, “외벽선을 도면 그대로 정확히” 재현하려는 목표 관점에서 다음 항목들의 검증/보완을 권장합니다.
+ +fitAndCenter()가 외벽선을 캔버스 60%(≈840 canvas unit, 약 8.4m)에 맞춰 추가 스케일링합니다. 도면이 그보다 크면 scale < 1이 곱해져 실제 치수 ↔ 캔버스 길이 정합이 깨집니다. 수동 입력 흐름은 실측/10을 그대로 좌표로 쓰므로, PDF 경로만 길이가 달라질 위험이 있습니다.
권장: 일반 주택(외곽 8.4m 초과 흔함) 기준으로 실측 비율을 보존하는 변환으로 재검토. 화면 맞춤이 필요하면 좌표 자체가 아니라 canvas viewport zoom/pan으로 처리하거나, 그리드 축척과 동일한 mm/unit 비율을 강제할 것.
+서버 validateOuterline()은 정점수·면적만 본다. 자기교차는 Gemini 프롬프트 지침과 CCW 정규화에만 의존한다. 꼬인 폴리곤이 들어오면 QPolygon의 sortedPointLessEightPoint 정렬과 충돌해 형상이 깨질 수 있다.
권장: 계획서대로 turf(또는 경량 segment-intersection)로 서버/클라이언트에서 자기교차 거부. SizeSetting의 0-area 가드 정신과 일관되게 처리.
로케일 …pdf.file.info는 “외벽선과 지붕형상이 함께 생성”된다고 안내하지만, usePdfImport는 외벽선(QLine) + WALL 폴리곤까지만 만든다. 수동 흐름의 ccwCheck → RoofShapeSetting 자동 오픈 → drawRoofPolygon 단계가 PDF 경로에선 호출되지 않아 지붕면은 수동 작성이 필요하다.
권장: ①요청 목표(외벽선 그리기)만 보면 충족이므로 문구를 동작에 맞게 정정하거나, ②PDF 적용 후 기존 useRoofShapeSetting 자산을 재사용해 지붕 자동화를 확장. (요청 범위 명확화 필요)
CLAUDE.md는 “feature code에서 env 직접 읽지 말고 src/config에서 import”를 규정한다. route는 process.env를 직접 읽는다. 다만 서버 시크릿은 클라이언트 config로 노출하면 안 되므로 서버 라우트에서의 직접 사용은 정당화 가능한 회색지대다.
권장: 현행 유지 가능. 일관성을 원하면 서버 전용 config 헬퍼로 묶되 클라이언트 번들 유입이 없도록 주의.
+프로젝트에 테스트 러너가 없고(CLAUDE.md), Gemini 출력은 비결정적이다. 회귀 검증은 수동 의존. 분석 소요(최대 60s 타임아웃)에 비해 진행률 UX가 약하다.
+권장: 좌표 변환부(toCanvasUnits/fitAndCenter/ensureCounterClockwise)는 순수 함수이므로 단위 테스트로 분리 검증 가능. 분석 중 스피너/단계 표시 추가 검토.
| 경로 | 구분 | 역할 / 핵심 라인 |
|---|---|---|
| src/app/api/gemini/floor-plan/route.js | 신규 | Gemini 분석 서버 라우트 · POST(L111) · validate(L64) · finally 폐기(L202) |
| src/hooks/pdf-import/usePdfImport.js | 신규 | 좌표 변환·캔버스 반영 · applyOuterline(L104) · drawOuterLines(L89) |
| src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx | 수정 | UI 통합 · INPUT_MODE(L34) · analyzePdfAndApply(L144) · UI(L486-591) |
| package.json | 수정 | @google/generative-ai ^0.24.1 (L23) |
| .env.{development,local.dev,localhost,production} | 수정 | GEMINI_API_KEY · GEMINI_MODEL |
| src/locales/ko.json · ja.json | 수정 | pdf.import.* / …size.pdf.* (각 30개) |
| docs/PDF Gemini 평면도 분석 기능 구현 계획.md / .html | 문서 | 초기 설계 문서 (2026-05-18) |
“새 기능 개발”이 아니라 기존 구현의 검증·보완으로 방향을 잡는 것을 권합니다. 우선순위 순:
+fitAndCenter 스케일 전략부터 재설계.yarn lint)에 맞춰 마무리.실제 코드 보완에 착수하기 전, 위 R1·R3는 제품 의사결정이 필요하므로 먼저 합의하는 것을 권합니다. 합의되면 brainstorming → 구현 → 검증 순으로 진행하겠습니다.
+ + + +