대상 구현물: screen_01_main_simulation_v2.html — Google Maps JavaScript API(위성지도 · Places 주소검색 · DrawingManager 폴리곤) 기반 간이 발전량/수익 시뮬레이터. 본 문서는 실제 구현 동작을 기준으로 한 요구사항과 검증용 테스트케이스를 정의한다.
무엇을, 어디까지 검증하는가
| 항목 | 내용 |
|---|---|
| 목적 | 발전소 오너가 로그인 없이 위성지도에서 패널 영역을 그려, 예상 설비용량·연간 발전량·수익을 즉시 확인하고 회원가입(2단계)으로 전환하도록 유도. |
| 범위(In) | API 키 처리 · 지도 초기화 · 주소 자동완성 검색 · 폴리곤 그리기/편집 · 면적→지표 산출 · FIT 단가 반영 · 진행 스텝 표시 · 결과 포맷팅 · CTA. |
| 범위 외(Out) | 3D 음영(SPA) 분석, NEDO 실시간 일사량 API, 실측 비교(2단계), 인버터 연동(3단계), 회원가입/결제 백엔드, 서버 저장. |
| 가정 | 유효한 Google Maps API 키 존재(Maps JavaScript API + Places API 활성화). 산출은 단일 상수 기반 간이 모델이며 정밀 시뮬레이션 아님. |
테스트의 기대값 계산 근거 (코드 상수와 일치)
면적(㎡) = 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.
우선순위: MUST SHOULD COULD
| ID | 요구사항 | 우선순위 |
|---|---|---|
| FR-01 | API 키 우선순위 — 키는 ?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-10 | FIT 단가 반영 — FIT 입력값 변경 시 수익과 25년 누적이 즉시 갱신된다. 빈값/비숫자는 0으로 처리. | MUST |
| FR-11 | 초기화 — ‘초기화’ 클릭 시 폴리곤 제거, 결과값 ‘—’ 리셋, 스텝 ‘주소’로 복귀, 안내 힌트 재표시. | SHOULD |
| FR-12 | 진행 스텝 — 주소 → 영역 그리기 → 결과 3단계 인디케이터가 상태에 따라 done/cur/todo로 전환된다. | SHOULD |
| FR-13 | 숫자 포맷 — 모든 수치는 천단위 콤마(toLocaleString), 용량은 소수 1자리, 수익은 ¥ 접두. | COULD |
| FR-14 | 전환 CTA — ‘내 발전소로 등록하고 실측 비교하기’ 버튼으로 2단계(회원가입) 유도. 상단 ‘홈/대시보드/솔루션’ 내비 제공. | SHOULD |
품질 속성
| 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 |
전제조건 · 절차 · 기대결과 · 연결 요구사항
| TC | 절차 | 기대결과 | FR |
|---|---|---|---|
| TC-A1 | localStorage·쿼리 없이 페이지 접속 | 내장 DEFAULT_KEY로 지도 정상 로드. 키 배지 "Maps 연결됨"(녹색). | FR-01 |
| TC-A2 | ?key=AIza...유효 붙여 접속 | 해당 키로 로드, localStorage에 저장됨(이후 쿼리 없이도 유지). | FR-01 |
| TC-A3 | ?key=INVALID 로 접속 | 지도 인증 실패 → 오류 배너 노출, 배지 "키 오류". (gm_authFailure) | FR-03 |
| TC-A4 | DevTools에서 localStorage 비우고 DEFAULT_KEY를 공란으로 가정 후 접속 | 지도 미로드, 키 입력 오버레이 표시. 키 입력+‘지도 시작’ 시 저장 후 로드. | FR-02 |
| TC-A5 | 네트워크 차단 상태에서 접속(스크립트 로드 실패) | "스크립트를 불러오지 못했습니다" 오류 배너 표시. | NFR-05 |
| TC-A6 | 상단 ‘키 변경’ 클릭 | localStorage 키 삭제 후 새로고침 → 기본키로 복귀. (주의: 임의 키로 교체가 아닌 기본키 리셋 — 알려진 제약) | FR-01 |
| 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 |
| 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 |
| 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-D3 | D1 상태에서 FIT를 18→24 변경 | 수익 즉시 ¥4,250,400로 갱신, 누적 재계산. | FR-10 |
| TC-D4 | FIT 입력을 공란 또는 문자 | FIT=0 처리 → 수익 ¥0. 오류·NaN 미표시. | FR-10 |
| TC-D5 | 아주 작은 면적(예: 2㎡) 폴리곤 | 패널 0장(floor), 용량 0kW, 발전량 0, 수익 ¥0. 깨지지 않음. | FR-09 |
| TC-D6 | 천단위·소수 포맷 확인 | 발전량 177,100처럼 콤마, 용량 소수1자리, 수익 ¥ 접두. | FR-13 |
| TC | 절차 | 기대결과 | FR |
|---|---|---|---|
| TC-E1 | 점 2개만 찍고 폴리곤 종료 시도 | 면적 ≈ 0 → 지표 0. 앱 비정상 종료 없음. | FR-09 |
| TC-E2 | 자기교차(나비형) 폴리곤 작성 | computeArea가 반환한 값으로 계산(정의상 근사). 오류 없이 수치 표시. | FR-09 |
| TC-E3 | 매우 큰 영역(수만 ㎡) 작성 | 큰 수치도 콤마 포맷으로 정상 표시, 레이아웃 깨짐 없음. | FR-09·FR-13 |
| TC-E4 | 지도 줌아웃/이동 후 재그리기 | 위치 무관 정상 동작, 단일 폴리곤 유지. | FR-07 |
| TC | 절차 | 기대결과 | FR/NFR |
|---|---|---|---|
| TC-F1 | 상단 내비 ‘대시보드/솔루션’ 클릭 | 각 화면(screen_02 / screen_04)으로 이동. | FR-14 |
| TC-F2 | CTA ‘내 발전소로 등록…’ 클릭 | 2단계(회원가입) 전환 동선 진입(프로토타입: 동일 페이지/링크). | FR-14 |
| TC-F3 | Chrome/Safari/Firefox/Edge 교차 확인 | 지도·검색·그리기·산출 동일 동작. | NFR-06 |
| TC-F4 | DS 토큰 점검(개발자도구) | 색·타이포가 --bw-* 토큰 기반, Pretendard 적용. | NFR-04 |
현재 구현의 한계와 후속 과제
| 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 테스트 스펙을 추출한다.