# 2026-04-15 통합 작업 메모 ## 0. 작업 요약 - SBS 선거 API를 기준으로 `광역단체장(3)`, `기초단체장(4)`, `교육감(11)` 실연동을 정리했다. - 선거 종류 변경 시 실제 SBS `선거구` 코드 기준으로 지역 목록과 요청 코드가 맞물리도록 보정했다. - `기초단체장` 지역 옵션 교체 중 발생하던 `ArgumentNullException (key)`를 ViewModel 방어 로직으로 수정했다. - 콤보박스 변경 후 값이 그대로 남아 있던 문제를 선택 변경 즉시 재조회 흐름으로 바꿨다. - `System.Text.Json.JsonException`은 region API 응답이 최상위 배열(`[...]`)인 경우를 허용하도록 수정했다. - 미지원 조합에서는 이전 값이 계속 보이지 않도록 상태 문구와 보드 표시 규칙을 보정했다. ## 1. 선거종류(Sunger Types)별 점검 결과 ### `3` 시도지사 / 광역단체장 - 선거구 목록: `sungerInfo/region?type=선거구&sungerType=3` - 개표 요청: `gaepyo/3/sungergus?ids=<선거구 id>` - 사전 투표율 요청: `tupyo/3/sidos?ids=<시도 id>` - 부산 기준 확인: - 개표 코드: `3260000` - 사전 코드: `26` - 결론: - 개표 연동 정상 - 사전 투표율 연동 정상 ### `4` 시군구장 / 기초단체장 - 선거구 목록: `sungerInfo/region?type=선거구&sungerType=4` - 개표 요청: `gaepyo/4/sungergus?ids=<선거구 id>` - 부산 해운대구 기준 확인: - 개표 코드: `4260900` - 결론: - 개표 연동 정상 - 사전 투표율은 SBS API가 `400` 반환으로 미지원 ### `11` 교육감 - 선거구 목록: `sungerInfo/region?type=선거구&sungerType=11` - 개표 요청: `gaepyo/11/sungergus?ids=<선거구 id>` - 부산 기준 확인: - 개표 코드: `11260000` - 결론: - 개표 연동 정상 - 사전 투표율은 SBS API가 `400` 반환으로 미지원 ## 2. SBS 선거 API 실연동 - 기준 문서: `https://documenter.getpostman.com/view/39408930/2sBXqCNNyS` - 기준 호스트: `http://202.31.153.141:8421/` - API 응답 헤더에 charset이 없어서, 본문은 UTF-8 바이트 기준으로 직접 디코딩한다. ### 현재 지원 범위 - `광역단체장` - 사전 투표율: 지원 - 개표: 지원 - `교육감` - 사전 투표율: 미지원 - 개표: 지원 - `기초단체장` - 사전 투표율: 미지원 - 개표: 지원 ### 확인된 API 제한사항 - `tupyo/4/...` 계열은 현재 `기초단체장`에 대해 `400`을 반환한다. - `tupyo/11/...` 계열은 현재 `교육감`에 대해 `400`을 반환한다. - 위 두 경우는 앱 오류가 아니라 API 제공 범위 밖으로 본다. ## 3. 기초단체장 지역 선택 규칙 - 기초단체장 목록은 `시도 + 시군구/기초단체장명` 결합 문자열로 표시한다. - 예: `부산광역시 해운대구` - 실제 개표 요청은 SBS API의 `선거구 id`를 사용한다. - 예: `부산광역시 해운대구 -> 4260900` - 데이터 탭의 `지역 코드`는 현재 선택된 요청 코드(시도 코드 또는 선거구 코드)를 표시한다. - 기초단체장 선택 목록은 API `sungerInfo/region?type=선거구&sungerType=4` 기준으로 구성한다. ## 4. 데이터 탭 표시 기준 - 데이터 탭에는 기존 `선거구명`, `지역 코드` 외에 다음 정보를 함께 표시한다. - `시도명` - `송출 선거구명` - 데이터 탭은 원본 JSON 전문을 그대로 보여주는 용도는 아니다. - API 응답을 ViewModel용 값으로 정규화한 뒤 표시한다. - `DistrictName`은 선택/저장용 원본 문자열로 유지한다. - 송출용 분리 값은 별도 필드로 관리한다. - `RegionName` - `ElectionDistrictName` - Karisma/Tornado3 송출 변수 `시도명NN`, `선거구명NN`은 위 분리 값을 직접 사용한다. ## 5. Null-Key 예외 원인과 처리 - 원인: - `기초단체장`으로 전환하면서 `DistrictOptions`를 교체하는 순간, `ComboBox.SelectedValue`가 일시적으로 `null`을 보낼 수 있었다. - 이 값이 그대로 `Dictionary.TryGetValue(null, ...)` 경로로 들어가며 `System.ArgumentNullException (Parameter 'key')`가 발생했다. ### 적용한 방어 규칙 - `DistrictName`, `DistrictCode`, `ElectionType`는 내부적으로 null이 아닌 문자열 상태를 유지한다. - 지역 옵션 교체 중에는 `_isUpdatingDistrictOptions` 플래그로 transient UI 값을 무시한다. - 옵션 교체 전의 `preferredName`, `preferredCode`를 캡처해 마지막 유효 선택값 기준으로 복원한다. ## 6. 변수 매핑 관련 기록 - Karisma 장면 변수 지원 범위 로깅을 추가했다. - 현재 컷에 없는 변수명은 경고로 확인 가능하다. - 다음 alias 매핑을 보강했다. - `기준시`, `기준시01`, `기준시02` - `유권자수`, `유권자수01` - `투표자수`, `투표자수01` - `득표수바NN` - `정당원NN` - `정당색NN` ### 아직 주의가 필요한 변수군 - 의석수 계열 - 판세 지도/그래프 계열 - 경력/공약 계열 - 일부 사진/차트 전용 컷 변수 ## 7. 콤보박스 변경 즉시 갱신 - `선거 종류`, `선거구명`, `지역 코드`, `방송 단계`가 바뀌면 짧은 debounce 후 자동으로 `RefreshAsync(...)`를 다시 호출한다. - 지역 옵션 재구성 중(`_isUpdatingDistrictOptions`)이나 API 결과 반영 중(`_isApplyingRefreshResult`)에는 내부 setter 연쇄로 인한 재조회는 막는다. - 이 변경으로 콤보박스만 바뀌고 `후보현황`, `정보값`이 이전 조회 결과에 머물러 있던 문제를 줄인다. ## 8. JSON 응답 파싱 보정 - `sungerInfo/region...` 계열은 `{ value: [...] }`가 아니라 최상위 배열(`[...]`)로 오는 경우가 있다. - 클라이언트는 이제 `value` envelope와 최상위 배열을 모두 허용한다. - 광역단체장/교육감/기초단체장 지역 옵션도 SBS `선거구` 목록 기준으로 읽어서 실제 요청 코드와 맞춘다. - 선택 변경 debounce는 `CancellationTokenSource` 취소 대신 revision 비교로 바꿔 디버그 출력에 반복 `TaskCanceledException`이 쌓이는 흐름을 줄였다. - 선거 종류 전환/상태 복원 도중 비동기 선거구 목록 갱신이 늦게 끝나더라도, 마지막 현재 선택값 기준으로 다시 매칭하도록 보정했다. - 미지원 단계나 API 오류가 나면 `StatusText`에 마지막 경고 메시지를 남겨 화면에서 이유를 바로 확인할 수 있게 했다. - 데이터 탭 상단에 `StatusText`를 노출해 마지막 갱신 상태/미지원 사유를 바로 볼 수 있게 했다. - 미지원 조합에서는 투표율/후보 보드를 숨기고 상태 문구만 보이도록 해 이전 수신값을 현재 데이터로 오해하는 흐름을 줄였다. ## 9. 주요 변경 파일 - `Tornado3_2026Election/Services/SbsElectionApiClient.cs` - SBS API 요청/응답 처리 - 선거 종류별 지역 옵션 구성 - JSON 파싱 보정 - `Tornado3_2026Election/ViewModels/DataViewModel.cs` - null-safe 지역 선택 처리 - 선택 변경 즉시 갱신 - 상태 문구 및 미지원 조합 표시 - `Tornado3_2026Election/MainWindow.xaml` - 데이터 탭에 `시도명`, `송출 선거구명`, `StatusText` 표시 - `Tornado3_2026Election/Services/KarismaTornado3Adapter.cs` - `RegionName`, `ElectionDistrictName` 기반 송출 변수 매핑 - `Tornado3_2026Election/Domain/ElectionDataSnapshot.cs` - 송출용 분리 지역 필드 추가 - `Tornado3_2026Election/Persistence/AppState.cs` - 실제 연동 기준 기본값 정리 ## 10. 현재 상태 및 남은 체크포인트 - `dotnet build Tornado3_2026Election.slnx` 통과 - 기존 경고는 유지 - `WindowsBase` 참조 충돌 경고 - MSIX 인증서 경고 - `MockTornado3Adapter.ConnectionChanged` 미사용 경고 - 코드상 연동/파싱/표시 흐름은 정리 완료 - 남은 실운영 체크: - 앱 실행 상태에서 `광역단체장 -> 교육감 -> 기초단체장` 전환 확인 - `개표 <-> 사전` 전환 시 상태 문구와 보드 표시 확인 - 실제 송출 컷에서 `시도명NN`, `선거구명NN` 반영 확인