Skip to content

A production-ready blogging platform built with Next.js 16, featuring type-safe APIs, rich text editing, category management, and image uploads. Developed as part of the technical assessment for the Full-Stack Developer position at Kapybara HQ.

Notifications You must be signed in to change notification settings

Muhammedijas981/blog-platform

Repository files navigation

πŸ“ Multi-User Blogging Platform

Full-Stack Developer Position Submission - Kapybara HQ

A production-ready blogging platform built with Next.js 16, featuring type-safe APIs, rich text editing, category management, and image uploads. Developed as part of the technical assessment for the Full-Stack Developer position at Kapybara HQ.


πŸš€ Live Demo

View Live Application β†’

Deployed on Vercel with Neon PostgreSQL database


πŸ“‹ Table of Contents

  1. Quick Start
  2. Tech Stack
  3. Features Implemented
  4. Project Structure
  5. Architecture Decisions
  6. Environment Setup
  7. Time Breakdown

πŸš€ Quick Start

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • Neon PostgreSQL account (free tier works)
  • Cloudinary account (free tier works)

Installation (5 minutes)

  1. Clone the repository cd blog-platform
  2. Install dependencies npm install
  3. Create .env file (see Environment Setup section) Edit .env with your credentials
  4. Push database schema to Neon npx drizzle-kit push
  5. Start development server npm run dev
  6. Open browser at http://localhost:3000 text

That's it! πŸŽ‰

The application is now running locally with a connected PostgreSQL database.


πŸ› οΈ Tech Stack

Core Requirements (As Specified)

Technology Version Purpose
Next.js 16.0.0 Full-stack React framework with App Router
TypeScript 5.0+ Type safety across entire codebase
PostgreSQL Latest Relational database (hosted on Neon)
Drizzle ORM Latest Type-safe database ORM
tRPC 11.0+ End-to-end type-safe API layer
Zod 3.22+ Schema validation for tRPC
React Query 5.0+ Server state management (via tRPC)
Zustand 4.4+ Client-side global state
Tailwind CSS 3.4+ Utility-first CSS framework

Additional Libraries (For Better UX)

Library Purpose Time Saved
shadcn/ui Pre-built accessible components ~3-4 hours
Tiptap Rich text editor (WYSIWYG) Better UX
Cloudinary Image CDN and storage ~2 hours
Material-UI Icons Outlined icon set ~1 hour
React Hot Toast Toast notifications ~30 min
next-themes Dark mode support ~1 hour

Why These Choices?

  1. Neon PostgreSQL: Serverless, auto-scaling, generous free tier, instant setup
  2. Tiptap over Markdown: Better UX for content creators (trade-off: +2 hours dev time)
  3. shadcn/ui: Reduced UI development time by 70%
  4. Cloudinary: No server storage management, global CDN, free tier sufficient
  5. Monorepo: Single deployment, shared types, faster development

βœ… Features Implemented

πŸ”΄ Priority 1 - Core Requirements (100% Complete)

  • Blog Post CRUD - Create, read, update, delete with full validation
  • Category CRUD - Full category management system
  • Multi-Category Assignment - Assign multiple categories per post
  • Blog Listing Page - All posts with pagination and filters
  • Individual Post View - Detailed post page with full content
  • Category Filtering - Real-time filtering by category
  • Responsive Navigation - Mobile drawer menu, desktop horizontal nav
  • Clean Professional UI - Minimalist design, consistent spacing

Status: βœ… All Priority 1 features fully implemented and tested

🟑 Priority 2 - Expected Features (100% Complete)

  • Landing Page - 5 sections (Header, Hero, Features, Posts, CTA)
  • Dashboard Page - Post management with search and filters
  • Draft vs Published - Save drafts, publish when ready
  • Loading States - Animated spinners throughout app
  • Error Handling - User-friendly toast notifications
  • Mobile Responsive - Fully responsive across all devices
  • Rich Text Editor - Tiptap with formatting toolbar

Status: βœ… All Priority 2 features fully implemented

