O
Osolar InsightSPEC
요구사항 명세 · 테스트케이스

지도 기반 무상 발전량 시뮬레이션

대상 구현물: screen_01_main_simulation_v2.html — Google Maps JavaScript API(위성지도 · Places 주소검색 · DrawingManager 폴리곤) 기반 간이 발전량/수익 시뮬레이터. 본 문서는 실제 구현 동작을 기준으로 한 요구사항과 검증용 테스트케이스를 정의한다.

버전 v2 퍼널 1단계 · 탐색(Explore) 비로그인 Byteworx DS v1.0.4
1

개요 & 범위

무엇을, 어디까지 검증하는가

항목내용
목적발전소 오너가 로그인 없이 위성지도에서 패널 영역을 그려, 예상 설비용량·연간 발전량·수익을 즉시 확인하고 회원가입(2단계)으로 전환하도록 유도.
범위(In)API 키 처리 · 지도 초기화 · 주소 자동완성 검색 · 폴리곤 그리기/편집 · 면적→지표 산출 · FIT 단가 반영 · 진행 스텝 표시 · 결과 포맷팅 · CTA.
범위 외(Out)3D 음영(SPA) 분석, NEDO 실시간 일사량 API, 실측 비교(2단계), 인버터 연동(3단계), 회원가입/결제 백엔드, 서버 저장.
가정유효한 Google Maps API 키 존재(Maps JavaScript API + Places API 활성화). 산출은 단일 상수 기반 간이 모델이며 정밀 시뮬레이션 아님.
2

산출 모델 정의

테스트의 기대값 계산 근거 (코드 상수와 일치)

패킹 계수
0.77
패널 단위면적
2.0 ㎡/장
패널 출력
0.4 kW(400W)
연 일사량
1,150 kWh/kW
면적(㎡) = google.maps.geometry.spherical.computeArea(path)
패널수(장) = floor( 면적 × 0.77 ÷ 2.0 )
용량(kW) = 패널수 × 0.4
발전량(kWh/년) = 용량 × 1,150
수익(¥/년) = round( 발전량 × FIT단가 )
25년 누적 = round( 수익 × 25 ÷ 1e6 × 10 ) ÷ 10 → "○○.○M"
ℹ️

기준 예시 — 면적 1,000㎡, FIT ¥18 ⇒ 패널 385장, 용량 154kW, 발전량 177,100kWh/년, 수익 ¥3,187,800/년, 25년 누적 79.7M.

3

기능 요구사항 (FR)

우선순위: MUST SHOULD COULD

ID요구사항우선순위
FR-01API 키 우선순위 — 키는 ?key= 쿼리 > localStorage(gmaps_key) > 내장 DEFAULT_KEY 순으로 해석한다. ?key= 사용 시 localStorage에 저장.MUST
FR-02키 부재 처리 — 해석된 키가 없으면 지도를 로드하지 않고 키 입력 오버레이를 표시한다. (내장 기본키 존재 시 미발생)SHOULD
FR-03인증 실패 처리 — 키가 무효하거나 API 미활성화면 gm_authFailure 훅이 작동해 오류 배너를 노출하고 키 배지를 "키 오류"로 바꾼다.MUST
FR-04지도 초기화hybrid(위성+라벨), 중심 千葉 山武(35.6074, 140.4087), zoom 18, gestureHandling:greedy, 스트리트뷰/전체화면 컨트롤 비활성.MUST
FR-05주소 자동완성 — Places Autocomplete(일본 country:jp 제한). 후보 선택 시 viewport에 맞춰 이동(없으면 center+zoom 19). 스텝을 ‘주소완료’로 전환하고 그리기 버튼 활성화.MUST
FR-06폴리곤 그리기 — ‘영역 그리기’ 클릭 시 DrawingManager가 폴리곤 모드 진입. 모서리 클릭으로 작성, 닫으면 모드 해제.MUST
FR-07단일 폴리곤 보장 — 새 폴리곤 완성 또는 재그리기 시작 시 기존 폴리곤은 제거되어 항상 1개만 유지된다.MUST
FR-08꼭짓점 편집 반영 — 폴리곤은 editable. 꼭짓점 추가/이동/삭제(set_at/insert_at/remove_at) 시 면적·지표가 실시간 재계산된다.MUST
FR-09지표 산출 — 면적→패널수→용량→발전량→수익을 2절 공식대로 계산해 결과 카드에 표시한다.MUST
FR-10FIT 단가 반영 — FIT 입력값 변경 시 수익과 25년 누적이 즉시 갱신된다. 빈값/비숫자는 0으로 처리.MUST
FR-11초기화 — ‘초기화’ 클릭 시 폴리곤 제거, 결과값 ‘—’ 리셋, 스텝 ‘주소’로 복귀, 안내 힌트 재표시.SHOULD
FR-12진행 스텝 — 주소 → 영역 그리기 → 결과 3단계 인디케이터가 상태에 따라 done/cur/todo로 전환된다.SHOULD
FR-13숫자 포맷 — 모든 수치는 천단위 콤마(toLocaleString), 용량은 소수 1자리, 수익은 ¥ 접두.COULD
FR-14전환 CTA — ‘내 발전소로 등록하고 실측 비교하기’ 버튼으로 2단계(회원가입) 유도. 상단 ‘홈/대시보드/솔루션’ 내비 제공.SHOULD
4

