Next Store | E-Commerce Platform 3 - Next.js, TypeScript, Prisma, PostgreSQL, Vercel Blob, Clerk, Stripe Fullstack Project (including Admin Panel)
A beautifully designed, high-performance e-commerce platform built with Next.js 14, TypeScript, Prisma, PostgreSQL, Vercel Blob Storage, Clerk authentication, Stripe payments, and shadcn/ui. Next Store offers a seamless online shopping experience with fast checkout, secure payments, and a curated selection of products.
- Live-Demo: https://store-next-beta.vercel.app/
- Features & Functionalities
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables Setup
- Database Setup
- API Endpoints
- Routes & Pages
- Components Guide
- Server Actions
- How It Works
- Reusing Components
- Deployment
- Keywords
- Educational Value
- Learning Resources
- Troubleshooting
- Contributing
- License
- Author
- Acknowledgments
-
🛍️ Product Management
- Browse products with grid and list views
- Search and filter products by name or company
- Featured products showcase on homepage
- Detailed product pages with images, descriptions, and reviews
- Admin CRUD operations for products
-
🛒 Shopping Cart
- Add/remove items from cart
- Update item quantities
- Real-time cart total calculations
- Persistent cart per user session
-
💳 Secure Checkout
- Stripe embedded checkout integration
- Secure payment processing
- Order confirmation and tracking
-
⭐ Favorites System
- Save favorite products
- Quick access to saved items
- Toggle favorites with one click
-
📝 Product Reviews
- Submit product reviews with ratings (1-5 stars)
- View all reviews for each product
- Average rating calculation
- Review management (view and delete your reviews)
-
👤 User Authentication
- Clerk-powered authentication
- Multiple sign-in options (Google, GitHub, Email)
- Protected routes and admin access control
- User profile management
-
👨💼 Admin Dashboard
- Admin-only product management
- Sales overview and analytics
- Order management
- Image upload and management
-
🎨 Modern UI/UX
- Dark mode support
- Responsive design (mobile-first)
- Beautiful shadcn/ui components
- Smooth animations and transitions
- Loading states and error handling
-
📸 Image Management
- Upload product images to Vercel Blob Storage
- Automatic image optimization
- Image deletion on product removal
- Next.js 14 - React framework with App Router
- TypeScript - Type-safe development
- React 18 - UI library
- Tailwind CSS - Utility-first CSS framework
- shadcn/ui - Beautiful, accessible UI components
- Radix UI - Unstyled, accessible component primitives
- next-themes - Dark mode implementation
- Embla Carousel - Carousel component for hero section
- React Icons - Icon library
- React Share - Social sharing functionality
- Prisma ORM - Type-safe database access
- NeonDB - Serverless PostgreSQL database
- Next.js Server Actions - Server-side data mutations
- Next.js API Routes - RESTful API endpoints
- Clerk - Authentication and user management
- Stripe - Payment processing and checkout
- Vercel Blob Storage - Image and file storage
- Vercel - Hosting and deployment platform
- Zod - Schema validation
- ESLint - Code linting
- TypeScript - Static type checking
nextjs-store/
├── app/ # Next.js App Router directory
│ ├── about/ # About page
│ ├── admin/ # Admin dashboard routes
│ │ ├── layout.tsx # Admin layout with sidebar
│ │ ├── products/ # Product management
│ │ │ ├── [id]/ # Dynamic product routes
│ │ │ │ └── edit/ # Edit product page
│ │ │ ├── create/ # Create product page
│ │ │ ├── loading.tsx # Loading state
│ │ │ └── page.tsx # Products list page
│ │ ├── sales/ # Sales dashboard
│ │ │ ├── loading.tsx
│ │ │ └── page.tsx
│ │ └── Sidebar.tsx # Admin sidebar component
│ ├── api/ # API routes
│ │ ├── confirm/ # Stripe payment confirmation
│ │ │ └── route.ts
│ │ └── payment/ # Stripe checkout session
│ │ └── route.ts
│ ├── cart/ # Shopping cart page
│ │ └── page.tsx
│ ├── checkout/ # Checkout page
│ │ └── page.tsx
│ ├── favorites/ # User favorites page
│ │ ├── loading.tsx
│ │ └── page.tsx
│ ├── orders/ # User orders page
│ │ ├── loading.tsx
│ │ └── page.tsx
│ ├── products/ # Products pages
│ │ ├── [id]/ # Single product page
│ │ │ └── page.tsx
│ │ ├── loading.tsx
│ │ └── page.tsx # Products list page
│ ├── reviews/ # Reviews page
│ │ ├── loading.tsx
│ │ └── page.tsx
│ ├── favicon.ico # Site favicon
│ ├── globals.css # Global styles
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Homepage
│ ├── providers.tsx # Context providers
│ └── theme-provider.tsx # Theme context provider
├── components/ # Reusable components
│ ├── cart/ # Cart-related components
│ │ ├── CartItemColumns.tsx
│ │ ├── CartItemsList.tsx
│ │ ├── CartTotals.tsx
│ │ └── ThirdColumn.tsx
│ ├── form/ # Form components
│ │ ├── Buttons.tsx
│ │ ├── CheckboxInput.tsx
│ │ ├── FormContainer.tsx
│ │ ├── FormInput.tsx
│ │ ├── ImageInput.tsx
│ │ ├── ImageInputContainer.tsx
│ │ ├── PriceInput.tsx
│ │ └── TextAreaInput.tsx
│ ├── global/ # Global utility components
│ │ ├── Container.tsx
│ │ ├── EmptyList.tsx
│ │ ├── LoadingContainer.tsx
│ │ ├── LoadingTable.tsx
│ │ └── SectionTitle.tsx
│ ├── home/ # Homepage components
│ │ ├── FeaturedProducts.tsx
│ │ ├── Hero.tsx
│ │ └── HeroCarousel.tsx
│ ├── navbar/ # Navigation components
│ │ ├── CartButton.tsx
│ │ ├── DarkMode.tsx
│ │ ├── LinksDropdown.tsx
│ │ ├── Logo.tsx
│ │ ├── Navbar.tsx
│ │ ├── NavSearch.tsx
│ │ ├── SignOutLink.tsx
│ │ └── UserIcon.tsx
│ ├── products/ # Product-related components
│ │ ├── FavoriteToggleButton.tsx
│ │ ├── FavoriteToggleForm.tsx
│ │ ├── ProductsContainer.tsx
│ │ ├── ProductsGrid.tsx
│ │ └── ProductsList.tsx
│ ├── reviews/ # Review components
│ │ ├── Comment.tsx
│ │ ├── ProductReviews.tsx
│ │ ├── Rating.tsx
│ │ ├── RatingInput.tsx
│ │ ├── ReviewCard.tsx
│ │ └── SubmitReview.tsx
│ ├── single-product/ # Single product page components
│ │ ├── AddToCart.tsx
│ │ ├── BreadCrumbs.tsx
│ │ ├── ProductRating.tsx
│ │ ├── SelectProductAmount.tsx
│ │ └── ShareButton.tsx
│ └── ui/ # shadcn/ui components
│ ├── breadcrumb.tsx
│ ├── button.tsx
│ ├── card.tsx
│ ├── carousel.tsx
│ ├── checkbox.tsx
│ ├── dropdown-menu.tsx
│ ├── input.tsx
│ ├── label.tsx
│ ├── popover.tsx
│ ├── select.tsx
│ ├── separator.tsx
│ ├── skeleton.tsx
│ ├── table.tsx
│ ├── textarea.tsx
│ ├── toast.tsx
│ ├── toaster.tsx
│ └── use-toast.ts
├── lib/ # Utility libraries
│ └── utils.ts # Utility functions (cn, etc.)
├── prisma/ # Prisma configuration
│ ├── schema.prisma # Database schema
│ ├── seed.js # Database seeding script
│ └── products.json # Sample product data
├── public/ # Static assets
│ ├── images/ # Image assets
│ │ ├── hero1.jpg
│ │ ├── hero2.jpg
│ │ ├── hero3.jpg
│ │ ├── hero4.jpg
│ │ └── product-*.jpg
│ └── logo.png # Site logo
├── utils/ # Utility functions
│ ├── actions.ts # Server actions
│ ├── db.ts # Prisma client instance
│ ├── format.ts # Formatting utilities
│ ├── links.ts # Navigation links
│ ├── schemas.ts # Zod validation schemas
│ ├── supabase.ts # Image upload/delete (Vercel Blob)
│ └── types.ts # TypeScript type definitions
├── .env # Environment variables (not committed)
├── .env.local # Local environment variables (not committed)
├── middleware.ts # Next.js middleware (Clerk auth)
├── next.config.mjs # Next.js configuration
├── package.json # Dependencies and scripts
├── tailwind.config.ts # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
└── README.md # This fileBefore you begin, ensure you have the following installed:
- Node.js 18.x or higher
- npm or yarn package manager
- Git for version control
- Clone the repository
git clone https://github.com/your-username/nextjs-store.git
cd nextjs-store- Install dependencies
npm install- Set up environment variables
Create .env and .env.local files in the root directory (see Environment Variables Setup section below).
- Set up the database
# Generate Prisma Client
npx prisma generate
# Push schema to database
npx prisma db push
# Seed the database (optional)
node prisma/seed.js- Run the development server
npm run dev- Open your browser
Navigate to http://localhost:3000 to see the application.
This project requires several environment variables to function properly. Create two files: .env and .env.local in the root directory.
This file contains non-sensitive configuration variables:
# NeonDB Database Connection
DATABASE_URL="postgresql://user:password@host:port/database?sslmode=require"
DIRECT_URL="postgresql://user:password@host:port/database?sslmode=require"
# Admin User ID (Clerk)
ADMIN_USER_ID="user_xxxxxxxxxxxxx"
# Website URL
NEXT_PUBLIC_WEBSITE_URL="https://your-domain.vercel.app/"
# Stripe Configuration
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_xxxxxxxxxxxxx"
STRIPE_SECRET_KEY="sk_test_xxxxxxxxxxxxx"
# Optional: For webhook verification
# STRIPE_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxx"This file contains sensitive secrets (never commit to git):
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_xxxxxxxxxxxxx"
CLERK_SECRET_KEY="sk_test_xxxxxxxxxxxxx"
# Vercel Blob Storage
BLOB_READ_WRITE_TOKEN="vercel_blob_rw_xxxxxxxxxxxxx"- Go to Neon Console
- Create a new project or select an existing one
- Go to Connection Details
- Copy the Pooled connection string → Use for
DATABASE_URL - Copy the Direct connection string → Use for
DIRECT_URL
Format:
DATABASE_URL="postgresql://user:password@host-pooler.region.aws.neon.tech/dbname?sslmode=require"
DIRECT_URL="postgresql://user:password@host.region.aws.neon.tech/dbname?sslmode=require"- Go to Clerk Dashboard
- Create a new application or select an existing one
- Go to API Keys section
- Copy Publishable Key → Use for
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY - Copy Secret Key → Use for
CLERK_SECRET_KEY - To get
ADMIN_USER_ID:- Sign in to your application
- Go to Users section in Clerk dashboard
- Click on your user
- Copy the User ID → Use for
ADMIN_USER_ID
- Go to Stripe Dashboard
- Navigate to Developers → API keys
- Copy Publishable key → Use for
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY - Copy Secret key → Use for
STRIPE_SECRET_KEY - For webhooks (optional):
- Go to Developers → Webhooks
- Create a webhook endpoint
- Copy the Signing secret → Use for
STRIPE_WEBHOOK_SECRET
- Go to Vercel Dashboard
- Select your project
- Navigate to Storage tab (top navigation)
- Click Create next to Blob
- Name your blob store (e.g.,
product-images) - Click Connect to connect it to your project
- The
BLOB_READ_WRITE_TOKENwill be automatically added to your Vercel environment variables - Copy the token from Vercel dashboard → Settings → Environment Variables
- Add it to your local
.env.localfile
Set NEXT_PUBLIC_WEBSITE_URL to your production domain:
NEXT_PUBLIC_WEBSITE_URL="https://your-domain.vercel.app/"- Never commit
.envor.env.localfiles to version control - Both files are already in
.gitignore - Use quotes around values that contain special characters
- For production, add all variables to your Vercel project settings
The project uses Prisma ORM with the following models:
- Product - Stores product information
- Favorite - User favorite products
- Review - Product reviews and ratings
- Cart - Shopping cart
- CartItem - Individual cart items
- Order - Customer orders
# Generate Prisma Client
npx prisma generate
# Push schema to database (development)
npx prisma db push
# Create a migration (production)
npx prisma migrate dev --name migration_name
# Seed the database
node prisma/seed.js
# Open Prisma Studio (database GUI)
npx prisma studiomodel Product {
id String @id @default(uuid())
name String
company String
description String
featured Boolean
image String
price Int
clerkId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
favorites Favorite[]
reviews Review[]
cartItems CartItem[]
}
model Favorite {
id String @id @default(uuid())
clerkId String
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Review {
id String @id @default(uuid())
clerkId String
productId String
rating Int
comment String
authorName String
authorImageUrl String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Cart {
id String @id @default(uuid())
clerkId String
cartItems CartItem[]
numItemsInCart Int @default(0)
cartTotal Int @default(0)
shipping Int @default(5)
tax Int @default(0)
taxRate Float @default(0.1)
orderTotal Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model CartItem {
id String @id @default(uuid())
productId String
cartId String
amount Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Order {
id String @id @default(uuid())
clerkId String
products Int @default(0)
orderTotal Int @default(0)
tax Int @default(0)
shipping Int @default(0)
email String
isPaid Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}The project includes two API routes for Stripe payment processing:
Creates a Stripe checkout session for payment processing.
Request Body:
{
"orderId": "order-uuid",
"cartId": "cart-uuid"
}Response:
{
"clientSecret": "cs_test_xxxxxxxxxxxxx"
}Usage Example:
const response = await fetch("/api/payment", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ orderId, cartId }),
});
const { clientSecret } = await response.json();Confirms payment and updates order status after Stripe checkout completion.
Query Parameters:
session_id- Stripe checkout session ID
Response:
- Redirects to
/orderspage on success
How It Works:
- Retrieves the Stripe checkout session
- Updates order status to
isPaid: trueif payment is complete - Deletes the cart after successful payment
- Redirects user to orders page
/- Homepage with hero section and featured products/about- About page/products- Products listing page with search functionality/products/[id]- Single product detail page/cart- Shopping cart page/checkout- Checkout page with Stripe embedded checkout/favorites- User's favorite products (requires authentication)/orders- User's order history (requires authentication)/reviews- User's submitted reviews (requires authentication)
/admin/sales- Sales dashboard and analytics/admin/products- Product management list/admin/products/create- Create new product/admin/products/[id]/edit- Edit existing product
All routes are protected by Clerk middleware. Admin routes additionally check for ADMIN_USER_ID match.
Middleware Configuration:
// middleware.ts
import { clerkMiddleware } from "@clerk/nextjs/server";
export default clerkMiddleware();
export const config = {
matcher: ["/((?!_next|favicon.ico|public).*)"],
};- Wrapper component for consistent page layout
- Usage:
<Container className="py-20">{children}</Container>
- Loading state component with skeleton UI
- Usage:
<LoadingContainer />
- Displays empty state messages
- Usage:
<EmptyList resourceName="products" />
- Consistent section heading component
- Usage:
<SectionTitle text="Featured Products" />
- Wrapper for form elements with consistent styling
- Usage:
<FormContainer title="Create Product">{form}</FormContainer>
- Reusable text input component
- Usage:
<FormInput name="name" label="Product Name" />
- Specialized input for price with currency formatting
- Usage:
<PriceInput name="price" label="Price" />
- Textarea component for longer text inputs
- Usage:
<TextAreaInput name="description" label="Description" />
- File input for image uploads
- Usage:
<ImageInput />
- Checkbox component with label
- Usage:
<CheckboxInput name="featured" label="Featured Product" />
- Container that handles product fetching and layout switching
- Usage:
<ProductsContainer layout="grid" search={searchTerm} />
- Grid layout for product display
- Usage:
<ProductsGrid products={products} />
- List layout for product display
- Usage:
<ProductsList products={products} />
- Button to toggle favorite status
- Usage:
<FavoriteToggleButton productId={productId} />
- Displays all items in the cart
- Usage:
<CartItemsList cartItems={cartItems} />
- Displays cart totals (subtotal, tax, shipping, total)
- Usage:
<CartTotals cart={cart} />
- Column components for cart item display
- Usage:
<FirstColumn name={name} image={image} />
- Displays all reviews for a product
- Usage:
<ProductReviews productId={productId} />
- Form component for submitting reviews
- Usage:
<SubmitReview productId={productId} />
- Individual review card component
- Usage:
<ReviewCard review={review} />
- Star rating display component
- Usage:
<Rating rating={4.5} />
- Main navigation bar component
- Usage: Automatically included in root layout
- Search input in navbar
- Usage: Included in Navbar
- Cart icon button with item count
- Usage: Included in Navbar
- Dark mode toggle button
- Usage: Included in Navbar
- Dropdown menu for navigation links
- Usage: Included in Navbar
These are shadcn/ui components. You can add more using:
npx shadcn-ui@latest add [component-name]Common components used:
Button- Styled button componentCard- Card container componentInput- Text input componentTable- Table componentToast- Toast notification systemSkeleton- Loading skeleton component
Server Actions are defined in utils/actions.ts. They handle all server-side data mutations.
const products = await fetchFeaturedProducts();
// Returns: Product[] - All products where featured: trueconst products = await fetchAllProducts({ search: "lamp" });
// Returns: Product[] - Filtered products by search termconst product = await fetchSingleProduct("product-uuid");
// Returns: Product - Single product or redirects if not found// Server action for creating a product
// Handles image upload, validation, and database insertion// Server action for updating product details// Server action for updating product image
// Handles old image deletion and new image upload// Server action for deleting a product
// Also deletes associated image from storageconst itemCount = await fetchCartItems();
// Returns: number - Number of items in cart// Server action for adding items to cart
// Creates cart if doesn't exist, updates totals// Server action for updating cart item quantity// Server action for removing item from cartconst favoriteId = await fetchFavoriteId({ productId });
// Returns: string | null - Favorite ID if exists// Server action for toggling favorite statusconst favorites = await fetchUserFavorites();
// Returns: Favorite[] with product data// Server action for creating a product reviewconst reviews = await fetchProductReviews("product-uuid");
// Returns: Review[] - All reviews for a productconst { rating, count } = await fetchProductRating("product-uuid");
// Returns: { rating: string, count: number }// Server action for deleting a review// Server action for creating an order
// Deletes unpaid orders, creates new orderconst orders = await fetchUserOrders();
// Returns: Order[] - All paid orders for userconst orders = await fetchAdminOrders();
// Returns: Order[] - All paid orders (admin only)- User visits the site
- Clerk middleware checks authentication status
- Protected routes require sign-in
- After sign-in, user session is maintained
- Admin routes check
ADMIN_USER_IDmatch
-
Create Product:
- Admin fills form with product details
- Image is uploaded to Vercel Blob Storage
- Image URL is returned and stored in database
- Product is created with all details
-
Update Product:
- Admin edits product details
- If image is updated, old image is deleted
- New image is uploaded and URL updated
- Product record is updated in database
-
Delete Product:
- Product is deleted from database
- Associated image is deleted from storage
- Related favorites, reviews, and cart items are cascade deleted
- User adds product to cart
- Cart is created if doesn't exist
- Cart item is added or quantity updated
- Cart totals are recalculated (subtotal, tax, shipping, total)
- Cart persists across sessions per user
- User clicks checkout from cart
- Order is created with cart details
- Stripe checkout session is created via
/api/payment - User completes payment in embedded Stripe checkout
- After payment,
/api/confirmis called - Order status is updated to
isPaid: true - Cart is deleted
- User is redirected to orders page
- User selects image file
- File is validated (size, type)
- Image is uploaded to Vercel Blob Storage using
uploadImage() - Public URL is returned
- URL is stored in database
- Image is served from Vercel Blob CDN
- User views product page
- If user hasn't reviewed, review form is shown
- User submits rating and comment
- Review is validated and saved
- Product rating is recalculated
- Review appears on product page
Simply copy the component file and its dependencies:
# Example: Reusing the Container component
cp components/global/Container.tsx your-project/components/Check package.json for required packages:
npm install tailwind-merge clsxUpdate import paths to match your project structure:
// Before
import Container from "@/components/global/Container";
// After (if using different path)
import Container from "../components/Container";import Container from "@/components/global/Container";
export default function MyPage() {
return (
<Container className="py-20">
<h1>My Content</h1>
</Container>
);
}import FormContainer from "@/components/form/FormContainer";
import FormInput from "@/components/form/FormInput";
import { createProductAction } from "@/utils/actions";
export default function CreateForm() {
return (
<FormContainer title="Create Item">
<form action={createProductAction}>
<FormInput name="name" label="Name" />
<button type="submit">Submit</button>
</form>
</FormContainer>
);
}import ProductsGrid from "@/components/products/ProductsGrid";
export default async function ProductsPage() {
const products = await fetchProducts();
return <ProductsGrid products={products} />;
}import { Suspense } from "react";
import LoadingContainer from "@/components/global/LoadingContainer";
import ProductsGrid from "@/components/products/ProductsGrid";
export default function ProductsPage() {
return (
<Suspense fallback={<LoadingContainer />}>
<ProductsGrid products={products} />
</Suspense>
);
}Most components are designed to be reusable. To adapt them:
- Update Types: Modify TypeScript interfaces to match your data structure
- Update Actions: Replace server actions with your own data fetching logic
- Update Styling: Adjust Tailwind classes to match your design system
- Remove Dependencies: Remove Clerk-specific code if not using Clerk
- Push to GitHub
git add .
git commit -m "Ready for deployment"
git push origin main-
Import to Vercel
- Go to Vercel Dashboard
- Click Add New Project
- Import your GitHub repository
- Vercel will auto-detect Next.js
-
Configure Environment Variables
- Go to Settings → Environment Variables
- Add all variables from
.envand.env.local - Set for all environments (Production, Preview, Development)
-
Deploy
- Vercel will automatically deploy
- Your site will be live at
your-project.vercel.app
The project includes a custom build script:
{
"scripts": {
"build": "npx prisma generate && next build"
}
}This ensures Prisma Client is generated before building.
- All environment variables are set in Vercel
- Database is accessible from Vercel
- Stripe keys are set (use production keys)
- Clerk keys are set
- Vercel Blob Storage is connected
- Domain is configured (if using custom domain)
- Test all major features (cart, checkout, admin)
Technologies:
- Next.js 14
- React 18
- TypeScript
- Prisma ORM
- NeonDB
- PostgreSQL
- Vercel Blob Storage
- Clerk Authentication
- Stripe Payments
- Tailwind CSS
- shadcn/ui
- Radix UI
- Zod Validation
- Server Actions
- App Router
Features:
- E-commerce
- Online Store
- Shopping Cart
- Product Management
- Payment Processing
- User Authentication
- Admin Dashboard
- Product Reviews
- Favorites System
- Image Upload
- Dark Mode
- Responsive Design
Concepts:
- Server-Side Rendering (SSR)
- Static Site Generation (SSG)
- API Routes
- Server Actions
- Type-Safe Database
- Form Validation
- Error Handling
- Loading States
This project demonstrates:
-
Modern Next.js Patterns:
- App Router architecture
- Server Components vs Client Components
- Server Actions for mutations
- API Routes for external integrations
-
Type Safety:
- TypeScript throughout
- Prisma type generation
- Zod schema validation
-
Database Design:
- Relational database modeling
- Cascade deletions
- Efficient queries
-
Authentication & Authorization:
- Clerk integration
- Protected routes
- Role-based access (admin)
-
Payment Integration:
- Stripe embedded checkout
- Payment confirmation flow
- Order management
-
File Storage:
- Vercel Blob Storage
- Image upload handling
- Public URL generation
-
UI/UX Best Practices:
- Responsive design
- Dark mode
- Loading states
- Error handling
- Form validation
-
Code Organization:
- Component reusability
- Separation of concerns
- Utility functions
- Type definitions
- Verify
DATABASE_URLandDIRECT_URLare correct - Check if database is accessible
- Ensure SSL mode is set correctly
- Verify
BLOB_READ_WRITE_TOKENis set - Check Vercel Blob store is connected
- Ensure token has read/write permissions
- Verify Clerk keys are correct
- Check middleware configuration
- Ensure Clerk app is properly configured
- Verify Stripe keys are correct
- Check API route is accessible
- Ensure return URL is correct
- Run
npx prisma generatebefore build - Check all environment variables are set
- Verify all dependencies are installed
Contributions are welcome! To contribute:
- 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
This project is licensed under the MIT License. Feel free to use, modify, and distribute the code as per the terms of the license.
This is an open-source project - feel free to use, enhance, and extend this project further!
If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://www.arnobmahmud.com.
Enjoy building and learning! 🚀
Thank you! 😊







