A modern, full-stack blog platform built with React/TypeScript frontend and Cloudflare Workers backend, styled like Medium.
- Modern React Architecture: Built with Vite, TypeScript, and functional components
- State Management: Recoil for optimized state management with minimal re-renders
- Responsive Design: Mobile-first design with Tailwind CSS
- Medium-style UI: Clean, minimalist design following Medium's aesthetic
- Authentication: JWT-based authentication with protected routes
- Blog Management: Create, edit, view, and manage blog posts
- Search & Filtering: Search blogs by title/content and filter by tags
- Optimistic Updates: Smooth UX with loading states and error handling
- Serverless Architecture: Cloudflare Workers with Hono framework
- Database: PostgreSQL with Prisma ORM
- Authentication: JWT-based auth with secure password hashing
- Rate Limiting: Endpoint-specific rate limiting
- Validation: Zod schemas for request validation
- CORS & Error Handling: Global middleware for cross-origin requests and error handling
medium-blog/
├── backend/ # Cloudflare Workers backend
│ ├── src/
│ │ ├── controllers/ # Business logic
│ │ ├── middleware/ # Rate limiting, auth, CORS
│ │ ├── routes/ # API routes
│ │ ├── services/ # Database and auth services
│ │ ├── validators/ # Zod schemas
│ │ └── types/ # TypeScript types
│ ├── prisma/ # Database schema and migrations
│ └── wrangler.jsonc # Cloudflare Workers config
├── frontend/ # React frontend
│ ├── src/
│ │ ├── components/
│ │ │ ├── ui/ # Reusable UI components
│ │ │ ├── layout/ # Header, Layout, Sidebar
│ │ │ └── blog/ # Blog-specific components
│ │ ├── hooks/ # Custom React hooks
│ │ ├── pages/ # Route components
│ │ ├── services/ # API service layer
│ │ ├── store/ # Recoil state management
│ │ ├── styles/ # Tailwind CSS and component styles
│ │ ├── types/ # TypeScript interfaces
│ │ └── utils/ # Utility functions
│ ├── public/ # Static assets
│ ├── index.html # HTML template
│ ├── package.json # Frontend dependencies
│ └── vite.config.ts # Vite configuration
- React 18 with TypeScript
- Vite for build tooling
- Tailwind CSS for styling
- Recoil for state management
- React Router for routing
- Axios for API requests
- Lucide React for icons
- Cloudflare Workers (Serverless)
- Hono framework
- PostgreSQL database
- Prisma ORM
- Zod for validation
- JWT for authentication
- Node.js 18+
- PostgreSQL database
- Cloudflare account (for deployment)
-
Navigate to backend directory:
cd backend -
Install dependencies:
npm install
-
Set up environment variables: Create
.envfile in backend directory:DATABASE_URL="postgresql://username:password@host:port/database" DIRECT_URL="postgresql://username:password@host:port/database" JWT_SECRET="your-jwt-secret"
-
Run database migrations:
npx prisma migrate dev npx prisma generate --no-engine
-
Start development server:
npm run dev
Backend will be running at http://localhost:8787
-
Navigate to frontend directory:
cd frontend -
Install dependencies:
npm install
-
Set up environment variables: Create
.env.localfile in frontend directory:VITE_API_BASE_URL=http://localhost:8787/api/v1
-
Start development server:
npm run dev
Frontend will be running at http://localhost:5174
POST /api/v1/signup- User registrationPOST /api/v1/signin- User login
GET /api/v1/blog/:id- Get specific blogPOST /api/v1/blog- Create new blogPUT /api/v1/blog/:id- Update blog
GET /api/v1/user/profile- Get user profilePUT /api/v1/user/profile- Update profilePUT /api/v1/user/password- Change passwordGET /api/v1/user/blogs- Get user's blogsDELETE /api/v1/user/account- Delete account
GET /api/v1/public/blogs- Get published blogs (with pagination/search)GET /api/v1/public/blog/:id- Get public blogGET /api/v1/public/author/:id/blogs- Get author's blogsGET /api/v1/public/tags- Get popular tags
- Component Composition: Reusable UI components with consistent props interface
- Custom Hooks: Business logic separated into custom hooks (
useAuth,useBlogs) - Optimized Rendering: Recoil selectors prevent unnecessary re-renders
- Error Boundaries: Graceful error handling throughout the app
- Loading States: Skeleton screens and loading indicators
- Utility-First: Tailwind CSS for rapid development
- Component Classes: Custom CSS classes in
components.cssfor complex components - Medium Aesthetic: Clean typography, generous whitespace, subtle shadows
- Responsive Design: Mobile-first with progressive enhancement
- User signs up/signs in via
/signupor/signin - Backend returns JWT token
- Token stored in localStorage and automatically included in API requests
- Protected routes check authentication status
- Token refresh handled automatically
- Password Hashing: Secure bcrypt hashing
- JWT Authentication: Stateless authentication
- Rate Limiting: Request throttling per endpoint
- Input Validation: Zod schemas validate all inputs
- CORS Protection: Configured for cross-origin requests
- SQL Injection Protection: Prisma ORM parameterized queries
-
CORS Errors:
- Ensure backend CORS middleware includes your frontend URL
- Default ports: Backend (8787), Frontend (5174)
-
Database Connection Issues:
- Verify
DATABASE_URLandDIRECT_URLin.env - Run
npx prisma migrate devto apply migrations - Check database connectivity
- Verify
-
React/Recoil Compatibility:
- Use React 18.2.0 (not React 19) for Recoil compatibility
- Clear browser cache if experiencing stale API calls
-
Wrangler Version Issues:
- Use Wrangler 4.33.2+ for latest compatibility
- Update with
npm install wrangler@4.33.2
-
API Endpoint Mismatches:
- Frontend calls
/api/v1/public/blogs - Backend serves at
/api/v1/public/blogs - Clear browser cache if seeing wrong endpoints
- Frontend calls
cd backend
npm run deployBuild the frontend and deploy to any static hosting service:
cd frontend
npm run build
# Deploy dist/ folder to Vercel, Netlify, etc.