Production-grade multi-round auction platform for Telegram.
· Architecture · API · Auction Mechanics · Concurrency · Testing · Deployment
┌─────────────────────────────────────────────────────────────────────┐
│ SINGLE-CORE │
│ HTTP: 2,779 req/sec peak, 197 req/s standard load │
│ WebSocket: 200,018 emit/sec peak, 175,970/sec sustained │
│ Latency: 1.5ms mean, 5ms p99 │
│ │
│ CLUSTER MODE (12 cores, sticky sessions) │
│ HTTP: 7,216 req/sec peak, 99.96% success (+160%) │
│ WebSocket: 251,640 emit/sec peak, 12M emits, 80% success (+26%) │
│ │
│ Grade: A+ (production-ready) │
└─────────────────────────────────────────────────────────────────────┘
Full benchmarks: BENCHMARK_REPORT.md · Live Reports
| Feature | Description |
|---|---|
| Multi-round auctions | Items distributed across rounds (e.g., 3+5+2), partial winners each round |
| 5-layer concurrency | Redlock → Redis cooldown → MongoDB transactions → optimistic locking → unique indexes |
| High-performance bidding | Redis Lua script (~1.4ms mean), WebSocket real-time updates |
| Anti-sniping | Configurable window with automatic round extensions |
| Financial integrity | Frozen balances, atomic operations, complete audit trail |
| Telegram native | Login Widget, Mini App auth, bot notifications (GrammyJS) |
| Horizontal scaling | Cluster mode + Redis adapter for multi-server deployments |
Backend: NestJS 11 + Fastify · MongoDB 8 · Redis + Redlock · Socket.IO · JWT Frontend: React 19 + Vite · TypeScript · i18n (en/ru) Infra: Docker Compose · Node.js 22+
# Docker (recommended)
cp backend/.env.example backend/.env
docker compose up --build
# Local development
docker compose -f docker-compose.infra.yml up -d
npm install && npm run devAccess: Frontend localhost:5173 · API localhost:4000/api · Docs localhost:4000/api/docs
PENDING → ACTIVE → COMPLETED
├── Round 1: Top 3 win
├── Round 2: Top 5 win
└── Round 3: Top 2 win → Remaining refunded
1. Redlock → Acquire distributed lock (fail-fast)
2. Redis cooldown → 1s between bids per user
3. MongoDB tx → Snapshot isolation + retry
4. Optimistic → Version check on user/bid
5. Unique index → No duplicate amounts
balance = available for bidding
frozenBalance = locked in active bids
Place bid: balance -= X, frozenBalance += X
Win: frozenBalance -= X (spent)
Refund: frozenBalance -= X, balance += X
| Endpoint | Description |
|---|---|
POST /api/auth/telegram/webapp |
Mini App authentication |
GET /api/auctions |
List auctions |
POST /api/auctions/:id/bid |
Place bid (Redis high-performance) |
GET /api/auctions/:id/leaderboard |
Current rankings |
GET /api/users/balance |
Get balance |
// Authenticate & join
socket.emit('auth', jwtToken);
socket.emit('join-auction', auctionId);
// Place bid (63K/sec possible)
socket.emit('place-bid', { auctionId, amount: 1000 });
// Receive updates
socket.on('new-bid', data => { /* ... */ });
socket.on('bid-response', ({ success, amount }) => { /* ... */ });| Variable | Description |
|---|---|
MONGODB_URI |
MongoDB connection (replica set required) |
REDIS_URL |
Redis connection |
JWT_SECRET |
JWT signing secret |
TELEGRAM_BOT_TOKEN |
Bot token for notifications |
CLUSTER_WORKERS |
0=single, auto=all cores |
- Short: 20/sec · Medium: 100/10sec · Long: 300/min
# HTTP
pnpm run load-test # Standard
pnpm run load-test:stress # Extreme
# WebSocket
npx artillery run test/artillery/websocket-extreme.yml # 63K emit/s- MongoDB transactions — Atomic financial operations
- Redis Lua scripts — Single call for all validation + bid placement (~0.02ms)
- Background sync — 5s interval balances speed vs durability
- WebSocket bidding — Eliminates HTTP overhead for max throughput
- Unique bid amounts — Deterministic leaderboards, no ties
More details: docs/architecture.md · docs/concurrency.md
MIT