Live
Black Hat USAAI BusinessBlack Hat AsiaAI BusinessMy forays into cyborgism: theory, pt. 1LessWrongThe Engineer as Reader: Why Literature Skills Matter for Software Engineers in the Age of AIMedium AIWhen Enterprises Build an Agent OS, the Operating Model Must Change TooMedium AIBuilding a RAG-Powered Smart AI Chatbot for E-commerce application using LangChainMedium AIIntelligence isn’t genetic it’s something to be built part 2Medium AIWhich AI Tool Should You Use for What?Medium AIAI and Authority: What Happens When Writing No Longer Proves ExpertiseMedium AIThe One-Person Unicorn Is Impossible Until AI Outputs Are Officially RecognizedMedium AIb8671llama.cpp ReleasesWashington state will require labels on AI images and set limits on chatbotsHacker News AI TopCan we ever trust AI to watch over itself?Hacker News AI TopAI models will scheme to protect other AI models from being shut downHacker News AI TopBlack Hat USAAI BusinessBlack Hat AsiaAI BusinessMy forays into cyborgism: theory, pt. 1LessWrongThe Engineer as Reader: Why Literature Skills Matter for Software Engineers in the Age of AIMedium AIWhen Enterprises Build an Agent OS, the Operating Model Must Change TooMedium AIBuilding a RAG-Powered Smart AI Chatbot for E-commerce application using LangChainMedium AIIntelligence isn’t genetic it’s something to be built part 2Medium AIWhich AI Tool Should You Use for What?Medium AIAI and Authority: What Happens When Writing No Longer Proves ExpertiseMedium AIThe One-Person Unicorn Is Impossible Until AI Outputs Are Officially RecognizedMedium AIb8671llama.cpp ReleasesWashington state will require labels on AI images and set limits on chatbotsHacker News AI TopCan we ever trust AI to watch over itself?Hacker News AI TopAI models will scheme to protect other AI models from being shut downHacker News AI Top
AI NEWS HUBbyEIGENVECTOREigenvector

How I Built a Desktop Trading Journal with Electron, React, and SQLite

DEV Communityby WilliamApril 4, 20264 min read2 views
Source Quiz

Last week I shipped a desktop app called Aurafy. It's a trading journal for futures traders that runs entirely locally. No cloud, no accounts, no subscription. I wanted to share the technical decisions behind it because I think the "local first" approach is underrated for tools that handle sensitive financial data. The Stack The app is built as a monorepo with three pieces: Server: Express.js + better-sqlite3. The server runs inside the Electron process (no child process spawn, which cuts startup time to under 2 seconds). SQLite with WAL mode handles all persistence. Every write uses synchronous = FULL because losing trade data is unacceptable. Client: React + Vite + Tailwind CSS + Recharts. Standard SPA that talks to the Express server over localhost. TanStack Query handles all data fetch

Last week I shipped a desktop app called Aurafy. It's a trading journal for futures traders that runs entirely locally. No cloud, no accounts, no subscription. I wanted to share the technical decisions behind it because I think the "local first" approach is underrated for tools that handle sensitive financial data.

The Stack

The app is built as a monorepo with three pieces:

Server: Express.js + better-sqlite3. The server runs inside the Electron process (no child process spawn, which cuts startup time to under 2 seconds). SQLite with WAL mode handles all persistence. Every write uses synchronous = FULL because losing trade data is unacceptable.

Client: React + Vite + Tailwind CSS + Recharts. Standard SPA that talks to the Express server over localhost. TanStack Query handles all data fetching and caching.

Electron wrapper: The main process starts the Express server in-process, opens a BrowserWindow pointing to localhost, and handles native features like screen recording permissions and floating camera windows.

Why Local First?

Trading data is sensitive. Your P&L, your account sizes, your mistakes. Most trading journals upload all of this to their cloud. I didn't want that.

With SQLite, everything lives in ~/Library/Application Support/aurafy/data/journal.db. The user can back it up, move it, or delete it. No API keys, no OAuth flows, no "please log in again."

The tradeoff is no cross-device sync. But for a trading journal that you use at your desk, this hasn't been an issue. Traders don't journal on their phones.

Screen Recording in Electron

One feature I'm proud of is the built-in screen recorder. Traders record their sessions to review later, similar to how athletes watch game film.

Electron's desktopCapturer API provides screen capture. I combine it with getUserMedia for microphone input, mix both audio streams using the Web Audio API, and feed everything into a MediaRecorder.

The camera overlay is a separate BrowserWindow with transparent: true, alwaysOnTop: true, and frame: false. It floats above all apps like Loom's camera bubble. The HTML is dead simple: a circular div with a video element showing the webcam feed.

CSV Import with Auto-Detection

Traders export their data from platforms like Tradovate and NinjaTrader as CSV files. The challenge is that every platform uses different column names, date formats, and instrument naming conventions.

Tradovate calls the instrument "MNQM6" while NinjaTrader calls it "MNQ 06-26". Both mean the same thing: Micro Nasdaq futures, June 2026 contract.

I wrote a parser that:

  • Auto-detects the platform by checking column headers

  • Normalizes instrument names using regex (strip the contract month code)

  • Matches to a local instruments table with tick sizes and point values

  • Pairs entry/exit executions and calculates P&L

The whole import flow is: drop CSV → see preview with detected trades → confirm. No manual mapping.

Lessons Learned

Run the server in-process. My first version spawned a Node child process for the Express server. This added 3+ seconds to startup and caused issues with macOS code signing (the OS saw it as two separate apps). Running Express inside Electron's main process using require() fixed both problems.

SQLite's WAL mode matters. Without it, writes block reads. With journal_mode = WAL and synchronous = FULL, you get concurrent reads during writes and guaranteed durability on crash.

Electron auto-update is fragile. electron-updater creates draft releases on GitHub, which means download URLs return 404 until you manually publish them. I added a CI step that auto-publishes after both Mac and Windows builds complete.

ELECTRON_RUN_AS_NODE will haunt you. If this env var is set (which it is in some development environments), Electron runs as plain Node.js and require('electron') returns a string instead of the module. I spent hours debugging this.

Try It

Aurafy is free and available at aurafy.dev. The code handles futures contracts (ES, NQ, CL, MES, MNQ) with proper point values and tick sizes.

If you're interested in the Electron + Express + SQLite architecture pattern, happy to answer questions in the comments.

Was this article helpful?

Sign in to highlight and annotate this article

AI
Ask AI about this article
Powered by Eigenvector · full article context loaded
Ready

Conversation starters

Ask anything about this article…

Daily AI Digest

Get the top 5 AI stories delivered to your inbox every morning.

Knowledge Map

Knowledge Map
TopicsEntitiesSource
How I Built…releaseavailableversionupdateapplicationplatformDEV Communi…

Connected Articles — Knowledge Graph

This article is connected to other articles through shared AI topics and tags.

Knowledge Graph100 articles · 164 connections
Scroll to zoom · drag to pan · click to open

Discussion

Sign in to join the discussion

No comments yet — be the first to share your thoughts!

More in Products