A production-ready full-stack Product Dashboard built with Next.js, React, Prisma ORM, and PostgreSQL.
- Credentials Authentication: Email/password login and signup
- Google OAuth Integration: One-click login with Google (auto-create accounts)
- Forgot Password Flow: OTP-based password reset with email verification
- Secure Session Management: NextAuth v4 with JWT tokens
- Protected Routes: Automatic redirection for unauthenticated users
- Password Security: Bcrypt hashing with 12 salt rounds
- CRUD Operations: Create, read, update, delete products
- Stock Management: Track inventory levels and status
- Categorization: Organize products by category
- Price Management: Set and modify product pricing
- Search & Filtering: Find products by name, category, price range
- Pagination: Handle large product lists efficiently
- Category Distribution: Bar chart showing products per category
- Stock Availability: Pie chart for in-stock vs out-of-stock
- Price Distribution: Bar chart for price range analysis
- Timeline Analytics: Line chart for products added over 30 days
- Real-time Updates: Charts refresh when products change
- Responsive Design: Mobile-first Tailwind CSS styling
- Clean Dashboard: Intuitive product management interface
- Loading States: Visual feedback during operations
- Error Handling: User-friendly error messages
- Confirmation Dialogs: Safety for destructive actions
- Empty States: Helpful messages for new users
- Frontend: Next.js 15 (App Router), React 19
- Styling: Tailwind CSS
- Authentication: NextAuth v4
- Database: PostgreSQL (Prisma ORM)
- Charts: Recharts
- Validation: Zod
- Security: Bcrypt for password hashing
- Email: Nodemailer (for OTP delivery)
product-dashboard/
├── app/
│ ├── api/
│ │ ├── auth/
│ │ │ ├── [...nextauth]/route.ts # NextAuth configuration
│ │ │ ├── signup/route.ts # User registration API
│ │ │ ├── forgot-password/route.ts # Password reset initiation
│ │ │ └── verify-otp/route.ts # OTP verification
│ ├── auth/
│ │ ├── layout.tsx # Auth pages layout
│ │ ├── login/page.tsx # Login page
│ │ ├── signup/page.tsx # Signup page
│ │ ├── forgot-password/page.tsx # Password reset page
│ │ └── error/page.tsx # Auth error page
│ ├── dashboard/
│ │ └── page.tsx # Main dashboard
│ ├── actions/
│ │ └── products.ts # Server actions for products
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Root redirect
│ └── globals.css # Global styles
├── components/
│ ├── ProductForm.tsx # Product form component
│ ├── ProductTable.tsx # Products table with actions
│ └── Charts.tsx # Chart components
├── lib/
│ ├── auth.ts # NextAuth configuration
│ ├── prisma.ts # Prisma client singleton
│ ├── password.ts # Password hashing utilities
│ ├── otp.ts # OTP generation & verification
│ ├── email.ts # Email sending service
│ └── validation.ts # Input validation schemas
├── prisma/
│ └── schema.prisma # Database schema
├── middleware.ts # Auth middleware
├── next.config.js # Next.js configuration
├── tailwind.config.ts # Tailwind configuration
├── postcss.config.js # PostCSS configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies
- User enters credentials on
/auth/login - Credentials sent to NextAuth Credentials Provider
- Bcrypt verifies password against database
- Session created with JWT token
- User redirected to
/dashboard
- User fills form on
/auth/signup - Data validated with Zod schema
- Password hashed with Bcrypt
- User created in database
- Auto-login with credentials
- Redirect to
/dashboard
- User clicks "Forgot Password" on
/auth/login - Enters email on
/auth/forgot-password - OTP generated and sent via email
- User enters OTP and new password
- Password updated in database
- Redirected to login
- User clicks "Continue with Google"
- Redirected to Google OAuth screen
- User grants permissions
- If user exists → Login
- If user doesn't exist → Auto-create account
- Session created and redirected to
/dashboard
model User {
id String @id @default(cuid())
name String
email String @unique
password String? // Nullable for Google OAuth users
role String @default("user")
products Product[] // One-to-many relation
otpTokens OTPToken[] // One-to-many relation
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}model Product {
id String @id @default(cuid())
name String
category String
price Float
stock Int
status String @default("in_stock")
userId String // Foreign key
user User @relation(fields: [userId])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}model OTPToken {
id String @id @default(cuid())
email String
otp String
expiresAt DateTime // 10 minute expiry
userId String? // Optional reference to user
user User? @relation(fields: [userId])
createdAt DateTime @default(now())
}- Node.js 18+ and npm
- PostgreSQL database (local or Neon)
- Google OAuth credentials (for social login)
- Gmail app password (for OTP emails)
# Clone or extract project
cd product-dashboard
# Install dependencies
npm install
# Create .env.local from example
cp .env.local.example .env.local
# Edit .env.local with your values
# - DATABASE_URL (PostgreSQL connection string)
# - NEXTAUTH_SECRET (generate with: openssl rand -base64 32)
# - NEXTAUTH_URL (http://localhost:3000 for development)
# - GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET
# - SMTP credentials for email# Generate Prisma client
npm run prisma:generate
# Create database and tables
npm run prisma:migrate
# Optional: Open Prisma Studio to view data
npm run prisma:studio# Development server
npm run dev
# Open http://localhost:3000 in browser
# You'll be redirected to login- Login to dashboard
- Click "Add Product" button
- Fill in product details:
- Name: "Wireless Headphones"
- Category: "Electronics"
- Price: 79.99
- Stock: 15
- Click "Add Product"
- Product appears in table
- In dashboard, use search bar at top
- Type product name (case-insensitive)
- Results filter automatically
- Or select category filter
- Click "Analytics" tab
- See four charts:
- Products by category (bar)
- Stock availability (pie)
- Price distribution (bar)
- Products added timeline (line)
- Charts update automatically when products change
- Click "Forgot Password" on login page
- Enter registered email
- Check email for OTP
- Enter OTP and new password
- Password updated and can login with new password
POST /api/auth/[...nextauth]- NextAuth endpointsPOST /api/auth/signup- Register new userPOST /api/auth/forgot-password- Request OTPPOST /api/auth/verify-otp- Reset password with OTP
getProducts()- Fetch user's products with pagination/filterscreateProduct()- Add new productupdateProduct()- Modify existing productdeleteProduct()- Remove productgetProductStats()- Get analytics data
✅ Implemented Security Measures:
- Password hashing with Bcrypt (12 rounds)
- NextAuth v4 JWT session tokens
- Server-side session validation
- Protected API routes with
getServerSession - CSRF protection via NextAuth
- SQL injection prevention (Prisma parameterized queries)
- Input validation with Zod schemas
- OTP expiration (10 minutes)
- Secure password reset flow
- Google OAuth only accepts users with valid tokens
- Set
NEXTAUTH_SECRETto long random string - Set
NEXTAUTH_URLto your production domain - Use environment variables for all secrets
- Enable HTTPS in production
- Set up database backups
- Monitor failed login attempts
- Configure CORS if APIs are called externally
- Use Neon or managed PostgreSQL service
- Add rate limiting to auth endpoints
- Enable database connection pooling
- Invalid email/password → "Invalid email or password"
- Email already exists → "Email already in use"
- Expired OTP → "Invalid or expired OTP"
- Passwords don't match → "Passwords don't match"
- Unauthorized access → 401 Unauthorized
- Product not found → 404 Not Found
- Validation failed → 400 Bad Request
- Server error → 500 Internal Server Error
- All forms show loading states
- API failures display error messages
- Retry functionality available
- Server Components: Auth pages and dashboard use server-side rendering
- Server Actions: Direct database mutations without API layer
- Pagination: Products loaded 10 at a time
- Database Indexes: userId and category fields indexed
- Image Optimization: Uses Next.js Image component
- CSS Optimization: Tailwind purges unused styles
- Code Splitting: Dynamic imports for charts
# Push to GitHub
git add .
git commit -m "Initial commit"
git push origin main
# Deploy on Vercel dashboard
# 1. Connect GitHub repo
# 2. Add environment variables
# 3. Deploy
# Automatic deployments on pushEnsure:
- Node.js 18+ runtime
- Environment variables set
- PostgreSQL accessible
- Build completes:
npm run build - Start command:
npm run start
- Check email exists and is correct
- Verify password (case-sensitive)
- Check database connection
- Verify
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET - Check redirect URI matches Google Console settings
- Ensure cookies enabled in browser
- Check email credentials in
.env.local - Verify Gmail app password (not main password)
- Check spam folder
- Verify database connection
- Run
npm run prisma:migrate - Check user ID in session
- Ensure Recharts is installed:
npm install recharts - Check browser console for errors
- Verify product data exists
- Batch product operations
- Product images/gallery
- Inventory alerts
- User roles & permissions
- Bulk import/export (CSV)
- Advanced filtering and sorting
- Email notifications
- Two-factor authentication
- API rate limiting
- Audit logs
- Dark mode
- Mobile app
Private project
For issues or questions, contact development team.