🟒 Priority 3 - Bonus Features (90% Complete)

  • Full 5-Section Landing Page - Complete with all sections
  • Search Functionality - Search by title and content
  • Post Statistics - Word count and reading time
  • Dark Mode - System-aware with manual toggle
  • Image Upload - Cloudinary integration for post images
  • Post Preview - Live preview before publishing
  • Pagination - Server-side pagination for efficiency
  • Advanced Editor Features - Bold, italic, lists, formatting
  • SEO Meta Tags - Not implemented (time constraint)

Status: βœ… 8/9 bonus features implemented


πŸ“ Project Structure

blog-platform/
β”œβ”€β”€ app/                          # Next.js 16 App Router
β”‚   β”œβ”€β”€ page.tsx                  # Landing page (Hero + Features)
β”‚   β”œβ”€β”€ posts/
β”‚   β”‚   β”œβ”€β”€ page.tsx              # All posts listing (with search/filter)
β”‚   β”‚   β”œβ”€β”€ new/page.tsx          # Create new post
β”‚   β”‚   └── [slug]/
β”‚   β”‚       β”œβ”€β”€ page.tsx          # View individual post
β”‚   β”‚       └── edit/page.tsx     # Edit post
β”‚   β”œβ”€β”€ categories/
β”‚   β”‚   β”œβ”€β”€ manage/page.tsx       # Category CRUD dashboard
β”‚   β”‚   └── [slug]/page.tsx       # Posts by category
β”‚   β”œβ”€β”€ api/trpc/[trpc]/route.ts  # tRPC API handler
β”‚   β”œβ”€β”€ layout.tsx                # Root layout (theme provider)
β”‚   └── globals.css               # Global Tailwind styles
β”‚
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ forms/
β”‚   β”‚   β”œβ”€β”€ PostForm.tsx          # Post create/edit form
β”‚   β”‚   β”œβ”€β”€ RichTextEditor.tsx    # Tiptap editor wrapper
β”‚   β”‚   └── PostPreview.tsx       # Preview dialog
β”‚   β”œβ”€β”€ layout/
β”‚   β”‚   β”œβ”€β”€ Header.tsx            # Navigation with mobile drawer
β”‚   β”‚   β”œβ”€β”€ Footer.tsx            # Footer component
β”‚   β”‚   └── ThemeToggle.tsx       # Dark mode toggle
β”‚   β”œβ”€β”€ posts/
β”‚   β”‚   β”œβ”€β”€ PostCard.tsx          # Post card component
β”‚   β”‚   └── PostStats.tsx         # Word count & reading time
β”‚   └── ui/                       # shadcn/ui components
β”‚       β”œβ”€β”€ button.tsx
β”‚       β”œβ”€β”€ card.tsx
β”‚       β”œβ”€β”€ dialog.tsx
β”‚       β”œβ”€β”€ sheet.tsx             # Mobile drawer
β”‚       └── ... (20+ components)
β”‚
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ db/
β”‚   β”‚   β”œβ”€β”€ index.ts              # Drizzle database connection
β”‚   β”‚   └── schema.ts             # Database schema definitions
β”‚   └── trpc/
β”‚       β”œβ”€β”€ trpc.ts               # tRPC initialization & context
β”‚       └── routers/
β”‚           β”œβ”€β”€ index.ts          # Root router (aggregates all)
β”‚           β”œβ”€β”€ post.ts           # Post CRUD procedures
β”‚           └── category.ts       # Category CRUD procedures
β”‚
β”œβ”€β”€ lib/
β”‚   └── utils.ts                  # Utility functions (date format, etc.)
β”‚
β”œβ”€β”€ trpc/
β”‚   └── client.ts                 # tRPC React client setup
β”‚
β”œβ”€β”€ .env                          # Environment variables (not in git)
β”œβ”€β”€ drizzle.config.ts             # Drizzle ORM configuration
β”œβ”€β”€ tailwind.config.ts            # Tailwind CSS config
└── tsconfig.json                 # TypeScript configuration

Why This Structure?

  1. App Router Organization: Feature-based routing matches Next.js 16 conventions
  2. Server/Client Separation: Clear boundary between server code and client components
  3. Component Co-location: Related components grouped by feature
  4. Single tRPC Router: All API routes aggregated in one place for discoverability
  5. Flat Hierarchy: Minimal nesting for easier navigation

πŸ— Architecture Decisions

1. Monorepo Approach (Single Project)

Decision: Full-stack in one Next.js project

