# fluidex/dingir-exchange architecture

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

- Interactive diagram: https://gitdiagram.com/fluidex/dingir-exchange
- Repository: https://github.com/fluidex/dingir-exchange

## Overview

#### Purpose and Executables
Dingir Exchange is a Rust trading-server backend centered on a high-throughput, in-memory order-matching engine. It intentionally excludes account onboarding and cryptocurrency deposit/withdrawal. Runtime binaries separate core trading, durable event processing, HTTP-style REST access, and message inspection:
- `src/bin/matchengine.rs`
- `src/bin/persistor.rs`
- `src/bin/restapi.rs`
- `src/bin/dump_unify_messages.rs`

#### Core Matching Engine
The matching engine is a fully asynchronous but single-threaded state owner: order-book mutation, sequencing, trades, balances, and user state should remain within this boundary to preserve deterministic ordering and avoid concurrent state mutation.
- `src/matchengine/server.rs`
- `src/matchengine/controller.rs`
- `src/matchengine/sequencer.rs`
- `src/matchengine/market/order.rs`
- `src/matchengine/market/trade.rs`

Requests enter the engine server/controller, are sequenced, then mutate market and account state. Resulting order-state changes, trades, and market data become outbound messages and persistence inputs.

#### Market, User, and Asset Domains
Market state and trade execution are distinct from user/account balances. Asset management applies balance updates and controls how those updates are emitted or coordinated; user management owns user-level exchange state. This is the primary business-state boundary beneath the controller.
- `src/matchengine/market/mod.rs`
- `src/matchengine/asset/asset_manager.rs`
- `src/matchengine/asset/balance_manager.rs`
- `src/matchengine/asset/update_controller.rs`
- `src/matchengine/user_manager.rs`

#### Messaging and Event Boundary
The system has a dedicated producer/consumer/persistence messaging layer, likely used to decouple engine mutations from durable operation logs and downstream consumers. Kafka is a material external dependency: the project requires `librdkafka`, and examples include Kafka monitoring.
- `src/message/producer.rs`
- `src/message/consumer.rs`
- `src/message/persist.rs`
- `examples/js/kafka_client.ts`

This boundary should carry ordered engine outputs rather than allow consumers to directly mutate matching state.

#### Durability and Historical Storage
Durability combines append-style operation logging with Redis-like fork-and-save snapshots. The persistor component bridges engine/message outputs to durable state; SQL storage holds longer-lived relational records such as trades, kline data, markets, accounts, and transfers.
- `src/matchengine/persist/persistor.rs`
- `src/matchengine/persist/state_save_load.rs`
- `src/storage/database.rs`
- `migrations/20200123090047_trade_log.sql`
- `migrations/20210114140803_kline.sql`

PostgreSQL is the documented local dependency, launched alongside Kafka through the orchestration environment.

#### API Surfaces and Clients
gRPC is the documented primary server interface, implemented with Tokio/Hyper/Tonic. A separate REST API process exposes management, user, public/personal history, trading-view data, and state access; it should query or coordinate with the authoritative engine/persisted data rather than duplicate matching logic.
- `src/restapi/mod.rs`
- `src/restapi/manage.rs`
- `src/restapi/public_history.rs`
- `src/restapi/personal_history.rs`
- `src/restapi/tradingview.rs`

JavaScript and Python examples act as external clients and signing/integration references:
- `examples/js/RESTClient.ts`
- `examples/js/ordersigner.proto`
- `examples/python/put_order.py`

#### Configuration and Deployment
Configuration is layered by environment and service-specific REST settings. Local integration infrastructure is under `orchestra`; release packaging builds a Docker image.
- `src/config.rs`
- `config/default.yaml`
- `config/restapi/default.yaml`
- `orchestra`
- `release/Dockerfile`

