Concepts & Architecture
Workspaces, sessions, the Go backend, and how the pieces fit.
Traffic Jam is three cooperating processes plus one database. Understanding the split — what runs where, and where state lives — makes the rest of the documentation easier to navigate.
The three layers
| Layer | Technology | Responsibility |
|---|---|---|
| Desktop shell | Electron (electron/main.cjs) | Spawns and supervises the Go API, allocates a loopback port, generates the capability token, serves the frontend over the traffic-jam://app scheme |
| Frontend | React + Vite (TypeScript) | All UI: capture library, analysis tabs, API lab, replay dialogs. Talks to the backend only over HTTP |
| API backend | Go (server/, wired with uber-go/fx) | Parsing, TLS decryption, replay, storage. Exposes a JSON REST API under /api |
In the packaged macOS app the shell starts the bundled traffic-jam-api binary on a free 127.0.0.1 port. In development you run the two halves yourself: npm run dev:api starts Go on 127.0.0.1:8790, and npm run dev:web starts Vite, which proxies /api to http://127.0.0.1:8790. See /docs/en/getting-started/installation/.
Workspaces, sessions, and requests
The data model is a small hierarchy:
- Capture folder (workspace) — a directory you register to organize evidence. Folders nest; sessions are filed into them. Managed through
PUT/PATCH/DELETE /api/folders. - Capture session — one imported capture: a
pcap/pcapngfile (with optional TLS keylog) or a HAR file. A session carries parse stats, warnings, TLS fingerprints, and recovered certificates. - Request/response exchange — a single HTTP transaction reassembled from the capture, with ordered headers, bodies, timing, and the TLS fingerprint (JA3/JA4, ciphers, ALPN, SNI) attached to its connection.
The frontend lists sessions via GET /api/sessions (summaries only) and lazily loads full details with GET /api/sessions/{id}. The desktop shell’s workspace tabs — Captures, Browser capture, Android, API lab, Timeline, Compare, TLS, Workbench — are views over this same data.
How the frontend talks to the backend
Every call goes through src/shared/api/client.ts, which prefixes apiBaseUrl and adds one header when a token is configured:
X-Traffic-Jam-Token: <capability token>
The backend resolves the base URL and token from the Electron preload bridge (window.trafficJam) in desktop builds, or from VITE_TRAFFIC_JAM_API_BASE_URL / VITE_TRAFFIC_JAM_API_TOKEN in the web build.
The API security middleware (withAPISecurity in handler.go) enforces two independent checks on every request:
- Origin allowlist. A request carrying an
Originheader must come from an allowed origin or it is rejected with HTTP 403. Always allowed: the desktop origintraffic-jam://app,localhost, and loopback IPs (127.0.0.1,::1). Additional exact origins can be added with the comma-separatedTRAFFIC_JAM_ALLOWED_ORIGINSenv var. - Capability token. When
TRAFFIC_JAM_API_TOKENis set, the request must present the same value inX-Traffic-Jam-Token(compared in constant time) or it is rejected with HTTP 401. The standalone dev API has no token by default; the desktop shell generates a cryptographically random 32-byte token on every launch and passes it only to its own backend and renderer.
| Env var (backend) | Default | Purpose |
|---|---|---|
TRAFFIC_JAM_ADDR | 127.0.0.1:8790 | Listen address |
TRAFFIC_JAM_API_TOKEN | empty (no token required) | Capability token; empty disables the check |
TRAFFIC_JAM_ALLOWED_ORIGINS | empty | Extra exact browser origins beyond loopback/desktop |
TRAFFIC_JAM_DB_PATH | .traffic-jam/traffic-jam-v2.sqlite3 | SQLite database file |
TRAFFIC_JAM_CAPTURE_DIR | .traffic-jam/live-captures | Live-capture artifact directory |
TRAFFIC_JAM_MAX_UPLOAD_BYTES | 4 GiB | Upload size cap |
[!NOTE] The API binds to loopback only. It is a local analysis tool, not a network service; do not point
TRAFFIC_JAM_ADDRat a public interface.
The capture pipeline
Importing a capture (POST /api/import, or /api/import-har for HAR) runs entirely in-process — TShark is not required:
- Read packets.
gopacket/pcapgoiterate thepcap/pcapngfile. - Reassemble TCP streams. Segments are grouped by flow and reordered; capture gaps are reported as warnings. UDP on 443/8443 is flagged as QUIC/HTTP3, which cannot be decrypted with TLS keylogs.
- Decrypt TLS. TLS 1.2/1.3 records are decrypted using keys from an external NSS keylog file or from a pcapng Decryption Secrets Block. The ClientHello/ServerHello are parsed for JA3/JA4 and certificate extraction.
- Parse HTTP. The plaintext stream is parsed into request/response exchanges.
- Persist. The session, exchanges, fingerprints, and certificates are written to SQLite.
Live capture instead drives mitmdump (and tshark for packet-level capture) as child processes; see /docs/en/capture/.
SQLite persistence
All durable state lives in one SQLite database (modernc.org/sqlite, single writer connection). Imported sessions survive API restarts. The tables:
| Table | Stores |
|---|---|
capture_sessions, capture_folders | Imported captures and their folder hierarchy |
traffic_exchanges | Reassembled request/response pairs |
tls_fingerprints, tls_certificates | ClientHello fingerprints and recovered certs |
replay_history | Sent replays and their responses |
endpoint_annotations | Review status, tags, notes per endpoint |
client_certs | Uploaded mTLS client certificates (PEM/PKCS#12) |
decode_scripts, decode_pipelines | Custom decode/encode scripts and per-endpoint pipelines |
fingerprint_profiles, canary_checks, canary_runs | Versioned fingerprint snapshots and canary drift checks |
protobuf_schemas, protobuf_bindings | Uploaded .proto schemas and endpoint bindings |
route_model_rules | Route-catalog modeling rules |
The API lab
The API lab (the api-re feature, workspace tab API lab) is the reverse-engineering surface. It reads the selected capture sessions and layers on a route catalog, global search, signature analysis, decode pipelines, single and bulk replay (capped at 50 requests per batch by the backend), replay-chain variables, and JWT tooling. Replay and its safety model are covered in /docs/en/replay/; the investigation and findings workflow in /docs/en/analysis/ and /docs/en/security/; exporting a standalone Go collector in /docs/en/collector/.
[!WARNING] Features such as
alg=nonetest tokens, credential A/B replay, and mutation probes are for authorized testing of systems you have permission to assess.
Where data lives on disk
- Web/dev:
.traffic-jam/traffic-jam-v2.sqlite3under the working directory, with live-capture artifacts in.traffic-jam/live-captures(or beside a custom database). - Desktop app: the SQLite database sits in Electron’s user-data directory (
traffic-jam-v2.sqlite3); open it via Capture → Open Traffic Jam Data Folder.
Environment variables and file formats are collected in /docs/en/reference/.