비기능 요구사항 (NFR)

품질 속성

ID요구사항분류
NFR-01보안 — API 키는 Google Cloud에서 HTTP 리퍼러(osolar-insight.pier.bworx.io/*) 및 API 범위 제한을 적용한다. 내장 키 노출 위험을 문서화.Security
NFR-02프라이버시 — 사용자 입력 키는 브라우저 localStorage에만 저장하며 서버로 전송하지 않는다.Privacy
NFR-03성능 — Maps 스크립트는 async 비동기 로드. 꼭짓점 드래그 중 재계산이 지연 없이(60fps 체감) 반영.Perf
NFR-04디자인 일관성 — Byteworx DS v1.0.4 시맨틱 토큰·Pretendard·컴포넌트 규약 준수(하드코딩 색 최소화).Design
NFR-05견고성 — Maps 스크립트 로드 실패(onerror) 시 오류 배너로 사용자에게 안내한다.Robust
NFR-06호환성 — 최신 Chrome/Edge/Safari/Firefox 데스크탑에서 동작. (모바일 레이아웃은 향후 과제)Compat
5

테스트케이스 (TC)

전제조건 · 절차 · 기대결과 · 연결 요구사항

A. API 키 & 인증

TC절차기대결과FR
TC-A1localStorage·쿼리 없이 페이지 접속내장 DEFAULT_KEY로 지도 정상 로드. 키 배지 "Maps 연결됨"(녹색).FR-01
TC-A2?key=AIza...유효 붙여 접속해당 키로 로드, localStorage에 저장됨(이후 쿼리 없이도 유지).FR-01
TC-A3?key=INVALID 로 접속지도 인증 실패 → 오류 배너 노출, 배지 "키 오류". (gm_authFailure)FR-03
TC-A4DevTools에서 localStorage 비우고 DEFAULT_KEY를 공란으로 가정 후 접속지도 미로드, 키 입력 오버레이 표시. 키 입력+‘지도 시작’ 시 저장 후 로드.FR-02
TC-A5네트워크 차단 상태에서 접속(스크립트 로드 실패)"스크립트를 불러오지 못했습니다" 오류 배너 표시.NFR-05
TC-A6상단 ‘키 변경’ 클릭localStorage 키 삭제 후 새로고침 → 기본키로 복귀. (주의: 임의 키로 교체가 아닌 기본키 리셋 — 알려진 제약)FR-01

B. 지도 & 주소 검색

TC절차기대결과FR
TC-B1지도 로드 직후 상태 확인위성(hybrid) 뷰, 千葉 山武 중심, zoom 18. 검색창 활성화, 그리기 버튼 활성.FR-04
TC-B2검색창에 千葉県山武市 입력일본 주소 자동완성 후보 표시(최소 1건).FR-05
TC-B3자동완성 후보 선택지도가 해당 위치로 이동/확대. 스텝1(주소) ✓ 처리, 스텝2(그리기) 활성.FR-05·FR-12
TC-B4존재하지 않는 문자열 입력(예: asdfqwer)후보 없음. 지도 이동 없음, 오류 없음.FR-05
TC-B5비-일본 주소(예: Seoul) 입력country:jp 제한으로 후보 미표시(또는 일본 내 결과만).FR-05

C. 폴리곤 그리기 & 편집

TC절차기대결과FR
TC-C1‘영역 그리기’ 클릭 → 모서리 4점 클릭 후 닫기파란 반투명 폴리곤 생성. 그리기 모드 자동 해제, ‘초기화’ 활성, 힌트 숨김. 결과 산출, 스텝3 진입.FR-06·FR-09·FR-12
TC-C2폴리곤이 있는 상태에서 다시 ‘영역 그리기’기존 폴리곤 제거되고 새로 그리기 시작(중복 없음).FR-07
TC-C3완성된 폴리곤의 꼭짓점을 드래그하여 넓힘면적·패널수·용량·발전량·수익이 실시간 증가 반영.FR-08
TC-C4변 중간 핸들을 끌어 꼭짓점 추가insert_at 트리거, 지표 재계산.FR-08
TC-C5‘초기화’ 클릭폴리곤 삭제, 결과값 모두 ‘—’/‘¥ —’, 스텝 ‘주소’ 복귀, 힌트 재표시.FR-11
TC-C6주소 검색 전 ‘영역 그리기’ 시도버튼 동작은 하되, 지도 기본 위치 위에 그려짐(논리적 흐름은 주소→그리기 권장).FR-06

D. 산출 정확성 (계산 검증)

TC입력 / 절차기대결과FR
TC-D1면적 ≈ 1,000㎡ 폴리곤, FIT 18패널 385장, 용량 154.0kW, 발전량 177,100kWh, 수익 ¥3,187,800, 누적 79.7M.FR-09
TC-D2면적 ≈ 2,500㎡, FIT 10패널 962장(floor 962.5), 용량 384.8kW, 발전량 442,520kWh, 수익 ¥4,425,200.FR-09
TC-D3D1 상태에서 FIT를 18→24 변경수익 즉시 ¥4,250,400로 갱신, 누적 재계산.FR-10
TC-D4FIT 입력을 공란 또는 문자FIT=0 처리 → 수익 ¥0. 오류·NaN 미표시.FR-10
TC-D5아주 작은 면적(예: 2㎡) 폴리곤패널 0장(floor), 용량 0kW, 발전량 0, 수익 ¥0. 깨지지 않음.FR-09
TC-D6천단위·소수 포맷 확인발전량 177,100처럼 콤마, 용량 소수1자리, 수익 ¥ 접두.FR-13

E. 엣지 & 비정상

TC절차기대결과FR
TC-E1점 2개만 찍고 폴리곤 종료 시도면적 ≈ 0 → 지표 0. 앱 비정상 종료 없음.FR-09
TC-E2자기교차(나비형) 폴리곤 작성computeArea가 반환한 값으로 계산(정의상 근사). 오류 없이 수치 표시.FR-09
TC-E3매우 큰 영역(수만 ㎡) 작성큰 수치도 콤마 포맷으로 정상 표시, 레이아웃 깨짐 없음.FR-09·FR-13
TC-E4지도 줌아웃/이동 후 재그리기위치 무관 정상 동작, 단일 폴리곤 유지.FR-07

F. UI · 디자인 · 호환

TC절차기대결과FR/NFR
TC-F1상단 내비 ‘대시보드/솔루션’ 클릭각 화면(screen_02 / screen_04)으로 이동.FR-14
TC-F2CTA ‘내 발전소로 등록…’ 클릭2단계(회원가입) 전환 동선 진입(프로토타입: 동일 페이지/링크).FR-14
TC-F3Chrome/Safari/Firefox/Edge 교차 확인지도·검색·그리기·산출 동일 동작.NFR-06
TC-F4DS 토큰 점검(개발자도구)색·타이포가 --bw-* 토큰 기반, Pretendard 적용.NFR-04
6

알려진 제약 & 추적 항목

현재 구현의 한계와 후속 과제

ID내용
LIM-1‘키 변경’ 버튼은 임의 키 교체가 아니라 기본키로 리셋한다. 다른 키 사용은 ?key= 필요. (UX 개선 후보)
LIM-2내장 DEFAULT_KEY가 클라이언트에 노출된다 → 리퍼러 제한 필수(NFR-01). 미적용 시 무단 사용 위험.
LIM-3산출은 단일 상수 간이 모델 — 방위/경사/실제 일사 편차 미반영. 정밀화는 3D 음영·NEDO 엔진(별도)로.
LIM-4모바일(<640px) 레이아웃 미최적화(패널 388px 고정). 반응형은 후속.
LIM-5패널 단위면적 2.0㎡/장은 표준 가정값 — 실제 모듈/간격에 따라 ±. 사용자 보정 입력은 후속.
⚠️

본 명세는 v2 구현 시점 기준이다. 구현 변경 시 본 문서와 테스트 기대값을 함께 갱신할 것. 이 HTML이 리뷰용 source이며, 필요 시 여기서 MD/YAML 테스트 스펙을 추출한다.