A comprehensive Next.js-based artisan marketplace platform featuring video-first product showcases, AI-powered content processing, and secure authentication. Built with modern web technologies and designed for scalability.
- Artisan Onboarding: Complete profile setup with optional audio recording support
- AI-Powered Content Processing: Automatic transcription and professional text enhancement
- Video-First Product Showcase: Upload and display products with rich video content
- Secure Authentication: NextAuth.js integration with role-based access control
- Shopping Cart: Add products to cart and manage purchases
- Responsive Design: Modern UI with Tailwind CSS and Framer Motion animations
- PWA Support: Progressive Web App capabilities with offline support
- Speech-to-Text: Convert audio recordings to text using Deepgram AI
- Text Enhancement: Automatically rephrase and improve artisan descriptions using Google Gemini
- Smart Onboarding: Optional audio recording for more natural profile creation
- Database: PostgreSQL with Prisma ORM
- File Storage: Cloudinary integration for images and videos
- Security: Password hashing with bcrypt, JWT sessions
- State Management: React Query for server state management
- UI Components: Radix UI components with custom styling
- Sign Up: New artisans sign up and are automatically redirected to dashboard
- Onboarding Guard: Dashboard checks if onboarding is completed
- Forced Onboarding: If not completed, artisans are redirected to
/onboarding - Profile Creation: Complete profile with optional audio recording and AI enhancement
- Access Granted: Once completed, artisans can access all features
- Onboarding Enforcement: Artisans cannot skip onboarding or access protected features
- Role-Based Access: Different user roles (USER, ARTISAN) have different access levels
- Session Management: Secure authentication with NextAuth.js
Before you begin, ensure you have the following installed:
You'll need accounts and API keys for the following services:
-
Google AI - For text summarization and enhancement
- Visit Google AI Studio
- Create a new API key
-
Deepgram - For speech-to-text transcription
- Visit Deepgram Console
- Create a new API key
-
Cloudinary - For file storage (images and videos)
- Visit Cloudinary Dashboard
- Get your Cloud Name, API Key, and API Secret
Create a .env.local file in the root directory with the following variables:
# Database Configuration
DATABASE_URL="postgresql://username:password@localhost:5432/karigarmart"
# NextAuth Configuration
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="your-nextauth-secret-key-here"
# Google AI API (Required for text summarization)
GOOGLE_AI_API_KEY="your-google-ai-api-key"
# Deepgram API (Required for speech-to-text)
DEEPGRAM_API_KEY="your-deepgram-api-key"
# Cloudinary Configuration (Required for file uploads)
CLOUDINARY_CLOUD_NAME="your-cloudinary-cloud-name"
CLOUDINARY_API_KEY="your-cloudinary-api-key"
CLOUDINARY_API_SECRET="your-cloudinary-api-secret"- DATABASE_URL: PostgreSQL connection string
- NEXTAUTH_URL: Your application URL (change for production)
- NEXTAUTH_SECRET: Random secret key for JWT signing (generate with
openssl rand -base64 32) - GOOGLE_AI_API_KEY: Google AI API key for Gemini model
- DEEPGRAM_API_KEY: Deepgram API key for speech recognition
- CLOUDINARY_*: Cloudinary credentials for file storage
git clone <repository-url>
cd google-hacknpm install# Copy the example environment file
cp .env.example .env.local
# Edit the environment variables
nano .env.local# Generate Prisma client
npx prisma generate
# Run database migrations
npx prisma migrate dev
# Seed the database with initial data
npx prisma db seednpm run devOpen http://localhost:3000 with your browser to see the application.
- POST
/api/auth/signup - Body:
{ email, password, name, role } - Response:
{ success: boolean, user: User }
- POST
/api/auth/signin - Body:
{ email, password } - Response:
{ success: boolean, user: User }
- GET
/api/artisan/onboarding/status - Response:
{ isOnboarded: boolean }
- POST
/api/artisan/onboarding - Body:
{ story, about } - Response:
{ success: boolean, profile: ArtisanProfile }
- GET
/api/artisan/products - Response:
{ products: Product[] }
- GET
/api/products - Query Parameters:
?page=1&limit=10&search=term - Response:
{ products: Product[], total: number }
- GET
/api/products/[id] - Response:
{ product: Product }
- GET
/api/products/search - Query Parameters:
?q=search-term - Response:
{ products: Product[] }
- POST
/api/post - Body:
{ "title": "string", "description": "string", "price": "number", "artisanId": "string (UUID)", "videoUrl": "string (valid URL)", "imageUrl": "string (optional, valid URL)" } - Response:
{ success: boolean, product: Product }
- POST
/api/tts - Body:
FormDatawithaudiofile - Response:
{ success: boolean, transcription: string }
- POST
/api/summary - Body:
{ text: string } - Response:
{ success: boolean, summary: string }
- POST
/api/upload - Body:
FormDatawithfile - Supported Types: Images (JPEG, PNG, GIF, WebP), Videos (MP4, MOV, AVI, WebM)
- Size Limit: 50MB
- Response:
{ success: boolean, data: { url: string, public_id: string } }
- GET
/api/cart - Response:
{ items: CartItem[] }
- POST
/api/cart - Body:
{ productId: string, quantity: number } - Response:
{ success: boolean, item: CartItem }
- PUT
/api/cart - Body:
{ productId: string, quantity: number } - Response:
{ success: boolean, item: CartItem }
- DELETE
/api/cart - Body:
{ productId: string } - Response:
{ success: boolean }
- GET
/api/user/profile - Response:
{ user: User }
- PUT
/api/user/profile - Body:
{ name: string, email: string } - Response:
{ success: boolean, user: User }
model User {
id String @id @default(uuid()) @db.Uuid
email String @unique
passwordHash String
name String
role Role @default(USER)
createdAt DateTime @default(now())
artisanProfile ArtisanProfile?
cartItems CartItem[]
}model ArtisanProfile {
id String @id @default(uuid()) @db.Uuid
userId String @unique @db.Uuid
story String @db.Text
about String @db.Text
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
products Product[]
}model Product {
id String @id @default(uuid()) @db.Uuid
artisanId String @db.Uuid
title String
description String @db.Text
price Decimal @db.Decimal(10, 2)
imageUrl String
videoUrl String
publishDate DateTime @default(now())
artisan ArtisanProfile @relation(fields: [artisanId], references: [id], onDelete: Cascade)
cartItems CartItem[]
}model CartItem {
id String @id @default(uuid()) @db.Uuid
userId String @db.Uuid
productId String @db.Uuid
quantity Int @default(1)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
@@unique([userId, productId])
}npm run dev- Start development servernpm run build- Build for productionnpm start- Start production servernpm run db:seed- Seed the database with initial data
# Generate Prisma client
npx prisma generate
# Create a new migration
npx prisma migrate dev --name migration-name
# Reset database (development only)
npx prisma migrate reset
# View database in Prisma Studio
npx prisma studio
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ ├── auth/ # Authentication pages
│ ├── dashboard/ # Dashboard page
│ ├── onboarding/ # Onboarding page
│ └── ...
├── components/ # React components
│ ├── ui/ # Reusable UI components
│ └── ...
├── hooks/ # Custom React hooks
├── lib/ # Utility libraries
└── types/ # TypeScript type definitions
-
Database Connection Issues
- Ensure PostgreSQL is running
- Check DATABASE_URL format
- Verify database exists
-
API Key Issues
- Verify all API keys are correctly set
- Check API key permissions and quotas
-
File Upload Issues
- Verify Cloudinary credentials
- Check file size limits (50MB max)
- Ensure supported file formats
-
Authentication Issues
- Check NEXTAUTH_SECRET is set
- Verify NEXTAUTH_URL matches your domain