CryptoPulse is a high-performance backend for a cryptocurrency tracking application. It consists of two main services: an api-server (a RESTful API for user management, watchlists, and data retrieval) and a work-server (a background worker that continuously fetches data from the CoinGecko API). The services are decoupled via a Redis cache, ensuring the API remains fast and responsive while data is kept up-to-date by the worker.
- Project Overview
- Folder Structure
- Features
- Getting Started
- API Endpoints
- Logging
- Background Jobs (work-server)
- Contributing
CryptoPulse is built with Node.js, Express, MongoDB, and Redis. The api-server handles all client-facing requests, managing user authentication (JWT & Google OAuth), profile settings, and watchlist modifications. All cryptocurrency data is served directly from a Redis cache to ensure low latency.
The work-server runs on a schedule (node-cron) to populate and refresh this Redis cache by fetching data from the CoinGecko API. It fetches the top 500 coins for general display and intelligently fetches any other specific coins that users have added to their watchlists.
CryptoPulse/
│
├── api-server/ # REST API server
│ ├── src/
│ │ ├── config/ # Database & Redis configs
│ │ ├── controllers/ # Request handlers (logic)
│ │ ├── middleware/ # Auth, validation, file handling
│ │ ├── models/ # Mongoose schemas
│ │ ├── routes/ # API route definitions
│ │ ├── utils/ # Utilities (logger, cloudinary, etc.)
│ │ ├── app.js # Express app configuration
│ │ ├── index.js # Main entry point
│ │ └── constants.js # App constants
│ ├── logs/ # Winston log files (gitignored)
│ ├── public/ # Static files/uploads
│ └── package.json # Dependencies
│
└── work-server/ # Background worker service
├── src/
│ ├── config/ # Database & Redis configs
│ ├── models/ # Mongoose schemas
│ ├── utils/ # Axios instance
│ ├── index.js # Cron jobs and data fetching logic
│ └── constants.js # Worker constants
└── package.json # Dependencies
- Authentication: Secure user registration and login with JWT (access/refresh tokens) and Google OAuth 2.0 integration.
- User Management: Update user profiles, change passwords, and upload avatars to Cloudinary.
- Crypto Data: Blazing-fast paginated coin data and single-coin lookups, read directly from the Redis cache.
- Watchlist Management: Authenticated users can add, remove, and view coins on their personal watchlist.
- Security: Hardened with
helmet,cors,express-rate-limitfor request limiting, andexpress-validatorfor input sanitization. - Logging: Robust multi-transport logging (console, file) using
winstonfor error, warn, and http levels.
- Scheduled Jobs: Uses
node-cronto run data-fetching tasks automatically on a defined schedule. - Efficient Caching: Fetches and caches the top 500 coins (ranked by market cap) from the CoinGecko API to serve the main dashboard pages.
- Dynamic Watchlist Fetching: Intelligently queries the database for all unique coins on user watchlists and fetches any that are not already in the cache (e.g., coins ranked #501+), ensuring all user-requested data is available.
- Node.js (v18+ recommended)
- MongoDB
- Redis
- Cloudinary account
- CoinGecko API Key
- Google Developer Console OAuth2 credentials
Create a .env file in the root CryptoPulse/ folder with the following:
# MongoDB
MONGO_URI=mongodb://your_mongo_host:27017/your_db_name
# Redis
REDIS_HOST=your_redis_host
REDIS_PORT=your_redis_port
REDIS_USERNAME=your_redis_username
REDIS_PASSWORD=your_redis_password
# Cloudinary (for avatar uploads)
CLOUDINARY_CLOUD_NAME=your_cloudinary_cloud_name
CLOUDINARY_API_KEY=your_cloudinary_api_key
CLOUDINARY_API_SECRET=your_cloudinary_api_secret
# CoinGecko API (for work-server)
CoinGecko_URL_COIN=https://your_coingecko_api_url
CoinGecko_API_KEY=your_coingecko_api_key
# Google OAuth2
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_REDIRECT_URI=http://your_api_url/api/v1/users/auth/google/callback
# JWT Secrets
ACCESS_TOKEN_SECRET=your_access_token_secret
ACCESS_TOKEN_EXPIRY=your_access_token_expiry
REFRESH_TOKEN_SECRET=your_refresh_token_secret
REFRESH_TOKEN_EXPIRY=your_refresh_token_expiry
# Server Configuration
CORS_ORIGIN=http://your_frontend_origin # e.g., http://localhost:3000
PORT=5000 # Port for api-server-
Install dependencies for both servers
# API server cd api-server npm install # Worker server cd ../work-server npm install
-
Start MongoDB and Redis Ensure both services are running on your local machine or are accessible.
-
Run the API server
cd ../api-server node src/index.js -
Run the worker server (in a separate terminal)
cd ../work-server node index.js
(Auth) = Requires a valid JWT access token.
Base: /api/v1/users
| Method | Endpoint | Description |
|---|---|---|
POST |
/register |
Register a new user. (Expects multipart/form-data for avatar) |
POST |
/login |
Login with email or username and password. |
GET |
/auth/google |
Redirects to Google's consent screen for OAuth. |
GET |
/auth/google/callback |
Callback URL for Google to complete the auth process. |
GET |
/logout (Auth) |
Logs out the user and clears refresh token. |
POST |
/refresh-token |
Get a new access token using a valid refresh token. |
POST |
/change-password (Auth) |
Change the user's password. |
GET |
/current-user (Auth) |
Fetch the currently logged-in user's profile. |
POST |
/update-account (Auth) |
Update user's fullName and email. |
POST |
/update-avatar (Auth) |
Update user's avatar. (Expects multipart/form-data) |
Base: /api/v1/coins
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
Get a paginated list of coins. Query: ?page=1 or ?page=2. |
GET |
/:id |
Get detailed data for a single coin by ID (e.g., bitcoin). |
Base: /api/v1/watchlist
| Method | Endpoint | Description |
|---|---|---|
GET |
/ (Auth) |
Get all coin data for items on the user's watchlist. |
POST |
/ (Auth) |
Add a coin to the watchlist. Body: { "coinId": "cardano" }. |
DELETE |
/:coinId (Auth) |
Remove a coin from the watchlist (e.g., /api/v1/watchlist/cardano). |
- Logs are managed via Winston and saved to
api-server/logs/. error.log: Allerrorlevel messages.warn.log: Allwarnlevel messages.http.log: Allhttplevel messages (request logs).combined.log: Full log aggregation.
The work-server operates independently to keep the Redis cache fresh. It runs two primary jobs on a schedule:
-
Top 500 Coins (Runs Every 2 Minutes)
- Fetches the top 500 coins (2 pages, 250 coins each) from the CoinGecko API.
- Caches each coin's data individually (e.g.,
coin:bitcoin->{...data}). - Saves the list of IDs for each page (e.g.,
page:1->["bitcoin", "ethereum", ...]). This is used by theGET /api/v1/coinsendpoint.
-
Watchlist Coins (Runs Every 5 Minutes)
- Queries the MongoDB
Watchlistcollection for all uniquecoinIds across all users. - Checks Redis to see which of these coins are not currently cached (i.e., coins ranked #501+).
- Fetches data for only the missing coins from CoinGecko in batches.
- Caches the newly fetched coin data in Redis, where it can be retrieved by the
GET /api/v1/watchlistendpoint.
- Queries the MongoDB
Contributions, issues, and feature requests are welcome!
- Fork the repo
- Create a new branch (
git checkout -b feature-name) - Commit your changes (
git commit -m 'Add feature') - Push to the branch (
git push origin feature-name) - Open a pull request