A high-performance, SEO-optimized frontend for a full-stack blogging platform. Built with Next.js (App Router), TypeScript, and Shadcn UI, this project showcases the bleeding edge of modern web development features like Server Actions, advanced caching strategies, and streaming.
This frontend is designed to consume the Dockerized Express/Prisma Backend.
- Framework: Next.js 16+ (App Router)
- Language: TypeScript
- Styling: Tailwind CSS, Shadcn UI
- Icons: Lucide React
- Validation: Zod
- Forms: React Server Actions,
useActionState - Notifications: Sonner
- Animation: Framer Motion (optional integration ready)
- Server Components First: 95% of the application runs on the server for maximum performance and SEO.
- Advanced Caching: Utilizes React's
cache(), the'use cache'directive, andrevalidateTagfor granular, on-demand cache invalidation. - Streaming & Suspense: Implements granular
<Suspense>boundaries with Skeleton loaders to prevent blocking the UI while fetching data. - Dynamic SEO: Fully dynamic metadata generation for Open Graph, Twitter Cards, and Canonical URLs for every blog post.
- Middleware Protection: A robust
proxy.ts(middleware) handles route protection and Role-Based Access Control (RBAC). - HttpOnly Cookies: Authentication relies on secure cookies set by the backend, ensuring tokens are never exposed to client-side JavaScript.
- Server Actions: All mutations (Login, Register, Create Post, Update Profile) are handled via Server Actions, keeping API keys and logic off the client.
- Admin Dashboard: A secured dashboard with a Sidebar, Stats overview, and Data Tables.
- Interactive Search: Debounced search functionality with URL state management.
- Responsive Design: Fully mobile-responsive Navbar, Sidebar, and Layouts.
- Engagement: Users can read and post reviews on articles.
- Node.js (v18 or higher)
- Backend API Running: Ensure your Backend API is running on port
5000.
Clone the repository:
git clone https://github.com/devsafix/blog-app-client
cd blog-app-clientInstall dependencies:
npm installCreate a .env.local file in the root directory:
cp .env.example .env.localRequired Variables:
# The URL of your running backend (Express)
API_BASE_URL="http://localhost:5000/api/v1"
# Must match the JWT_SECRET in your backend .env (used for Middleware verification)
JWT_SECRET="your-super-secret-key-change-this"npm run dev
# The app will be available at http://localhost:3000src/
│── actions
│── app/
│ ├── (auth)/ # Login & Register routes (Auth Layout)
│ ├── (common)/ # Public routes (Home, Blog, About)
│ ├── dashboard/ # Admin/User Dashboard (Protected)
│ │ ├── posts/ # CRUD for Posts (Admin only)
│ │ ├── settings/ # User Profile Settings
│ │ └── page.tsx # Stats Overview
│ ├── layout.tsx # Root Layout with Toaster & Context
│ └── globals.css # Tailwind directives
│── components/
│ ├── dashboard/ # Sidebar, Header
│ ├── modules/ # Feature-specific components (ReviewForm, etc.)
│ ├── shared/ # Reusable (Navbar, Footer, Pagination)
│ └── ui/ # Shadcn UI primitives (Button, Input, etc.)
│── lib/
│ ├── actions.ts # Server Actions (Mutations)
│ ├── auth.ts # Auth utilities (JWT verification)
│ ├── data.ts # Data fetching (Cached functions)
│ └── utils.ts # CN helper
│── types/ # TypeScript interfaces
│── proxy.ts # Route protection & RBAC logic
We avoid useEffect for data fetching. Instead, we fetch directly in Server Components using lib/data.ts.
// Example: Cached Data Fetching
export async function getPostById(id: string) {
"use cache";
cacheTag(`post:${id}`);
// ... fetch logic
}We avoid API Routes (/api/auth/...) for mutations. Instead, we use Server Actions in lib/actions.ts.
// Example: Server Action
export async function createPostAction(formData: FormData) {
"use server";
// ... validate, fetch backend, revalidateTag('posts')
}The proxy.ts file runs on the Edge. It decodes the HttpOnly cookie to check for the user's role (ADMIN vs USER) before the request even reaches the layout, providing instant redirects for unauthorized access.
npm run dev # Start dev server with Turbopack
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLint- Fork the project
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request