A full-stack product catalog application with separate admin panel and user shop interface. Built with Next.js, Node.js, MySQL, and Docker.
- Next.js 16 with TypeScript and App Router
- SASS (indentation-based) for styling
- Redux Toolkit Query for state management and API calls
- Formik & Yup for form handling and validation
- Next.js Image optimization
- Node.js with Express
- MySQL 8.0 with Sequelize ORM
- Multer for image uploads
- Slugify for generating URL-friendly slugs
- Hardcoded authentication for admin access
- Docker and Docker Compose for containerization
- Development mode with hot reload for both frontend and backend
- Modern gradient design with product grid layout
- Search functionality by product title
- Category filters with checkboxes
- Price range filtering (min/max)
- Sort by price (Low to High, High to Low)
- Product cards with images, titles, prices, and availability
- Click on products to view details
- "Admin Panel" button in header
- Full product information display
- Product image, title, description, category, price, and availability
- Related products section (3-4 items from the same category)
- User-friendly view (no admin actions visible to regular users)
Authentication Required - Hardcoded credentials:
- Username:
admin - Password:
admin123
Features:
- Dashboard with statistics (Total Products, In Stock, Out of Stock)
- Table view of all products
- Product management:
- Create new products with image upload
- Edit existing products (optional image update)
- Delete products with confirmation
- "View Shop" button to switch to user interface
- Logout functionality
- Purple gradient login page design
- Form validation with Formik and Yup
- Auto-generated slugs from product titles
- Image preview during upload
- Full CRUD operations
- Real-time updates with RTK Query cache invalidation
Product Table (MySQL):
id(INTEGER, AUTO_INCREMENT, PRIMARY KEY)title(VARCHAR(255), required) - Product namedescription(TEXT, required) - Product descriptionimage(VARCHAR(255), required) - Product image path/URLcategory(ENUM, required) - Product category (Clothing, Shoes, Electronics, Accessories, Home & Garden, Sports, Books, Toys)price(DECIMAL(10,2), required) - Product priceavailability(BOOLEAN, required, default: true) - Stock availabilityslug(VARCHAR(255), required, unique) - URL-friendly identifier (auto-generated)createdAt(DATETIME) - Creation timestampupdatedAt(DATETIME) - Last update timestamp
- Docker and Docker Compose installed on your system
- OR Node.js (v20+), npm/pnpm, and MySQL 8.0
- Clone the repository:
git clone <repository-url>
cd assignment-next-node- Build and start all services:
docker compose up --buildOr with sudo if you have permission issues:
sudo docker compose up --build-
Wait for all services to start (backend will retry MySQL connection automatically)
-
Access the application:
- User Shop: http://localhost:3000
- Admin Panel: http://localhost:3000/admin
- Username:
admin - Password:
admin123
- Username:
- Backend API: http://localhost:5000/api
- MySQL: localhost:3307 (mapped from container port 3306)
- Stop the application:
docker compose downTo stop and remove all data:
docker compose down -vThe Docker setup runs in development mode with hot reload enabled:
- Frontend: Changes to
.tsx,.ts,.sassfiles will automatically refresh - Backend: Changes to
.jsfiles will automatically restart the server with nodemon - Volume mounts enable live code updates without rebuilding containers
- Install and start MySQL:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install mysql-server
sudo systemctl start mysql
sudo systemctl enable mysql
# Create database
sudo mysql -u root
CREATE DATABASE product_catalog;
EXIT;- Navigate to the backend folder:
cd backend- Install dependencies:
npm install- Create
.envfile:
PORT=5000
DB_HOST=localhost
DB_PORT=3306
DB_NAME=product_catalog
DB_USER=root
DB_PASSWORD=your_mysql_password
NODE_ENV=development
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123- Start the backend server:
npm run devThe backend will run on http://localhost:5000 and automatically create the database tables.
- Navigate to the frontend folder:
cd frontend- Install dependencies:
pnpm install
# or
npm install- Create
.env.localfile:
NEXT_PUBLIC_API_URL=http://localhost:5000/api- Start the development server:
pnpm dev
# or
npm run devThe frontend will run on http://localhost:3000
POST /api/auth/login- Admin login with hardcoded credentials
GET /api/products- Get all products (with filters)- Query params:
search,category,minPrice,maxPrice,sortBy,page,limit
- Query params:
GET /api/products/:slug- Get product by slugGET /api/products/:slug/related- Get related productsPOST /api/products- Create new product (with image upload)PUT /api/products/:id- Update product (optional image update)DELETE /api/products/:id- Delete product
GET /api/health- Check server status
assignment-next-node/
├── backend/
│ ├── src/
│ │ ├── config/
│ │ │ └── db.js # MySQL connection with retry logic
│ │ ├── controllers/
│ │ │ ├── authController.js # Admin authentication
│ │ │ └── productController.js # CRUD logic
│ │ ├── middleware/
│ │ │ └── upload.js # Multer config
│ │ ├── models/
│ │ │ └── Product.js # Sequelize model
│ │ ├── routes/
│ │ │ ├── authRoutes.js # Auth endpoints
│ │ │ └── productRoutes.js # Product endpoints
│ │ └── server.js # Express app
│ ├── uploads/ # Uploaded images
│ ├── .env # Environment variables
│ ├── .gitignore
│ ├── Dockerfile.dev # Development Dockerfile
│ └── package.json
├── frontend/
│ ├── app/
│ │ ├── admin/
│ │ │ ├── login/
│ │ │ │ ├── page.tsx # Admin login page
│ │ │ │ └── page.module.sass
│ │ │ ├── page.tsx # Admin dashboard
│ │ │ └── page.module.sass
│ │ ├── products/
│ │ │ └── [slug]/
│ │ │ ├── page.tsx # Product detail (user view)
│ │ │ └── page.module.sass
│ │ ├── globals.sass
│ │ ├── layout.tsx
│ │ ├── page.tsx # User shop homepage
│ │ └── page.module.sass
│ ├── src/
│ │ ├── components/
│ │ │ ├── AddProductDialog.tsx # Create product form
│ │ │ ├── UpdateProductDialog.tsx # Update product form
│ │ │ ├── ProductCard.tsx # Product card component
│ │ │ ├── ProductFilters.tsx # Filter sidebar
│ │ │ ├── Providers.tsx # Redux provider
│ │ │ └── *.module.sass
│ │ └── store/
│ │ ├── api.ts # RTK Query API
│ │ └── store.ts # Redux store
│ ├── .env.local
│ ├── Dockerfile.dev # Development Dockerfile
│ ├── next.config.ts
│ ├── package.json
│ └── tsconfig.json
├── docker-compose.yml
└── README.md
- Navigate to http://localhost:3000
- Click "Admin Panel" button in the header
- Login with:
- Username:
admin - Password:
admin123
- Username:
- You'll be redirected to the admin dashboard
- In the admin panel, click "Add Product" button
- Fill in the form:
- Title (required, min 3 characters)
- Image (required, max 5MB, JPG/PNG/GIF/WebP)
- Category (required, select from dropdown)
- Price (required, positive number)
- Availability (checkbox for stock status)
- Description (required, min 10 characters)
- The slug is auto-generated from the title
- Click "Add Product" to save
- In the admin panel table, click "Edit" on any product
- Modify the desired fields
- Optionally upload a new image (leave empty to keep current)
- Click "Update Product" to save changes
- In the admin panel table, click "Delete" on any product
- Confirm the deletion in the popup dialog
- Search: Type in the search box to filter by product title
- Category: Check/uncheck categories to filter products
- Price Range: Enter min and/or max price values
- Sort: Select sorting option from the dropdown
- Click on any product card to view full details
- View related products from the same category at the bottom
- Click "Back to Products" to return to the shop
PORT=5000
DB_HOST=mysql
DB_PORT=3306
DB_NAME=product_catalog
DB_USER=root
DB_PASSWORD=rootpassword
NODE_ENV=development
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123NEXT_PUBLIC_API_URL=http://localhost:5000/api
INTERNAL_API_URL=http://backend:5000/apiThe docker-compose.yml file configures all environment variables automatically.
- Frontend: Running in Next.js dev mode with
pnpm dev - Backend: Running with nodemon for automatic server restarts
- Volume Mounts: Code changes reflect immediately without rebuilding containers
- MySQL data is persisted in a Docker volume named
mysql_data - Uploaded images are stored in
backend/uploads/directory - Data persists between container restarts
- Admin credentials are hardcoded in environment variables
- Login state stored in browser localStorage
- No JWT or session management (simplified for development)
- RTK Query
keepUnusedDataFor: 0ensures fresh data - Cache invalidation on create/update/delete operations
refetchOnReconnectandrefetchOnMountOrArgChangeenabled
- Backend retries MySQL connection 5 times with 5-second delays
- Ensures MySQL is fully initialized before connecting
- Automatic table creation and schema sync on startup
-
MySQL (mysql:8.0)
- Port: 3307:3306 (host:container)
- Healthcheck with mysqladmin ping
- Volume: mysql_data
-
Backend (Node.js)
- Port: 5000:5000
- Depends on MySQL healthcheck
- Development mode with nodemon
- Volume mounts for hot reload
-
Frontend (Next.js)
- Port: 3000:3000
- Depends on backend
- Development mode with pnpm dev
- Volume mounts for hot reload
All services communicate via app-network bridge network.
If containers fail to start:
docker compose down -v
docker compose up --buildThe application uses these ports:
3000- Frontend (Next.js)5000- Backend API3307- MySQL (mapped from container's 3306)
If any port is in use:
- Stop the conflicting service
- OR modify the ports in
docker-compose.yml
Check if MySQL container is running:
docker ps | grep mysqlView MySQL logs:
docker compose logs mysqlThe backend will automatically retry connection 5 times.
If you can't login to admin panel:
- Verify credentials:
admin/admin123 - Check browser console for errors
- Verify backend is running: http://localhost:5000/api/health
- Clear localStorage and try again
If your code changes don't appear:
- Check if containers are running:
docker ps - View frontend logs:
docker compose logs frontend - View backend logs:
docker compose logs backend - Restart containers:
docker compose restart
Check that the backend/uploads directory exists:
ls -la backend/uploadsFix permissions if needed:
chmod 755 backend/uploadsAdd your user to the docker group:
sudo usermod -aG docker $USER
newgrp dockerOr run with sudo:
sudo docker compose up --buildIf port 3307 is also in use, edit docker-compose.yml:
mysql:
ports:
- "3308:3306" # Change to any available portFor production deployment:
- Create production Dockerfiles without dev dependencies
- Use environment-based configuration
- Implement proper authentication (JWT, sessions)
- Enable HTTPS/SSL
- Use proper secrets management
- Configure CORS properly
- Set up proper logging and monitoring
- Use production-ready MySQL configuration
- Enable database backups
- Admin credentials are hardcoded (development only)
- No password hashing (development only)
- LocalStorage authentication (development only)
- For production, implement proper authentication with JWT/sessions
- Enable HTTPS in production
- Sanitize all user inputs
- Implement rate limiting
- Use environment variables for all secrets
ISC
Product Catalog Application with Admin Panel and User Shop Interface