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! π