Why:

  • βœ… Next.js 16 App Router is designed for full-stack
  • βœ… Shared TypeScript types between frontend/backend
  • βœ… Single deployment (Vercel optimized for this)
  • βœ… Faster development (no API versioning issues)
  • βœ… tRPC requires monorepo for type inference

2. Neon PostgreSQL

Decision: Chose Neon over Supabase or local PostgreSQL

Why:

  • βœ… Serverless: Auto-scales to zero (cost-effective)
  • βœ… Instant setup: Database ready in 30 seconds
  • βœ… Generous free tier: 3GB storage, 100 hours compute
  • βœ… Branch database: Each git branch can have its own DB
  • βœ… Connection pooling: Built-in, no extra setup

Benefits of Neon:

  • βœ… Serverless (no server management)
  • βœ… Auto-scaling (scales to zero when idle)
  • βœ… Branch databases (test schema changes safely)
  • βœ… Fast setup (30 seconds)

Free Tier Limits: Perfect for demo projects

  • Storage: 3 GB
  • Compute: 100 hours/month
  • Projects: Unlimited

3. Cloudinary for Images

Decision: Client-side upload to Cloudinary CDN

Why:

  • βœ… No server storage: Offload to CDN
  • βœ… Global delivery: Fast worldwide
  • βœ… Free tier: 10GB storage, 25GB bandwidth/month
  • βœ… Automatic optimization: WebP conversion, resizing
  • βœ… Simple setup: Unsigned upload preset

Benefits of Cloudinary:

  • βœ… No server storage needed
  • βœ… Automatic image optimization
  • βœ… Global CDN delivery
  • βœ… Free tier: 10GB storage

Alternative Considered: Next.js /public folder

  • ❌ Would require file system handling
  • ❌ No CDN benefits
  • ❌ Slower for users far from server

πŸ” Environment Setup

1. Create .env File

Create a .env file in the project root:

# Database Connection (Neon PostgreSQL)
DATABASE_URL="postgresql://username:[email protected]/neondb?sslmode=require"

# Cloudinary Configuration (for image uploads)
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your_cloud_name"
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET="blog_uploads"

2. Neon PostgreSQL Setup (2 minutes)

  1. Sign up at neon.tech (free, no credit card)
  2. Create project β†’ Name it "blog-platform"
  3. Copy connection string from dashboard
  4. Paste into .env as DATABASE_URL

3. Cloudinary Setup (3 minutes)

  1. Sign up at cloudinary.com (free)
  2. Go to Settings β†’ Upload β†’ Upload Presets
  3. Click "Add upload preset"
  4. Configure:
    • Preset name: blog_uploads
    • Signing Mode: Select "Unsigned" (important!)
    • Folder: blog-platform/posts (optional)
    • Allowed formats: jpg, png, webp
    • Max file size: 2 MB
  5. Copy Cloud Name and Preset Name to .env

4. Initialize Database Schema

npx drizzle-kit push

This creates all tables in your Neon database based on server/db/schema.ts.


⏱ Time Breakdown

Total Time Invested: ~15 hours

Phase Tasks Time Spent
Day 1-2: Setup & Backend Project init, Neon setup, Drizzle schema, tRPC routers, CRUD operations ~4 hours
Day 3-4: Core Features Post listing, individual post view, post form, category management, filtering ~5 hours
Day 5-6: Priority 2 & UI Landing page, rich text editor, mobile responsive, loading states, dark mode ~4 hours
Day 7: Polish & Deployment Image upload, search, pagination, bug fixes, README, Vercel deployment ~2 hours

Time-Saving Decisions

Decision Time Saved
Used shadcn/ui components ~3-4 hours
Neon (vs local PostgreSQL setup) ~1 hour
Cloudinary (vs custom file handling) ~2 hours
tRPC (vs REST API boilerplate) ~2 hours
Total Saved: ~8-9 hours

Acknowledgments

This project was built as part of the technical assessment for the Full-Stack Developer position at Kapybara HQ.

πŸ“„ License

This project was created for assessment purposes. All rights reserved.

About

A production-ready blogging platform built with Next.js 16, featuring type-safe APIs, rich text editing, category management, and image uploads. Developed as part of the technical assessment for the Full-Stack Developer position at Kapybara HQ.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published