A complete trading platform backend built to production standards — real-time order matching, ACID wallet system, event-driven architecture, and full observability.
- ⚡ Price-Time Priority Order Matching Engine — goroutine-safe, channel-based, deadlock-free
- 💰 ACID Wallet System — row-level locking, version column, DB-level balance constraint
- 📡 Real-Time WebSocket Feeds — live order book updates with topic-based subscriptions
- 🔐 4-Role RBAC — Admin, Broker, Trader, Support with JWT access + refresh tokens
- 📊 Prometheus Observability — request latency, trade count, WebSocket connections, rate limit hits
- 📨 Kafka Event Streaming — async trade notifications, audit trails, analytics consumers
- 🔑 Idempotency — duplicate order protection via partial unique index
- 🧪 Full Test Coverage — unit, integration (real Postgres), and E2E smoke tests (33 tests total)
- 📖 Swagger UI — interactive API documentation
┌─────────────────────────────────────────────────────────────────────┐
│ HTTP Clients / WebSocket │
└──────────────────────────────┬──────────────────────────────────────┘
│
┌──────────▼──────────┐
│ Gin HTTP Server │ :8080
│ Auth · Rate Limit │
│ Prometheus Metrics │
│ Swagger UI │
└──────────┬──────────┘
┌────────────────────┼─────────────────────┐
│ │ │
┌──────▼──────┐ ┌─────────▼──────┐ ┌─────────▼──────┐
│ Handlers │ │ WebSocket Hub │ │ /metrics │
│ auth/wallet│ │ Real-time feed │ │ Prometheus │
│ asset/order│ └─────────────────┘ └────────────────┘
│ admin │
└──────┬──────┘
│
┌──────▼──────────────────────────────────┐
│ Services Layer │
│ AuthService · WalletService · AssetSvc │
│ OrderService · AdminService │
└──────┬──────────────────────────────────┘
│
┌──────▼──────────────────────────────────┐
│ Repository Layer │
│ UserRepo · WalletRepo · OrderRepo │
│ AssetRepo · TradeRepo · PortfolioRepo │
└──────┬──────────────────────────────────┘
│
┌──────▼──────────────────────────────────┐
│ Infrastructure │
│ PostgreSQL · Redis · Kafka · WebSocket │
└─────────────────────────────────────────┘
┌──────────────────────────────────────────┐
│ Matching Engine (goroutine) │
│ Channel-based · Price-Time Priority │
│ Atomic DB transactions · FOR UPDATE │
│ Publishes to Kafka + Redis Pub/Sub │
└──────────────────────────────────────────┘
| Layer | Technology |
|---|---|
| Language | Go 1.24 |
| HTTP Framework | Gin |
| ORM | GORM + sqlx + raw SQL migrations |
| Database | PostgreSQL |
| Cache | Redis (go-redis/v9) |
| Message Queue | Kafka (segmentio/kafka-go) |
| Auth | JWT (golang-jwt/v5) + bcrypt |
| Real-time | WebSocket (gorilla/websocket) |
| Metrics | Prometheus (prometheus/client_golang) |
| API Docs | Swagger (swaggo/swag) |
| Logging | Zerolog (structured JSON) |
| Testing | Testify + integration tests against real Postgres |
| CI/CD | GitHub Actions |
| Containerization | Docker + Docker Compose |
Runs as a single goroutine consuming from a buffered chan *models.Order. Both order rows are locked with SELECT … FOR UPDATE in ascending ID order to prevent deadlocks. The entire trade — order fills, wallet debits/credits, portfolio updates, trade record — commits in one ACID transaction.
Every balance mutation uses SELECT … FOR UPDATE inside a transaction + bumps a version column. A CHECK (balance >= 0) DB constraint acts as the final safety net against race conditions.
Order placement accepts an Idempotency-Key header stored with a partial unique index (user_id, idempotency_key). Duplicate requests return the original order — no double execution.
Redis-backed sliding window rate limiter (ZADD + ZCARD pipeline). Fails open if Redis is unavailable. Returns X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset headers.
- Structured JSON logs via Zerolog
- Prometheus metrics at
/metrics - Audit logs in Postgres for every trade, order, and admin action
MultiTrade-Platform/
├── cmd/api/
│ └── main.go # Entry point — wires all dependencies
├── internal/
│ ├── admin/ # Admin service: user management, analytics
│ ├── auth/ # JWT service, auth service, unit tests
│ ├── cache/ # Redis client (price cache, pub/sub, rate limit)
│ ├── config/ # Viper-based config loader
│ ├── cronjobs/ # Scheduled maintenance (expire orders, reconcile wallets)
│ ├── handlers/ # Gin HTTP handlers
│ ├── kafka/ # Producer, consumers (notification, audit, analytics)
│ ├── matchingengine/ # Price-time priority matching engine + tests
│ ├── middleware/ # JWT auth, RBAC, rate limiting, Prometheus
│ ├── models/ # Domain structs
│ ├── repository/ # Postgres implementations
│ ├── trading/ # Asset service + Order service
│ ├── wallet/ # Wallet service + integration tests
│ └── websocket/ # Hub, client, upgrade handler
├── migrations/ # Sequential SQL migrations
├── scripts/
│ └── smoke_e2e.go # Full E2E smoke test
├── postman/ # Postman collection + environment
├── docker-compose.yml # Postgres + Redis + Kafka local dev stack
└── go.mod
- Go 1.24+
- Docker & Docker Compose
docker-compose up -dStarts PostgreSQL :5433 · Redis :6379 · Kafka/Redpanda :9092
cp .env.example .envgo run ./cmd/apiMigrations run automatically. Server starts on http://localhost:8080
| URL | Description |
|---|---|
| http://localhost:8080/swagger/index.html | Interactive Swagger UI |
| http://localhost:8080/metrics | Prometheus metrics |
| http://localhost:8080/health | Health check |
| ws://localhost:8080/ws | WebSocket real-time feed |
| Method | Path | Description |
|---|---|---|
| POST | /auth/register |
Register (admin/broker/trader/support) |
| POST | /auth/login |
Login — returns JWT pair (rate-limited: 10/min/IP) |
| POST | /auth/refresh |
Exchange refresh token |
| GET | /auth/me |
Current user info |
| Method | Path | Description |
|---|---|---|
| GET | /wallet |
Current balance |
| POST | /wallet/deposit |
Deposit funds |
| POST | /wallet/withdraw |
Withdraw funds |
| GET | /wallet/transactions |
Paginated transaction history |
| Method | Path | Description |
|---|---|---|
| POST | /orders |
Place limit order BUY/SELL with Idempotency-Key |
| GET | /orders |
Own order history |
| DELETE | /orders/:id |
Cancel pending order |
| Method | Path | Description |
|---|---|---|
| GET | /admin/users |
List users |
| PATCH | /admin/users/:id/status |
Suspend/activate user |
| GET | /admin/analytics/volume |
Hourly trade volume |
| GET | /admin/audit |
Paginated audit logs |
| GET | /admin/health |
DB + Redis + Kafka health |
| Role | Permissions |
|---|---|
admin |
Full admin API, user management, analytics |
broker |
Create and manage assets |
trader |
Place/cancel orders, wallet operations |
support |
Read-only access |
# All tests
go test ./...
# By package
go test -v ./internal/auth/...
go test -v ./internal/wallet/...
go test -v ./internal/matchingengine/...
# E2E (server must be running)
go run scripts/smoke_e2e.go| Package | Tests | Type |
|---|---|---|
internal/auth |
9 tests | Unit (stub repo, no DB) |
internal/wallet |
8 tests | Integration (real Postgres) |
internal/matchingengine |
2 tests | Integration — 25 concurrent orders |
scripts/smoke_e2e.go |
14 checks | E2E against live server |
Import postman/TradeVerse.postman_collection.json and postman/TradeVerse_Environment.json into Postman. Set base_url to http://localhost:8080 — Register/Login requests auto-populate the access_token variable.
Fathima Sithara — Backend Engineer (Go · Distributed Systems)
Also check out:
- 💬 Real-Time Chat App — Distributed messaging with Go microservices
- 🛒 E-Commerce Platform — Next.js + Node.js full-stack app
⭐ If this project helped you, please give it a star!