Architecture
System Overview
Arbi's infrastructure is a microservices architecture with a unified frontend, backend APIs, and blockchain integrations. All services are containerized, auto-deployed via GitHub Actions, and exposed through Nginx reverse proxy.
βββββββββββββββββββββββββββ
β Internet (HTTPS) β
βββββββββββββ¬ββββββββββββββ
β
βββββββββββββΌβββββββββββββββ
β Nginx Reverse Proxy β
β SSL/TLS Termination β
βββββββββββββ¬βββββββββββββββ
β
βββββββββββββββββΌββββββββββββββββ
β β β
βββββββββΌβββββ ββββββββΌβββββββ ββββββΌββββββ
β Frontend β β Backend β β Docs β
β (3500) β β APIs β β (3200) β
ββββββββββββββ ββββββββ¬βββββββ ββββββββββββ
β
βββββββββββββββββββββΌββββββββββββββββββββ
β β β
ββββββββΌβββββββ ββββββββββΌβββββββββ ββββββββΌβββββββ
β Wallet API β β Email API β β Onchain API β
β (3100) β β (3400) β β (8000) β
ββββββββ¬βββββββ ββββββββββ¬βββββββββ ββββββββ¬βββββββ
β β β
ββββββββΌβββββββ ββββββββββΌβββββββββ ββββββββΌβββββββ
β Alchemy β β Gmail API β β DexScreenerβ
β Base/SOL β β (OAuth2) β β (Prices) β
βββββββββββββββ βββββββββββββββββββ βββββββββββββββ
Core Components
1. Unified Frontend (Port 3500)
Purpose: Single-page application serving all UI components
Tech: Vanilla JavaScript, HTML, CSS (neobrutalist design)
Routing: Client-side hash routing (/, /wallet, /email, /analytics, /onchain)
Why this approach: - Single deployment instead of 5 separate sites - Consistent design system across all pages - Unified API proxying (no CORS issues) - Easier maintenance
2. Backend APIs
Each service runs as independent container with REST API:
| Service | Port | Purpose | External APIs |
|---|---|---|---|
| Wallet | 3100 | Portfolio tracking | Alchemy, DexScreener, CoinGecko |
| 3400 | Email monitoring | Gmail API | |
| Analytics | 3300 | System metrics | SQLite |
| Onchain | 8000 | Transaction monitoring | Alchemy, DexScreener |
Design pattern: Express.js + SQLite/in-memory storage + external API clients
3. Nginx Reverse Proxy
Configuration:
location /api/wallet/ {
proxy_pass http://localhost:3100/api/;
}
location /api/email/ {
proxy_pass http://localhost:3400/api/;
}
location /api/onchain/ {
proxy_pass http://localhost:8000/api/;
}
Benefits: - Single SSL certificate for all services - API proxying avoids CORS - Easy service routing - Health check endpoints
Data Flow
Wallet Balance Retrieval
1. Frontend β GET /api/wallet/balances
2. Nginx β Forward to localhost:3100
3. Wallet API β Alchemy API (Base & Solana balances)
4. Wallet API β CoinGecko (ETH & SOL prices)
5. Wallet API β Calculate USD values
6. Wallet API β Return JSON
7. Nginx β Forward response
8. Frontend β Display in UI
Token Holdings
1. Frontend β GET /api/wallet/tokens
2. Wallet API β Alchemy getTokenBalances (Base)
3. Wallet API β For each token:
- Query DexScreener for price
- Filter by chain and liquidity
- Calculate USD value
4. Wallet API β Return array of tokens
5. Frontend β Render table with search
Transaction Monitoring
1. Background thread (5-min loop):
- Alchemy getAssetTransfers (fromAddress)
- Alchemy getAssetTransfers (toAddress)
- Deduplicate by hash
- Extract token symbol, amount
- Query DexScreener for USD value
- Store in SQLite
- Send Discord notification
2. Frontend β GET /api/onchain/transactions
3. Onchain API β Query SQLite
4. Frontend β Display transaction list
External Dependencies
APIs
- Alchemy: Base & Solana RPC, transaction history
- DexScreener: Token price discovery (DEX liquidity)
- CoinGecko: Native token prices (ETH, SOL)
- Gmail API: OAuth2 email access
- Discord Webhooks: Real-time notifications
Rate Limits
- Alchemy: 330 req/s (free tier) - no issue with 5-min polling
- DexScreener: No official limit, we don't hit it
- CoinGecko: 10-30 calls/min (free tier) - cached 5 minutes
- Gmail API: 250 quota units/user/second - no issue
Storage
SQLite Databases
- Onchain:
/data/onchain.db- Transaction history - Email: In-memory (stateless, Gmail is source of truth)
- Analytics:
/data/analytics.db- System snapshots
Why SQLite: - Embedded, no separate database server - Perfect for read-heavy workloads - Handles millions of rows easily - Backs up with Docker volumes
Docker Volumes
Security Model
Credentials
- Stored in
/root/.openclaw/workspace/.credentials(not in git) - Injected as environment variables in Docker
- Gmail OAuth token in Docker volume (writable)
API Keys
- Alchemy: Read-only RPC access
- Gmail: Read-only OAuth scope
- Discord: Webhook URLs (write-only)
Private Keys
- Base wallet private key: Not used in backend services (sign transactions manually)
- Solana wallet private key: Not used in backend services
Philosophy: Services only READ blockchain/email data, never sign/send transactions autonomously.
Deployment Model
CI/CD Pipeline
Push to main β GitHub Actions β SSH to server β
Pull code β Docker build β Docker up -d β Health check
Zero-Downtime Updates
- Docker containers restart individually
- Nginx keeps serving during restarts
- Frontend cached by browser
- APIs respond within 30s of restart
Rollback Strategy
# View recent images
docker images | grep arbi
# Roll back to previous image
docker stop arbi-frontend
docker run -d --name arbi-frontend <old-image-id>
Design Decisions
Why Unified Frontend?
Problem: 5 separate subdomain sites meant: - 5 separate deployments - 5 SSL certificates - Inconsistent design - CORS issues
Solution: Single SPA with client-side routing - 1 deployment - 1 SSL cert - Unified neobrutalist design - API proxying via Nginx
Why Backend-First Architecture?
Problem: Direct blockchain RPC calls from browser: - CORS issues with public RPCs - API keys exposed in frontend - Slow response times
Solution: Backend APIs fetch data server-side - Proxy requests through Nginx - Cache responses - Hide API keys - Process data before returning
Why Polling Instead of Webhooks?
Problem: Blockchain data changes constantly
Solution: 5-minute polling loop - Simple to implement - Stays within rate limits - Easy to debug - Reliable (no webhook failures)
Why SQLite Instead of PostgreSQL?
Problem: Need persistent transaction history
Solution: SQLite embedded database - No separate database server - Perfect for read-heavy workloads - Backs up with Docker volumes - Handles 1M+ rows easily
Scaling Considerations
Current Load
- ~50 requests/hour to APIs
- ~100 blockchain queries/hour
- 2 new transactions per day (avg)
- 5-10 emails per day
Bottlenecks: None. Current architecture overkill for load.
If Scaling Needed
- Multiple wallets: Add Redis cache for balances
- High transaction volume: Switch to PostgreSQL
- Many users: Add API authentication
- Global deployment: Use CDN for frontend
But current setup handles 100x load easily.