Main entry points: [`src/matchengine/sequencer.rs`](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/sequencer.rs) (Sequencer), [`src/matchengine/persist/persistor.rs`](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/persist/persistor.rs) (Persistence pipeline), [`src/restapi/mod.rs`](https://github.com/fluidex/dingir-exchange/blob/master/src/restapi/mod.rs) (REST handlers), [`src/matchengine/server.rs`](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/server.rs) (Engine server)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtimes["Runtime processes"]
  node_matchengine_bin["Match engine binary<br/>Rust binary<br/>[matchengine.rs]"]
  node_persistor_bin["Persistor binary<br/>Rust binary<br/>[persistor.rs]"]
  node_restapi_bin["REST API binary<br/>Rust binary<br/>[restapi.rs]"]
  node_message_dump["Message dump tool<br/>Rust binary"]
end

subgraph group_engine["Authoritative matching engine"]
  node_engine_server["Engine server<br/>gRPC server<br/>[server.rs]"]
  node_controller["Engine controller<br/>command controller<br/>[controller.rs]"]
  node_sequencer["Sequencer<br/>ordered command stream<br/>[sequencer.rs]"]
  node_market["Market and order books<br/>matching domain<br/>[mod.rs]"]
  node_assets["Assets and balances<br/>accounting domain<br/>[asset_manager.rs]"]
  node_users["User state<br/>user domain<br/>[user_manager.rs]"]
end

subgraph group_events["Messaging and durability"]
  node_producer["Event producer<br/>message producer<br/>[producer.rs]"]
  node_kafka["Kafka<br/>event broker"]
  node_consumer["Event consumer<br/>message consumer<br/>[consumer.rs]"]
  node_persistor["Persistence pipeline<br/>operation persistence<br/>[persistor.rs]"]
  node_snapshots[("Fork-and-save snapshots<br/>state snapshots<br/>[state_save_load.rs]")]
end

subgraph group_api["API access"]
  node_restapi["REST handlers<br/>HTTP API<br/>[mod.rs]"]
  node_external_clients(("JS and Python clients<br/>external clients<br/>[RESTClient.ts]"))
end

subgraph group_storage["Historical storage"]
  node_sql_storage[("PostgreSQL records<br/>relational storage<br/>[database.rs]")]
end

node_orchestra{{"Local orchestration<br/>deployment environment"}}

node_matchengine_bin -->|"runs"| node_engine_server
node_engine_server -->|"requests"| node_controller
node_controller -->|"orders commands"| node_sequencer
node_sequencer -->|"mutates"| node_market
node_sequencer -->|"updates"| node_assets
node_sequencer -->|"updates"| node_users
node_market -->|"orders, trades, market data"| node_producer
node_assets -->|"balance events"| node_producer
node_producer -->|"publishes"| node_kafka
node_kafka -->|"consumes"| node_consumer
node_consumer -->|"persistence inputs"| node_persistor
node_persistor_bin -->|"runs"| node_persistor
node_persistor -->|"saves state"| node_snapshots
node_persistor -->|"writes records"| node_sql_storage
node_restapi_bin -->|"runs"| node_restapi
node_external_clients -->|"REST requests"| node_restapi
node_restapi -->|"coordinates trading and state"| node_engine_server
node_restapi -->|"queries history"| node_sql_storage
node_message_dump -.->|"inspects"| node_kafka
node_orchestra -.->|"starts"| node_kafka
node_orchestra -.->|"starts"| node_sql_storage

click node_matchengine_bin "https://github.com/fluidex/dingir-exchange/blob/master/src/bin/matchengine.rs"
click node_persistor_bin "https://github.com/fluidex/dingir-exchange/blob/master/src/bin/persistor.rs"
click node_restapi_bin "https://github.com/fluidex/dingir-exchange/blob/master/src/bin/restapi.rs"
click node_message_dump "https://github.com/fluidex/dingir-exchange/blob/master/src/bin/dump_unify_messages.rs"
click node_engine_server "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/server.rs"
click node_controller "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/controller.rs"
click node_sequencer "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/sequencer.rs"
click node_market "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/market/mod.rs"
click node_assets "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/asset/asset_manager.rs"
click node_users "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/user_manager.rs"
click node_producer "https://github.com/fluidex/dingir-exchange/blob/master/src/message/producer.rs"
click node_consumer "https://github.com/fluidex/dingir-exchange/blob/master/src/message/consumer.rs"
click node_persistor "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/persist/persistor.rs"
click node_snapshots "https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/persist/state_save_load.rs"
click node_restapi "https://github.com/fluidex/dingir-exchange/blob/master/src/restapi/mod.rs"
click node_sql_storage "https://github.com/fluidex/dingir-exchange/blob/master/src/storage/database.rs"
click node_external_clients "https://github.com/fluidex/dingir-exchange/blob/master/examples/js/RESTClient.ts"
click node_orchestra "https://github.com/fluidex/dingir-exchange/tree/master/orchestra"

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_matchengine_bin,node_persistor_bin,node_restapi_bin,node_message_dump toneBlue
class node_engine_server,node_controller,node_sequencer,node_market,node_assets,node_users toneAmber
class node_producer,node_kafka,node_consumer,node_persistor,node_snapshots toneMint
class node_restapi,node_external_clients toneRose
class node_sql_storage toneIndigo
class node_orchestra toneNeutral
```

## Components

### Runtime processes

- [Match engine binary](https://github.com/fluidex/dingir-exchange/blob/master/src/bin/matchengine.rs): Rust binary · `src/bin/matchengine.rs`
- [Persistor binary](https://github.com/fluidex/dingir-exchange/blob/master/src/bin/persistor.rs): Rust binary · `src/bin/persistor.rs`
- [REST API binary](https://github.com/fluidex/dingir-exchange/blob/master/src/bin/restapi.rs): Rust binary · `src/bin/restapi.rs`
- [Message dump tool](https://github.com/fluidex/dingir-exchange/blob/master/src/bin/dump_unify_messages.rs): Rust binary · Inspects unified messages. · `src/bin/dump_unify_messages.rs`

### Authoritative matching engine

Single-threaded owner of ordered exchange state.

- [Engine server](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/server.rs): gRPC server · Primary request entry point. · `src/matchengine/server.rs`
- [Engine controller](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/controller.rs): command controller · `src/matchengine/controller.rs`
- [Sequencer](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/sequencer.rs): ordered command stream · Preserves deterministic mutation order. · `src/matchengine/sequencer.rs`
- [Market and order books](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/market/mod.rs): matching domain · `src/matchengine/market/mod.rs`
- [Assets and balances](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/asset/asset_manager.rs): accounting domain · `src/matchengine/asset/asset_manager.rs`
- [User state](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/user_manager.rs): user domain · `src/matchengine/user_manager.rs`

### Messaging and durability

- [Event producer](https://github.com/fluidex/dingir-exchange/blob/master/src/message/producer.rs): message producer · Publishes ordered engine outputs. · `src/message/producer.rs`
- **Kafka**: event broker · External durable consumer boundary.
- [Event consumer](https://github.com/fluidex/dingir-exchange/blob/master/src/message/consumer.rs): message consumer · `src/message/consumer.rs`
- [Persistence pipeline](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/persist/persistor.rs): operation persistence · Bridges event outputs to durable state. · `src/matchengine/persist/persistor.rs`
- [Fork-and-save snapshots](https://github.com/fluidex/dingir-exchange/blob/master/src/matchengine/persist/state_save_load.rs): state snapshots · `src/matchengine/persist/state_save_load.rs`

### API access

- [REST handlers](https://github.com/fluidex/dingir-exchange/blob/master/src/restapi/mod.rs): HTTP API · Management, trading, state, and history access. · `src/restapi/mod.rs`
- [JS and Python clients](https://github.com/fluidex/dingir-exchange/blob/master/examples/js/RESTClient.ts): external clients · Signing and integration examples. · `examples/js/RESTClient.ts`

### Historical storage

- [PostgreSQL records](https://github.com/fluidex/dingir-exchange/blob/master/src/storage/database.rs): relational storage · Stores trades, klines, markets, accounts, and transfers. · `src/storage/database.rs`

### Other components

- [Local orchestration](https://github.com/fluidex/dingir-exchange/tree/master/orchestra): deployment environment · Launches local Kafka and PostgreSQL dependencies. · `orchestra`

## Connections

- Match engine binary → Engine server: runs
- Engine server → Engine controller: requests
- Engine controller → Sequencer: orders commands
- Sequencer → Market and order books: mutates
- Sequencer → Assets and balances: updates
- Sequencer → User state: updates
- Market and order books → Event producer: orders, trades, market data
- Assets and balances → Event producer: balance events
- Event producer → Kafka: publishes
- Kafka → Event consumer: consumes
- Event consumer → Persistence pipeline: persistence inputs
- Persistor binary → Persistence pipeline: runs
- Persistence pipeline → Fork-and-save snapshots: saves state
- Persistence pipeline → PostgreSQL records: writes records
- REST API binary → REST handlers: runs
- JS and Python clients → REST handlers: REST requests
- REST handlers → Engine server: coordinates trading and state
- REST handlers → PostgreSQL records: queries history
- Message dump tool → Kafka: inspects
- Local orchestration → Kafka: starts
- Local orchestration → PostgreSQL records: starts
