선별 시스템 데스크톱 클라이언트
현장 Kiosk 모드로 운영되는 React + Electron 데스크톱 앱
배경
현장 작업자가 사용하는 농산물 AI 자동 등급 분류 시스템의 데스크톱 UI다. 전국 20곳 이상 현장에서 Kiosk 모드(1920×1080)로 운영되며, 실시간 모니터링·AI 비전/중량 설정·자동 분류·통계 리포트를 제공한다. 최대 80개 이상의 분류 출구를 동시에 표시하는 화면에서 산업용 PC의 제한된 성능으로 15fps까지 프레임이 떨어지는 렌더링 문제와, 비전 설정 페이지가 한 컴포넌트에 몰려 유지보수가 어려운 상황이었다.
시스템 구조
- 상태 관리: Recoil(전역 상태) + TanStack Query(서버 상태). Generic TypeScript 패턴으로 API 레이어를 타입 안전하게 감쌌다.
- 렌더링 최적화:
react-window가상 스크롤(최대 80개 출구),React.memo+ 커스텀 비교 함수, debounce + boundary checking. - 통신 전략: Adaptive Polling(가동 1초 ↔ 유휴 5초 자동 전환) + WebSocket 서버 푸시 병행. 유휴 시간 네트워크 부하를 줄이면서 상태 변화는 즉시 반영.
- UI 라이브러리: Chakra UI + Styled-Components 혼용, Chart.js 기반 대시보드, Storybook으로 컴포넌트 개발 환경 구성.
해결 과정
분류 출구 렌더링 회복. 출구 80개를 매 틱마다 리렌더링하던 구조를 react-window 가상 스크롤로 바꾸고, 화면에 보이는 항목만 그리도록 했다. RailMap 미니맵과 양방향 스크롤 동기화를 넣어, 항목 클릭 시 목록이 해당 위치로 센터 정렬된다. 카드 컴포넌트에 React.memo와 커스텀 비교 함수를 붙여 불필요한 리렌더를 막았다.
비전 설정 모놀리스 분해. 한 컴포넌트에 등급 경계·그레이드 프리뷰·설정 입력이 뒤섞여 있던 비전 설정 페이지를 components·contexts·hooks·types·utils 서브모듈로 나눴다. 드래그 핸들러에 debounce와 boundary checking을 적용해 등급 경계 드래그가 60fps로 움직이게 했다.
Adaptive Polling. 유휴 상태에서도 1초 주기 폴링이 도는 구조를 바꿔, 선별 가동 중 1초·유휴 상태 5초로 자동 전환하는 폴링 훅을 썼다. WebSocket 서버 푸시를 병행해, PC·GPU·카메라 상태 업데이트의 폴링 의존도를 낮췄다.
Electron 빌드 안정화. Windows에서 Chromium Shared Dictionary 캐시 에러로 콜드 스타트 실패가 100%였던 문제는 Shared Dictionary 비활성화와 디스크 캐시 경로 강제 지정으로 해결했다. Windows·macOS·Linux 3개 플랫폼 프로덕션 빌드를 electron-builder로 구성.
API 레이어 타입 안전화. Generic TypeScript 패턴으로 apiClient / uploadApiClient를 감쌌고, 19개 API 모듈이 공통 타입 시스템 위에 올라가도록 정리했다.
PDF·Excel 리포트 생성. jspdf + html2canvas + jszip으로 품질 리포트 PDF/Excel을 클라이언트에서 직접 생성한다. 현장에서 네트워크가 제한되어도 리포트 산출이 가능하다.
성과
- 분류 출구 리스트 렌더링 15fps → 60fps, 10,000건 이상 결과 이미지도 끊김 없이 스크롤.
- 비전 설정 등급 경계 드래그 10fps → 60fps, 모놀리스 페이지를 5개 서브모듈로 분해.
- Adaptive Polling으로 유휴 시간 네트워크 부하 감소, 상태 업데이트 지연 5~30초 → 1초 이내.
- Windows 콜드 스타트 실패율 100% → 0%, 3개 플랫폼(Windows / macOS / Linux) 프로덕션 빌드 제공.
- 19 API 모듈 · 24 커스텀 훅 · 107 컴포넌트 규모 클라이언트, Storybook 기반 컴포넌트 개발 환경 구성.
- v3.5.2로 전국 20곳 이상 현장에 배포.