Systemarchitektur¶
Tech-Stack¶
| Komponente | Technologie | Version |
|---|---|---|
| Runtime | Node.js | v20 (LTS) |
| Sprache | TypeScript | 5.6.3 |
| Datenbank | PostgreSQL | 16 |
| Blockchain | ethers.js | 6.13.0 |
| Push-Notifications | web-push | 3.6.7 |
| Prozess-Management | Cron | System-Crontab |
Verzeichnisstruktur¶
bo-engine/
├── cli/ # CLI-Scripts und Cron-Wrapper
│ ├── settle.ts # Settlement-Orchestrator
│ ├── run.ts # Compute + Merkle + DB (591 Zeilen)
│ ├── approve_settlement.ts # Validierungs-Gates
│ ├── commit_from_db.ts # Blockchain-Commit
│ ├── export_inputsDB.ts # Winner-Export
│ ├── export_affiliatesDB.ts # Affiliate-Export
│ ├── refresh-global-stats.ts # Dashboard-Stats
│ ├── cron-settle.sh # Cron-Wrapper Settlement
│ ├── cron-recover-intents.sh # Cron-Wrapper Recovery
│ ├── cron-refresh-seeds.sh # Cron-Wrapper Seeds
│ └── cron-resolve-pending-claims.sh
│
├── core/ # Reine Geschäftslogik
│ ├── settlementCompute.ts # Berechnungsalgorithmus (299 Zeilen)
│ ├── charityCompute.ts # Charity-Berechnung
│ └── invariants.ts # Merkle-Invarianten
│
├── io/ # I/O-Schicht
│ ├── ChainReader.ts # Read-Only-Blockchain-Zugriff
│ └── artifactWriter.ts # Artefakt-Dateischreiber
│
├── merkle/ # Merkle-Tree-Implementierung
│ └── merkleBuilder.ts # Tree-Konstruktion + Proof-Generation
│
├── workers/ # Hintergrund-Worker
│ ├── refreshSeeds.ts # VRF/Drand-Daemon (264 Zeilen)
│ ├── recoverBuyIntents.ts # Buy-Intent-Recovery
│ ├── resolvePendingClaims.ts # Claim-Recovery
│ ├── backfill_claim_events.ts # Event-Backfill
│ ├── updatePotSizes.ts # Pot-Synchronisation
│ ├── notifyWinners.ts # Push-Notifications
│ ├── awardAffiliateBonus.ts # Affiliate-Bonus
│ ├── awardLeaderboardBonus.ts # Leaderboard-Bonus
│ └── reEngagementEmail.ts # Re-Engagement-Kampagnen
│
├── watchdog/ # Monitoring-System
│ ├── run.ts # Watchdog-Runner
│ ├── types.ts # Check-Typen
│ ├── checks/
│ │ ├── onchain.ts # Blockchain-Checks
│ │ ├── database.ts # DB-Checks
│ │ └── service.ts # Service-Checks
│ └── alerting/
│ └── telegram.ts # Telegram-Alerting
│
├── services/ # Service-Schicht
│ ├── finalizeBuyIntent_v2.ts # Buy-Intent-Finalisierung (294 Zeilen)
│ ├── processBonusGrant.ts # Auto-Bonus-Vergabe
│ ├── emailService.ts # E-Mail via Resend API
│ ├── emailTemplates.ts # HTML-Templates
│ └── pushService.ts # Web-Push via VAPID
│
├── types/ # TypeScript-Definitionen
│ ├── solidity.ts # Contract-Typen + ABIs
│ └── index.ts # Shared Types
│
├── lib/ # Utility-Bibliotheken
│ └── claimEventLogger.ts # Claim-Event-Logging
│
├── abi/ # Smart-Contract-ABIs
│ └── SettlementV4.json
│
├── artifacts/ # Settlement-Artefakte (pro Tag)
│ └── dayId=X/
│ ├── inputs.json
│ ├── affiliates.json
│ ├── settlement_result.json
│ ├── winners_merkle.json
│ ├── affiliate_merkle.json
│ ├── commit_bundle.json
│ └── checksums.json
│
├── logs/ # Log-Verzeichnisse
│ ├── settlement/ # 30 Tage Retention
│ ├── recovery/ # 14 Tage Retention
│ ├── claim-recovery/ # 14 Tage Retention
│ └── seeds/ # 14 Tage Retention
│
├── env.ts # Environment-Loader
├── package.json # Dependencies
├── tsconfig.json # TypeScript-Config
└── CRON_SETUP.md # Cron-Dokumentation
Architekturprinzipien¶
1. Database-as-Source-of-Truth¶
Die Datenbank ist die einzige Wahrheitsquelle. Filesystem-Artefakte sind Audit-Kopien:
settlement_artifacts (DB) ←── Source of Truth
│
├── artifacts/dayId=X/ ←── Audit-Kopie (Filesystem)
└── settlement_runs (DB) ←── Berechnungsergebnis
2. Idempotenz¶
Jede Operation ist idempotent gestaltet:
- Settlement-Runs:
run_hash = sha256(commitBundle)- Duplikate erkannt - finalizeBuyIntent: Prüft ob Ticket bereits existiert
- Bonus-Vergabe:
bonus_awarded-Flag verhindert Doppelvergabe - Leaderboard: Prüft
extra_bonus_vouchersauf existierende Awards
3. Pipeline mit Step-Tracking¶
settlement_pipeline_runs
├── status: RUNNING → DONE/FAILED
├── export_ok: boolean
├── affiliate_ok: boolean
├── compute_ok: boolean
├── approve_ok: boolean
├── commit_ok: boolean
└── stats_ok: boolean
Jeder Schritt wird einzeln getracked. Bei Fehler: status='FAILED', Exit Code 1.
4. Separation of Concerns¶
┌────────────────────────────────────────────────┐
│ CLI Layer (cli/) │
│ - Orchestrierung, DB-Zugriff, I/O │
├────────────────────────────────────────────────┤
│ Core Layer (core/) │
│ - Reine Berechnungslogik, keine Side-Effects │
├────────────────────────────────────────────────┤
│ IO Layer (io/) │
│ - Blockchain-Reads, Artefakt-Schreiber │
├────────────────────────────────────────────────┤
│ Service Layer (services/) │
│ - Transaktionale Geschäftsoperationen │
└────────────────────────────────────────────────┘
5. Dual-RPC-Fallback¶
Kritische Operationen nutzen Primary + Fallback RPC:
// recoverBuyIntents.ts
const primary = new JsonRpcProvider(RPC_URL);
const fallback = new JsonRpcProvider(FALLBACK_RPC_URL ?? RPC_URL);
Interaktionen mit anderen Systemen¶
┌─────────┐
│ App │
│(Next.js)│
└────┬────┘
│ buy_intents, users
▼
┌──────────┐ ┌──────────────┐ ┌──────────────────┐
│Blockchain│◄────►│ BO-Engine │◄────►│ PostgreSQL │
│(Arbitrum)│ │ │ │ (chainbets) │
└──────────┘ └──────┬───────┘ └──────────────────┘
│
┌────┴────┐
│Telegram │
│ Bot │
└─────────┘
Abhängigkeiten (package.json)¶
{
"dependencies": {
"dotenv": "^17.2.3",
"ethers": "^6.13.0",
"pg": "^8.17.2",
"web-push": "^3.6.7"
},
"devDependencies": {
"ts-node": "^10.9.2",
"typescript": "^5.6.3"
}
}
Bewusst minimale Dependencies - keine Frameworks, kein ORM, kein Express.