No updates detected yet. GitHub releases will appear here.
Loading the full README. The saved excerpt is shown below.
건물 옥상에 태양광 모듈 배치를 설계하고 발전 시뮬레이션 입력을 받는 웹 애플리케이션입니다. Google Maps 위성 이미지에서 대상 영역을 크롭하고, 크롭 팝업의 캔버스 에디터에서 지붕 면과 개구부를 그리면 자동으로 최적 배치를 계산합니다. 일본어/영어 인터페이스를 지원합니다.Read the full README ↗
건물 옥상에 태양광 모듈 배치를 설계하고 발전 시뮬레이션 입력을 받는 웹 애플리케이션입니다. Google Maps 위성 이미지에서 대상 영역을 크롭하고, 크롭 팝업의 캔버스 에디터에서 지붕 면과 개구부를 그리면 자동으로 최적 배치를 계산합니다. 일본어/영어 인터페이스를 지원합니다.
html2canvas) → 크롭 팝업 진입select 선택/이동, drawRoof 지붕면, drawOpening 개구부(제외 영역), flowSetting 처마(흐름방향), mergeSelected 지붕면 병합, editRoof 꼭짓점 편집, deleteSelected, deleteAll, undoflowSetting으로 지정한 처마 변(eave)에 평행하도록 그리드 정렬<html lang> 속성 자동 동기화| 기술 | 버전 | 용도 |
|---|---|---|
| Next.js | 16.2.0 | App Router, output: "standalone", React Compiler 활성화 |
| React | 19.2.4 | React Compiler |
| TypeScript | ^5 | strict mode |
| Tailwind CSS | v4 | @tailwindcss/postcss (CSS 커스텀 프로퍼티 기반) |
| @vis.gl/react-google-maps | ^1.7.1 | Google Maps 통합 |
| html2canvas | ^1.4.1 | 지도 영역 캡처 |
| lucide-react | ^0.577.0 | 아이콘 |
| polygon-clipping | ^0.15.7 | 지붕면 병합용 폴리곤 boolean 연산 (union / intersection) |
| OpenRouter API | — | 지붕 자동 감지 추론 (Chat Completions). 전용 SDK 없이 fetch 로 직접 호출 |
| zod | ^4.3.6 | AI 응답·요청 스키마 검증 (최종 SSOT) |
| babel-plugin-react-compiler | 1.0.0 | React Compiler |
| ESLint | ^9 | flat config (eslint-config-next) |
pnpm install
.env.local 파일에 Google Maps API 키를 설정합니다:
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your_api_key_here
OPENROUTER_API_KEY=your_openrouter_api_key_here
OPENROUTER_MODEL=openai/gpt-5.6-sol
QSP/MUSBI BFF API(모듈 목록 조회 등)와 API 문서(/reference)를 로컬에서 호출하려면 dev 전용 키(QSP_API_HOST, MUSBI_API_HOST, ENABLE_API_DOCS)도 필요합니다. 이 키들은 .env.dev에 있지만 next dev는 .env.dev 파일명을 자동 로드하지 않습니다 — Next.js가 자동 로드하는 파일은 .env · .env.local · .env.development 등으로 한정되며, .env.dev/.env.prod는 배포 시 Jenkins가 .env로 병합하는 용도입니다. 따라서 로컬에서는 .env.dev를 .env.local로 복사해 사용합니다:
cp .env.dev .env.local # 기존 .env.local 이 있으면 append: cat .env.dev >> .env.local
.env.local은.gitignore대상이라 커밋되지 않습니다.- env 파일은 서버 시작 시점에만 로드되므로, 복사 후
pnpm dev를 재시작해야 적용됩니다.
개발 서버 실행:
pnpm dev
http://localhost:3000에서 확인합니다.
pnpm build # next build (standalone output)
pnpm start # 프로덕션 서버
pnpm lint # ESLint
npx tsc --noEmit # 타입 체크
.env 파일에 API 키를 설정한 후:
docker compose up --build # 빌드 및 실행
docker compose up --build -d # 백그라운드
docker compose down # 중지
단독 빌드:
docker build --build-arg NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your_api_key_here -t solar-pv-system .
docker run -p 3000:3000 \
-e OPENROUTER_API_KEY=your_openrouter_api_key_here \
-e OPENROUTER_MODEL=openai/gpt-5.6-sol \
solar-pv-system
좌측 사이드바(설계/시뮬레이션 탭)와 우측 Google Maps 메인 영역으로 구성된 SPA입니다. 크롭 후에는 메인 영역 위에 CropPopup(폴리곤 편집/패널 배치 캔버스)이 오버레이됩니다.
src/app/
├── components/
│ ├── AiDetectControls.tsx # AI 지붕 분석 트리거 (분석 시작/취소, prod 프로파일에서는 미렌더)
│ ├── CropPopup.tsx # 크롭 이미지 위 캔버스 폴리곤 에디터 + 패널 렌더링
│ ├── MapView.tsx # Google Maps + 크롭 영역 선택 오버레이 (html2canvas 캡처)
│ ├── RoofEditToolbar.tsx # 지붕 편집 툴바 (지도 위 플로팅)
│ └── lnb/ # 좌측 사이드바 (Lnb / LnbDesign / LnbSim / address-input-lnb)
├── utils/
│ ├── i18n.ts # 일/영 번역 사전 + `t(key, lang)` 함수
│ ├── mergePolygons.ts # 지붕면 병합 (인접 판정 + 폴리곤 union)
│ └── panelPlacement.ts # 좌표 변환 및 패널 배치 계산 엔진
├── types/index.ts # 도메인 타입
├── globals.css # CSS 커스텀 프로퍼티 테마
├── layout.tsx # 루트 레이아웃 (Server Component)
└── page.tsx # 메인 페이지 (Client Component, 전역 상태 소유)
page.tsx가 모든 상태(언어, 탭, 크롭 데이터, 폴리곤 영역, 픽셀 영역, 배치된 패널, 시뮬레이션 입력 등)를 소유하고 자식 컴포넌트에 props로 전달하는 Props-Down / Callbacks-Up 패턴을 사용합니다. RoofEditToolbar의 활성 도구에서 CropPopup의 drawingMode(install/exclude/null)를 파생합니다.
utils/panelPlacement.ts)세 가지 진입점을 제공합니다:
| 함수 | 좌표계 | 단위 | 호출 위치 |
|---|---|---|---|
placePanels | lat/lng | mm | 지도 직접 배치 (크롭 미사용 경로) |
placePanelsOnCanvas | 픽셀 | mm | 내부 구현 |
placePanelsOnCanvasCm | 픽셀 | cm | UI 진입점 (크롭 팝업) |
공통 처리 단계:
metersPerPixel 스케일) 변환MARGIN_CM만큼 설치 폴리곤은 내부로 축소, 제외(개구) 폴리곤은 바깥으로 확장(개구 주변 이격)eaveEdgeIndex) 또는 폴리곤의 가장 긴 변을 기준축으로 그리드 생성page.tsx는 패널 긴 변을 처마와 평행하게(landscape 고정) 호출하며, 경사(寸)를 cos 투영 보정해 전달합니다. 배치 엔진은 처마선 기준으로 x·y 시작 위상을 스캔해 가장 많이 채워지는 결과를 채택하고, 오목 폴리곤·장애물은 패널 변 교차 검사로 제외합니다.
page.tsx에 고정값으로 선언되어 있습니다 (UI 입력 아님):
| 상수 | 값 | 의미 |
|---|---|---|
GAP_X_CM | 0.3 | 모듈 좌우 간격 (3 mm, 처마 평행) |
GAP_Y_CM | 3 | 모듈 상하 간격 (30 mm, 처마 수직) |
MARGIN_CM | 30 | 외주 여백 (300 mm) |
globals.css의 CSS 커스텀 프로퍼티(--bg-primary, --accent-blue, --radius-md 등)를 인라인 스타일로 적용합니다. Tailwind 유틸리티 클래스는 사용하지 않습니다.
This is the beginning of the README. Read the rest at the original. Read the full README ↗