A modern e-commerce platform with real-time notifications built with Next.js 15, Socket.io, and NextAuth v5.
- Overview
- Screenshots
- Features
- Tech Stack
- Architecture
- Getting Started
- Project Structure
- API Documentation
- Security
- Testing
- Deployment
- Contributing
- License
NovaCart is a full-stack e-commerce platform that implements a sophisticated real-time notification system. Users receive instant updates about order status, promotions, price drops, and stock alerts without page refresh, enhancing customer engagement and satisfaction.
- Real-time WebSocket communication with Socket.io
- Secure JWT authentication with NextAuth v5
- Multi-tab synchronization - notifications sync across browser tabs
- Type-safe with TypeScript strict mode
- Modern UI with Tailwind CSS 4 and React 19
- Production-ready security with JWT validation
Secure authentication with NextAuth v5 - Clean, modern login interface
Real-time toast popup appears instantly when new notification arrives
Dropdown notification center with filters, mark as read, and delete actions
Developer-friendly test interface for creating and managing notifications
- Instant delivery via WebSocket (no polling required)
- 11 notification types: orders, promotions, price drops, stock alerts, etc.
- Toast popups with smooth animations
- Badge counter with shake animation
- Mark as read/unread functionality
- Bulk operations (mark all as read, delete)
- NextAuth v5 with credentials provider
- JWT token generation and validation
- Cryptographic signature verification
- Token expiration handling (30 days)
- User-specific room isolation in WebSocket
- Ownership checks on all operations
- Notification Bell - Badge with unread count
- Notification Center - Dropdown with filters and actions
- Toast Notifications - Non-invasive popup alerts
- Responsive Design - Works on mobile and desktop
- Dark Theme - Modern, polished UI
- Connection pooling for WebSocket
- Database indexes on critical fields
- Singleton pattern for client connections
- Optimized queries with pagination
- Next.js 15 Turbopack for fast builds
- Next.js 15.5.5 - React framework with App Router
- React 19 - UI library
- TypeScript 5 - Type safety
- Tailwind CSS 4 - Styling
- Zustand - State management
- Socket.io Client - WebSocket client
- react-hot-toast - Toast notifications
- Headless UI - Accessible components
- Next.js API Routes - RESTful API
- Socket.io - WebSocket server
- NextAuth v5 - Authentication
- Prisma - ORM
- PostgreSQL - Database (via Prisma Postgres)
- jsonwebtoken - JWT handling
- bcrypt - Password hashing
- tsx - TypeScript execution
- ESLint - Code linting
- Prettier - Code formatting (recommended)
┌─────────────────────────────────────────────────────────┐
│ Browser Client │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Dashboard │ │ Test Page │ │ Auth Pages │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌────┴──────────────────┴──────────────────┴────┐ │
│ │ Custom Hooks Layer │ │
│ │ useSocket() │ useNotifications() │ │
│ └────┬──────────────────┬───────────────────────┘ │
│ │ │ │
│ ┌────┴────────┐ ┌────┴────────┐ │
│ │ Socket.io │ │ Zustand │ │
│ │ Client │ │ Store │ │
│ └────┬────────┘ └─────────────┘ │
└─────────┼───────────────────────────────────────────────┘
│
│ WebSocket (JWT Auth)
│
┌─────────┼───────────────────────────────────────────────┐
│ │ Next.js Server │
│ ┌────┴────────┐ │
│ │ Socket.io │ ┌─────────────────┐ │
│ │ Server │โ────────┤ Custom Server │ │
│ └────┬────────┘ │ (server.ts) │ │
│ │ └─────────────────┘ │
│ │ │
│ ┌────┴──────────────────────────────────────┐ │
│ │ API Routes (REST) │ │
│ │ /api/notifications │ │
│ │ /api/notifications/[id] │ │
│ │ /api/notifications/[id]/mark-read │ │
│ │ /api/notifications/mark-all-read │ │
│ │ /api/auth/[...nextauth] │ │
│ └────┬──────────────────────────────────────┘ │
│ │ │
│ ┌────┴────────┐ │
│ │ NextAuth │ │
│ │ (JWT Auth) │ │
│ └────┬────────┘ │
│ │ │
│ ┌────┴────────┐ │
│ │ Prisma │ │
│ │ ORM │ │
│ └────┬────────┘ │
└─────────┼───────────────────────────────────────────────┘
│
│ SQL
│
┌─────────┼───────────────────────────────────────────────┐
│ ┌────┴────────┐ │
│ │ PostgreSQL │ │
│ │ Database │ │
│ └─────────────┘ │
└───────────────────────────────────────────────────────────┘
1. New Notification Created:
Client → POST /api/notifications → Prisma → PostgreSQL
↓
Socket.io emit → All user's tabs → Update Zustand → UI refresh + Toast
2. Mark as Read:
Client → PUT /api/notifications/[id]/mark-read → Prisma → PostgreSQL
↓
Socket.io emit → All user's tabs → Update Zustand → UI refresh
3. WebSocket Connection:
Client login → NextAuth JWT → useSocket hook → Socket.io connect with JWT
↓
Server validates JWT → Join user room → Send initial notifications
Before you begin, ensure you have the following installed:
- Node.js 18+ and npm - Download here
- PostgreSQL database - Installation guide or use Prisma Postgres
- Git - Download here
Follow these steps in order to get NovaCart running locally:
git clone https://github.com/Francescodib/novacart
cd novacartnpm installThis will install all required packages including Next.js, Socket.io, Prisma, and more.
Create a .env file in the root directory by copying the example:
cp .env.example .envThen edit .env and configure:
# Database - Choose ONE option:
# Option A: Prisma Postgres (Easiest - Managed by Prisma)
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=YOUR_API_KEY"
# Option B: Local PostgreSQL
# DATABASE_URL="postgresql://postgres:password@localhost:5432/novacart"
# NextAuth - Generate with: openssl rand -base64 32
NEXTAUTH_SECRET="paste-generated-secret-here"
NEXTAUTH_URL="http://localhost:3000"
# Application
NEXT_PUBLIC_APP_URL="http://localhost:3000"Generate a secure secret:
openssl rand -base64 32Copy the output and paste it as NEXTAUTH_SECRET in your .env file.
Run these commands in order:
# 1. Push the schema to your database
npx prisma db push
# 2. Generate Prisma Client
npx prisma generate
# 3. Seed test data (creates test user + sample notifications)
npm run db:seedโ Database seeding complete! You now have:
- Test user:
test@novacart.com/password123 - 3 sample notifications
npm run devWait for the server to start. You should see:
✓ Ready in Xms
๐ Socket.io server listening on port 3000
-
Open your browser and navigate to: http://localhost:3000/auth/login
-
Login with test credentials:
- Email:
test@novacart.com - Password:
password123
- Email:
-
You'll be redirected to the Dashboard where you can see your notifications!
- Go to the Test Page: http://localhost:3000/test-socket
- Click "๐ฆ Crea Notifica Ordine" to create a test notification
- Watch the toast popup appear instantly
- See the notification bell badge update in real-time
- Open the dashboard in TWO browser tabs side-by-side
- In one tab, click the notification bell and mark a notification as read
- Watch it automatically update in the other tab - no refresh needed!
- Notification Bell (top right) - Click to open notification center
- Notification Center - Filter by "All" or "Unread"
- Toast Notifications - Automatic popups for new notifications
- User Menu (avatar) - Logout and see session handling
Database connection error?
- Verify PostgreSQL is running:
pg_isready - Check
DATABASE_URLin.envis correct - If using Prisma Postgres, verify your API key
Port 3000 already in use?
# Find and kill the process
lsof -ti:3000 | xargs kill -9JWT validation errors in console?
- Ensure you've logged out and logged in again after changing
NEXTAUTH_SECRET - Old sessions have invalid tokens
WebSocket not connecting?
- Check console for errors
- Verify
NEXT_PUBLIC_APP_URLmatches your development URL - Try hard refresh (Cmd+Shift+R or Ctrl+Shift+R)
novacart/
├── prisma/
│ ├── schema.prisma # Database schema
│ └── seed.ts # Database seeding script
├── public/ # Static assets
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API Routes
│ │ │ ├── auth/ # Authentication endpoints
│ │ │ └── notifications/# Notification CRUD endpoints
│ │ ├── auth/ # Auth pages (login)
│ │ ├── dashboard/ # Main dashboard page
│ │ ├── test-socket/ # Test page for notifications
│ │ ├── layout.tsx # Root layout
│ │ └── page.tsx # Home page
│ ├── components/ # React components
│ │ └── notifications/ # Notification UI components
│ │ ├── NotificationBell.tsx
│ │ ├── NotificationCenter.tsx
│ │ ├── NotificationItem.tsx
│ │ └── NotificationToastProvider.tsx
│ ├── hooks/ # Custom React hooks
│ │ ├── useSocket.ts # WebSocket management
│ │ └── useNotifications.ts
│ ├── lib/ # Utility libraries
│ │ ├── auth.ts # NextAuth configuration
│ │ ├── db.ts # Prisma client
│ │ ├── socket.ts # Socket.io client
│ │ └── socket-server.ts # Socket.io server utilities
│ ├── store/ # State management
│ │ └── notificationStore.ts # Zustand store
│ ├── types/ # TypeScript types
│ │ ├── notification.ts # Notification types
│ │ └── next-auth.d.ts # NextAuth type extensions
│ └── generated/ # Generated Prisma Client
├── server.ts # Custom Next.js server with Socket.io
├── socket-handler.ts # WebSocket event handlers
├── package.json
├── tsconfig.json
├── tailwind.config.ts
└── next.config.ts
All API routes require authentication via NextAuth session.
Headers:
Cookie: next-auth.session-token=...
Get all notifications for the authenticated user.
Response:
{
"notifications": [
{
"id": "cm...",
"userId": "cm...",
"type": "ORDER_SHIPPED",
"title": "Order Shipped",
"message": "Your order #12345 has been shipped!",
"read": false,
"actionUrl": "/orders/12345",
"metadata": null,
"createdAt": "2025-01-15T10:30:00Z"
}
]
}Create a new notification.
Body:
{
"userId": "cm...",
"type": "PROMOTION",
"title": "Special Offer",
"message": "20% off all products!",
"actionUrl": "/promotions"
}Response:
{
"message": "Notifica creata con successo",
"notification": { ... }
}Get a specific notification by ID.
Delete a notification (only if owned by user).
Mark a notification as read.
Mark all user's notifications as read.
Client → Server:
notifications:fetch- Request all notificationsnotification:mark-read- Mark notification as read
Server → Client:
notifications:initial- Initial notification list on connectnotification:new- New notification creatednotification:updated- Notification updated (e.g., marked as read)notification:deleted- Notification deletednotifications:all-read- All notifications marked as read
- User logs in via credentials
- NextAuth validates password with bcrypt
- JWT token generated with:
userIdandemailin payload- HMAC signature with
NEXTAUTH_SECRET - 30-day expiration
- Token stored in session
- Token passed to WebSocket on connection
- Server validates JWT signature and expiration
- Server verifies
userIdin token matches requested user
- โ JWT Authentication - Cryptographic token validation
- โ Password Hashing - bcrypt with salt rounds
- โ Ownership Checks - Users can only access their own data
- โ Room Isolation - WebSocket rooms per user
- โ Token Expiration - Automatic session timeout
- โ CSRF Protection - NextAuth built-in protection
- โ Type Safety - TypeScript prevents common errors
Required for production:
NEXTAUTH_SECRET- Strong random string (min 32 chars)DATABASE_URL- PostgreSQL connection stringNEXTAUTH_URL- Your production domain
-
Test Real-time Notifications:
- Login and go to
/test-socket - Click "Create Notification"
- See toast popup and bell badge update
- Login and go to
-
Test Multi-tab Sync:
- Open dashboard in two browser tabs
- Mark notification as read in one tab
- See it update in the other tab
-
Test Security:
- Try accessing
/api/notificationswithout login → 401 - Try accessing another user's notification → 403
- Try accessing
The seed script creates:
- Email: test@novacart.com
- Password: password123
- 3 sample notifications
Run npm run db:seed to recreate.
-
Push to GitHub
git add . git commit -m "Initial commit" git push origin main
-
Deploy on Vercel
- Go to vercel.com
- Import your GitHub repository
- Configure environment variables
- Deploy
-
Set up Database
- Use Vercel Postgres or external PostgreSQL
- Run migrations:
npx prisma db push
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]Build and run:
docker build -t novacart .
docker run -p 3000:3000 --env-file .env novacart| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://user:pass@host:5432/db |
NEXTAUTH_URL |
Application URL | https://novacart.com |
NEXTAUTH_SECRET |
Secret for JWT signing | openssl rand -base64 32 |
NEXT_PUBLIC_APP_URL |
Public app URL for client | https://novacart.com |
NODE_ENV |
Environment | production |
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use TypeScript strict mode
- Follow existing code patterns
- Add comments for complex logic
- Update README for new features
This project is licensed under the MIT License - see the LICENSE file for details.
Francesco Di Biase
- GitHub: @Francescodib
- LinkedIn: francescodibiase79
- Next.js team for the amazing framework
- Socket.io for real-time capabilities
- NextAuth.js for authentication
- Prisma for the excellent ORM
- Tailwind CSS for the styling system
- Next.js Documentation
- Socket.io Documentation
- NextAuth Documentation
- Prisma Documentation
- Tailwind CSS Documentation
Built with โค๏ธ using Next.js, Socket.io, and TypeScript