Skip to content

6ixline/nodejs-express-rest-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›’ Product Catalog REST API

A production-grade, multi-role backend built with Node.js, Express 5 & MySQL


Node.js Express MySQL Sequelize JWT License: ISC


A fully-featured RESTful API with three independent authentication contexts, bulk Excel import, image management, a real-time enquiry system, and security best practices baked in from day one.


πŸ“‹ Table of Contents


πŸ” Overview

This project is a scalable backend API for a product catalog platform - vehicle parts, SKUs, and inventory - designed to serve three distinct user roles: Admins, End Users, and Internal Staff.

Key design principles followed throughout:

  • βœ… Separation of concerns - Controllers β†’ Services β†’ Models (no business logic in routes)
  • βœ… Role-isolated authentication - Three separate JWT secrets and middleware stacks
  • βœ… Fail-safe data ingestion - Excel files are validated before import, not after
  • βœ… Production-ready logging - Winston for structured logs, Morgan for HTTP request trails
  • βœ… Defensive security - Helmet headers, CORS, rate limiting, bcrypt, Joi validation on every endpoint

✨ Features

πŸ” Authentication & Security

  • Multi-role JWT (Admin / User / Internal)
  • Refresh token rotation with cookie storage
  • OTP-based password reset via email
  • bcrypt password hashing
  • Helmet HTTP security headers
  • Rate limiting & CORS protection

πŸ“¦ Product Catalog

  • Full CRUD for Products, Makes & Categories
  • FULLTEXT search on keywords & reference codes
  • Bulk status updates across multiple records
  • Slug generation for SEO-friendly URLs
  • Product reference code linking

πŸ“₯ Bulk Data Operations

  • Download Excel template for import
  • Pre-import validation (returns row-level errors)
  • Bulk product import via .xlsx / .xls
  • Bulk keyword import
  • Bulk image upload with missing image reports
  • Excel reports for product image coverage

πŸ‘₯ User-Facing Features

  • User registration, login & profile management
  • Favorites system (add, remove, bulk remove, count)
  • Product enquiry submission & tracking
  • Admin enquiry management with stats
  • File upload (single & multi, up to 10 files)
  • Admin dashboard statistics endpoint

πŸ› οΈ Tech Stack

Category Technology Purpose
Runtime Node.js 18+ JavaScript server runtime
Framework Express.js v5 HTTP server & routing
Database MySQL 8 Relational data storage
ORM Sequelize v6 Database modelling & queries
Auth jsonwebtoken Access & refresh token signing
Security bcryptjs Password hashing
Validation Joi Request body & param schemas
File Uploads Multer v2 Multipart form handling
Excel ExcelJS Bulk import / export
Email Nodemailer OTP & transactional email
Logging Winston + Morgan Structured logs + HTTP access logs
Security Headers Helmet HTTP response header hardening
Rate Limiting rate-limit-express Brute-force protection
Dev Server Nodemon Hot reload during development

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Client (HTTP Request)                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Express.js App                            β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚  Global Middleware Stack                              β”‚   β”‚
β”‚   β”‚  cookie-parser β†’ helmet β†’ morgan β†’ cors β†’            β”‚   β”‚
β”‚   β”‚  body-parser β†’ rate-limiter                          β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                               β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚  /admin  β”‚  β”‚  /user   β”‚  β”‚/internal β”‚  β”‚  /file   β”‚   β”‚
β”‚   β”‚  Routes  β”‚  β”‚  Routes  β”‚  β”‚  Routes  β”‚  β”‚  Routes  β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜   β”‚
β”‚        β”‚              β”‚              β”‚              β”‚          β”‚
β”‚   β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚          Auth / Role Middleware (JWT Verify)           β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                            β”‚                                   β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚              Controllers (Request β†’ Response)           β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                            β”‚                                   β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚          Services (Business Logic Layer)                β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                            β”‚                                   β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚          Sequelize Models (ORM Layer)                   β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      MySQL Database                           β”‚
β”‚              (Connection Pool: max 5 connections)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Project Structure

