// TRADERVIEW — WALKTHROUGH

Tutorial index Docs hub
Progress
01 / 18

01.First launch & orientation

Desktop vs web binary, embedded Postgres bootstrap, auto-login local user, the topbar, the Cmd-K tile launcher, and the boot path from main.rs to app.js.

One workspace, two binaries

TraderView ships from a single Rust workspace and produces two executable shells. Both depend on the same library crates (traderview-core, traderview-db, traderview-import, traderview-expense, traderview-ocr) and serve the same vanilla-JS frontend verbatim. The only thing that distinguishes them is the Postgres backend and the auth layer.

ModeBinaryPostgresAuthAudience
Desktoptraderview-desktopembedded (downloaded via postgresql_embedded on first launch)auto-login local usersingle user, offline
Webserverexternal (DATABASE_URL)argon2 + JWT bearermulti-user, hosted

Pick the mode that matches your deployment and skip the rest of the table — the UI is identical from here on.

Desktop boot — embedded Postgres bootstrap

On macOS the app installs into /Applications and launches like any Tauri v2 app. The Rust side does the following before the WebView is shown:

  1. Locate the app-data dir. ~/Library/Application Support/com.menketechnologies.traderview/pg/ (macOS), ~/.local/share/com.menketechnologies.traderview/pg/ (Linux), %APPDATA%\com.menketechnologies.traderview\pg\ (Windows).
  2. Recover from a stale lock. If postmaster.pid exists, the bootstrap reads the recorded PID and checks if that process is still alive. If not, the lockfile is removed — a SIGKILL'd parent on the previous run no longer blocks startup.
  3. Reuse the persisted password. A random password file (mode 0600) is written on first init and reused on every subsequent launch so authentication survives across runs.
  4. Download Postgres if missing. First launch fetches a portable PostgreSQL into ~/.theseus (~80 MB). Subsequent launches reuse that cache.
  5. Start the cluster, bind to a random localhost port, run migrations. 46 migrations under migrations/0001_*.sql through migrations/0046_*.sql are applied in order; new migrations apply on the next launch.
  6. Hold the Embedded handle across axum::serve. The worker thread owns the handle for the lifetime of the server and drops it explicitly after serve returns. An earlier version dropped at function exit, which silently called pg_ctl stop mid-request — every subsequent query timed out with "pool timed out".
  7. Start the axum router on the localhost port and the Tauri WebView. The WebView loads frontend/index.html via the tauri://localhost custom scheme.

No external services. No cloud account. No network round-trip required after the first-run download. Embedded Postgres is shut down cleanly when you quit the app.

Web boot — external Postgres + JWT

The web binary (cargo run --bin server or the server binary from a release archive) expects two required environment variables and a handful of optional ones:

VariableDefaultPurpose
DATABASE_URLrequiredPostgres connection string. Pool is max_connections=32, min_connections=4, acquire_timeout=15s.
TRADERVIEW_JWT_SECRETrequiredHMAC secret for JWT signing. Rotate to invalidate outstanding tokens.
TRADERVIEW_BIND0.0.0.0:8080axum listen address.
TRADERVIEW_CORS_ORIGIN*CORS allowlist.
TRADERVIEW_LOGinfotracing-subscriber env-filter directive (e.g. traderview_web=debug,tower_http=info).

