Electron, React, SQLite를 사용해 데스크톱 트레이딩 저널을 만든 방법
Source: Dev.to
위에 제공된 Source 링크 아래에 번역하고자 하는 전체 텍스트를 붙여 주시면, 해당 내용을 한국어로 번역해 드리겠습니다.
(코드 블록, URL, 마크다운 형식 및 기술 용어는 그대로 유지됩니다.)
개요
지난 주에 나는 Aurafy라는 데스크톱 앱을 출시했습니다. 이 앱은 선물 트레이더를 위한 거래 저널이며 완전히 로컬에서 실행됩니다—클라우드도 없고, 계정도 없으며, 구독도 없습니다. 민감한 금융 데이터를 다루는 도구에 대해 “로컬‑first” 접근 방식이 과소평가되고 있기 때문에 그 뒤에 있는 기술적 결정을 공유하고 싶었습니다.
아키텍처
앱은 세 부분으로 구성된 모노레포입니다:
Server
- Express.js + better‑sqlite3
- Electron 메인 프로세스 내부에서 실행됩니다 (자식 프로세스 생성이 없으며, 시작 시간을 2초 이하로 단축합니다)
- WAL 모드의 SQLite가 모든 영속성을 처리합니다
- 모든 쓰기는
synchronous = FULL을 사용하여 내구성을 보장합니다
Client
- React, Vite, Tailwind CSS, Recharts
localhost를 통해 Express 서버와 통신하는 표준 SPA- TanStack Query가 데이터 가져오기와 캐싱을 담당합니다
Electron Wrapper
- 메인 프로세스가 인‑프로세스로 Express 서버를 시작하고,
localhost를 가리키는BrowserWindow를 열며, 화면 녹화 권한 및 플로팅 카메라 창과 같은 네이티브 기능을 처리합니다.
데이터 저장 및 보안
거래 데이터(P&L, 계좌 규모, 실수)는 매우 민감합니다. SQLite를 사용하면 모든 것이 다음 위치에 저장됩니다:
~/Library/Application Support/aurafy/data/journal.db
- 사용자는 파일을 직접 백업, 이동 또는 삭제할 수 있습니다.
- API 키, OAuth 흐름, 로그인 프롬프트가 없습니다.
- 트레이드‑오프: 장치 간 동기화가 없으며, 이는 트레이더들이 보통 책상에서 저널링하기 때문에 문제가 되지 않았습니다.
내장 화면 녹화기
핵심 기능은 트레이딩 세션을 나중에 검토할 수 있도록 녹화하는 것으로, 운동선수가 경기 영상을 보는 방식과 유사합니다.
-
Electron의
desktopCapturerAPI가 화면 캡처를 제공합니다. -
마이크 입력을 위해
getUserMedia와 결합합니다. -
오디오 스트림은 Web Audio API를 사용해 믹싱한 뒤
MediaRecorder에 전달합니다. -
카메라 오버레이는 별도의
BrowserWindow에서 다음 옵션으로 실행됩니다:{ transparent: true, alwaysOnTop: true, frame: false }이는 Loom의 카메라 버블처럼 모든 앱 위에 떠 있습니다. HTML은 웹캠 피드를 표시하는
요소를 포함한 간단한 원형로 구성됩니다.
CSV Import from Trading Platforms
트레이더들은 Tradovate 및 NinjaTrader와 같은 플랫폼에서 데이터를 CSV 파일로 내보냅니다. 각 플랫폼은 열 이름, 날짜 형식, 그리고 계약명(예: MNQM6 vs. MNQ 06-26)이 서로 다릅니다.
제가 만든 파서는 다음을 수행합니다:
- 자동 감지: 열 헤더를 확인하여 플랫폼을 식별합니다.
- 정규화: 정규식으로 계약 월 코드를 제거하여 상품명을 표준화합니다.
- 매칭: 틱 사이즈와 포인트 값이 포함된 로컬 상품 테이블에 연결합니다.
- 페어링: 진입/청산 실행을 짝지어 P&L을 계산합니다.
수입 흐름은 다음과 같습니다:
Drop CSV → preview detected trades → confirm
수동 매핑이 필요하지 않습니다.
성능 최적화
- In‑process server: 첫 번째 버전은 Express를 위해 Node 자식 프로세스를 생성했으며, 시작 시간이 3 초 이상 늘어나고 macOS 코드‑서명 문제를 일으켰습니다 (OS가 이를 두 개의 별도 앱으로 인식).
require()를 사용해 Electron 메인 프로세스 내에서 Express를 실행하면 두 문제 모두 해결됩니다. - SQLite WAL mode: WAL이 없으면 쓰기가 읽기를 차단합니다.
journal_mode = WAL및synchronous = FULL을 사용하면 쓰기 중에도 동시 읽기가 가능하고, 충돌 시 내구성이 보장됩니다.
Auto‑update Challenges
electron-updater는 GitHub에 초안 릴리스를 생성하는데, 수동으로 게시하기 전까지 404 오류가 반환됩니다. macOS와 Windows 빌드가 모두 완료된 후 릴리스를 자동으로 게시하는 CI 단계를 추가했습니다.
Development Gotchas
ELECTRON_RUN_AS_NODE: 이 환경 변수가 설정되어 있으면(일부 개발 환경에서 흔함), Electron이 일반 Node.js처럼 실행되고require('electron')이 모듈이 아니라 문자열을 반환합니다. 이 때문에 몇 시간씩 디버깅을 해야 했습니다.
Availability
Aurafy는 무료이며 에서 사용할 수 있습니다. 코드는 선물 계약(ES, NQ, CL, MES, MNQ)을 적절한 포인트 값과 틱 사이즈로 처리합니다.
질문
Electron + Express + SQLite 아키텍처 패턴에 관심이 있으시면, 댓글에 자유롭게 질문을 남겨 주세요.