A production-grade, eCommerce-style backend built with Node.js, Express, and MongoDB, designed using the MVC architecture. It features authentication, multi-provider email verification (Nodemailer & Resend), Stripe payments & webhooks, order processing, in-memory Redis caching (15-minute TTL), BullMQ background queues, Cloudinary media storage, and comprehensive analytics — ideal for developers building scalable, real-world applications.
- 🌐 Interactive Redoc API Documentation: Served locally at
http://localhost:8002/(built with OpenAPI 3.1 & Redoc) - 📎 Postman API Documentation: View Postman Documentation
- 📜 OpenAPI Specifications: Multi-file OpenAPI 3.1 definitions located in
/docs(openapi.yaml,admin.yaml,auth.yaml,book.yaml,cart.yaml,order.yaml,review.yaml,user.yaml,wishlist.yaml,schema.yaml) - 🛠️ CLI Documentation Commands:
npm run doc:bundle– Bundles modular YAML specs intodocs/bundle/openapi.yamlnpm run doc:build– Builds standalone HTML documentation todocs/apidoc.html
- ✅ JWT-based User & Admin Authentication
- ✅ Multi-Provider Email OTP Verification (Nodemailer Gmail SMTP & Resend API with 1-minute expiration window)
- ✅ Automatic Admin Account Seeding on Server Startup (
seeds/initilizeAdmin.js) - ✅ Role-Based Access Control (RBAC) with Self-Protection Guards
- ✅ Account Activation & Suspension Management (
/admin/activateUser,/admin/deactivateUser) - ✅ Role Modification & Promotion/Demotion (
/admin/change-role) - ✅ Multi-tier API Rate Limiting (Read, Mutation, Auth, General)
- ✅ Input & Parameter Validation (
validateUser,validateId) - ✅ Secure Environment-based Configuration
- ✅ Centralized Error Handling & Operational Exceptions
- ✅ Complete CRUD Operations for Books
- ✅ Book Review & Rating System with Dynamic Recalculation
- ✅ Wishlist Management
- ✅ Advanced Filtering, Search, Sorting & Pagination
- ✅ Soft-deletion preserving historical order records
- ✅ Shopping Cart Management with Redis Caching (15-minute TTL)
- ✅ Complete Order Management & Stripe Checkout Sessions
- ✅ Real-time Inventory Reservation & Restocking
- ✅ 7-Day Refund Window Policy & Automated Stripe Refunds
- ✅ BullMQ Queue System for Background Order & Email Processing
- ✅ Stripe Payment Integration (Checkout Sessions & Webhooks)
- ✅ Payment Status Tracking (
pending,paid,refunded,failed) - ✅ Automated PDF Invoice Generation
- ✅ Admin Dashboard with Key Business Metrics
- ✅ Sales & Revenue Analytics (Daily, Weekly, Monthly, Yearly)
- ✅ Order Analytics & Order Growth Tracking
- ✅ Average Order Value (AOV) Analytics
- ✅ Book Performance, Sales & Revenue Analytics
- ✅ Inventory & Stock Analytics (Low-stock & Dead stock detection)
- ✅ Category-wise Sales & Revenue Trends
- ✅ Book Rating Distribution Analytics
- ✅ Customer Analytics & Top Spenders
- ✅ Payment Analytics (Stripe status volume & rates)
- ✅ Redis In-Memory Caching (15-minute TTL): Cache-aside strategy on Book details, Customer Carts, Orders, and Personal Reviews
- ✅ BullMQ Distributed Queue System: Background worker processing for orders and automated emails
- ✅ Multi-Provider Email Dispatching: Seamlessly switch between Gmail SMTP and Resend API (
EMAIL_PROVIDER)
- ✅ Clean MVC Project Structure
- ✅ Modular & Maintainable Codebase
- ✅ Centralized Error Handling (
AppError&catchAsync) - ✅ Secure Configuration Management with environment validation
BookStore/
├── config/ # Database and Redis client configuration (redisClient.js)
├── controllers/ # Express route controllers (MVC)
│ ├── adminController.js
│ ├── authController.js
│ ├── booksController.js
│ ├── cartController.js
│ ├── errorController.js
│ ├── orderController.js
│ ├── reviewController.js
│ ├── userController.js
│ └── wishlistController.js
├── docs/ # Multi-file OpenAPI 3.1 specifications & Redoc docs
├── middlewares/ # Authentication (protect, restrictTo), rate limiters, validators
├── models/ # Mongoose schemas & models (User, Books, Cart, Order, Review, Wishlist)
├── queues/ # BullMQ queue definitions (emailQueue.js, orderQueue.js)
├── routes/ # Express API route declarations
├── seeds/ # Database seed scripts (initilizeAdmin.js, userSeeds.js, reviewSeeds.js)
├── services/ # External service integrations (Stripe, Cloudinary)
├── utils/ # Helper utilities & email templates
│ ├── validateEnv.js # Startup environment variable validation & diagnostics
│ ├── sendEmail.js # Multi-provider email dispatcher (replaces nodemailer.js)
│ ├── AppError.js
│ ├── AppFeatures.js
│ ├── catchAsync.js
│ ├── generateInvoice.js
│ ├── otpGenerator.js
│ └── emailTemplates/ # HTML templates (verification OTP, password reset, order confirmation)
├── workers/ # BullMQ background workers (emailWorker.js, orderWorker.js)
├── .env # Environment variables
├── package.json
├── server.js # Main application entry point & Express server
└── README.md
- Runtime: Node.js 22+
- Framework: Express.js 5.x
- Database: MongoDB + Mongoose
- Authentication: JWT (JSON Web Tokens) + Bcrypt
- Email: Nodemailer (Gmail SMTP) & Resend API (configurable via
EMAIL_PROVIDER) - Payments: Stripe (Checkout Sessions & Webhooks)
- Image Storage: Cloudinary
- In-Memory Caching: Redis (ioredis, 15-minute TTL cache-aside pattern)
- Background Jobs: BullMQ + Redis
- API Documentation: OpenAPI 3.1 + Redocly + Postman
- Architecture: MVC (Model-View-Controller)
Before running the project, make sure you have:
- Node.js: v22 or higher
- MongoDB: Local MongoDB instance or MongoDB Atlas cluster
- Redis: Local Docker container or Redis Cloud instance
- Docker: (Optional) for running Redis locally
- Stripe Account: With test API keys and Stripe CLI (for local webhook testing)
- Cloudinary Account: For book cover image uploads
- Email Service Provider:
- Gmail Account with Google App Password (if using
EMAIL_PROVIDER=smtp), OR - Resend Account with API Key (if using
EMAIL_PROVIDER=resend, recommended for cloud platforms like Render)
- Gmail Account with Google App Password (if using
git clone https://github.com/PanchalKeyur0806/BookStore.git
cd BookStore
npm installCreate a .env file in the root directory and configure the following variables:
# Server Configuration
PORT=8002
NODE_ENV=development
CORS_ORIGIN=*
# MongoDB Database Connection
DB_STRING=mongodb+srv://<username>:<password>@cluster0.kqdlh.mongodb.net/BookStore
# Local alternative: mongodb://localhost:27017/BookStore
# Admin Account Initialization (Automatic on server startup)
ADMIN_EMAIL=admin@bookstore.com
ADMIN_PASSWORD=your_admin_secure_password
ADMIN_NAME=Admin User
ADMIN_PHONE=9999999999
# Redis Configuration (Docker or Cloud Redis)
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
# JWT Authentication
JWT_SECRET_KEY=your_super_secret_jwt_key
JWT_EXPIRES=7d
# Email Configuration
# Set to 'smtp' for local Gmail SMTP development
# Set to 'resend' for production / cloud deployment (e.g., Render)
EMAIL_PROVIDER=resend
# Resend Settings (Used when EMAIL_PROVIDER=resend)
RESEND_API_KEY=your_resend_api_key
# Default test sender for domains not yet registered on Resend:
EMAIL_FROM=onboarding@resend.dev
# Production sender once domain is verified on Resend:
EMAIL_FROM_PROD=BookStore <bookstore@yourdomain.com>
# Gmail SMTP Settings (Used when EMAIL_PROVIDER=smtp)
USER_EMAIL=your_email@gmail.com
GMAIL_APP_PASSWORD=your_gmail_app_password
# Stripe Payments & Webhooks
STRIPE_SECRET_KEY=your_stripe_secret_key
STRIPE_WEBHOOK=your_stripe_webhook_signing_secret
# Cloudinary Media Storage
CLOUDINARY_NAME=your_cloudinary_cloud_name
CLOUDINARY_API_KEY=your_cloudinary_api_key
CLOUDINARY_API_SECRET=your_cloudinary_api_secretThe application features a unified email dispatcher (utils/sendEmail.js) supporting both Gmail SMTP and the Resend API. You can switch providers dynamically using EMAIL_PROVIDER in your .env.
Cloud hosting platforms (such as Render free tier, Heroku, AWS EC2) often block outbound SMTP ports (25, 465, 587) by default. The Resend integration sends emails over HTTPS API, bypassing port blocks completely.
- Create a free account at Resend.com.
- Navigate to API Keys and generate an API key.
- In
.env:- Set
EMAIL_PROVIDER=resend - Set
RESEND_API_KEY=re_... - For initial testing without a custom domain, use
EMAIL_FROM=onboarding@resend.dev. - In production with a verified domain, configure
EMAIL_FROM_PROD=BookStore <bookstore@yourdomain.com>.
- Set
- Go to your Google Account Settings.
- Ensure 2-Step Verification is enabled.
- Search for App Passwords and generate a new app password for "BookStore".
- In
.env:- Set
EMAIL_PROVIDER=smtp - Set
USER_EMAIL=your_gmail_address@gmail.com - Set
GMAIL_APP_PASSWORD=your_16_character_app_password
- Set
On application startup, the server automatically executes initilizeAdmin() from seeds/initilizeAdmin.js:
- Checks MongoDB for an existing account matching
ADMIN_EMAIL. - If absent, automatically generates a verified administrator account (
role: 'admin',isEmailVerified: true,isActive: true) satisfying all required user schema fields (name,email,password,dateOfBirth,phoneNumber,gender,address). - You can also trigger the admin seed script manually from the CLI:
node seeds/initilizeAdmin.js
- Make sure Docker Desktop is running.
- Run Redis in a detached container:
docker run -d --name redis -p 6379:6379 redis
- Start an existing container:
docker start redis
- Stop the Redis container:
docker stop redis
- Verify container status:
docker ps
If deploying to production or using Redis Cloud:
- Obtain your host, port, username, and password from your Redis Cloud dashboard.
- Add them to
.env:REDIS_HOST=your-redis-cloud-endpoint.redislabs.com REDIS_PORT=15497 REDIS_USERNAME=default REDIS_PASSWORD=your_redis_password
The application enforces a 15-minute Time-To-Live (TTL) (EX: 15) across all cached read endpoints to maximize throughput and ensure data freshness:
| Resource | Route | Cache Key | TTL | Invalidation & Refresh Behavior |
|---|---|---|---|---|
| Book Details | GET /books/:bookId |
book:{bookId} |
15 mins | Populated on cache miss; updated in Redis on PATCH /books/:bookId |
| Customer Cart | GET /cart |
user:{userId}:cart |
15 mins | Populated on cache miss; resynchronized on POST /cart/add & DELETE /cart/remove/:bookId |
| Order Details | GET /orders/order/:orderId |
order:{orderId} |
15 mins | Populated on cache miss; verifies order ownership before caching |
| Personal Review | GET /reviews/:bookId/me |
user:{id}:book:{bookId} |
15 mins | Fast cache-aside retrieval of authenticated user's book review |
Redis also powers the BullMQ distributed queue system:
email-queue: Dispatches transactional order notification emails asynchronously in the background.order-processing: Handles asynchronous order queue events and payment reconciliation.
- Sign up at Cloudinary.
- From the dashboard, copy:
- Cloud Name →
CLOUDINARY_NAME - API Key →
CLOUDINARY_API_KEY - API Secret →
CLOUDINARY_API_SECRET
- Cloud Name →
- Add them to your
.envfile.
- Create a Stripe account and enable Test Mode.
- Go to Developers > API Keys and copy your Secret Key:
STRIPE_SECRET_KEY=sk_test_...
- Install the Stripe CLI for local webhook testing:
stripe login
- Start webhook forwarding to the local backend:
stripe listen --forward-to localhost:8002/webhook
- Copy the displayed webhook secret (
whsec_...) and add it to.env:STRIPE_WEBHOOK=whsec_...
Ensure Redis is running locally (docker start redis) or connected via Redis Cloud.
stripe listen --forward-to localhost:8002/webhooknpm run devThe server will start on http://localhost:8002 (or your configured PORT).
npm run validate:env# Bundle modular YAML specs into a single bundle
npm run doc:bundle
# Build standalone Redoc HTML documentation
npm run doc:buildAll endpoints except public catalog browsing and authentication require a valid Bearer JWT token in the Authorization header (Bearer <token>).
Requires role: 'admin'. Base rate limiter: 30 req/min (getRateLimiter). Mutation endpoints enforce 10 req/min (mutationLimiter).
| Method | Endpoint | Description | Key Middlewares & Validations |
|---|---|---|---|
GET |
/admin/dashboard |
Aggregated dashboard statistics (revenue, orders, low stock, users) | protect, restrictTo('admin') |
GET |
/admin/getSalesAnalytics |
Revenue & sales trends grouped by day, week, or month | startDate, endDate, groupBy |
GET |
/admin/book/analytics |
Catalog health (active, inactive, low-stock, best/low selling) | Aggregated across Books & Orders |
GET |
/admin/book/deadstock |
Books with zero sales in the last 30 days (paginated) | page, limit |
GET |
/admin/book/performance |
Detailed book sales, copies sold, and revenue performance | page, limit |
GET |
/admin/book/category/revenue |
Sales count and revenue distribution across all book categories | Aggregated across all paid orders |
GET |
/admin/book/category/trend |
Monthly category sales trends over a specified date range | startDate, endDate (max 1 year) |
GET |
/admin/book/rating/distribution |
Review star rating counts (1 to 5 stars) per book | page, limit |
GET |
/admin/order/analytics |
Total counts per order status and platform cancellation rate | Aggregated across Orders |
GET |
/admin/order/order-growth |
Day-by-day order counts with automated date densification | startDate, endDate (max 90 days) |
GET |
/admin/order/avg-order-value |
Monthly Average Order Value (AOV) and revenue trend | startDate, endDate (max 1 year) |
GET |
/admin/customer/analytics |
Customer growth, top spenders, and returning customer rate | startDate, endDate (max 1 year) |
GET |
/admin/payment/analytics |
Payment volume, amounts, and success/failure rates | Aggregated by Stripe payment status |
PATCH |
/admin/activateUser/:userId |
Reactivate a suspended user account (isActive: true) |
mutationLimiter, validateId('userId') |
PATCH |
/admin/deactivateUser/:userId |
Suspend a user account (isActive: false). Guards against self-deactivation & admin suspension. |
mutationLimiter, validateId('userId'), self & admin guard |
PATCH |
/admin/change-role/:userId |
Update a user's role (admin or user). Guards against self-role changes. |
mutationLimiter, validateId('userId'), role enum validation |
Public access with rate limiting.
| Method | Endpoint | Description | Key Middlewares & Validations |
|---|---|---|---|
POST |
/auth/register |
Register new account & dispatch 6-digit OTP (1-minute expiry) | Input validation, OTP generation, Email dispatch |
POST |
/auth/login |
Authenticate existing user & issue JWT | Email & password check, suspension guard |
POST |
/auth/verifyOtp |
Verify email using 6-digit OTP within 1-minute window | OTP matching, token expiry validation |
POST |
/auth/resendOtp |
Generate and resend fresh 6-digit verification OTP (1-minute expiry) | Email check, OTP cooldown |
POST |
/auth/forgotpassword |
Initiate password reset with token via email | Crypto token generation, Email dispatch |
PATCH |
/auth/resetpassword/:token |
Reset password using verified reset token | Token verification, password hashing |
Requires authenticated session (protect).
| Method | Endpoint | Description | Key Middlewares & Validations |
|---|---|---|---|
GET |
/users/me |
Retrieve profile of the currently logged-in user | getRateLimiter (30 req/min) |
PATCH |
/users/updateMe |
Update profile information and shipping address | mutationLimiter (10 req/min), validateUser |
GET |
/users/orders |
Retrieve authenticated user's order history | getRateLimiter |
POST |
/users/favBooks |
Add a book to user's favorites collection | mutationLimiter, book existence check |
GET |
/users/all |
Admin query: List all users with regex filters and sorting | getRateLimiter, restrictTo('admin'), pagination |
GET |
/users/:userId |
Admin query: Retrieve a user by ObjectId | getRateLimiter, validateId('userId'), restrictTo('admin') |
| Method | Endpoint | Access | Description | Key Features |
|---|---|---|---|---|
GET |
/books |
Public | List active books with regex search, sorting, and pagination | Regex on title and author, sorting (new, old), pagination |
POST |
/books |
Admin | Create a new book with Cloudinary cover image | mutationLimiter, Multer file upload, validateBooks |
GET |
/books/:bookId |
Public | Fetch book details by ID | Redis cache-aside lookup (book:{bookId}, 15 min TTL) |
PATCH |
/books/:bookId |
Admin | Update book metadata or replace cover image | mutationLimiter, validateId('bookId'), Redis cache synchronized (15 min TTL) |
DELETE |
/books/:bookId |
Admin | Soft-delete a book (isDeleted: true) |
Preserves historical orders; returns HTTP 204 |
| Method | Endpoint | Access | Description | Key Features |
|---|---|---|---|---|
GET |
/cart |
Customer (user) |
Retrieve active shopping cart | Redis cache-aside lookup (user:{userId}:cart, 15 min TTL) |
POST |
/cart/add |
Customer (user) |
Add book to cart with quantity | Stock validation, dynamic total recalculation, Redis cache sync (15 min TTL) |
DELETE |
/cart/remove/:bookId |
Customer (user) |
Remove book item from cart | Price and quantity reconciliation, Redis cache sync (15 min TTL) |
| Method | Endpoint | Access | Description | Key Features |
|---|---|---|---|---|
GET |
/wishlist |
Customer (user) |
Retrieve customer's saved wishlist books | Populated book catalog details |
POST |
/wishlist/:bookId |
Customer (user) |
Add book to wishlist | Real-time existence & duplicate prevention |
DELETE |
/wishlist/:bookId |
Customer (user) |
Remove book from wishlist | Atomic pull update |
| Method | Endpoint | Access | Description | Key Features |
|---|---|---|---|---|
GET |
/books/:bookId/review |
Authenticated | Get paginated reviews for a specific book | Regex query msg, sorting, auto-populated author |
POST |
/books/:bookId/review |
Customer (user) |
Create a review and rating (1–5 stars) | Auto-recalculates book rating average & quantity |
PATCH |
/books/:bookId/review |
Customer (user) |
Update review commentary or rating | Verifies book existence; synchronizes rating aggregate |
DELETE |
/books/:bookId/review |
Customer (user) |
Delete review and star rating | Resynchronizes book score; returns HTTP 204 |
GET |
/reviews/all |
Admin | Platform-wide review monitoring | Filter by review text regex, sorting, pagination |
GET |
/reviews/:bookId/me |
Customer (user) |
Retrieve logged-in user's review for a book | Redis cached lookup (user:{id}:book:{bookId}, 15 min TTL) |
| Method | Endpoint | Access | Description | Key Features |
|---|---|---|---|---|
POST |
/orders/createcheckoutsession |
Customer (user) |
Create a Stripe checkout session from cart | makeReservation inventory reservation; BullMQ async order generation |
GET |
/orders/refundPayment/:stripePaymentId |
Customer (user) |
Request refund for a paid order | checkRefundStatus: Enforces 7-day refund window and paid status |
GET |
/orders/all |
Admin | Platform-wide order list with sorting | page, limit, sort |
GET |
/orders/order/:orderId |
Customer / Admin | Fetch order details by ID | Redis cache (order:{orderId}, 15 min TTL); strictly validates user ownership |
GET |
/orders/success |
Public | Stripe redirect callback handler | Redirects to home page |
POST |
/webhook |
Stripe | Raw JSON Stripe webhook listener | Handles session completed, expired, refund confirmation, inventory restock |
The application implements a centralized error handling system (controllers/errorController.js) distinguishing between operational errors and unexpected programmer errors.
{
"status": "success",
"message": "Operation completed successfully",
"data": { ... }
}{
"status": "Error",
"message": "Specific error explanation"
}400 Bad Request: Validation failure (validateUser,validateId), business rule breach (self-deactivation, role constraints, 7-day refund window expiration, inventory shortage).401 Unauthorized: Missing Bearer token, expired JWT, or invalid signature.403 Forbidden: Role permission failure (e.g. non-admin accessing admin routes) or unverified email account.404 Not Found: Entity not found in database or ownership mismatch.429 Too Many Requests: Client exceeded rate limiting thresholds.500 Internal Server Error: Unexpected non-operational error.
- 🔍 Improve and optimize pagination, search, and sorting functionality for better performance and scalability.
- ⚙️ Improve the background worker architecture so workers can be managed automatically with the main application, eliminating the need to start a separate worker process manually during local development.
📧 Contact: panchalkeyur694@gmail.com