First load: visit / → register a user → log in → JWT lands in localStorage → every fetch from js/api.js attaches Authorization: Bearer …. The /health, /config, /auth/*, and /client-errors routes are public; everything else requires the bearer header.

The topbar — what every chip means

Across the top of every view sits a thin strip with eleven actions and a search box. Left to right:

  • Logo + brand — wordmark and version string (synced at build time from Cargo.toml).
  • Account picker — switch between accounts. Each broker import lands in its own accounts row; the picker scopes every downstream query.
  • Quick-nav chips — Dashboard · Trades · Journal · Reports · Watchlists · Charts · Live · Scanner. These are the same 8 routes the global keyboard shortcuts target (Cmd+Opt+D/T/J/R/W/C/L/M).
  • Symbol search — full-text autocomplete over symbols + your watchlists. Enter jumps to the per-symbol research dossier (step 08).
  • Cmd-K launcher button — opens the 648-tile categorized launcher. The same overlay opens on Cmd+K from any view.
  • Help / tutorial — the ? key (no modifier) opens an in-app keyboard cheat-sheet across three searchable tables (48 globals + 70+ scoped ctxmenu items + view-scoped binds).

The Cmd-K launcher — 648 tiles, 10 categories

There is no fixed nav strip. The topbar carries the most-used routes; everything else lives in the Cmd-K launcher. Tiles are grouped into the categories below; type any substring to filter; Enter jumps to the first match.

⚡ Live Markets         6 tiles    Scanner / Halts / Catalysts / Pre-market / Tape / Heatmap
📊 Trading            16 tiles    Webull / Live Positions / Paper / New Trade / Plans / Hotkeys
📓 Journal             9 tiles    Journal / AI Journal / Trade Reviews / Compare / Replay / Discipline
🔎 Charts & Research 178 tiles    Charts / Research / Watchlists / Screener / Scanners / Sectors / …
📈 Reports            23 tiles    Dashboard / Reports / R-Multiple / Forecast / Fill Quality / Tax / …
🧷 Strategy            7 tiles    Backtest / Walk-forward / Custom Indicators / Strategy Alerts / Alerts / Webhooks
💬 Community           4 tiles    Shares / Forum / Mentorship / Boards
⚙️  Admin             18 tiles    Import / CSV Wizard / Exports / Accounts / Tags / Search / Settings / API tokens

The exact tile count drifts as views are added — the launcher reads its catalog from a single registry at boot, so the count in the README is generated, not typed. Pin / unpin tiles from the launcher to put your daily routes on the topbar.

Recommended first-run path

  1. Open the launcher (Cmd+K), type "accounts", Enter — create an account row for each broker you'll import (step 02).
  2. Import a broker CSV from the Import tile, or run the Generic column-mapping wizard for anything not on the built-in list.
  3. Run the FIFO roll-upPOST /api/trades/rollup is called automatically on every import, but you can re-run it on demand from the Trades view.
  4. Open the Dashboard (Cmd+Opt+D) — equity curve + summary stats + world-markets snapshot grid all populate from the roll-up.
  5. Press ? at any time for the in-app shortcut cheat-sheet.

Boot-time hardening you don't have to configure

  • Per-view race tokens. Every navigation increments a global token in app.js. Each view captures the token at render start and bails after each await if it has gone stale — prevents the document.getElementById(...)-returns-null crash that hits naïve SPAs when slow async resolves into a replaced DOM.
  • Browser-side error sink. window.onerror, unhandledrejection, and an overridden console.error all POST to /api/client-errors, queue-capped at 200 so a console-error loop can't run away.
  • WebKit SecurityError guards. Under Tauri's tauri://localhost custom scheme, navigator.sendBeacon, Notification.requestPermission, new Notification, speechSynthesis.speak, and localStorage all throw cross-origin SecurityErrors. Each is try/caught so boot survives.
  • CSP allows ws://127.0.0.1:* so WebSocket connections to the dynamic backend port aren't blocked under the custom scheme.
  • Real concurrency for fan-out routes. premarket::snapshot, markets::snapshot, market_data::quotes, and compare::compare all use futures_util::future::join_all; a previous serial-loop version blocked /api/premarket/snapshot for 150 seconds and starved the pool.
Diagnose If the WebView loads but every view says "loading…" forever, the Postgres pool probably can't connect. Check the desktop log at ~/Library/Logs/com.menketechnologies.traderview/app.log (macOS) or run the web binary in the foreground — both surface the actual sqlx error.