diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..c263594 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## Summary + +- Summary item + +## Validation + +- [ ] Tests or checks run locally +- [ ] Documentation updated, if needed +- [ ] No unrelated source files changed + +## Notes + +Link the issue this PR addresses and call out any known follow-up work. diff --git a/0 b/0 deleted file mode 100644 index e69de29..0000000 diff --git a/GABC...WXYZ b/GABC...WXYZ deleted file mode 100644 index e69de29..0000000 diff --git a/MICROSERVICES_VISUAL_GUIDE.md b/MICROSERVICES_VISUAL_GUIDE.md deleted file mode 100644 index 2e36714..0000000 --- a/MICROSERVICES_VISUAL_GUIDE.md +++ /dev/null @@ -1,553 +0,0 @@ -# Microservices Architecture - Visual Guide - -Quick visual reference for the Open-Audit microservices architecture. - ---- - -## πŸ—οΈ Architecture Overview - -### System Diagram - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STELLAR BLOCKCHAIN β”‚ -β”‚ (Horizon + Soroban RPC) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ Polls for new events - β”‚ Stream or batch mode - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INDEXER WORKER β”‚ -β”‚ (src/worker/indexer.ts) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Horizon Stream │──│ Event Processor │──│ Redis Publisher β”‚ β”‚ -β”‚ β”‚ or Polling β”‚ β”‚ + Translator β”‚ β”‚ (Auto-queue) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ Publish to channel - β”‚ "stellar:events" - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ REDIS PUB/SUB β”‚ -β”‚ (redis:7-alpine) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Channel: "stellar:events" β”‚ β”‚ -β”‚ β”‚ - Message queuing during downtime β”‚ β”‚ -β”‚ β”‚ - Persistent storage (AOF enabled) β”‚ β”‚ -β”‚ β”‚ - Health checks every 10s β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ Subscribe to channel - β”‚ "stellar:events" - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ WEB SERVER β”‚ -β”‚ (server-decoupled.ts) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Redis Subscriber│──│ WebSocket Server │──│ Next.js Server β”‚ β”‚ -β”‚ β”‚ (Auto-reconnect)β”‚ β”‚ (Broadcaster) β”‚ β”‚ (HTTP/API) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ Broadcast via WebSocket - β”‚ ws://localhost:3000/ws/events - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ WEBSOCKET CLIENTS β”‚ -β”‚ (Browser / Test Client) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Browser β”‚ β”‚ Mobile App β”‚ β”‚ Test Client β”‚ β”‚ -β”‚ β”‚ Dashboard β”‚ β”‚ β”‚ β”‚ (Script) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## πŸ”„ Message Flow - -### Event Processing Pipeline - -``` -1. STELLAR BLOCKCHAIN - β”‚ - β”‚ New contract event emitted - β”‚ - β”œβ”€β–Ά Event ID: 0001234567890-0000000001 - β”œβ”€β–Ά Contract: CABC...1234 - β”œβ”€β–Ά Topic: "transfer" - └─▢ Data: [from, to, amount] - - β–Ό - -2. INDEXER WORKER - β”‚ - β”‚ Fetch event via Horizon - β”‚ - β”œβ”€β–Ά Parse XDR data - β”œβ”€β–Ά Translate using registry - └─▢ Serialize to JSON - - β–Ό - -3. REDIS PUB/SUB - β”‚ - β”‚ Receive on channel "stellar:events" - β”‚ - β”œβ”€β–Ά Queue if subscribers not ready - └─▢ Publish to all subscribers - - β–Ό - -4. WEB SERVER - β”‚ - β”‚ Receive from Redis subscription - β”‚ - β”œβ”€β–Ά Parse message - └─▢ Broadcast to all WebSocket clients - - β–Ό - -5. WEBSOCKET CLIENTS - β”‚ - β”‚ Receive event in real-time - β”‚ - β”œβ”€β–Ά Display in dashboard - └─▢ Log in console -``` - ---- - -## 🐳 Docker Compose Architecture - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Docker Compose Network β”‚ -β”‚ (open-audit-network) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ REDIS CONTAINER β”‚ β”‚ -β”‚ β”‚ Name: open-audit-redis β”‚ β”‚ -β”‚ β”‚ Image: redis:7-alpine β”‚ β”‚ -β”‚ β”‚ Port: 6379 β†’ 6379 β”‚ β”‚ -β”‚ β”‚ Volume: redis-data:/data β”‚ β”‚ -β”‚ β”‚ Health: redis-cli ping β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β–Ό β–Ό β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ INDEXER CONTAINER β”‚ β”‚ WEB CONTAINER β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Name: open-audit- β”‚ β”‚ Name: open-audit-web β”‚ β”‚ -β”‚ β”‚ indexer β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Build: Dockerfile. β”‚ β”‚ Build: Dockerfile.webβ”‚ β”‚ -β”‚ β”‚ worker β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Depends: Redis β”‚ β”‚ Depends: Redis β”‚ β”‚ -β”‚ β”‚ Health: node check β”‚ β”‚ Port: 3000 β†’ 3000 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Health: /api/health β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ POSTGRES CONTAINER (Optional) β”‚ β”‚ -β”‚ β”‚ Name: open-audit-db β”‚ β”‚ -β”‚ β”‚ Image: postgres:15-alpine β”‚ β”‚ -β”‚ β”‚ Port: 5432 β†’ 5432 β”‚ β”‚ -β”‚ β”‚ Volume: postgres-data:/var/lib/postgresql/data β”‚ β”‚ -β”‚ β”‚ Health: pg_isready β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## πŸ“Š PM2 Process Architecture - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ PM2 DAEMON β”‚ -β”‚ (~/.pm2 directory) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Process 1: web-server β”‚ β”‚ -β”‚ β”‚ ────────────────────────────────────────────────────────────│ β”‚ -β”‚ β”‚ Script: server-decoupled.ts β”‚ β”‚ -β”‚ β”‚ Mode: fork β”‚ β”‚ -β”‚ β”‚ Instances: 1 β”‚ β”‚ -β”‚ β”‚ Status: online β”‚ β”‚ -β”‚ β”‚ Uptime: 45m β”‚ β”‚ -β”‚ β”‚ Memory: 256 MB β”‚ β”‚ -β”‚ β”‚ CPU: 5% β”‚ β”‚ -β”‚ β”‚ Restarts: 0 β”‚ β”‚ -β”‚ β”‚ Logs: ./logs/web-server-*.log β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Process 2: indexer-worker β”‚ β”‚ -β”‚ β”‚ ────────────────────────────────────────────────────────────│ β”‚ -β”‚ β”‚ Script: src/worker/indexer.ts β”‚ β”‚ -β”‚ β”‚ Mode: fork β”‚ β”‚ -β”‚ β”‚ Instances: 1 β”‚ β”‚ -β”‚ β”‚ Status: online β”‚ β”‚ -β”‚ β”‚ Uptime: 45m β”‚ β”‚ -β”‚ β”‚ Memory: 180 MB β”‚ β”‚ -β”‚ β”‚ CPU: 15% β”‚ β”‚ -β”‚ β”‚ Restarts: 0 β”‚ β”‚ -β”‚ β”‚ Logs: ./logs/indexer-*.log β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -External: Redis Server (managed separately) - - Port: 6379 - - Command: redis-server -``` - ---- - -## πŸ”„ State Transitions - -### Redis Connection States - -``` -INDEXER WORKER / WEB SERVER REDIS CLIENT: - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ DISCONNECTED β”‚ -β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ connect() - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CONNECTING β”‚ -β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ ready event - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CONNECTED │────▢│ Message Queuing β”‚ -β”‚ (Ready) β”‚ β”‚ (Worker) β”‚ -β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ error/close event - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ RECONNECTING β”‚ -β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ retry strategy - β”‚ (exponential backoff) - β”‚ - β”œβ”€β–Ά Success β†’ CONNECTED - β”‚ - └─▢ Max retries β†’ DISCONNECTED -``` - -### Worker Lifecycle - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ START β”‚ -β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ - β”‚ npm run worker:indexer - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INITIALIZE β”‚ -β”‚ - Config β”‚ -β”‚ - Redis β”‚ -β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INDEXING │◀─┐ -β”‚ - Polling β”‚ β”‚ -β”‚ - Translateβ”‚ β”‚ -β”‚ - Publish β”‚ β”‚ -β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β”‚ New event β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ SIGTERM/SIGINT - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ SHUTDOWN β”‚ -β”‚ - Stop idx β”‚ -β”‚ - Flush Q β”‚ -β”‚ - Close DB β”‚ -β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ EXIT β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## πŸ“ File Structure Map - -``` -open-audit/ -β”‚ -β”œβ”€β”€ πŸ†• MICROSERVICES IMPLEMENTATION -β”‚ β”œβ”€β”€ src/worker/indexer.ts ← Standalone worker -β”‚ β”œβ”€β”€ server-decoupled.ts ← Decoupled server -β”‚ β”œβ”€β”€ docker-compose.microservices.yml ← Docker orchestration -β”‚ β”œβ”€β”€ Dockerfile.worker ← Worker image -β”‚ β”œβ”€β”€ Dockerfile.web ← Web image -β”‚ └── ecosystem.config.js ← PM2 config -β”‚ -β”œβ”€β”€ πŸ†• CONFIGURATION -β”‚ β”œβ”€β”€ .env.microservices.example ← Env template -β”‚ └── app/api/health/route.ts ← Health check (updated) -β”‚ -β”œβ”€β”€ πŸ†• DOCUMENTATION -β”‚ β”œβ”€β”€ MICROSERVICES_ARCHITECTURE.md ← Architecture guide -β”‚ β”œβ”€β”€ QUICKSTART_MICROSERVICES.md ← Quick start -β”‚ β”œβ”€β”€ MICROSERVICES_TESTING_GUIDE.md ← Testing guide -β”‚ β”œβ”€β”€ MICROSERVICES_DELIVERABLES.md ← Deliverables -β”‚ β”œβ”€β”€ TASK_3_COMPLETION_SUMMARY.md ← Summary -β”‚ └── MICROSERVICES_VISUAL_GUIDE.md ← This file -β”‚ -β”œβ”€β”€ πŸ†• TESTING TOOLS -β”‚ └── scripts/test-websocket-client.js ← WebSocket test client -β”‚ -β”œβ”€β”€ πŸ“ UPDATED FILES -β”‚ β”œβ”€β”€ server.ts ← Deprecation notice -β”‚ β”œβ”€β”€ README.md ← Microservices section -β”‚ └── package.json ← New scripts -β”‚ -└── πŸ’‘ LEGACY (Still functional) - β”œβ”€β”€ server.ts ← Monolithic server - └── lib/stellar/indexer.ts ← Used by worker -``` - ---- - -## 🎯 Decision Matrix - -### When to use which architecture? - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Scenario β”‚ Monolithic β”‚ Microservices β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Local development β”‚ βœ… β”‚ βœ… β”‚ -β”‚ Simple deployment β”‚ βœ… β”‚ ❌ β”‚ -β”‚ Production environment β”‚ ❌ β”‚ βœ… β”‚ -β”‚ High traffic (>1000 events/s) β”‚ ❌ β”‚ βœ… β”‚ -β”‚ Horizontal scaling required β”‚ ❌ β”‚ βœ… β”‚ -β”‚ Fault isolation needed β”‚ ❌ β”‚ βœ… β”‚ -β”‚ Zero-downtime deployments β”‚ ❌ β”‚ βœ… β”‚ -β”‚ Multiple concurrent users β”‚ ❌ β”‚ βœ… β”‚ -β”‚ Resource-constrained (1 CPU) β”‚ βœ… β”‚ ❌ β”‚ -β”‚ Learning/prototyping β”‚ βœ… β”‚ ❌ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Recommendation: Use Microservices for production, Monolithic for prototyping -``` - ---- - -## πŸ” Monitoring Dashboard - -### PM2 Monitoring Output - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ pm2 monit β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”Œβ”€ Process List ────────┐ β”Œβ”€ web-server Logs ───────────────┐│ -β”‚ β”‚ β”‚ β”‚ β”‚β”‚ -β”‚ β”‚ 0 web-server online β”‚ β”‚ [server] Connected to Redis β”‚β”‚ -β”‚ β”‚ ↻ 0 restarts β”‚ β”‚ [server] Subscribed to channel β”‚β”‚ -β”‚ β”‚ ⏱ 45m uptime β”‚ β”‚ [server] Received 1,234 events β”‚β”‚ -β”‚ β”‚ πŸ’Ύ 256 MB memory β”‚ β”‚ [server] Broadcasting to 12 cl β”‚β”‚ -β”‚ β”‚ πŸ”₯ 5% CPU β”‚ β”‚ β”‚β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚β”‚ -β”‚ β”‚ 1 indexer-worker online β”‚ β”Œβ”€ indexer-worker Logs ──────┐ β”‚β”‚ -β”‚ β”‚ ↻ 0 restarts β”‚ β”‚ β”‚ β”‚β”‚ -β”‚ β”‚ ⏱ 45m uptime β”‚ β”‚ [worker] Processing events β”‚ β”‚β”‚ -β”‚ β”‚ πŸ’Ύ 180 MB memory β”‚ β”‚ [worker] Published 1,234 msg β”‚ β”‚β”‚ -β”‚ β”‚ πŸ”₯ 15% CPU β”‚ β”‚ [worker] Queue: 0/1000 β”‚ β”‚β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Docker Stats Output - -``` -$ docker stats - -CONTAINER CPU % MEM USAGE / LIMIT NET I/O -open-audit-web 5.2% 245MB / 1GB 15MB / 8MB -open-audit-idx 12.1% 178MB / 1GB 25MB / 15MB -open-audit-redis 0.8% 32MB / 512MB 10MB / 10MB -open-audit-db 1.2% 95MB / 1GB 5MB / 3MB -``` - ---- - -## πŸ§ͺ Testing Flow - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TESTING WORKFLOW β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -1. START SERVICES - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ redis-server β”‚ or docker-compose up or pm2 start - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -2. VERIFY HEALTH - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ curl /health β”‚ β†’ Should return 200 OK - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -3. CONNECT CLIENT - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ test:websocket β”‚ β†’ Should see "Connected" - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -4. OBSERVE EVENTS - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Wait for eventsβ”‚ β†’ Should see real-time events - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -5. TEST RESILIENCE - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Stop Redis β”‚ β†’ Services should queue messages - β”‚ Start Redis β”‚ β†’ Services should reconnect + flush - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -6. TEST ISOLATION - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Restart worker β”‚ β†’ Web server keeps running - β”‚ Restart server β”‚ β†’ Worker keeps running - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -7. VERIFY SHUTDOWN - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Ctrl+C / kill β”‚ β†’ Should shutdown gracefully - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -βœ… ALL TESTS PASSED -``` - ---- - -## πŸ“Š Performance Comparison - -### Monolithic vs Microservices - -``` -LOAD TEST RESULTS (1000 events/second): - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Metric β”‚ Monolithic β”‚ Microservices β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ WebSocket Drops β”‚ 125 β”‚ 0 β”‚ -β”‚ CPU (Server) β”‚ 95% β”‚ 5% β”‚ -β”‚ CPU (Indexer) β”‚ - β”‚ 15% β”‚ -β”‚ Event Latency β”‚ 500ms β”‚ 50ms β”‚ -β”‚ Memory (Total) β”‚ 400MB β”‚ 425MB β”‚ -β”‚ Recovery Time β”‚ Manual β”‚ Auto (3s) β”‚ -β”‚ Downtime (Deploy) β”‚ 30s β”‚ 0s β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -VERDICT: Microservices architecture is 10x more reliable under load -``` - ---- - -## πŸŽ“ Quick Command Reference - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ COMMAND CHEATSHEET β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ DOCKER COMPOSE β”‚ -β”‚ β”œβ”€ npm run docker:up Start all services β”‚ -β”‚ β”œβ”€ npm run docker:down Stop all services β”‚ -β”‚ β”œβ”€ npm run docker:logs View logs (all services) β”‚ -β”‚ └─ docker ps Check service status β”‚ -β”‚ β”‚ -β”‚ PM2 β”‚ -β”‚ β”œβ”€ npm run start:pm2 Start all services β”‚ -β”‚ β”œβ”€ npm run stop:pm2 Stop all services β”‚ -β”‚ β”œβ”€ npm run monit:pm2 Monitor in real-time β”‚ -β”‚ └─ npm run logs:pm2 View logs (all services) β”‚ -β”‚ β”‚ -β”‚ MANUAL β”‚ -β”‚ β”œβ”€ redis-server Start Redis β”‚ -β”‚ β”œβ”€ npm run dev:decoupled Start web server β”‚ -β”‚ └─ npm run worker:indexer Start indexer worker β”‚ -β”‚ β”‚ -β”‚ TESTING β”‚ -β”‚ β”œβ”€ npm run test:websocket Test WebSocket connection β”‚ -β”‚ └─ curl localhost:3000/api/health Check health β”‚ -β”‚ β”‚ -β”‚ DEBUGGING β”‚ -β”‚ β”œβ”€ docker logs -f open-audit-web View web logs β”‚ -β”‚ β”œβ”€ docker logs -f open-audit-indexer View worker logs β”‚ -β”‚ β”œβ”€ pm2 logs web-server View web logs (PM2) β”‚ -β”‚ β”œβ”€ pm2 logs indexer-worker View worker logs (PM2) β”‚ -β”‚ └─ redis-cli MONITOR Monitor Redis commands β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## πŸŽ‰ Success Indicators - -``` -βœ… System is working correctly when: - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Health check returns HTTP 200 β”‚ -β”‚ curl http://localhost:3000/api/health β”‚ -β”‚ β†’ {"status":"healthy","redis":{"connected":true}} β”‚ -β”‚ β”‚ -β”‚ 2. WebSocket client connects successfully β”‚ -β”‚ npm run test:websocket β”‚ -β”‚ β†’ "βœ… Connected to WebSocket server" β”‚ -β”‚ β”‚ -β”‚ 3. Events appear in real-time β”‚ -β”‚ β†’ "πŸ“Š Event #1" β”‚ -β”‚ β†’ "Translated: Transferred 100 USDC..." β”‚ -β”‚ β”‚ -β”‚ 4. All containers/processes are healthy β”‚ -β”‚ docker ps OR pm2 status β”‚ -β”‚ β†’ All showing "healthy" or "online" β”‚ -β”‚ β”‚ -β”‚ 5. No errors in logs β”‚ -β”‚ docker logs / pm2 logs β”‚ -β”‚ β†’ Only info/success messages β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -🎊 CONGRATULATIONS! Your microservices system is running perfectly! -``` - ---- - -## πŸ“š Documentation Quick Links - -| Document | Use Case | -|----------|----------| -| **[QUICKSTART_MICROSERVICES.md](QUICKSTART_MICROSERVICES.md)** | Get running in 5 minutes | -| **[MICROSERVICES_ARCHITECTURE.md](MICROSERVICES_ARCHITECTURE.md)** | Technical deep-dive | -| **[MICROSERVICES_TESTING_GUIDE.md](MICROSERVICES_TESTING_GUIDE.md)** | Complete testing walkthrough | -| **[MICROSERVICES_DELIVERABLES.md](MICROSERVICES_DELIVERABLES.md)** | Implementation summary | -| **[TASK_3_COMPLETION_SUMMARY.md](TASK_3_COMPLETION_SUMMARY.md)** | Executive summary | -| **[.env.microservices.example](.env.microservices.example)** | Configuration reference | - ---- - -**Made with ❀️ for the Open-Audit community** diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 4a0b90d..0000000 --- a/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,246 +0,0 @@ -# Architecture Documentation - PR Summary - -## πŸ“‹ Issue Summary - -**Problem:** New contributors struggle to understand how data flows through the Open-Audit backend pipeline, from fetching raw XDR from Stellar RPC through the Translation Registry to the frontend dashboard. - -**Solution:** Created comprehensive architecture documentation with interactive diagrams, detailed component explanations, and step-by-step data flow examples. - ---- - -## βœ… Changes Made - -### New Files Created - -1. **`ARCHITECTURE.md`** (773 lines) - - Complete system architecture overview - - Interactive Mermaid flowchart showing all components - - Deep dive into each of the 5 major components: - - Stellar Network (RPC endpoint) - - Event Indexer (rate limit handling) - - Translation Engine (XDR decoding) - - WebSocket Server (real-time streaming) - - Frontend Dashboard (interactive UI) - - Step-by-step event journey from blockchain to UI - - Development guide for contributors - - Performance considerations and future enhancements - -2. **`docs/architecture-simple.md`** (simplified version) - - High-level data flow diagram - - Component responsibilities summary - - Data transformation examples - - Key architectural decisions - - Failure handling patterns - - Scalability considerations - -### Modified Files - -1. **`README.md`** - - Added "Architecture" section with quick overview - - Added link to detailed ARCHITECTURE.md - - Updated project structure to reflect actual codebase - - Added references to indexer and hooks - ---- - -## 🎨 Diagrams Included - -### 1. High-Level Architecture (Mermaid) -```mermaid -flowchart TB - StellarNetwork --> EventIndexer - EventIndexer --> TranslationEngine - TranslationEngine --> WebSocketServer - WebSocketServer --> FrontendDashboard -``` - -### 2. Detailed Component Diagram -Shows all services, their interactions, and data flow with: -- Stellar RPC Server -- Event Indexer with retry logic -- Translation Registry with blueprints -- WebSocket broadcasting -- React components and hooks - -### 3. Data Transformation Example -Demonstrates how a raw XDR event becomes human-readable text: -``` -Raw: 0x000000140000000200000000... -↓ -Decoded: from=Alice, to=Bob, amount=100 USDC -↓ -Display: "Alice transferred 100.00 USDC to Bob" -``` - ---- - -## πŸ“š Documentation Coverage - -### For Backend Developers -- **Event Indexer:** How polling works, rate limit handling, cursor management -- **Translation Engine:** Blueprint system, XDR decoding, registry lookup -- **WebSocket Server:** Real-time broadcasting, message format - -### For Frontend Developers -- **Dashboard Components:** EventFeedTable, SearchBar, StatsBar -- **React Hooks:** useLiveFeed WebSocket integration -- **Data Flow:** How events reach the UI - -### For New Contributors -- **System Overview:** 30,000-foot view of the entire pipeline -- **Data Flow:** Step-by-step journey of a single event -- **Getting Started:** How to run locally and add features -- **Adding Blueprints:** Complete guide with code examples - ---- - -## πŸ” Key Sections - -### 1. System Overview -High-level explanation of the 5-component architecture - -### 2. Architecture Diagram -Interactive Mermaid flowchart with color-coded services - -### 3. Component Deep Dive -Detailed explanation of each component: -- What it does -- How it works -- Configuration options -- Code examples - -### 4. Data Flow -Complete event journey with examples: -- Contract execution β†’ RPC β†’ Indexer β†’ Translator β†’ WebSocket β†’ UI - -### 5. Development Guide -Practical instructions for: -- Running locally -- Adding new blueprints -- Testing changes -- Debugging issues - -### 6. Performance & Scalability -- Rate limiting strategies -- WebSocket scaling -- Future enhancements - ---- - -## 🎯 Impact on Contributors - -### Before This PR -- New contributors had to read code to understand architecture -- Data flow was implicit, not documented -- Backend optimization required deep code diving -- Indexing bugs were hard to understand without context - -### After This PR -- Clear visual diagrams show the complete system -- Data flow is explicitly documented with examples -- Each component has dedicated explanation section -- Contributors can quickly identify where to make changes - ---- - -## πŸ“Š Documentation Metrics - -- **Total Lines:** 1,200+ lines of documentation -- **Diagrams:** 3 Mermaid flowcharts -- **Code Examples:** 15+ snippets -- **Components Documented:** 5 major services -- **Files Created:** 2 (ARCHITECTURE.md, docs/architecture-simple.md) -- **Files Modified:** 1 (README.md) - ---- - -## ✨ Example Use Cases - -### Use Case 1: Understanding Rate Limit Handling -**Before:** Grep through `indexer.ts` to understand retry logic -**After:** Read "Event Indexer" section with diagram and explanation - -### Use Case 2: Adding a New Contract Blueprint -**Before:** Reverse-engineer existing blueprints -**After:** Follow step-by-step guide in "Adding a New Contract Blueprint" - -### Use Case 3: Debugging Event Loss -**Before:** Unclear where events might be dropped -**After:** Follow data flow diagram to identify bottleneck - -### Use Case 4: Optimizing Backend Performance -**Before:** Unclear what components exist and their interactions -**After:** Review architecture diagram to identify optimization points - ---- - -## πŸš€ Next Steps - -This documentation provides the foundation for: - -1. **Onboarding new contributors** β€” Clear system understanding -2. **Architecture discussions** β€” Visual reference for proposals -3. **Bug investigations** β€” Data flow helps identify issues -4. **Feature planning** β€” Understand impact across components -5. **Performance optimization** β€” Identify bottlenecks - ---- - -## πŸ“ Testing - -To verify the documentation: - -1. **Diagram rendering:** - - View ARCHITECTURE.md on GitHub (Mermaid auto-renders) - - Check all diagrams display correctly - -2. **Links:** - - All internal links resolve correctly - - External links (Stellar docs) are valid - -3. **Code examples:** - - All TypeScript snippets have correct syntax - - File paths reference actual files in the repo - -4. **Accuracy:** - - Verified against actual codebase structure - - Tested locally with `npm run dev:ws` - ---- - -## πŸ™ Acknowledgments - -This architecture documentation was created by analyzing: -- Existing codebase structure -- Implementation summary -- Code comments and types -- README and contributing guidelines - -Special attention was paid to: -- **Accuracy:** All diagrams match actual code -- **Clarity:** Explanations suitable for beginners -- **Completeness:** Covers entire data pipeline -- **Practicality:** Includes actionable development guides - ---- - -## πŸ“Œ Closes Issue - -This PR resolves the issue requesting backend architecture documentation for new contributors looking to help with optimization and indexing bugs. - -**Before:** Contributors struggled to understand the complex backend pipeline -**After:** Clear diagrams and documentation make the system accessible to everyone - ---- - -## Branch Information - -- **Branch:** `docs/add-architecture-diagram` -- **Base:** `main` -- **Type:** Documentation -- **Breaking Changes:** None -- **Requires Review:** Documentation clarity and accuracy - ---- - -**Ready for review!** πŸŽ‰ diff --git a/RECONCILIATION_QUICKSTART.md b/RECONCILIATION_QUICKSTART.md deleted file mode 100644 index 832af7b..0000000 --- a/RECONCILIATION_QUICKSTART.md +++ /dev/null @@ -1,330 +0,0 @@ -# Reconciliation Worker - Quick Start Guide - -## πŸš€ TL;DR - Get Started in 5 Minutes - -### Prerequisites - -- Node.js 18+ -- PostgreSQL or SQLite -- Redis (for job queue) - -### 1. Install & Setup Database - -```bash -# Install dependencies -npm install - -# Run database migrations -npm run db:migrate - -# Seed default configuration -npm run db:seed -``` - -### 2. Configure Environment - -Update `.env.local`: - -```env -DATABASE_URL=postgresql://user:password@localhost:5432/openaudit -REDIS_URL=redis://localhost:6379 -``` - -### 3. Start Redis - -```bash -redis-server -# or: docker run -d -p 6379:6379 redis:latest -``` - -### 4. Start Application - -```bash -npm run dev -``` - -### 5. Verify System Health - -```bash -curl http://localhost:3000/api/health -``` - ---- - -## πŸ“‹ Core Concepts - -### What It Does - -The reconciliation worker: - -1. **Stores** all blockchain events in PostgreSQL -2. **Monitors** database for data loss or corruption -3. **Compares** local data with Stellar RPC source daily (automatic) -4. **Detects** missing or corrupted events -5. **Repairs** automatically (optional) or flags for review -6. **Records** everything in an audit trail - -### Key Files - -| File | Purpose | -| --------------------------------- | ------------------------- | -| `prisma/schema.prisma` | Database schema | -| `lib/reconciliation/engine.ts` | Core reconciliation logic | -| `lib/jobs/queue.ts` | Job queue (Bull + Redis) | -| `lib/reconciliation/scheduler.ts` | Cron scheduler | -| `app/api/reconciliation/` | REST API endpoints | - ---- - -## πŸ§ͺ Test It - -### Scenario 1: Detect Missing Events - -```bash -# 1. Delete an event from database -sqlite> DELETE FROM events WHERE id = 'event-12345'; - -# 2. Trigger reconciliation -curl -X POST http://localhost:3000/api/reconciliation/trigger \ - -H "Content-Type: application/json" \ - -d '{"startLedger": 1000, "endLedger": 10000}' - -# 3. Check results -curl http://localhost:3000/api/reconciliation/status -``` - -### Scenario 2: Check Audit Trail - -```bash -# Get detailed reconciliation report -curl "http://localhost:3000/api/reconciliation/report/[jobId]" - -# Get as HTML for viewing in browser -curl "http://localhost:3000/api/reconciliation/report/[jobId]?format=html" -``` - -### Scenario 3: Automatic Daily Run - -The system automatically runs at **2 AM UTC daily**. - -To change the schedule: - -```bash -curl -X PUT http://localhost:3000/api/reconciliation/config \ - -H "Content-Type: application/json" \ - -d '{"cronSchedule": "0 12 * * *"}' # Noon UTC instead -``` - ---- - -## πŸ“Š Monitoring - -### Check System Health - -```bash -curl http://localhost:3000/api/health -``` - -### View Job Status - -```bash -curl http://localhost:3000/api/reconciliation/status -``` - -### Get Job History - -```bash -curl http://localhost:3000/api/reconciliation/history?limit=10 -``` - -### Get Configuration - -```bash -curl http://localhost:3000/api/reconciliation/config -``` - ---- - -## πŸ”§ API Endpoints - -| Endpoint | Method | Purpose | -| ------------------------------------ | ------- | ------------------------------- | -| `/api/health` | GET | System health check | -| `/api/reconciliation/trigger` | POST | Manually trigger reconciliation | -| `/api/reconciliation/status` | GET | Current job status | -| `/api/reconciliation/config` | GET/PUT | View/update configuration | -| `/api/reconciliation/history` | GET | View past reconciliation jobs | -| `/api/reconciliation/report/[jobId]` | GET | Detailed reconciliation report | - ---- - -## πŸ› οΈ Configuration - -Edit configuration via API: - -```bash -curl -X PUT http://localhost:3000/api/reconciliation/config \ - -H "Content-Type: application/json" \ - -d '{ - "cronSchedule": "0 2 * * *", # 2 AM UTC daily - "batchSize": 1000, # Events per batch - "lookbackDays": 7, # Days to reconcile - "autoFix": false, # Auto-repair missing events - "alertThreshold": 0.1, # Alert if >0.1% discrepancies - "enabled": true # Enable/disable - }' -``` - ---- - -## πŸ“ˆ Performance Tips - -1. **Batch Size** β€” Increase for faster processing (default 1000) -2. **Concurrency** β€” More workers for parallel processing -3. **Lookback Window** β€” Smaller = faster (default 7 days) -4. **Frequency** β€” More frequent = catches issues sooner - ---- - -## πŸ› Troubleshooting - -### Queue Not Processing? - -```bash -# Check queue status -curl http://localhost:3000/api/reconciliation/status - -# Verify Redis is running -redis-cli ping # Should return PONG -``` - -### Database Connection Failed? - -```bash -# Verify DATABASE_URL in .env.local -# Test with: -npx prisma db execute --stdin < /dev/null -``` - -### Events Not Being Saved? - -```bash -# Check health endpoint -curl http://localhost:3000/api/health - -# Verify database has events table -npx prisma studio -``` - ---- - -## πŸ“ Example Usage - -### Complete Workflow Example - -```bash -# 1. Check health -curl http://localhost:3000/api/health - -# 2. View current config -curl http://localhost:3000/api/reconciliation/config - -# 3. Manually trigger reconciliation for past 1000 ledgers -curl -X POST http://localhost:3000/api/reconciliation/trigger \ - -H "Content-Type: application/json" \ - -d '{ - "startLedger": 49000000, - "endLedger": 50000000, - "autoFix": false - }' - -# 4. Check job status -curl http://localhost:3000/api/reconciliation/status - -# 5. View detailed report -curl "http://localhost:3000/api/reconciliation/report/[jobId]" - -# 6. View audit history -curl http://localhost:3000/api/reconciliation/history?limit=5 -``` - ---- - -## πŸ“š Learn More - -See **[RECONCILIATION_IMPLEMENTATION.md](RECONCILIATION_IMPLEMENTATION.md)** for: - -- Detailed architecture diagrams -- Complete API documentation -- Database schema reference -- Advanced configuration options -- Performance tuning guide -- Troubleshooting guide - ---- - -## βœ… Acceptance Criteria - -This implementation satisfies: - -**Criterion 1: Detect Artificially Deleted Records** - -- βœ… Identifies when events are deleted from database -- βœ… Reports exact event IDs and ledger ranges -- βœ… Suggests auto-fix action: "reindex" - -**Criterion 2: Clear Audit Trail** - -- βœ… Records all reconciliation actions with timestamps -- βœ… Logs event details (what was detected/fixed) -- βœ… Administrator-facing reports via API - ---- - -## 🚨 Alert Thresholds - -System alerts when: - -- Discrepancy rate > `alertThreshold` (default 0.1%) -- Reconciliation job fails -- Missing events detected -- Data integrity mismatches found - ---- - -## 🎯 Next Steps - -1. βœ… Install and seed database -2. βœ… Start Redis and application -3. βœ… Verify health endpoint -4. βœ… Trigger test reconciliation -5. βœ… Review audit trail -6. βœ… Configure cron schedule -7. βœ… Monitor via health endpoint - -Your Open-Audit instance now guarantees **100% data completeness**! πŸŽ‰ - ---- - -## Support Commands - -```bash -# View database with Prisma Studio -npm run db:studio - -# Run tests -npm test - -# Format code -npm run format - -# Check logs -tail -f logs/*.log - -# Clear old jobs from queue -# (Uses bull-cli or directly via API) -``` - ---- - -**Ready to ensure data integrity?** Start reconciling now! πŸš€ diff --git a/RESILIENCE_IMPLEMENTATION_GUIDE.md b/RESILIENCE_IMPLEMENTATION_GUIDE.md deleted file mode 100644 index aca7430..0000000 --- a/RESILIENCE_IMPLEMENTATION_GUIDE.md +++ /dev/null @@ -1,763 +0,0 @@ -# Resilience Layer Implementation Guide - -## 🎯 Executive Summary - -Successfully implemented a **bulletproof resilience layer** for Stellar RPC ingestion that provides: - -- βœ… **Token-bucket rate limiting** (prevents self-inflicted flooding) -- βœ… **Circuit breaker pattern** (isolates failing nodes) -- βœ… **Automatic fallback** (switches to backup nodes) -- βœ… **Exponential backoff** (gradually increases retry delays) -- βœ… **Comprehensive testing** (100% coverage of failure scenarios) -- βœ… **Zero memory leaks** (proper cleanup of timers and promises) - ---- - -## πŸ“¦ Deliverables - -### Core Implementation - -| File | Purpose | Lines | Status | -|------|---------|-------|--------| -| `lib/resilience/token-bucket.ts` | Token-bucket rate limiter | 250 | βœ… Complete | -| `lib/resilience/circuit-breaker.ts` | Circuit breaker state machine | 450 | βœ… Complete | -| `lib/resilience/resilient-client.ts` | Combined resilient wrapper | 350 | βœ… Complete | -| `lib/resilience/config.ts` | Configuration presets | 200 | βœ… Complete | -| `lib/resilience/index.ts` | Public API exports | 50 | βœ… Complete | - -### Stellar Integration - -| File | Purpose | Status | -|------|---------|--------| -| `lib/stellar/resilient-stellar-client.ts` | Drop-in Stellar client replacement | βœ… Complete | - -### Testing Suite - -| File | Purpose | Tests | Status | -|------|---------|-------|--------| -| `__tests__/token-bucket.test.ts` | Rate limiter tests | 20+ | βœ… Complete | -| `__tests__/circuit-breaker.test.ts` | Circuit breaker tests | 25+ | βœ… Complete | -| `__tests__/resilient-client.test.ts` | Integration tests | 30+ | βœ… Complete | - -### Documentation - -| File | Purpose | Status | -|------|---------|--------| -| `lib/resilience/README.md` | Complete API documentation | βœ… Complete | -| `RESILIENCE_IMPLEMENTATION_GUIDE.md` | This file | βœ… Complete | - ---- - -## πŸš€ Quick Start (5 Minutes) - -### Step 1: Import and Configure - -```typescript -import { createResilientClient, getResilientClientConfig } from "./lib/resilience"; - -// Option A: Use environment-based presets -const config = getResilientClientConfig("testnet", "production"); -const client = createResilientClient(config); - -// Option B: Custom configuration -const client = createResilientClient({ - endpoints: [ - { id: "primary", url: "https://soroban-testnet.stellar.org", priority: 0 }, - { id: "backup", url: "https://rpc-testnet.stellar.org", priority: 1 }, - ], - rateLimiter: { capacity: 10, refillRate: 5 }, - circuitBreaker: { failureThreshold: 5, successThreshold: 2, resetTimeout: 5000 }, -}); -``` - -### Step 2: Replace Existing RPC Calls - -**Before (vulnerable):** -```typescript -const { SorobanRpc } = await import("stellar-sdk"); -const server = new SorobanRpc.Server("https://soroban-testnet.stellar.org"); -const events = await server.getEvents({ startLedger: 1000, filters: [...] }); -``` - -**After (resilient):** -```typescript -import { fetchContractEventsResilient } from "./lib/stellar/resilient-stellar-client"; - -const events = await fetchContractEventsResilient(["CONTRACT_ID"], 1000); -``` - -### Step 3: Monitor Health - -```typescript -import { getHealthStatus } from "./lib/stellar/resilient-stellar-client"; - -const health = getHealthStatus(); -console.log(`Healthy: ${health.healthy}`); -console.log(`Using endpoint: ${health.currentEndpoint}`); -console.log(`Available tokens: ${health.rateLimiter.availableTokens}`); -``` - -### Step 4: Clean Up on Shutdown - -```typescript -import { disposeResilientClient } from "./lib/stellar/resilient-stellar-client"; - -process.on("SIGTERM", () => { - disposeResilientClient(); - process.exit(0); -}); -``` - ---- - -## πŸ“‹ Acceptance Criteria - Verification - -### βœ… Isolation & Fail-Fast Verification - -**Requirement:** System correctly transitions to protective "OPEN" circuit state on HTTP 500/429 errors without crashing. - -**Test:** `__tests__/circuit-breaker.test.ts` - Lines 95-120 - -```typescript -it("should open after reaching failure threshold", async () => { - const breaker = createCircuitBreaker({ - failureThreshold: 3, - successThreshold: 2, - resetTimeout: 1000, - }); - - const failingFn = async () => { - const error: any = new Error("HTTP 500"); - error.response = { status: 500 }; - throw error; - }; - - // Trigger 3 failures (threshold) - for (let i = 0; i < 3; i++) { - await expect(breaker.execute(failingFn)).rejects.toThrow(); - } - - expect(breaker.getState()).toBe(CircuitState.OPEN); // βœ… PASS -}); -``` - -**Result:** βœ… **VERIFIED** - Circuit opens after configured threshold, system remains stable. - ---- - -### βœ… Automated Recovery Verification - -**Requirement:** System safely switches back to "CLOSED" state once upstream health stabilizes. - -**Test:** `__tests__/circuit-breaker.test.ts` - Lines 220-250 - -```typescript -it("should close circuit after successThreshold successes", async () => { - // Trip the circuit - for (let i = 0; i < 2; i++) { - await expect(breaker.execute(failingFn)).rejects.toThrow(); - } - expect(breaker.getState()).toBe(CircuitState.OPEN); - - // Wait for HALF_OPEN - await new Promise((resolve) => setTimeout(resolve, 150)); - expect(breaker.getState()).toBe(CircuitState.HALF_OPEN); - - // Success threshold is 2, so 2 successful requests should close it - const successFn = async () => "success"; - await breaker.execute(successFn); - await breaker.execute(successFn); - - expect(breaker.getState()).toBe(CircuitState.CLOSED); // βœ… PASS -}); -``` - -**Result:** βœ… **VERIFIED** - Automatic recovery through HALF_OPEN β†’ CLOSED transition. - ---- - -### βœ… No Leaky Goroutines/Promises - -**Requirement:** Proper cleanup of timers and promises to avoid memory leaks. - -**Test:** `__tests__/token-bucket.test.ts` - Lines 285-305 - -```typescript -it("should clean up refill timer on dispose", async () => { - bucket = createTokenBucket({ capacity: 10, refillRate: 10 }); - - await bucket.acquire(); - await bucket.acquire(); - - const tokensBefore = bucket.metrics().availableTokens; - - bucket.dispose(); // Stop refill timer - - await new Promise((resolve) => setTimeout(resolve, 300)); - - // Tokens should not have increased (timer was cleared) - expect(bucket.metrics().availableTokens).toBe(tokensBefore); // βœ… PASS -}); - -it("should reject queued requests on dispose", async () => { - bucket = createTokenBucket({ capacity: 1, refillRate: 1 }); - await bucket.acquire(); // Drain - - const promise = bucket.acquire(); // Queue a request - bucket.dispose(); // Dispose immediately - - await expect(promise).rejects.toThrow("disposed"); // βœ… PASS -}); -``` - -**Result:** βœ… **VERIFIED** - All timers cleared, queued promises rejected cleanly. - ---- - -## πŸ§ͺ Running Tests - -### Run All Tests - -```bash -npm test lib/resilience -``` - -**Expected Output:** -``` -βœ“ lib/resilience/__tests__/token-bucket.test.ts (20 tests) 2.5s -βœ“ lib/resilience/__tests__/circuit-breaker.test.ts (25 tests) 3.2s -βœ“ lib/resilience/__tests__/resilient-client.test.ts (30 tests) 4.1s - -Test Files 3 passed (3) - Tests 75 passed (75) - Start at 10:30:00 - Duration 9.8s -``` - -### Run Specific Test - -```bash -# Circuit breaker only -npm test lib/resilience/__tests__/circuit-breaker.test.ts - -# Integration tests only -npm test lib/resilience/__tests__/resilient-client.test.ts -``` - -### Run with Coverage - -```bash -npm test -- --coverage lib/resilience -``` - ---- - -## πŸ”§ Configuration Reference - -### Environment-Based Presets - -```typescript -import { getResilientClientConfig } from "./lib/resilience/config"; - -// Development: Lenient for debugging -const devConfig = getResilientClientConfig("testnet", "development"); -// capacity: 20, refillRate: 10, failureThreshold: 10 - -// Staging: Production-like -const stagingConfig = getResilientClientConfig("testnet", "staging"); -// capacity: 10, refillRate: 5, failureThreshold: 5 - -// Production: Conservative protection -const prodConfig = getResilientClientConfig("mainnet", "production"); -// capacity: 10, refillRate: 5, failureThreshold: 5 -``` - -### Scenario-Based Presets - -```typescript -import { - AGGRESSIVE_RESILIENCE_CONFIG, - LENIENT_RESILIENCE_CONFIG, -} from "./lib/resilience/config"; - -// High-traffic protection (strict limits) -const aggressiveClient = createResilientClient(AGGRESSIVE_RESILIENCE_CONFIG); -// capacity: 5, refillRate: 2, failureThreshold: 3 - -// Testing/development (permissive) -const lenientClient = createResilientClient(LENIENT_RESILIENCE_CONFIG); -// capacity: 50, refillRate: 25, failureThreshold: 15 -``` - -### Custom Configuration - -```typescript -const customConfig = { - endpoints: [ - { id: "primary", url: process.env.PRIMARY_RPC_URL!, priority: 0 }, - { id: "backup", url: process.env.BACKUP_RPC_URL!, priority: 1 }, - ], - rateLimiter: { - capacity: parseInt(process.env.RATE_LIMIT_CAPACITY || "10"), - refillRate: parseInt(process.env.RATE_LIMIT_REFILL_RATE || "5"), - maxQueueSize: 100, - }, - circuitBreaker: { - failureThreshold: parseInt(process.env.CIRCUIT_FAILURE_THRESHOLD || "5"), - successThreshold: 2, - resetTimeout: 5000, - maxResetTimeout: 60000, - requestTimeout: 10000, - }, -}; -``` - ---- - -## πŸ“Š Monitoring Integration - -### Health Check API - -```typescript -import express from "express"; -import { getHealthStatus, getResilientMetrics } from "./lib/stellar/resilient-stellar-client"; - -const app = express(); - -app.get("/health", (req, res) => { - const health = getHealthStatus(); - - res.status(health.healthy ? 200 : 503).json({ - status: health.healthy ? "healthy" : "degraded", - timestamp: new Date().toISOString(), - details: { - currentEndpoint: health.currentEndpoint, - circuits: health.circuitStates, - rateLimiter: health.rateLimiter, - }, - }); -}); - -app.get("/metrics", (req, res) => { - const metrics = getResilientMetrics(); - - res.json({ - rateLimiter: metrics.rateLimiter, - circuitBreakers: metrics.circuitBreakers.map(cb => ({ - endpoint: cb.endpoint.id, - state: cb.metrics.state, - failures: cb.metrics.totalFailures, - successes: cb.metrics.totalSuccesses, - timeouts: cb.metrics.totalTimeouts, - })), - }); -}); -``` - -### Prometheus Metrics Export - -```typescript -import { getResilientMetrics } from "./lib/stellar/resilient-stellar-client"; - -// Pseudo-code for Prometheus -function exportMetrics() { - const metrics = getResilientMetrics(); - - // Rate limiter gauges - gauge("rpc_rate_limiter_available_tokens", metrics.rateLimiter.availableTokens); - gauge("rpc_rate_limiter_queued_requests", metrics.rateLimiter.queuedRequests); - counter("rpc_rate_limiter_total_consumed", metrics.rateLimiter.totalConsumed); - counter("rpc_rate_limiter_total_rejected", metrics.rateLimiter.totalRejected); - - // Circuit breaker metrics per endpoint - for (const cb of metrics.circuitBreakers) { - const labels = { endpoint: cb.endpoint.id }; - - gauge("rpc_circuit_breaker_state", stateToNumber(cb.metrics.state), labels); - counter("rpc_circuit_breaker_failures", cb.metrics.totalFailures, labels); - counter("rpc_circuit_breaker_successes", cb.metrics.totalSuccesses, labels); - counter("rpc_circuit_breaker_timeouts", cb.metrics.totalTimeouts, labels); - } -} - -setInterval(exportMetrics, 10000); // Every 10 seconds -``` - -### DataDog Integration - -```typescript -import { StatsD } from "hot-shots"; -import { getResilientMetrics } from "./lib/stellar/resilient-stellar-client"; - -const dogstatsd = new StatsD(); - -setInterval(() => { - const metrics = getResilientMetrics(); - - dogstatsd.gauge("stellar.rpc.rate_limiter.available_tokens", - metrics.rateLimiter.availableTokens); - dogstatsd.gauge("stellar.rpc.rate_limiter.queued_requests", - metrics.rateLimiter.queuedRequests); - - for (const cb of metrics.circuitBreakers) { - dogstatsd.gauge("stellar.rpc.circuit_breaker.state", - stateToNumber(cb.metrics.state), - [`endpoint:${cb.endpoint.id}`]); - } -}, 10000); -``` - ---- - -## 🎯 Production Deployment Checklist - -### Pre-Deployment - -- [ ] Run all tests: `npm test lib/resilience` -- [ ] Review configuration for your environment -- [ ] Configure primary and backup RPC endpoints -- [ ] Set appropriate rate limits based on upstream capacity -- [ ] Set circuit breaker thresholds based on SLA requirements -- [ ] Test with mock failures in staging - -### Deployment - -- [ ] Deploy resilience layer code -- [ ] Update RPC call sites to use resilient client -- [ ] Configure environment variables -- [ ] Set up health check endpoint -- [ ] Configure metrics export -- [ ] Set up alerts for circuit state changes - -### Post-Deployment - -- [ ] Monitor health check endpoint -- [ ] Verify metrics are being exported -- [ ] Watch for circuit breaker state changes -- [ ] Monitor rate limiter queue depth -- [ ] Check for any rejected requests -- [ ] Verify fallback to backup nodes works - -### Ongoing - -- [ ] Review metrics weekly -- [ ] Adjust thresholds based on observed patterns -- [ ] Add more backup endpoints if needed -- [ ] Test disaster recovery scenarios monthly - ---- - -## πŸ”₯ Troubleshooting Guide - -### Issue: Too many rejected requests - -**Symptoms:** `TokenBucket queue full` errors in logs - -**Diagnosis:** -```typescript -const metrics = getResilientMetrics(); -console.log("Rejected:", metrics.rateLimiter.totalRejected); -console.log("Queued:", metrics.rateLimiter.queuedRequests); -``` - -**Solution:** Increase rate limits -```typescript -rateLimiter: { - capacity: 20, // Increase from 10 - refillRate: 10, // Increase from 5 - maxQueueSize: 200, // Increase from 100 -} -``` - ---- - -### Issue: Circuit flapping (opening and closing frequently) - -**Symptoms:** Rapid state changes in logs - -**Diagnosis:** -```typescript -const metrics = getResilientMetrics(); -for (const cb of metrics.circuitBreakers) { - console.log(`${cb.endpoint.id}:`, { - state: cb.metrics.state, - consecutiveFailures: cb.metrics.consecutiveFailures, - lastFailure: new Date(cb.metrics.lastFailureTime || 0), - }); -} -``` - -**Solution:** Increase failure threshold -```typescript -circuitBreaker: { - failureThreshold: 10, // Increase from 5 (more tolerant) - resetTimeout: 3000, // Decrease from 5000 (faster recovery) -} -``` - ---- - -### Issue: Not failing over to backup - -**Symptoms:** Requests keep failing on primary, backup never used - -**Diagnosis:** -```typescript -const current = getCurrentRpcEndpoint(); -console.log("Current endpoint:", current.id); - -const metrics = getResilientMetrics(); -const primaryCircuit = metrics.circuitBreakers.find(cb => cb.endpoint.id === "primary"); -console.log("Primary circuit state:", primaryCircuit?.metrics.state); -``` - -**Solution:** Verify backup is configured correctly -```typescript -endpoints: [ - { id: "primary", url: PRIMARY_URL, priority: 0 }, - { id: "backup", url: BACKUP_URL, priority: 1 }, // Make sure priority > 0 -], -``` - ---- - -### Issue: Memory leak - -**Symptoms:** Memory usage grows over time, Node.js eventually crashes - -**Diagnosis:** -```bash -# Check for leaked timers -node --expose-gc --trace-gc your-app.js -``` - -**Solution:** Ensure proper cleanup -```typescript -// Always dispose on shutdown -process.on("SIGTERM", () => { - disposeResilientClient(); - process.exit(0); -}); - -// Or if creating clients manually -try { - const client = createResilientClient(config); - await client.execute(...); -} finally { - client.dispose(); // Always cleanup -} -``` - ---- - -## πŸ“ˆ Performance Impact - -### Overhead Measurements - -| Component | Overhead per Request | Memory Footprint | -|-----------|---------------------|------------------| -| Token Bucket | ~0.5ms | ~10KB + queue | -| Circuit Breaker | ~1ms | ~5KB per endpoint | -| Combined (Resilient Client) | ~2ms | ~20KB + endpoints | - -### Benchmark Results - -``` -Direct RPC call (no resilience): 15ms average -With resilience layer: 17ms average (+2ms overhead) - -Throughput: -- Without resilience: 500 req/sec -- With resilience: 480 req/sec (-4% overhead) - -Memory: -- Baseline: 50MB -- With resilience: 55MB (+5MB for 5 endpoints) -``` - -**Conclusion:** Minimal overhead (~2ms per request, ~4% throughput reduction) for significant reliability improvements. - ---- - -## πŸŽ“ Architecture Deep Dive - -### Token Bucket Algorithm - -``` -Initial state: [●●●●●●●●●●] (capacity = 10) - -Request 1: [●●●●●●●●● ] ─> Token consumed -Request 2: [●●●●●●●● ] ─> Token consumed -Request 3: [●●●●●●● ] ─> Token consumed - -Time passes (100ms)... -Refill: [●●●●●●●● ] ─> Added 0.5 tokens (rate = 5/sec) - -Request 4: [●●●●●●● ] ─> Token consumed - -If bucket empty: -Request 5: [ ] ─> QUEUED (waits for refill) - -Refill: [● ] ─> Added 0.5 tokens -Request 5: [ ] ─> PROCESSED (consumed queued) -``` - -### Circuit Breaker State Machine - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CLOSED β”‚ -β”‚ (Normal operation, requests flow through) β”‚ -β”‚ β”‚ -β”‚ consecutiveFailures: 0 β”‚ -β”‚ Success: Reset counter β”‚ -β”‚ Failure: Increment counter β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ consecutiveFailures >= failureThreshold - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ OPEN β”‚ -β”‚ (Failing fast, requests rejected immediately) β”‚ -β”‚ β”‚ -β”‚ - Start resetTimeout timer β”‚ -β”‚ - Fail requests immediately β”‚ -β”‚ - Optional: Use fallback β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”‚ After resetTimeout - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ HALF_OPEN β”‚ -β”‚ (Testing recovery with canary requests) β”‚ -β”‚ β”‚ -β”‚ consecutiveSuccesses: 0 β”‚ -β”‚ Success: Increment counter β”‚ -β”‚ Failure: Back to OPEN (+ exponential backoff) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β”‚ Success β”‚ Failure - β”‚ (>= threshold) β”‚ - β–Ό β–Ό - CLOSED OPEN - (2x timeout) -``` - ---- - -## 🚒 Migration Guide - -### Step 1: Install (No External Dependencies) - -No installation needed - pure TypeScript implementation included in codebase. - -### Step 2: Update Imports - -**Before:** -```typescript -import { fetchContractEvents } from "./lib/stellar/client"; -``` - -**After:** -```typescript -import { fetchContractEventsResilient } from "./lib/stellar/resilient-stellar-client"; -``` - -### Step 3: Update Function Calls - -**Before:** -```typescript -const events = await fetchContractEvents( - ["CONTRACT_ID"], - TESTNET_CONFIG, - startLedger -); -``` - -**After:** -```typescript -// Config is auto-detected from environment -const events = await fetchContractEventsResilient( - ["CONTRACT_ID"], - startLedger -); -``` - -### Step 4: Add Health Monitoring - -```typescript -// Add to existing health check -import { getHealthStatus } from "./lib/stellar/resilient-stellar-client"; - -app.get("/health", (req, res) => { - const health = getHealthStatus(); - res.json({ ...existingHealth, rpcClient: health }); -}); -``` - -### Step 5: Configure Environment - -```env -# .env.production -NEXT_PUBLIC_NETWORK=mainnet -NODE_ENV=production - -# Optional: Override defaults -PRIMARY_RPC_URL=https://your-primary-rpc.com -BACKUP_RPC_URL=https://your-backup-rpc.com -RATE_LIMIT_CAPACITY=10 -RATE_LIMIT_REFILL_RATE=5 -CIRCUIT_FAILURE_THRESHOLD=5 -``` - ---- - -## βœ… Summary - -### What Was Built - -1. βœ… **Token-bucket rate limiter** - In-memory, configurable, FIFO queue -2. βœ… **Circuit breaker** - 3-state machine with exponential backoff -3. βœ… **Resilient client** - Combined wrapper with fallback chain -4. βœ… **Stellar integration** - Drop-in replacement for existing RPC calls -5. βœ… **Comprehensive tests** - 75+ tests covering all scenarios -6. βœ… **Production config** - Environment-based presets -7. βœ… **Monitoring hooks** - Health checks, metrics, alerts -8. βœ… **Documentation** - Complete API docs + implementation guide - -### What Problems It Solves - -- ❌ **HTTP 429 errors** β†’ βœ… Rate limiting prevents exceeding limits -- ❌ **HTTP 500 errors** β†’ βœ… Circuit breaker isolates failing nodes -- ❌ **Timeouts** β†’ βœ… Configurable request timeouts with detection -- ❌ **Cascading failures** β†’ βœ… Fail-fast prevents cascade -- ❌ **No fallback** β†’ βœ… Automatic backup node switching -- ❌ **Manual recovery** β†’ βœ… Automated recovery with canary testing -- ❌ **Memory leaks** β†’ βœ… Proper cleanup of all resources - -### Production Ready - -βœ… All acceptance criteria met -βœ… 75+ tests passing -βœ… Zero memory leaks verified -βœ… Performance overhead < 5% -βœ… Complete documentation -βœ… Monitoring integration ready - -**Status: READY FOR PRODUCTION DEPLOYMENT** - ---- - -## πŸ“ž Support - -For questions or issues: -1. Check `lib/resilience/README.md` for API reference -2. Review tests in `__tests__/` for usage examples -3. Check troubleshooting guide above -4. Monitor metrics and health endpoints - ---- - -**Last Updated:** 2026-06-20 -**Version:** 1.0.0 -**Status:** Production Ready βœ… diff --git a/RESILIENCE_QUICK_REFERENCE.md b/RESILIENCE_QUICK_REFERENCE.md deleted file mode 100644 index 70084cd..0000000 --- a/RESILIENCE_QUICK_REFERENCE.md +++ /dev/null @@ -1,342 +0,0 @@ -# πŸ›‘οΈ Resilience Layer - Quick Reference Card - -## πŸš€ Quick Start (Copy-Paste Ready) - -### Installation -```bash -# No installation needed - pure TypeScript, already in codebase -npm run test:resilience # Verify it works -``` - -### Drop-In Replacement (Easiest) -```typescript -// Before: -import { fetchContractEvents } from "./lib/stellar/client"; -const events = await fetchContractEvents(ids, config, ledger); - -// After: -import { fetchContractEventsResilient } from "./lib/stellar/resilient-stellar-client"; -const events = await fetchContractEventsResilient(ids, ledger); -``` - -### Custom Usage -```typescript -import { createResilientClient, getResilientClientConfig } from "./lib/resilience"; - -const client = createResilientClient( - getResilientClientConfig("testnet", "production") -); - -const result = await client.execute(async (rpcUrl) => { - return await yourRpcCall(rpcUrl); -}); - -client.dispose(); // Always cleanup -``` - ---- - -## πŸ“Š Configuration Presets - -| Preset | Use Case | Capacity | Rate | Threshold | -|--------|----------|----------|------|-----------| -| **Development** | Local testing | 20 | 10/sec | 10 failures | -| **Production** | Live traffic | 10 | 5/sec | 5 failures | -| **Aggressive** | High protection | 5 | 2/sec | 3 failures | -| **Lenient** | Testing/debug | 50 | 25/sec | 15 failures | - -```typescript -// Use preset -import { getResilientClientConfig } from "./lib/resilience/config"; -const config = getResilientClientConfig("testnet", "production"); - -// Or aggressive -import { AGGRESSIVE_RESILIENCE_CONFIG } from "./lib/resilience/config"; -const client = createResilientClient(AGGRESSIVE_RESILIENCE_CONFIG); -``` - ---- - -## πŸ”§ Common Configurations - -### Basic (Single Primary) -```typescript -{ - endpoints: [ - { id: "primary", url: "https://soroban-testnet.stellar.org", priority: 0 }, - ], - rateLimiter: { capacity: 10, refillRate: 5 }, - circuitBreaker: { failureThreshold: 5, successThreshold: 2, resetTimeout: 5000 }, -} -``` - -### With Backup -```typescript -{ - endpoints: [ - { id: "primary", url: "https://soroban-testnet.stellar.org", priority: 0 }, - { id: "backup", url: "https://rpc-testnet.stellar.org", priority: 1 }, - ], - rateLimiter: { capacity: 10, refillRate: 5 }, - circuitBreaker: { failureThreshold: 5, successThreshold: 2, resetTimeout: 5000 }, -} -``` - -### Multiple Backups -```typescript -{ - endpoints: [ - { id: "primary", url: PRIMARY_URL, priority: 0 }, - { id: "backup-1", url: BACKUP_1_URL, priority: 1 }, - { id: "backup-2", url: BACKUP_2_URL, priority: 2 }, - ], - rateLimiter: { capacity: 10, refillRate: 5 }, - circuitBreaker: { failureThreshold: 5, successThreshold: 2, resetTimeout: 5000 }, -} -``` - ---- - -## πŸ“ˆ Monitoring Snippets - -### Health Check -```typescript -import { getHealthStatus } from "./lib/stellar/resilient-stellar-client"; - -app.get("/health", (req, res) => { - const health = getHealthStatus(); - res.status(health.healthy ? 200 : 503).json(health); -}); -``` - -### Metrics Endpoint -```typescript -import { getResilientMetrics } from "./lib/stellar/resilient-stellar-client"; - -app.get("/metrics", (req, res) => { - const metrics = getResilientMetrics(); - res.json({ - rateLimiter: metrics.rateLimiter, - circuitBreakers: metrics.circuitBreakers.map(cb => ({ - endpoint: cb.endpoint.id, - state: cb.metrics.state, - failures: cb.metrics.totalFailures, - })), - }); -}); -``` - -### Log Circuit State Changes -```typescript -const client = createResilientClient({ - // ... config - onCircuitStateChange: (endpoint, oldState, newState) => { - if (newState === "OPEN") { - logger.error(`⚠️ ${endpoint.id} circuit OPENED`); - alerting.send({ severity: "critical", message: `${endpoint.id} down` }); - } else if (newState === "CLOSED") { - logger.info(`βœ“ ${endpoint.id} circuit CLOSED`); - } - }, -}); -``` - ---- - -## πŸ§ͺ Testing Commands - -```bash -# Run all resilience tests -npm run test:resilience - -# Watch mode (for development) -npm run test:resilience:watch - -# With coverage -npm run test:resilience:coverage - -# Specific test file -npm test lib/resilience/__tests__/circuit-breaker.test.ts -``` - ---- - -## πŸ› Troubleshooting Cheat Sheet - -### Problem: "TokenBucket queue full" -**Cause:** Rate limit too low -**Fix:** -```typescript -rateLimiter: { - capacity: 20, // ⬆️ Increase from 10 - refillRate: 10, // ⬆️ Increase from 5 - maxQueueSize: 200, // ⬆️ Increase from 100 -} -``` - -### Problem: Circuit keeps opening/closing (flapping) -**Cause:** Threshold too sensitive -**Fix:** -```typescript -circuitBreaker: { - failureThreshold: 10, // ⬆️ Increase from 5 - resetTimeout: 3000, // ⬇️ Decrease from 5000 (faster recovery) -} -``` - -### Problem: Not using backup endpoint -**Cause:** Circuit not opening or priority wrong -**Check:** -```typescript -const current = client.getCurrentEndpoint(); -console.log("Using:", current.id); // Should show "backup" if primary failed - -const metrics = client.metrics(); -console.log("Primary state:", - metrics.circuitBreakers.find(cb => cb.endpoint.id === "primary")?.metrics.state -); -``` - -### Problem: Memory leak -**Cause:** Not disposing client -**Fix:** -```typescript -// ALWAYS dispose on shutdown -process.on("SIGTERM", () => { - disposeResilientClient(); // For Stellar client - // OR - client.dispose(); // For manual client - process.exit(0); -}); -``` - ---- - -## πŸ“Š Circuit Breaker States - -``` -CLOSED (Normal) - └─> OPEN (Failing) - └─> HALF_OPEN (Testing) - β”œβ”€> CLOSED (Success) - └─> OPEN (Failed again, +backoff) -``` - -| State | Behavior | When | -|-------|----------|------| -| **CLOSED** | Normal operation | Initially, after recovery | -| **OPEN** | Fail-fast (rejects immediately) | After X failures | -| **HALF_OPEN** | Testing with canary requests | After cooldown period | - ---- - -## βš™οΈ Parameter Tuning Guide - -### Rate Limiter - -| Parameter | Low Traffic | Medium Traffic | High Traffic | -|-----------|-------------|----------------|--------------| -| `capacity` | 5-10 | 10-20 | 20-50 | -| `refillRate` | 2-5 | 5-10 | 10-25 | -| `maxQueueSize` | 50-100 | 100-200 | 200-500 | - -### Circuit Breaker - -| Parameter | Sensitive | Balanced | Tolerant | -|-----------|-----------|----------|----------| -| `failureThreshold` | 3 | 5 | 10-15 | -| `successThreshold` | 1-2 | 2-3 | 3-5 | -| `resetTimeout` | 3000ms | 5000ms | 10000ms | -| `requestTimeout` | 5000ms | 10000ms | 15000ms | - -### Recommendations - -**Critical services:** Sensitive settings (fail fast) -**Flaky services:** Tolerant settings (more forgiving) -**Development:** Lenient settings (faster iteration) -**Production:** Balanced settings (reliability + availability) - ---- - -## πŸ” Metrics to Monitor - -### Rate Limiter -- `availableTokens` - Should stay > 0 most of the time -- `queuedRequests` - Should be 0 or low (< 10) -- `totalRejected` - Should be 0 in normal operation - -### Circuit Breaker (per endpoint) -- `state` - Should be "CLOSED" most of the time -- `totalFailures` - Track trending (increasing = problem) -- `totalTimeouts` - Should be low (< 1% of requests) -- `consecutiveFailures` - Reset on success - -### Alerts to Set -- ⚠️ Circuit state changes to OPEN -- ⚠️ Rate limiter rejection rate > 1% -- ⚠️ Queue depth consistently > 50% capacity -- βœ… Circuit closes after being open (info alert) - ---- - -## πŸ“ File Reference - -| File | Purpose | -|------|---------| -| `lib/resilience/index.ts` | Main exports | -| `lib/resilience/config.ts` | Presets | -| `lib/stellar/resilient-stellar-client.ts` | Stellar integration | -| `RESILIENCE_IMPLEMENTATION_GUIDE.md` | Full guide | -| `lib/resilience/README.md` | API docs | - ---- - -## πŸ†˜ Emergency Commands - -```typescript -// Get current state -import { getHealthStatus, getCurrentRpcEndpoint } from "./lib/stellar/resilient-stellar-client"; - -console.log("Health:", getHealthStatus()); -console.log("Using endpoint:", getCurrentRpcEndpoint()); - -// Force use specific endpoint (testing only) -// Create new client with only that endpoint -const emergencyClient = createResilientClient({ - endpoints: [{ id: "emergency", url: EMERGENCY_URL, priority: 0 }], - // ... rest of config -}); - -// Increase rate limits temporarily -const lenientClient = createResilientClient(LENIENT_RESILIENCE_CONFIG); -``` - ---- - -## βœ… Pre-Deployment Checklist - -- [ ] Run tests: `npm run test:resilience` -- [ ] Configure endpoints (primary + backups) -- [ ] Set rate limits based on upstream capacity -- [ ] Set circuit breaker thresholds -- [ ] Add health check endpoint -- [ ] Add metrics export -- [ ] Configure alerts -- [ ] Test failover manually -- [ ] Add dispose to shutdown handler -- [ ] Document in runbook - ---- - -## πŸ“ž Quick Links - -- **API Docs:** `lib/resilience/README.md` -- **Implementation Guide:** `RESILIENCE_IMPLEMENTATION_GUIDE.md` -- **Complete Deliverables:** `RESILIENCE_DELIVERABLES.md` -- **Tests:** `lib/resilience/__tests__/` - ---- - -**Status:** βœ… Production Ready -**Version:** 1.0.0 -**Last Updated:** 2026-06-20 diff --git a/TEST_LINTER.md b/TEST_LINTER.md deleted file mode 100644 index cf39347..0000000 --- a/TEST_LINTER.md +++ /dev/null @@ -1,303 +0,0 @@ -# Testing the Registry Linter - -This document provides instructions for testing the 3-tier validation pipeline. - -## Prerequisites - -1. Install dependencies (including `ajv` and `tsx`): -```bash -npm install -``` - -## Test 1: Validate Current Registry (Should Pass) - -The current registry file should pass all validation checks: - -```bash -npm run lint:registry -``` - -**Expected Output**: -``` -πŸ” Starting Translation Registry Validation... - -βœ“ Schema loaded successfully -βœ“ Registry loaded successfully (25 entries) - -πŸ“‹ Running Tier 1: JSON Schema Validation... -βœ“ Schema validation passed - -πŸ“‹ Running Tier 2: Template Variable Cross-Examination... -πŸ“‹ Running Tier 3: Logical Consistency Checks... -βœ“ Logic validation passed - -================================================================================ -βœ… ALL VALIDATION CHECKS PASSED -================================================================================ - -25 registry entries validated successfully. -``` - -## Test 2: Validate Bad Example (Should Fail) - -Test the linter against a file with intentional errors: - -```bash -# Backup current registry -copy lib\translator\registry.json lib\translator\registry.backup.json - -# Use bad example -copy lib\translator\registry.bad-example.json lib\translator\registry.json - -# Run linter (should fail) -npm run lint:registry - -# Restore original -copy lib\translator\registry.backup.json lib\translator\registry.json -del lib\translator\registry.backup.json -``` - -**Expected Output**: Should detect and report 10+ errors including: -- Missing required fields -- Template variable mismatches -- Invalid contract_id formats -- Topics array length mismatches -- Duplicate entries -- Invalid type enums -- Test vector issues - -## Test 3: Test Individual Error Types - -### Test 3a: Template Variable Mismatch - -Create a test file `test-mismatch.json`: -```json -[ - { - "contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - "topics": ["transfer", "from", "to"], - "event_structure": { - "topics": [ - { "name": "from", "type": "address" }, - { "name": "to", "type": "address" } - ], - "data": { "name": "amount", "type": "i128" } - }, - "english_template": "Transfer of {value} from {from} to {to}" - } -] -``` - -Run: -```bash -copy test-mismatch.json lib\translator\registry.json -npm run lint:registry -``` - -**Expected Error**: -``` -❌ Template references '{value}' but event_structure only provides [from, to, amount] -``` - -### Test 3b: Invalid Contract ID - -Create test file with invalid contract_id: -```json -[ - { - "contract_id": "INVALID", - "topics": ["transfer", "from", "to"], - "event_structure": { - "topics": [ - { "name": "from", "type": "address" }, - { "name": "to", "type": "address" } - ], - "data": { "name": "amount", "type": "i128" } - }, - "english_template": "Transfer of {amount} from {from} to {to}" - } -] -``` - -**Expected Error**: Schema validation should fail on contract_id pattern (if schema is enhanced). - -### Test 3c: Topics Length Mismatch - -```json -[ - { - "contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - "topics": ["burn"], - "event_structure": { - "topics": [ - { "name": "from", "type": "address" }, - { "name": "to", "type": "address" } - ], - "data": { "name": "amount", "type": "i128" } - }, - "english_template": "Burned {amount}" - } -] -``` - -**Expected Error**: -``` -❌ Topics array length mismatch: expected 3 (1 event name + 2 fields), got 1 -``` - -### Test 3d: Duplicate Detection - -```json -[ - { - "contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - "topics": ["transfer", "from", "to"], - "event_structure": { - "topics": [ - { "name": "from", "type": "address" }, - { "name": "to", "type": "address" } - ], - "data": { "name": "amount", "type": "i128" } - }, - "english_template": "Transfer {amount} from {from} to {to}" - }, - { - "contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - "topics": ["transfer", "from", "to"], - "event_structure": { - "topics": [ - { "name": "from", "type": "address" }, - { "name": "to", "type": "address" } - ], - "data": { "name": "amount", "type": "i128" } - }, - "english_template": "Different template but same entry" - } -] -``` - -**Expected Error**: -``` -❌ Duplicate entry detected (same contract_id and topics as index 0) -``` - -## Test 4: Verify GitHub Actions Workflow - -You can test the GitHub Actions workflow locally using [act](https://github.com/nektos/act): - -```bash -# Install act (requires Docker) -# Then run: -act pull_request --workflows .github/workflows/registry-lint.yml -``` - -Or simply push a test branch and open a PR to see the workflow in action. - -## Test 5: Validate Legacy Script Still Works - -The old validation script should still work: - -```bash -npm run validate:registry -``` - -This runs the basic JSON schema validation without the advanced checks. - -## Continuous Testing - -Add to your development workflow: - -1. **Before committing registry changes**: - ```bash - npm run lint:registry - ``` - -2. **In git pre-commit hook** (optional): - Add to `.git/hooks/pre-commit`: - ```bash - #!/bin/sh - if git diff --cached --name-only | grep -q "lib/translator/registry.json"; then - npm run lint:registry || exit 1 - fi - ``` - -## Troubleshooting - -### Error: "Cannot find module 'ajv'" - -**Solution**: -```bash -npm install -``` - -### Error: "tsx: command not found" - -**Solution**: -```bash -npm install tsx --save-dev -``` - -Or use npx: -```bash -npx tsx scripts/lint-registry.ts -``` - -### Error: "Schema file not found" - -**Solution**: Ensure you're running from the project root directory: -```bash -cd "c:\Users\Admin\Desktop\Issues on ground\Open-Audit" -npm run lint:registry -``` - -### Linter passes but CI fails - -**Possible causes**: -1. Different Node.js versions (ensure v20+) -2. Schema file differences -3. Package versions mismatch - -**Solution**: Check CI logs for specific error and ensure local environment matches CI. - -## Performance Benchmarks - -Expected validation times: - -| Registry Size | Validation Time | -|--------------|----------------| -| 25 entries | < 1 second | -| 100 entries | < 2 seconds | -| 500 entries | < 5 seconds | -| 1000 entries | < 10 seconds | - -If validation is slower, check for: -- Large test_vectors arrays -- Very long template strings -- Disk I/O issues - -## Automated Testing - -You can add the linter to your test suite in `vitest.config.ts`: - -```typescript -import { describe, it, expect } from 'vitest'; -import { execSync } from 'child_process'; - -describe('Registry Validation', () => { - it('should pass all validation checks', () => { - expect(() => { - execSync('npm run lint:registry', { stdio: 'inherit' }); - }).not.toThrow(); - }); -}); -``` - -## Summary - -The 3-tier validation pipeline provides comprehensive error detection: - -- βœ… **Tier 1**: Catches structural and type errors -- βœ… **Tier 2**: Catches template variable mismatches -- βœ… **Tier 3**: Catches logical inconsistencies - -All tests should complete in under 5 seconds for typical registry sizes. diff --git a/docs/README.md b/docs/README.md index 7cc8dcd..bb3e8d3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,8 +13,6 @@ Choose the path below that best matches what you want to accomplish today. Get the standard development server (`server.ts`) up and running with live WebSocket streaming in under 5 minutes. - **[Microservices Quickstart](../QUICKSTART_MICROSERVICES.md)** Step-by-step instructions for deploying the decoupled production microservices topology using Docker Compose or PM2. -- **[Reconciliation Worker Quickstart](../RECONCILIATION_QUICKSTART.md)** - Setup guide for running standalone ledger background workers to automatically detect and reconcile missed events. - **[Contributing Guidelines](../CONTRIBUTING.md)** Essential contributor guidelines covering Git workflow, commit naming conventions, and environment preparation. @@ -27,9 +25,6 @@ Choose the path below that best matches what you want to accomplish today. Learn how to write versioned translation blueprints for smart contracts, register them, and run the automated validator (`npm run lint:registry`). - **[Code & Sanitization Standards](../CODE_STANDARDS.md)** Required TypeScript strict typing rules, UI display formatting, and HTML escaping/sanitization standards for contract descriptions. -- **[Translation Testing Guide](../TEST_LINTER.md)** - Instructions for writing unit tests against your translation blueprints and verifying custom ABI decoders. - --- ## πŸ—οΈ "I want to understand the architecture" @@ -39,14 +34,8 @@ Choose the path below that best matches what you want to accomplish today. Comprehensive system overview, high-level data flow diagram, and component deep dive (`server.ts`, polling indexer, translation registry). - **[Microservices Production Architecture](../MICROSERVICES_ARCHITECTURE.md)** Detailed breakdown of the production microservices architecture, featuring Redis Pub/Sub decoupling, standalone workers, and independent scaling. -- **[Visual Architecture Guide](../MICROSERVICES_VISUAL_GUIDE.md)** - ASCII diagrams, sequence flows, and comparative visual models illustrating event propagation across service boundaries. - **[Security Hardening Guide](../SECURITY_HARDENING_GUIDE.md)** Deep dive into defensive layers including XSS payload disarming, RPC rate-limit mitigation, and contract payload sanitization. -- **[Resilience Implementation Guide](../RESILIENCE_IMPLEMENTATION_GUIDE.md)** - Technical specifications for exponential backoff retries, circuit breakers, and Dead-Letter Queue (DLQ) persistence. -- **[Resilience Quick Reference](../RESILIENCE_QUICK_REFERENCE.md)** - Operational cheat-sheet covering configuration parameters, error codes, and manual recovery commands. ---