diff --git a/README.md b/README.md index 7386208..28820e8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Dashboard +Check out [Tech Stack Overview](./TECH_STACK_OVERVIEW.md) document to get +started. + ## Dependencies To build this project, you must have the following dependencies installed: diff --git a/TECH_STACK_OVERVIEW.md b/TECH_STACK_OVERVIEW.md new file mode 100644 index 0000000..67cf118 --- /dev/null +++ b/TECH_STACK_OVERVIEW.md @@ -0,0 +1,127 @@ +# Tech Stack Overview + +The Stellar Dashboard can be viewed at +[dashboard.stellar.org](https://dashboard.stellar.org). + +## Architecture at a Glance + +This is a **full-stack JavaScript/TypeScript application** with: + +- **Frontend**: React SPA (Single Page Application) +- **Backend**: Node.js/Express API server +- **Build Tool**: Vite +- **Package Manager**: npm + +## Frontend Stack + +**Purpose**: Dashboard UI displaying Stellar network metrics and data +visualization + +We use `muicss` library for the UI. It hasn't been updated in years, so it holds +us back from upgrading all dependencies to the latest versions. + +`react-d3-components` library was replaced by `d3`, which is used to build +charts. + +## Backend Stack + +**Purpose**: Serve API data, cache Stellar network metrics, proxy requests, and +connect to BigQuery + +### Key Responsibilities + +- **Cache Updates**: Periodically updates Stellar network data (lumens supply, + ledger stats) +- **API Proxy**: Proxies requests to `/api/*` (via Vite in dev, Express in + production) +- **Data Aggregation**: Fetches data from Stellar API and BigQuery +- **Rate limiting**: Rate limit is IP based and there are both endpoint-specific + and global limits + +### Environment Variables + +```bash +UPDATE_DATA=true # Enable periodic cache updates +DEV=true # Development mode +BQ_PROJECT_ID=... # BigQuery project ID used by backend/bigQuery.ts +REDIS_URL=... # Production Redis connection URL used by backend/redis.ts +PORT=5000 # Server port configuration (defaults to 5000) used by backend/routes.ts +TRUST_PROXY=... # Trusted proxy CIDRs configuration used by backend/routes.ts + +``` + +--- + +## Pinned Security Resolutions + +```json +{ + "resolutions": { + "**/ua-parser-js": "0.7.28" // Prevents vulnerable versions + } +} +``` + +This pins `ua-parser-js` to prevent dependency vulnerabilities. + +--- + +## External Services & APIs + +### Stellar Network + +- **Stellar SDK** queries the Stellar blockchain +- Fetches account data, transaction metrics, network stats + +### Google Cloud BigQuery + +- Stores historical ledger & transaction data +- Used for long-term trend analysis +- Requires service account JSON configuration + +### Redis Cache + +- **Port**: 6379 (default) +- **Purpose**: Store computed metrics to reduce repeated API calls +- **Required for**: Backend data updates + +--- + +## Build & Deployment + +### Deployment Platforms + +- **Heroku**: Configured via `Procfile` and `heroku-postbuild` script +- **Docker**: `Dockerfile` available for containerized deployment + +### Environment + +- **Node.js version**: 22.x (specified in `engines`) + +--- + +## Key Architectural Patterns + +### Frontend-Backend Communication + +``` +Frontend (React) + ↓ (HTTP requests via Axios) +Vite Dev Proxy (dev) / Express (prod) + ↓ (backend/routes.ts) +External APIs (Stellar SDK, BigQuery, Redis) +``` + +### Data Flow for Metrics + +1. Backend periodically fetches data from Stellar API +2. Computes aggregates (e.g., lumens in circulation) +3. Caches results in Redis +4. Frontend requests cached data via `/api/*` endpoints +5. Charts and widgets update in real-time + +### Caching Strategy + +- **Redis**: Primary cache for hot data +- **In-memory**: Some computed values cached in process +- **Update frequency**: 10-minute intervals (configurable) diff --git a/package-lock.json b/package-lock.json index 7d42aac..15ec040 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "morgan": "^1.8.2", "muicss": "^0.9.5", "react": "^18.2.0", - "react-d3-components": "^0.9.1", "react-dom": "^18.2.0", "redis": "^4.0.1" }, @@ -3354,16 +3353,6 @@ "sha.js": "^2.4.8" } }, - "node_modules/create-react-class": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", - "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -7423,7 +7412,6 @@ "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, "license": "MIT", "bin": { "prettier": "bin-prettier.js" @@ -7461,17 +7449,6 @@ "asap": "~2.0.3" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -7629,27 +7606,6 @@ "object-assign": "^4.1.0" } }, - "node_modules/react-d3-components": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/react-d3-components/-/react-d3-components-0.9.1.tgz", - "integrity": "sha512-TfUmlheSGDsa/x0h8wJ8FcR2+0zYy+VIF9vRhOFnRavnjkiQHrDzdmiVYoS+6Kte70cLtkr/Tej9vvggzLaqeQ==", - "license": "MIT", - "dependencies": { - "create-react-class": "^15.6.2", - "d3": "^3.5.3", - "prop-types": "^15.6.0" - }, - "peerDependencies": { - "react": "^0.14.0 || ^15.0.0 || ^16.0.0", - "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/react-d3-components/node_modules/d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==", - "license": "BSD-3-Clause" - }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -7663,12 +7619,6 @@ "react": "^18.3.1" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, "node_modules/react-property": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", diff --git a/package.json b/package.json index 54a838a..87ccdb4 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "morgan": "^1.8.2", "muicss": "^0.9.5", "react": "^18.2.0", - "react-d3-components": "^0.9.1", "react-dom": "^18.2.0", "redis": "^4.0.1" },