An opinionated Next.js app (App Router) for an online learning platform — courses, chapters, enrollments and a workspace for course creators.
Live preview: run locally with the steps in the Setup section.
Key highlights
- Frontend and backend combined in a Next.js App Router project.
- Server-side API routes under
app/api/*using Next.js route handlers. - Database access with Drizzle ORM against a PostgreSQL (Neon) database.
- Authentication with Clerk (pre-built
SignIn/SignUpcomponents).
Table of contents
- Project structure
- Tech stack
- Data model & database
- Backend & API integration
- Authentication
- Setup & environment
- How to contribute
Project Structure (high level)
app/— Next.js App Router pages, layouts, and server components.app/api/— server route handlers (REST endpoints) used by the frontend.app/(auth)/— Clerk sign-in / sign-up pages.app/workspace/— workspace UI for creators (course editor, lists, billing).
components/&app/_components/— shared UI components and smaller building blocks.config/— database and schema configuration (config/db.jsx,config/schema.js).public/screenshots/— placeholder images for the README and docs.drizzle.config.js— Drizzle configuration used to generate/migrate schema.
Tech stack
- Next.js (App Router) — frontend framework + server route handlers.
- React (server + client components mix).
- Tailwind CSS (project uses utility classes throughout the UI).
- Drizzle ORM — declarative typesafe queries against PostgreSQL.
- Neon (serverless Postgres) driver via
@neondatabase/serverless. - Clerk — user authentication and session management (
@clerk/nextjs).
Data model & database
- Schema lives in
config/schema.jsand is configured for PostgreSQL via Drizzle. - Drizzle config:
drizzle.config.jspoints to./config/schema.jsand usesdialect: 'postgresql'. - Database client:
config/db.jsxusesneon(process.env.DATABASE_URL)anddrizzleto createdb. - Primary tables (in the schema):
users,courses, andenrollCoursewith relations and JSON columns for course content and progress tracking.
Backend & API integration
- API routes are implemented as Next.js App Router route handlers under
app/api/*. - Server code imports
dbfromconfig/db.jsxand the table definitions fromconfig/schema.jsand uses Drizzle query builders (select,where,eq,desc,sql) to run queries. - Example:
app/api/courses/route.jsxreads the current authenticated user (via Clerk server helper) and returns courses filtered byuserEmailorciddepending on query params.
Authentication
- The app uses Clerk for auth. Client-side pages use
SignInandSignUpcomponents located underapp/(auth). - Server-side code uses Clerk's server helpers (for example
currentUser()from@clerk/nextjs/server) to access the authenticated user in API routes. - Authentication flow summary:
- Client opens
SignIn/SignUppage (Clerk handles UI and redirect flows). - On successful sign-in, Clerk issues session cookies or tokens for the domain.
- Server route handlers call Clerk's
currentUser()to get the user's identity and primary email. - The server uses that identity to scope DB queries (for example reading courses created by
user.primaryEmailAddress.emailAddress).
- Client opens
Environment & Setup
- Install dependencies
npm install- Create a
.env.localfile with at least the following variables:
DATABASE_URL— your Postgres/Neon connection string used byconfig/db.jsx.- Clerk env vars — see Clerk docs; commonly
CLERK_SECRET_KEYandNEXT_PUBLIC_CLERK_PUBLISHABLE_KEYor the environment variables your Clerk setup requires.
DATABASE_URL=postgres://user:pass@host:5432/dbname
# Clerk-specific environment values (follow Clerk docs for exact names)
CLERK_SECRET_KEY=...
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=...
- Run the dev server
npm run devNotes on migrations and Drizzle
- Drizzle is configured in
drizzle.config.js. Use the Drizzle/Drizzle Kit commands in your environment to create migrations or push schema changes (see Drizzle docs). - The schema file is
config/schema.jsand describes tables and column types (including JSON columns used to store course content and completed chapters).
How to contribute
- Clone the repo, run locally, and open a PR for features or fixes.
- Keep UI changes isolated to
components/orapp/_components/and API changes inapp/api/*.
Further reading & links
- Next.js App Router: https://nextjs.org/docs
- Drizzle ORM: https://orm.drizzle.team/
- Neon (Postgres serverless): https://neon.tech/
- Clerk: https://clerk.com/docs
Enjoy building!