src/
β”œβ”€β”€ app.js                          # Express setup, middleware stack, route mounting
β”œβ”€β”€ server.js                       # Entry point - DB sync + server start
β”‚
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ db.js                       # Sequelize + MySQL connection pool + SSL support
β”‚   β”œβ”€β”€ jwt.js                      # JWT config constants
β”‚   β”œβ”€β”€ logger.js                   # Winston logger (file + console transports)
β”‚   └── multer.js                   # Multer disk storage configuration
β”‚
β”œβ”€β”€ models/                         # Sequelize model definitions
β”‚   β”œβ”€β”€ index.js                    # Associations (hasMany, belongsTo, etc.)
β”‚   β”œβ”€β”€ userModel.js
β”‚   β”œβ”€β”€ adminModel.js
β”‚   β”œβ”€β”€ productModel.js             # FULLTEXT indexed on keyword + ref_code
β”‚   β”œβ”€β”€ categoryModel.js
β”‚   β”œβ”€β”€ makeModel.js
β”‚   β”œβ”€β”€ enquiryModel.js
β”‚   β”œβ”€β”€ favoriteProductModel.js
β”‚   β”œβ”€β”€ fileModel.js
β”‚   β”œβ”€β”€ refreshToken.js
β”‚   └── otpModel.js
β”‚
β”œβ”€β”€ controllers/                    # Thin layer - validates input, calls service, returns response
β”‚   β”œβ”€β”€ admin/
β”‚   β”‚   β”œβ”€β”€ authController.js
β”‚   β”‚   β”œβ”€β”€ dashboardController.js
β”‚   β”‚   β”œβ”€β”€ userController.js
β”‚   β”‚   β”œβ”€β”€ productController.js
β”‚   β”‚   β”œβ”€β”€ categoryController.js
β”‚   β”‚   β”œβ”€β”€ makeController.js
β”‚   β”‚   β”œβ”€β”€ bulkImportController.js
β”‚   β”‚   β”œβ”€β”€ imageImportController.js
β”‚   β”‚   └── adminEnquiryController.js
β”‚   β”œβ”€β”€ userController.js
β”‚   β”œβ”€β”€ internalUserController.js
β”‚   β”œβ”€β”€ favoriteProductController.js
β”‚   β”œβ”€β”€ userEnquiryController.js
β”‚   └── fileController.js
β”‚
β”œβ”€β”€ services/                       # All business logic lives here
β”‚   β”œβ”€β”€ adminService.js
β”‚   β”œβ”€β”€ userService.js
β”‚   β”œβ”€β”€ productService.js
β”‚   β”œβ”€β”€ categoryService.js
β”‚   β”œβ”€β”€ makeService.js
β”‚   β”œβ”€β”€ enquiryService.js
β”‚   β”œβ”€β”€ favoriteProductService.js
β”‚   β”œβ”€β”€ bulkImportService.js        # Excel parsing, row validation, DB insertion
β”‚   β”œβ”€β”€ imageImportService.js       # Image matching, bulk upload, report generation
β”‚   β”œβ”€β”€ dashboardService.js
β”‚   β”œβ”€β”€ emailService.js             # Nodemailer OTP dispatch
β”‚   └── fileService.js
β”‚
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ admin/
β”‚   β”‚   β”œβ”€β”€ index.js                # Mounts auth, dashboard, users, catalog, enquiry
β”‚   β”‚   β”œβ”€β”€ auth.js
β”‚   β”‚   β”œβ”€β”€ dashboard.js
β”‚   β”‚   β”œβ”€β”€ user.js
β”‚   β”‚   β”œβ”€β”€ product.js              # Makes, Categories, Products, Bulk Import, Images
β”‚   β”‚   └── adminEnquiryRoutes.js
β”‚   β”œβ”€β”€ userRoutes.js
β”‚   β”œβ”€β”€ internalUserRoutes.js
β”‚   β”œβ”€β”€ favoriteRoutes.js
β”‚   β”œβ”€β”€ userEnquiryRoutes.js
β”‚   └── fileRoutes.js
β”‚
β”œβ”€β”€ middlewares/
β”‚   β”œβ”€β”€ authMiddleware.js           # Verifies user JWT (cookie + Bearer header fallback)
β”‚   β”œβ”€β”€ adminMiddleware.js          # Verifies admin JWT
β”‚   β”œβ”€β”€ internalAuthMiddleware.js   # Verifies internal user JWT
β”‚   β”œβ”€β”€ roleMiddleware.js           # Role-based access control
β”‚   β”œβ”€β”€ isAdminOrUser.js            # Shared admin+user route guard
β”‚   β”œβ”€β”€ validateMiddleware.js       # Joi schema runner
β”‚   └── errorMiddleware.js          # Global error handler (4xx / 5xx)
β”‚
β”œβ”€β”€ validators/                     # Joi schemas - one file per domain
β”‚   β”œβ”€β”€ productSchemas.js
β”‚   β”œβ”€β”€ userProperty.js
β”‚   β”œβ”€β”€ admin.js
β”‚   β”œβ”€β”€ favoriteSchemas.js
β”‚   └── enquirySchemas.js
β”‚
└── utils/
    β”œβ”€β”€ apiResponse.js              # successResponse() / errorResponse() helpers
    β”œβ”€β”€ slug.js                     # slugify wrapper
    └── validation.js              # Shared validation helpers

