# jbocciadev/papertrader architecture

> Architecture diagram of the GitHub repository jbocciadev/papertrader, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-07-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/jbocciadev/papertrader
- Repository: https://github.com/jbocciadev/papertrader

## Overview

#### Purpose and deployment shape
PaperTrader is a paper-trading application split into three deployable services: a market-data service, a trading engine, and a server-rendered web application. Containerization and multi-service orchestration are defined in `docker-compose.yml`, with per-service images in `market-service/Dockerfile`, `trading-service/Dockerfile`, and `web-server/Dockerfile`.

#### Service entry points
- **Market service:** Node.js entry point at `market-service/app.js`; its package/runtime boundary is defined by `market-service/package.json`.
- **Trading service:** Python application starts at `trading-service/main.py`; gRPC serving is separated into `trading-service/app/grpc_server.py`.
- **Web server:** Python web entry point is `web-server/app/main.py`, serving application pages and static browser assets.

#### Market-data ingestion boundary
The market service is the external-market integration boundary. The README states it queries Finnhub using cURL-style quote requests and accepts ticker selection through the `TICKERS` environment variable. This isolates third-party quote retrieval from trading and UI concerns.
Grounding: `market-service/app.js`, `market-service/package.json`, `market-service/Dockerfile`.

#### Trading engine and RPC contract
The trading service owns trade-processing behavior and exposes it through gRPC. Its engine implementation is in `trading-service/app/engine.py`, while server-side request handling is in `trading-service/app/grpc_server.py`. The cross-service API is defined centrally in `protos/engine.proto`; generated Python bindings are checked into `trading-service/app/engine_pb2.py` and `trading-service/app/engine_pb2_grpc.py`.

Primary control flow is expected to cross this boundary as: caller submits an engine RPC → gRPC server dispatches to the engine → engine reads/writes trading state → response returns over the protobuf contract.

#### Persistence and trading state
The trading service maintains its own persistence layer and domain models, keeping business state behind the engine boundary. Database setup/access and initialization are separated from engine logic.
Grounding: `trading-service/app/database.py`, `trading-service/app/models.py`, `trading-service/app/init_db.py`.

SQLite is the intended development/test database, with PostgreSQL identified as the prospective deployment database. Database implementation details should therefore preserve portability across those backends.

#### Web application and browser boundary
The web server is a server-rendered Python application with landing, registration, login, dashboard, and profile views. It has its own models and database layer, suggesting web/account-facing state is managed separately from the trading-service persistence boundary.
Grounding: `web-server/app/main.py`, `web-server/app/models.py`, `web-server/app/database.py`.

The browser-facing dashboard consumes static JavaScript for holdings and ticker streaming, while HTML templates remain on the server-rendered side.
Grounding: `web-server/app/templates/dashboard.html`, `web-server/app/static/js/holdings.js`, `web-server/app/static/js/ticker-stream.js`.

#### Key integration and operational concerns
The web server contains generated gRPC client bindings (`web-server/app/engine_pb2.py`, `web-server/app/engine_pb2_grpc.py`), indicating it is the likely RPC client of the trading engine. The protobuf file is the compatibility-critical contract between them.

Environment configuration includes ticker selection and a development TLS workaround (`NODE_TLS_REJECT_UNAUTHORIZED=0`). The latter is explicitly non-production-safe and should be replaced by valid certificate handling. The application currently permits trades outside US market hours; market-hours enforcement is a future production policy boundary rather than a current engine constraint.

