jongkwan.dev
Back to projects

Sorting System Desktop Client

A React + Electron desktop app running in kiosk mode on site

AIOFARM·2022.06 - 2025.11·Frontend architecture and development lead
React
TypeScript
Electron
Vite
Recoil
TanStack Query
Chakra UI
Styled-Components
Chart.js
Storybook

Background

This is the desktop UI for an AI-based automatic grading system for agricultural produce, used by operators on site. It runs in kiosk mode (1920x1080) at more than 20 sites nationwide and provides live monitoring, AI vision and weight configuration, automatic grading, and statistical reports. On screens showing more than 80 sorting outlets at once, the limited performance of industrial PCs dropped rendering to 15fps. The vision configuration page had also grown into a single component that was hard to maintain.

System architecture

  • State management: Recoil for global state, TanStack Query for server state. The API layer is wrapped type-safely with a generic TypeScript pattern.
  • Rendering optimization: react-window virtual scrolling (up to 80 outlets), React.memo with a custom comparison function, debounce plus boundary checking.
  • Communication strategy: Adaptive polling (1s while running, 5s while idle, switched automatically) alongside WebSocket server push. Network load drops during idle time while status changes still appear immediately.
  • UI libraries: Chakra UI mixed with Styled-Components, dashboards built on Chart.js, and Storybook as the component development environment.

How it was built

Recovering sorting outlet rendering. The structure re-rendered all 80 outlets on every tick. Replacing it with react-window virtual scrolling draws only the items visible on screen. A RailMap minimap with two-way scroll synchronization centers the list on an item when it is clicked. Card components got React.memo with a custom comparison function to block unnecessary re-renders.

Breaking up the vision configuration monolith. The vision configuration page mixed grade boundaries, grade previews, and configuration inputs in one component. It was split into components, contexts, hooks, types, and utils submodules. Debounce and boundary checking on the drag handler brought grade boundary dragging to 60fps.

Adaptive polling. Polling ran on a 1-second interval even when idle. A polling hook now switches automatically between 1 second while sorting is running and 5 seconds while idle. WebSocket server push runs alongside it, reducing how much PC, GPU, and camera status updates depend on polling.

Stabilizing the Electron build. Cold start failed 100% of the time on Windows due to a Chromium shared dictionary cache error. Disabling the shared dictionary and forcing an explicit disk cache path fixed it. Production builds for Windows, macOS, and Linux are configured with electron-builder.

Type-safe API layer. A generic TypeScript pattern wraps apiClient and uploadApiClient, and 19 API modules were reorganized onto a shared type system.

PDF and Excel report generation. Quality report PDFs and Excel files are generated directly on the client with jspdf, html2canvas, and jszip. Reports can be produced even when network access on site is limited.

Results

  • Sorting outlet list rendering went from 15fps to 60fps, and result image sets of more than 10,000 entries scroll without stutter.
  • Grade boundary dragging in vision configuration went from 10fps to 60fps, and the monolithic page was split into 5 submodules.
  • Adaptive polling reduced idle-time network load and cut status update latency from 5-30 seconds to under 1 second.
  • Windows cold start failure rate went from 100% to 0%, with production builds shipped for 3 platforms (Windows, macOS, Linux).
  • The client comprises 19 API modules, 24 custom hooks, and 107 components, with a Storybook-based component development environment.
  • Deployed as v3.5.2 to more than 20 sites nationwide.