πŸš€ Getting Started

Prerequisites

  • Node.js v18+
  • MySQL v8+
  • npm v9+

Installation

# 1. Clone the repository
git clone https://github.com/your-username/product-catalog-api.git
cd product-catalog-api

# 2. Install dependencies
npm install

# 3. Set up environment variables
cp .env.example .env
# Open .env and fill in your values (see section below)

# 4. Start the development server
npm run dev

The server starts on http://localhost:5000 by default.


πŸ”§ Environment Variables

Create a .env file at the root of the project:

# ── Server ────────────────────────────────
PORT=5000
NODE_ENV=development          # development | production

# ── Database ──────────────────────────────
DB_HOST=localhost
DB_PORT=3306
DB_NAME=product_catalog_db
DB_USER=root
DB_PASSWORD=your_password
DB_SSL=false                  # Set to true for cloud databases

# ── JWT Secrets (keep these long & random) ──
JWT_USER_SECRET=your_user_jwt_secret_key
JWT_ADMIN_SECRET=your_admin_jwt_secret_key
JWT_INTERNAL_SECRET=your_internal_jwt_secret_key

# ── Token Expiry ──────────────────────────
JWT_ACCESS_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d

# ── Email (Nodemailer) ────────────────────
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your_email@gmail.com
SMTP_PASS=your_app_password

# ── Sync DB (development only) ────────────
SHOULD_SYNC=false             # Set to true to run sequelize.sync({ alter: true })

⚠️ Never commit your .env file. Add it to .gitignore.


πŸ“‘ API Reference

Base URL: http://localhost:5000/api

πŸ§‘β€πŸ’Ό Admin - Authentication

Method Endpoint Description Auth
POST /admin/auth/login Admin login β†’ returns access + refresh token -
POST /admin/auth/logout Invalidate refresh token πŸ”’
GET /admin/auth/me Get current admin profile πŸ”’
POST /admin/auth/change-password Update admin password πŸ”’
POST /admin/auth/refresh-token Rotate access token -
POST /admin/auth/create Create new admin account -

πŸ“Š Admin - Dashboard

Method Endpoint Description Auth
GET /admin/dashboard Aggregated platform statistics πŸ”’

πŸ‘₯ Admin - User Management

Method Endpoint Description Auth
GET /admin/users List all users (paginated) πŸ”’
GET /admin/users/:id Get single user πŸ”’
POST /admin/users Create user πŸ”’
PUT /admin/users/:id Update user πŸ”’
DELETE /admin/users/:id Delete user πŸ”’
DELETE /admin/users/bulk Bulk delete users πŸ”’
PATCH /admin/users Bulk update users πŸ”’

🏷️ Admin - Makes

Method Endpoint Description Auth
GET /admin/catalog/makes Paginated list with search πŸ”’
GET /admin/catalog/makes/active Active makes (for dropdowns) πŸ”’
GET /admin/catalog/makes/:id Get by ID πŸ”’
POST /admin/catalog/makes Create πŸ”’
PUT /admin/catalog/makes/:id Update πŸ”’
DELETE /admin/catalog/makes/:id Delete πŸ”’
POST /admin/catalog/makes/bulk-delete Bulk delete πŸ”’
POST /admin/catalog/makes/bulk-update-status Bulk toggle status πŸ”’