Main entry points: [`web-server/app/main.py`](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/main.py) (Server-rendered web app), [`trading-service/app/grpc_server.py`](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/grpc_server.py) (gRPC server), [`docker-compose.yml`](https://github.com/jbocciadev/papertrader/blob/main/docker-compose.yml) (Service orchestration), [`trading-service/app/engine.py`](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/engine.py) (Trade engine)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_deploy["Deployment"]
  node_compose{{"Service orchestration<br/>Docker Compose<br/>[docker-compose.yml]"}}
end

subgraph group_market["Market data"]
  node_market_image["Market image<br/>Dockerfile"]
  node_market_app["Quote ingestion<br/>Node.js service<br/>[app.js]"]
  node_market_runtime["Node runtime<br/>package manifest<br/>[package.json]"]
end

subgraph group_trading["Trading engine"]
  node_proto["Engine RPC contract<br/>Protocol Buffers<br/>[engine.proto]"]
  node_grpc_server["gRPC server<br/>Python RPC adapter<br/>[grpc_server.py]"]
  node_engine["Trade engine<br/>Python domain engine<br/>[engine.py]"]
  node_trading_models["Trading models<br/>domain models<br/>[models.py]"]
  node_trading_database[("Trading persistence<br/>database layer<br/>[database.py]")]
  node_trading_init["Database initialization<br/>initializer<br/>[init_db.py]"]
  node_trading_entry["Trading process<br/>Python entry point<br/>[main.py]"]
end

subgraph group_web["Web application"]
  node_web_entry["Server-rendered web app<br/>Python web server<br/>[main.py]"]
  node_web_models["Account models<br/>web domain models<br/>[models.py]"]
  node_web_database[("Account persistence<br/>database layer<br/>[database.py]")]
  node_web_grpc_client["Engine gRPC client<br/>generated Python binding<br/>[engine_pb2_grpc.py]"]
  node_dashboard["Dashboard template<br/>server-rendered HTML<br/>[dashboard.html]"]
  node_holdings_js["Holdings client<br/>browser JavaScript<br/>[holdings.js]"]
  node_ticker_js["Ticker stream client<br/>browser JavaScript<br/>[ticker-stream.js]"]
end

node_finnhub(("Finnhub<br/>external market API"))
node_browser(("Browser<br/>user agent"))

node_compose -->|"builds"| node_market_image
node_compose -->|"runs"| node_trading_entry
node_compose -->|"runs"| node_web_entry
node_market_image -->|"packages"| node_market_app
node_market_runtime -->|"defines runtime"| node_market_app
node_market_app -->|"quote requests"| node_finnhub
node_trading_entry -->|"starts"| node_grpc_server
node_proto -->|"defines RPCs"| node_grpc_server
node_grpc_server -->|"dispatches"| node_engine
node_engine -->|"uses"| node_trading_models
node_engine -->|"reads and writes"| node_trading_database
node_trading_init -->|"initializes"| node_trading_database
node_web_entry -->|"uses"| node_web_models
node_web_entry -->|"reads and writes"| node_web_database
node_web_entry -->|"submits engine RPCs"| node_web_grpc_client
node_web_grpc_client -->|"implements"| node_proto
node_web_grpc_client -->|"gRPC calls"| node_grpc_server
node_web_entry -->|"renders"| node_dashboard
node_dashboard -->|"loads"| node_holdings_js
node_dashboard -->|"loads"| node_ticker_js
node_browser -->|"HTTP requests"| node_web_entry
node_web_entry -->|"pages and assets"| node_browser

click node_compose "https://github.com/jbocciadev/papertrader/blob/main/docker-compose.yml"
click node_market_image "https://github.com/jbocciadev/papertrader/blob/main/market-service/Dockerfile"
click node_market_app "https://github.com/jbocciadev/papertrader/blob/main/market-service/app.js"
click node_market_runtime "https://github.com/jbocciadev/papertrader/blob/main/market-service/package.json"
click node_proto "https://github.com/jbocciadev/papertrader/blob/main/protos/engine.proto"
click node_grpc_server "https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/grpc_server.py"
click node_engine "https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/engine.py"
click node_trading_models "https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/models.py"
click node_trading_database "https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/database.py"
click node_trading_init "https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/init_db.py"
click node_trading_entry "https://github.com/jbocciadev/papertrader/blob/main/trading-service/main.py"
click node_web_entry "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/main.py"
click node_web_models "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/models.py"
click node_web_database "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/database.py"
click node_web_grpc_client "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/engine_pb2_grpc.py"
click node_dashboard "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/templates/dashboard.html"
click node_holdings_js "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/static/js/holdings.js"
click node_ticker_js "https://github.com/jbocciadev/papertrader/blob/main/web-server/app/static/js/ticker-stream.js"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_compose toneBlue
class node_market_image,node_market_app,node_market_runtime toneAmber
class node_proto,node_grpc_server,node_engine,node_trading_models,node_trading_database,node_trading_init,node_trading_entry toneMint
class node_web_entry,node_web_models,node_web_database,node_web_grpc_client,node_dashboard,node_holdings_js,node_ticker_js toneRose
class node_finnhub,node_browser toneNeutral
```

## Components

### Deployment

- [Service orchestration](https://github.com/jbocciadev/papertrader/blob/main/docker-compose.yml): Docker Compose · Runs the three deployable services. · `docker-compose.yml`

### Market data

- [Market image](https://github.com/jbocciadev/papertrader/blob/main/market-service/Dockerfile): Dockerfile · `market-service/Dockerfile`
- [Quote ingestion](https://github.com/jbocciadev/papertrader/blob/main/market-service/app.js): Node.js service · Retrieves selected ticker quotes from the external market API. · `market-service/app.js`
- [Node runtime](https://github.com/jbocciadev/papertrader/blob/main/market-service/package.json): package manifest · `market-service/package.json`

### Trading engine

- [Engine RPC contract](https://github.com/jbocciadev/papertrader/blob/main/protos/engine.proto): Protocol Buffers · Compatibility-critical cross-service API. · `protos/engine.proto`
- [gRPC server](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/grpc_server.py): Python RPC adapter · Dispatches engine RPCs to trading behavior. · `trading-service/app/grpc_server.py`
- [Trade engine](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/engine.py): Python domain engine · Owns trade-processing behavior and trading state access. · `trading-service/app/engine.py`
- [Trading models](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/models.py): domain models · `trading-service/app/models.py`
- [Trading persistence](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/database.py): database layer · Portable persistence targeting SQLite development and future PostgreSQL. · `trading-service/app/database.py`
- [Database initialization](https://github.com/jbocciadev/papertrader/blob/main/trading-service/app/init_db.py): initializer · `trading-service/app/init_db.py`
- [Trading process](https://github.com/jbocciadev/papertrader/blob/main/trading-service/main.py): Python entry point · `trading-service/main.py`

### Web application

- [Server-rendered web app](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/main.py): Python web server · Serves landing, account, dashboard, and profile pages. · `web-server/app/main.py`
- [Account models](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/models.py): web domain models · `web-server/app/models.py`
- [Account persistence](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/database.py): database layer · Separate web and account-facing state boundary. · `web-server/app/database.py`
- [Engine gRPC client](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/engine_pb2_grpc.py): generated Python binding · `web-server/app/engine_pb2_grpc.py`
- [Dashboard template](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/templates/dashboard.html): server-rendered HTML · `web-server/app/templates/dashboard.html`
- [Holdings client](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/static/js/holdings.js): browser JavaScript · `web-server/app/static/js/holdings.js`
- [Ticker stream client](https://github.com/jbocciadev/papertrader/blob/main/web-server/app/static/js/ticker-stream.js): browser JavaScript · `web-server/app/static/js/ticker-stream.js`

### Other components

- **Finnhub**: external market API
- **Browser**: user agent

## Connections

- Service orchestration → Market image: builds
- Service orchestration → Trading process: runs
- Service orchestration → Server-rendered web app: runs
- Market image → Quote ingestion: packages
- Node runtime → Quote ingestion: defines runtime
- Quote ingestion → Finnhub: quote requests
- Trading process → gRPC server: starts
- Engine RPC contract → gRPC server: defines RPCs
- gRPC server → Trade engine: dispatches
- Trade engine → Trading models: uses
- Trade engine → Trading persistence: reads and writes
- Database initialization → Trading persistence: initializes
- Server-rendered web app → Account models: uses
- Server-rendered web app → Account persistence: reads and writes
- Server-rendered web app → Engine gRPC client: submits engine RPCs
- Engine gRPC client → Engine RPC contract: implements
- Engine gRPC client → gRPC server: gRPC calls
- Server-rendered web app → Dashboard template: renders
- Dashboard template → Holdings client: loads
- Dashboard template → Ticker stream client: loads
- Browser → Server-rendered web app: HTTP requests
- Server-rendered web app → Browser: pages and assets
