A full-stack watch e-commerce site built with Next.js 15.5.3, MongoDB, and Razorpay payment integration.
- 🛍️ Product Catalog: Browse watches by collections with SSG (Static Site Generation)
- 🛒 Shopping Cart: Add/remove items, update quantities
- 💳 Secure Payments: Razorpay integration with signature verification
- 👨💼 Admin Panel: Manage orders, update order status
- 🔒 Secure Authentication: JWT-based admin authentication
- 📱 Responsive Design: Mobile-friendly UI with Tailwind CSS
- ⚡ Performance: ISR (Incremental Static Regeneration) for fast page loads
- Framework: Next.js 15.5.3 (App Router)
- Database: MongoDB
- Payment: Razorpay
- Styling: Tailwind CSS
- Authentication: JWT + bcrypt
- Language: TypeScript
- Node.js 18+ and npm
- MongoDB instance (local or MongoDB Atlas)
- Razorpay account with API keys
npm installCreate a .env.local file in the root directory:
# MongoDB
MONGODB_URI=mongodb://localhost:27017/watch-store
# Or use MongoDB Atlas: mongodb+srv://username:password@cluster.mongodb.net/watch-store
# Razorpay
RAZORPAY_KEY_ID=your_razorpay_key_id
RAZORPAY_KEY_SECRET=your_razorpay_key_secret
NEXT_PUBLIC_RAZORPAY_KEY_ID=your_razorpay_key_id
# JWT Secret for admin authentication
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production
# App URL
APP_URL=http://localhost:3000
# ISR Revalidation (in seconds)
REVALIDATE_SECONDS=60- Install MongoDB locally
- Start MongoDB service
- Update
MONGODB_URIin.env.local
- Create a MongoDB Atlas account
- Create a new cluster
- Get connection string and update
MONGODB_URI
Run the seed script to create an admin user:
npm run seedOr manually create an admin user in MongoDB:
// In MongoDB shell or Compass
use watch-store;
db.admins.insertOne({
username: "admin",
passwordHash: "$2a$10$...", // bcrypt hash of your password
role: "admin",
createdAt: new Date(),
updatedAt: new Date()
});To generate a bcrypt hash:
node -e "const bcrypt = require('bcryptjs'); console.log(bcrypt.hashSync('yourpassword', 10));"Create sample collections and products in MongoDB:
// Collections
db.collections.insertMany([
{
title: "Luxury Collection",
slug: "luxury-collection",
description: "Premium luxury timepieces",
image: "https://example.com/luxury.jpg",
createdAt: new Date(),
updatedAt: new Date()
}
]);
// Products
db.products.insertMany([
{
title: "Classic Watch",
slug: "classic-watch",
sku: "WATCH-001",
price: 50000, // in paisa (₹500.00)
currency: "INR",
collectionId: ObjectId("..."), // Use collection _id
images: ["https://example.com/watch1.jpg"],
description: "A classic timepiece",
specs: {
weight: "150g",
caseSize: "42mm",
movement: "Automatic"
},
stock: 10,
featured: true,
createdAt: new Date(),
updatedAt: new Date()
}
]);npm run devOpen http://localhost:3000 in your browser.
watch-store/
├── app/ # Next.js app directory
│ ├── api/ # API routes
│ │ ├── admin/ # Admin endpoints
│ │ ├── checkout/ # Checkout & payment
│ │ ├── collections/ # Collections API
│ │ ├── products/ # Products API
│ │ └── webhooks/ # Razorpay webhooks
│ ├── admin/ # Admin pages
│ ├── all/ # All products page
│ ├── cart/ # Shopping cart
│ ├── checkout/ # Checkout page
│ ├── collections/ # Collections pages (SSG)
│ ├── order/ # Order confirmation
│ ├── products/ # Product pages (SSG)
│ └── page.tsx # Home page
├── components/ # React components
├── lib/ # Utilities
│ ├── auth.ts # JWT authentication
│ ├── cart.ts # Cart management
│ ├── mongodb.ts # MongoDB connection
│ ├── models.ts # TypeScript models
│ └── razorpay.ts # Razorpay utilities
└── public/ # Static assets
GET /api/collections- List all collectionsGET /api/collections/[slug]- Get collection with productsGET /api/products- List products (with filters/pagination)GET /api/products/[slug]- Get product detailsPOST /api/checkout/create-order- Create order and Razorpay orderPOST /api/checkout/verify- Verify payment signaturePOST /api/webhooks/razorpay- Razorpay webhook handler
POST /api/admin/login- Admin loginGET /api/admin/orders- List ordersGET /api/admin/orders/[id]- Get order detailsPATCH /api/admin/orders/[id]- Update order status
- Customer fills checkout form
- Server creates order in MongoDB
- Server creates Razorpay order
- Client opens Razorpay checkout
- After payment, client sends payment details to
/api/checkout/verify - Server verifies signature and updates order status
- Webhook also confirms payment (redundancy)
Use Razorpay test keys for development. Test cards:
- Success: 4111 1111 1111 1111
- Failure: 4000 0000 0000 0002
- Push code to GitHub
- Import project in Vercel
- Add environment variables
- Deploy
- Create cluster
- Whitelist Vercel IPs (or use 0.0.0.0/0 for development)
- Get connection string
- Add to Vercel environment variables
- In Razorpay dashboard, add webhook URL:
https://yourdomain.com/api/webhooks/razorpay - Select events:
payment.captured - Copy webhook secret (if using separate secret)
- ✅ JWT-based admin authentication
- ✅ bcrypt password hashing
- ✅ Razorpay signature verification
- ✅ Input validation with Zod
- ✅ HTTP-only cookies for tokens
- ✅ Server-side payment verification
- ✅ Webhook signature verification
npm run build
npm startnpm run lint- Check
MONGODB_URIis correct - Ensure MongoDB is running (if local)
- Check network access (if Atlas)
- Verify API keys are correct
- Check webhook URL is accessible
- Ensure signature verification logic is correct
- Verify admin user exists in database
- Check password hash is correct
- Ensure JWT_SECRET is set
MIT
For issues and questions, please open an issue on GitHub.