πŸ“‚ Admin - Categories

Method Endpoint Description Auth
GET /admin/catalog/categories Paginated list with search πŸ”’
GET /admin/catalog/categories/active Active categories (for dropdowns) πŸ”’
GET /admin/catalog/categories/:id Get by ID πŸ”’
POST /admin/catalog/categories Create πŸ”’
PUT /admin/catalog/categories/:id Update πŸ”’
DELETE /admin/catalog/categories/:id Delete πŸ”’
POST /admin/catalog/categories/bulk-delete Bulk delete πŸ”’
POST /admin/catalog/categories/bulk-update-status Bulk toggle status πŸ”’

πŸ“¦ Admin - Products

Method Endpoint Description Auth
GET /admin/catalog/products Paginated list + filters + FULLTEXT search πŸ”’
GET /admin/catalog/products/:id Full product detail with images πŸ”’
GET /admin/catalog/products/ref/:refCode Products by reference code πŸ”’
POST /admin/catalog/products Create product πŸ”’
PUT /admin/catalog/products/:id Update product πŸ”’
DELETE /admin/catalog/products/:id Delete product πŸ”’
POST /admin/catalog/products/bulk-delete Bulk delete πŸ”’
POST /admin/catalog/products/bulk-update-status Bulk toggle status πŸ”’

πŸ“₯ Admin - Bulk Import & Images

Method Endpoint Description Auth
GET /admin/catalog/import/template Download Excel template -
POST /admin/catalog/import/validate Validate file (no DB write) πŸ”’
POST /admin/catalog/import/products Bulk import products from Excel πŸ”’
POST /admin/catalog/import/keywords Bulk import keywords πŸ”’
POST /admin/catalog/images/check-missing Report missing product images πŸ”’
POST /admin/catalog/images/bulk-upload Bulk upload images for all products πŸ”’
POST /admin/catalog/images/upload-specific Upload images for specific codes πŸ”’
GET /admin/catalog/images/missing-report Download missing images report (Excel) -
GET /admin/catalog/images/product-image-report Full product image coverage report -

πŸ“© Admin - Enquiries

Method Endpoint Description Auth
GET /admin/enquiry/stats Enquiry statistics summary πŸ”’
GET /admin/enquiry All enquiries with filters πŸ”’
GET /admin/enquiry/:enquiryId Single enquiry detail πŸ”’
PUT /admin/enquiry/:enquiryId Update status / priority / remarks πŸ”’
DELETE /admin/enquiry/:enquiryId Delete enquiry πŸ”’
DELETE /admin/enquiry/bulk Bulk delete enquiries πŸ”’

πŸ‘€ User - Auth & Profile

Method Endpoint Description Auth
POST /user/register Register new account -
POST /user/login Login β†’ tokens -
POST /user/logout Logout -
POST /user/refresh-token Rotate access token -
POST /user/forgot-password Request OTP via email -
POST /user/verify-otp Verify OTP code -
POST /user/reset-password Set new password -
GET /user/profile Get my profile πŸ”’
PUT /user/profile Update my profile πŸ”’
GET /user/property Get user properties πŸ”’

❀️ User - Favorites

Method Endpoint Description Auth
POST /user/favoriteproduct Add product to favorites πŸ”’
GET /user/favoriteproduct List favorites (paginated) πŸ”’
GET /user/favoriteproduct/count Get favorites count πŸ”’
GET /user/favoriteproduct/check/:productId Check if favorited πŸ”’
DELETE /user/favoriteproduct/:productId Remove from favorites πŸ”’
POST /user/favoriteproduct/bulk-remove Bulk remove favorites πŸ”’

πŸ“© User - Enquiries

Method Endpoint Description Auth
POST /user/enquiry Submit a new enquiry πŸ”’
GET /user/enquiry My enquiry history πŸ”’
GET /user/enquiry/:enquiryId Single enquiry detail πŸ”’

πŸ”§ Internal User

Method Endpoint Description Auth
POST /internal/login Internal staff login -
POST /internal/logout Logout -
POST /internal/refresh-token Rotate access token -
POST /internal/forgot-password Request OTP -
POST /internal/verify-otp Verify OTP -
POST /internal/reset-password Reset password -
GET /internal/profile Get profile πŸ”’
PUT /internal/profile Update profile πŸ”’

