A full-stack, production-ready blog application built with Next.js 16, featuring real-time interactions, rich text editing, and a comprehensive content management system.
- π° Article Management - Create, edit, delete, and publish articles with rich text editor
- π Advanced Search - Real-time search across articles with filtering capabilities
- π¬ Comments System - Engage with readers through nested comments
- β€οΈ Like & Save - Interactive engagement with like/dislike and bookmark features
- π Analytics Dashboard - Track article performance and user engagement
- π¨ Rich Text Editor - Powered by React Quill for professional content creation
- πΌοΈ Image Management - Cloudinary integration for optimized image uploads
- π Authentication - Secure user authentication via Clerk
- π Dark Mode - Seamless theme switching with next-themes
- π± Responsive Design - Mobile-first approach with Tailwind CSS
- β‘ Performance - Optimized with Next.js 16 App Router and Server Components
- βΏ Accessibility - Built with Radix UI primitives for WCAG compliance
- Framework: Next.js 16 (App Router)
- Language: TypeScript 5
- Styling: Tailwind CSS 4
- UI Components: Radix UI, shadcn/ui
- Rich Text: React Quill
- Icons: Lucide React
- Database: PostgreSQL
- ORM: Prisma 5.22
- Authentication: Clerk
- File Storage: Cloudinary
- Validation: Zod
- Package Manager: npm
- Linting: ESLint 9
- Type Checking: TypeScript
- Database Seeding: tsx
Before you begin, ensure you have the following installed:
- Node.js 18.x or higher
- npm or yarn or pnpm
- PostgreSQL database
- Git
git clone <repository-url>
cd blognpm installCreate a .env file in the root directory:
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/blog_db"
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
CLERK_SECRET_KEY=your_clerk_secret_key
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
# Cloudinary
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret# Generate Prisma Client
npx prisma generate
# Run migrations
npx prisma migrate dev
# Seed the database (optional)
npm run seednpm run devVisit http://localhost:3000 to see your application.
blog/
βββ actions/ # Server actions for data mutations
β βββ create-article.ts
β βββ edit-article.ts
β βββ delete-article.ts
β βββ like-dislike.ts
β βββ save-article.ts
β βββ create-comment.ts
β βββ search.ts
βββ app/ # Next.js App Router
β βββ (home)/ # Public home pages
β βββ about/ # About page
β βββ api/ # API routes
β βββ article/ # Article detail pages
β βββ dashboard/ # User dashboard
β βββ layout.tsx # Root layout
βββ components/ # React components
β βββ articles/ # Article-related components
β βββ comments/ # Comment components
β βββ dashboard/ # Dashboard components
β βββ home/ # Home page components
β βββ ui/ # Reusable UI components
βββ hooks/ # Custom React hooks
βββ lib/ # Utility functions
β βββ prisma.ts # Prisma client
β βββ query/ # Database queries
β βββ utils.ts # Helper functions
βββ prisma/ # Database schema and migrations
β βββ schema.prisma
β βββ seed.ts
βββ public/ # Static assets
# Development
npm run dev # Start development server
npm run dev:turbo # Start with Turbo mode
# Production
npm run build # Build for production
npm run start # Start production server
# Database
npm run seed # Seed database with sample data
npx prisma studio # Open Prisma Studio
npx prisma migrate dev # Run migrations
# Code Quality
npm run lint # Run ESLintmodel User {
id String @id @default(uuid())
clearkUserId String @unique
email String @unique
name String?
imageURL String?
articles Article[]
Comment Comment[]
likes Like[]
savedArticles SavedArticle[]
}- Stores user profile information
- Linked to Clerk authentication
- Manages user-generated content
model Article {
id String @id @default(uuid())
title String
content String
category String
featuredImage String
authorId String
author User @relation(fields: [authorId], references: [id])
comments Comment[]
likes Like[]
savedBy SavedArticle[]
createAt DateTime @default(now())
updatedAt DateTime @updatedAt
}- Main content entity
- Rich text content support
- Automatic timestamps
model Comment {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
articleId String
article Article @relation(fields: [articleId], references: [id])
body String
createdAt DateTime @default(now())
}- User comments on articles
- Linked to both user and article
model Like {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
articleId String
article Article @relation(fields: [articleId], references: [id])
createdAt DateTime @default(now())
@@unique([userId, articleId])
}- One like per user per article
- Unique constraint prevents duplicates
model SavedArticle {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
articleId String
article Article @relation(fields: [articleId], references: [id])
createdAt DateTime @default(now())
@@unique([userId, articleId])
}- Bookmark functionality
- Unique constraint per user-article pair
- One-to-Many: User β Articles, User β Comments
- Many-to-Many: Users β Articles (via Likes and SavedArticles)
- Cascade Deletes: Configured for data integrity
Create Article
// actions/create-article.ts
createArticle(formData: FormData)
- Input: title, content, category, featuredImage
- Returns: Created article or error
- Auth: RequiredEdit Article
// actions/edit-article.ts
editArticle(articleId: string, formData: FormData)
- Input: articleId, updated fields
- Returns: Updated article or error
- Auth: Required (must be author)Delete Article
// actions/delete-article.ts
deleteArticle(articleId: string)
- Input: articleId
- Returns: Success or error
- Auth: Required (must be author)Like/Dislike Article
// actions/like-dislike.ts
toggleLike(articleId: string)
- Input: articleId
- Returns: Updated like status
- Auth: RequiredSave Article
// actions/save-article.ts
toggleSave(articleId: string)
- Input: articleId
- Returns: Updated save status
- Auth: RequiredSearch Articles
// actions/search.ts
searchArticles(query: string)
- Input: search query
- Returns: Matching articles
- Auth: OptionalCreate Comment
// actions/create-comment.ts
createComment(articleId: string, body: string)
- Input: articleId, comment body
- Returns: Created comment
- Auth: RequiredFetch Articles
// lib/query/fetch-articles.ts
- fetchAllArticles(): Get all published articles
- fetchArticleById(id): Get single article with relations
- fetchUserArticles(userId): Get articles by author
- fetchSavedArticles(userId): Get user's saved articles- ArticleCard - Display article preview
- ArticleDetailPage - Full article view
- CreateArticlePage - Article creation form
- EditArticlePage - Article editing form
- AllArticlePage - Article listing with filters
- LikeButton - Interactive like/dislike button
- ArticleSearchInput - Search functionality
- CommentsList - Display all comments
- CommentInput - Add new comment
- CommentItem - Single comment display
- BlogDashboard - Main
- Users sign up/sign in via Clerk
- Clerk webhook creates user record in database
- User sessions managed by Clerk middleware
- Protected routes secured via middleware.ts
Built with shadcn/ui and Radix UI for:
- Accessible, keyboard-navigable interfaces
- Consistent design system
- Dark mode support
- Responsive layouts
# Install Vercel CLI
npm i -g vercel
# Deploy
vercelEnsure all environment variables are configured in your deployment platform:
- Database connection string
- Clerk API keys
- Cloudinary credentials
npx prisma migrate deployβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Development Lifecycle β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. Setup Environment
βββ Clone repository
βββ Install dependencies (npm install)
βββ Configure .env file
βββ Setup PostgreSQL database
βββ Run migrations (npx prisma migrate dev)
2. Local Development
βββ Start dev server (npm run dev)
βββ Access at http://localhost:3000
βββ Hot reload enabled
βββ Prisma Studio for DB inspection (npx prisma studio)
3. Feature Development
βββ Create feature branch (git checkout -b feature/name)
βββ Implement changes
βββ Test locally with seeded data
βββ Check for type errors (TypeScript)
βββ Run linter (npm run lint)
4. Code Review & Merge
βββ Commit changes (git commit -m "message")
βββ Push to remote (git push origin feature/name)
βββ Create Pull Request
βββ Code review by team
βββ Merge to main branch
5. Deployment
βββ Auto-deploy on merge (Vercel)
βββ Run production migrations
βββ Verify environment variables
βββ Monitor deployment logs
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Author Journey β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Step 1: Authentication
βββ Sign in/Sign up via Clerk
βββ Email/Password
βββ Google OAuth
βββ GitHub OAuth
Step 2: Dashboard Access
βββ Navigate to /dashboard
βββ View recent articles
βββ Check analytics
βββ Access saved articles
Step 3: Create Article
βββ Click "Create Article"
βββ Enter title
βββ Select category
βββ Upload featured image (Cloudinary)
βββ Write content (Rich Text Editor)
βββ Format text (bold, italic, headings)
βββ Add links
βββ Insert images
βββ Create lists
Step 4: Publish
βββ Submit article
βββ Validation (Zod schema)
βββ Save to database (Prisma)
βββ Redirect to article page
Step 5: Manage Content
βββ Article Management
βββ Edit existing articles
βββ Delete articles
βββ View engagement metrics
βββ Respond to comments
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Reader Journey β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Step 1: Discovery
βββ Landing Page (/)
βββ Browse featured articles
βββ View top articles
βββ Search by keyword
βββ Filter by category
Step 2: Read Article
βββ Article Detail Page (/article/[id])
βββ Read full content
βββ View author info
βββ Check publish date
βββ See engagement stats
Step 3: Interact
βββ Engagement Options
βββ Like/Dislike article
βββ Save for later
βββ Share article
βββ Leave comment
Step 4: Community
βββ Comments Section
βββ Read other comments
βββ Reply to comments
βββ Engage in discussions
βββ Follow conversations
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Data Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User Action β Server Action β Prisma ORM β PostgreSQL
Example: Creating an Article
1. User submits form
βββ /dashboard/article/create
2. Server Action (create-article.ts)
βββ Validate input (Zod)
βββ Check authentication (Clerk)
βββ Process data
3. Prisma Query
βββ prisma.article.create()
βββ Include relations (author)
βββ Return created article
4. Database Update
βββ Insert into Article table
βββ Update foreign keys
βββ Commit transaction
5. Response
βββ Revalidate cache
βββ Redirect to article
βββ Show success toast
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Auth Flow (Clerk) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. User Access
βββ Visit protected route
βββ middleware.ts checks auth
2. Not Authenticated
βββ Redirect to /sign-in
βββ Show Clerk sign-in UI
βββ Multiple auth methods
3. Sign In/Sign Up
βββ Clerk handles authentication
βββ Verify credentials
βββ Create session
βββ Generate JWT token
4. Webhook (Optional)
βββ Clerk sends user.created event
βββ Create User in database
βββ Store Clerk user ID
βββ Save email & profile
βββ Initialize user data
5. Authenticated
βββ Access granted
βββ Session stored in cookies
βββ User data available
βββ Protected routes accessible
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cloudinary Integration β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. User Selects Image
βββ File input in article form
2. Client-Side Upload
βββ next-cloudinary component
βββ Validate file type/size
βββ Show upload progress
βββ Generate preview
3. Cloudinary Processing
βββ Upload to cloud
βββ Optimize image
βββ Generate transformations
βββ Create responsive URLs
βββ Return secure URL
4. Store URL
βββ Save to database
βββ featuredImage field
βββ Associated with article
5. Display Image
βββ Render on frontend
βββ Responsive images
βββ Lazy loading
βββ Optimized delivery
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Search Implementation β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. User Input
βββ Search bar (header or article page)
βββ Type search query
2. Real-time Search
βββ Debounced input
βββ Wait for user to stop typing
βββ Trigger search action
3. Server Action (search.ts)
βββ Query database
βββ Search in title
βββ Search in content
βββ Search in category
βββ Filter by relevance
4. Prisma Query
βββ prisma.article.findMany()
βββ WHERE clause with contains
βββ Include author data
βββ Order by relevance
5. Display Results
βββ Update UI
βββ Show matching articles
βββ Highlight search terms
βββ Show result count
βββ Handle no results
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Deployment Pipeline β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. Code Push
βββ git push origin main
2. Vercel Detection
βββ Webhook triggered
βββ Start build process
3. Build Phase
βββ Install dependencies
βββ Run TypeScript compilation
βββ Run ESLint
βββ Generate Prisma Client
βββ Build Next.js app (npm run build)
4. Database Migration
βββ npx prisma migrate deploy
βββ Apply pending migrations
βββ Update production schema
5. Deployment
βββ Deploy to Vercel edge network
βββ Set environment variables
βββ Configure domains
βββ Enable CDN
6. Post-Deployment
βββ Run health checks
βββ Monitor error logs
βββ Verify functionality
βββ Notify team (optional)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client (Browser) β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
β β Pages β β Components β β Hooks β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js App Router β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
β β Routes β β Server β β API β β
β β β β Actions β β Routes β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Business Logic β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
β β Prisma β β Zod β β Utils β β
β β ORM β β Validation β β β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β External Services β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
β β PostgreSQL β β Clerk β β Cloudinary β β
β β Database β β Auth β β Images β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Server Components - Default rendering strategy for performance
- Server Actions - Type-safe mutations without API routes
- Optimistic Updates - Instant UI feedback before server confirmation
- Middleware - Route protection and authentication checks
- Component Composition - Reusable UI components with Radix UI
- Type Safety - End-to-end TypeScript with Prisma and Zod
-
Authentication & Authorization
- Clerk handles secure authentication
- JWT tokens for session management
- Protected routes via middleware
- User-specific data access controls
-
Data Validation
- Zod schemas for input validation
- Server-side validation on all mutations
- SQL injection prevention via Prisma
- XSS protection with React
-
Environment Variables
- Sensitive data in .env (not committed)
- Different configs for dev/prod
- Secure API key management
-
Database Security
- Parameterized queries via Prisma
- Unique constraints on critical fields
- Foreign key relationships enforced
- Connection pooling for performance
# Install testing dependencies
npm install -D vitest @testing-library/react @testing-library/jest-dom
# Run tests
npm run test- Test server actions with database
- Mock Clerk authentication
- Test Prisma queries
# Install Playwright
npm install -D @playwright/test
# Run E2E tests
npx playwright test-
Next.js Features
- App Router for automatic code splitting
- Server Components reduce client bundle
- Image optimization with next/image
- Font optimization with next/font
-
Database
- Prisma connection pooling
- Indexed fields for fast queries
- Efficient relations with include/select
-
Caching
- Next.js automatic caching
- Revalidation strategies
- Static generation where possible
-
Assets
- Cloudinary CDN for images
- Responsive image delivery
- Lazy loading components
Database Connection Error
# Check DATABASE_URL in .env
# Ensure PostgreSQL is running
# Verify database exists
npx prisma db pushClerk Authentication Issues
# Verify Clerk keys in .env
# Check middleware.ts configuration
# Ensure public routes are configuredBuild Errors
# Clear Next.js cache
rm -rf .next
# Regenerate Prisma Client
npx prisma generate
# Rebuild
npm run buildModule Not Found
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install- Vercel Analytics - Built-in performance monitoring
- Sentry - Error tracking and monitoring
- Prisma Pulse - Real-time database events
- LogRocket - Session replay and debugging
# Feature development
git checkout -b feature/new-feature
git add .
git commit -m "feat: add new feature"
git push origin feature/new-feature
# Bug fixes
git checkout -b fix/bug-description
git commit -m "fix: resolve bug description"
# Hotfix
git checkout -b hotfix/critical-issue
git commit -m "hotfix: critical issue fix"Follow Conventional Commits:
feat:- New featurefix:- Bug fixdocs:- Documentation changesstyle:- Code style changesrefactor:- Code refactoringtest:- Test additions/changeschore:- Build process or auxiliary tool changes
Contributions are welcome! Please follow these steps:
-
Fork the repository
# Click "Fork" on GitHub git clone https://github.com/your-username/blog.git -
Create a feature branch
git checkout -b feature/amazing-feature
-
Make your changes
- Follow code style guidelines
- Add tests if applicable
- Update documentation
-
Commit your changes
git commit -m 'feat: add amazing feature' -
Push to the branch
git push origin feature/amazing-feature
-
Open a Pull Request
- Describe your changes
- Link related issues
- Wait for review
- Use TypeScript for type safety
- Follow ESLint rules
- Use meaningful variable names
- Add comments for complex logic
- Keep components small and focused
- Write reusable utility functions
This project is licensed under the MIT License.
- Next.js - React framework
- Prisma - Database ORM
- Clerk - Authentication
- shadcn/ui - UI components
- Cloudinary - Media management
For questions or support, please open an issue on GitHub.
Built with β€οΈ using Next.js and modern web technologies