Home Quizzes Leaderboard Competitions Learn Hire Us
About Contact
Log In Sign Up
Learn Next.js Final Project --- Full-Stack Learning Platform

Final Project --- Full-Stack Learning Platform

⏱ 30 min read read
What We Are Building:

A full-stack Learning Platform with courses, student enrolment, progress
tracking, and an admin dashboard --- using the complete Next.js 14
stack.

Features:

• Public course listing page (SSG + ISR)

• Individual course pages with dynamic metadata

• Student sign-up and authentication (NextAuth.js)

• Protected dashboard --- enrol, track progress

• Admin CRUD API (Route Handlers + Prisma)

• Form validation (React Hook Form + Zod)

• Responsive UI (Tailwind CSS + shadcn/ui)

• Deployed on Vercel with environment variables

Concepts Used in This Project:

Lesson 1 --- App Router, Server Components, 'use client'

Lesson 2 --- File-based routing, layouts, dynamic [slug] routes

Lesson 3 --- Data fetching, ISR (revalidate: 3600)

Lesson 4 --- Route Handlers for CRUD API

Lesson 5 --- Tailwind CSS styling

Lesson 6 --- TypeScript components and props

Lesson 7 --- useState, controlled forms

Lesson 8 --- useEffect, custom hooks (useDebounce)

Lesson 9 --- Server Actions, React Hook Form + Zod

Lesson 10 --- Prisma ORM with PostgreSQL

Lesson 11 --- NextAuth.js with GitHub provider

Lesson 12 --- Dynamic metadata for SEO

Lesson 13 --- next/image for course thumbnails

Lesson 14 --- next/link, useRouter, active nav

Lesson 16 --- Suspense + streaming, loading.tsx

Lesson 19 --- Deployment to Vercel

After This Course --- What to Build Next:

1. Add payments with Stripe and protected premium content.

2. Build a real-time chat with Pusher or Ably.

3. Explore tRPC for end-to-end type-safe APIs.

4. Add full-text search with Algolia or Meilisearch.

5. Contribute to open-source Next.js projects on GitHub.

-----------------------------------------------------------------------
Congratulations on completing all 20 Next.js lessons! 🎉

-----------------------------------------------------------------------
Code Example
// Full project structure

// my-learning-platform/

// ├── app/

// │ ├── (marketing)/ ← public pages group

// │ │ ├── layout.tsx ← marketing layout with nav

// │ │ ├── page.tsx ← homepage (SSG)

// │ │ └── courses/

// │ │ ├── page.tsx ← course listing (ISR)

// │ │ └── [slug]/page.tsx ← course detail (SSG + dynamic meta)

// │ ├── (auth)/

// │ │ ├── login/page.tsx ← sign in

// │ │ └── register/page.tsx ← sign up

// │ ├── dashboard/

// │ │ ├── layout.tsx ← protected layout

// │ │ ├── loading.tsx ← skeleton

// │ │ ├── page.tsx ← my courses

// │ │ └── progress/page.tsx

// │ ├── api/

// │ │ ├── auth/[...nextauth]/route.ts

// │ │ ├── courses/route.ts

// │ │ └── courses/[id]/route.ts

// │ └── layout.tsx ← root layout

// ├── components/

// │ ├── CourseCard.tsx

// │ ├── NavBar.tsx

// │ └── ProgressBar.tsx

// ├── lib/

// │ ├── prisma.ts

// │ └── env.ts

// ├── store/

// │ └── useProgressStore.ts ← Zustand

// ├── auth.ts

// ├── middleware.ts

// └── prisma/schema.prisma

// app/(marketing)/courses/page.tsx --- ISR course listing

import Image from 'next/image';

import Link from 'next/link';

import { Metadata } from 'next';

export const metadata: Metadata = { title: 'All Courses' };

export const revalidate = 3600; // re-build every hour

async function getCourses() {

const res = await
fetch(`${process.env.NEXT_PUBLIC_APP_URL}/api/courses`);

return res.json();

}

export default async function CoursesPage() {

const courses = await getCourses();

return (

<main className="max-w-6xl mx-auto px-4 py-12">

<h1 className="text-4xl font-bold mb-8">All Courses</h1>

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3
gap-6">

{courses.map((c: any) => (

<Link key={c.id} href={`/courses/${c.slug}`}

className="rounded-xl border hover:shadow-lg transition
overflow-hidden group">

<div className="relative h-48">

<Image src={c.thumbnail} alt={c.title} fill

sizes="33vw" style={{ objectFit: 'cover' }}

className="group-hover:scale-105 transition" />

</div>

<div className="p-4">

<h2 className="font-bold text-lg mb-1">{c.title}</h2>

<p className="text-gray-500 text-sm
line-clamp-2">{c.description}</p>

<div className="mt-3 flex gap-3 text-xs text-gray-400">

<span>📖 {c.lessonCount} lessons</span>

<span>⏱ {c.duration}</span>

</div>

</div>

</Link>

))}

</div>

</main>

);

}
← Deployment --- Vercel & Environment Vari ✓ Back to Course →

Log in to track your progress and earn badges as you complete lessons.

Log In to Track Progress