πŸ“ File Upload

Method Endpoint Description Auth
POST /file/upload/single/:ownerType Single file upload πŸ”’
POST /file/upload/multiple/:ownerType Up to 10 files πŸ”’

πŸ”’ = Requires Authorization: Bearer <token> header or *_token cookie


πŸ” Authentication Flow

Three fully isolated auth contexts - each has its own JWT secret, middleware, and token model:

                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚          Login              β”‚
                        β”‚  POST /[role]/auth/login    β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚  Response:                             β”‚
               β”‚  β€’ accessToken  (15 min, in body)      β”‚
               β”‚  β€’ refreshToken (7 days, HttpOnly πŸͺ)  β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚           Protected Request                        β”‚
          β”‚  Authorization: Bearer <accessToken>              β”‚
          β”‚  - or - Cookie: user_token=<accessToken>          β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚  Token Expired?          β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           Yes     β”‚     No
                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚ POST /refresh-tokenβ”‚    β”‚ Request passes β”‚
                      β”‚ β†’ New access token β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚         Forgot Password Flow          β”‚
                  β”‚  1. POST /forgot-password β†’ OTP email β”‚
                  β”‚  2. POST /verify-otp β†’ validated      β”‚
                  β”‚  3. POST /reset-password β†’ new pass   β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“₯ Bulk Import Guide

  1. Download the Excel template: GET /api/admin/catalog/import/template
  2. Fill it in following this column spec:
Column Required Type Notes
product_code βœ… String Unique part number (primary key)
name βœ… String Product display name
make_id βœ… Integer Must match existing Make ID
category_id βœ… Integer Must match existing Category ID
mrp ❌ Decimal Maximum retail price
color ❌ String Colour description
keyword ❌ String Comma-separated search keywords
ref_code ❌ String Comma-separated reference codes
status ❌ Enum active / inactive / out_of_stock
  1. Validate first (no DB writes): POST /api/admin/catalog/import/validate
    • Returns row-level error messages if validation fails
  2. Import: POST /api/admin/catalog/import/products
    • Max file size: 10MB
    • Accepted formats: .xlsx, .xls

πŸ—„οΈ Database Schema

sk_admin ──────────────────────────────────────────┐
sk_user ──────┬──────────────────────────────────┐  β”‚
              β”‚                                  β”‚  β”‚
              β–Ό                                  β–Ό  β–Ό
         sk_favorite_product           sk_product ◄── sk_make
         sk_enquiry                       β”‚          sk_category
         sk_refresh_token              sk_file
         sk_otp
Table Description
sk_user End user accounts
sk_admin Admin accounts
sk_product Products (FULLTEXT indexed on keyword, ref_code)
sk_category Product categories
sk_make Vehicle/brand makes
sk_enquiry Customer enquiries
sk_favorite_product User ↔ Product favorites junction
sk_file Uploaded file metadata (path, type, owner)
sk_refresh_token Per-role refresh token storage
sk_otp Time-limited OTPs for password reset

🚒 Running in Production

# Set environment
NODE_ENV=production npm start

Recommended: Use PM2 for process management

npm install -g pm2

# Start
pm2 start src/server.js --name "catalog-api"

# Auto-restart on crash & server reboot
pm2 save
pm2 startup

# Monitor
pm2 monit

Checklist before going live:

  • Set all .env secrets to strong random values
  • Set DB_SSL=true if using a cloud database
  • Set SHOULD_SYNC=false in production
  • Configure allowed origins in corsOptions
  • Set up a reverse proxy (Nginx / Caddy) in front of Express
  • Enable HTTPS (Let's Encrypt / Cloudflare)

🀝 Contributing

Contributions are welcome!

# 1. Fork the repo & create your branch
git checkout -b feature/your-feature-name

# 2. Commit with conventional commits
git commit -m "feat: add your feature"

# 3. Push and open a PR
git push origin feature/your-feature-name

πŸ“„ License

Distributed under the ISC License. See LICENSE for more information.


Made with ❀️ and Node.js

⬆ Back to top

About

Production-ready REST API with multi-role JWT auth, bulk Excel import & MySQL - built with Node.js & Express 5

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors