A full-stack LMS (Learning Management System) built with Next.js 16 App Router, Auth.js v5, Prisma 7, and Neon Postgres. Designed for course creators who want a clean, production-ready starter to scale and manage their digital education business.
Live demo: https://techwithphantom.vercel.app/
- Overview
- Screenshots
- Key Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables
- Database & Prisma
- Deployment
- License
Tech with Phantom is a full-stack LMS platform that includes:
- A public landing page for marketing and course promotion
- A course directory with search and category filtering
- Course curriculum pages with lesson lists and free preview lessons
- An LMS viewer for authenticated learners
- Auth system with Email/Password and Google OAuth
- A learner dashboard with profile, orders, memberships, and settings pages
The modern, responsive landing page showcasing the platform with hero section, features, and call-to-action.
Clean authentication interface with email/password and Google OAuth options.
Browse and search through available courses with filtering and sorting capabilities.
- Authentication: Email/password + Google OAuth via Auth.js v5 with JWT sessions
- Course Directory: Searchable, filterable grid of published courses
- Lesson Viewer: Protected lesson player with sidebar navigation
- Free Preview: Individual lessons can be unlocked as free previews without auth
- Access Control:
/coursesroute is gated β only authenticated users can access - Learner Dashboard: Profile info, order history, membership status, account settings
- Responsive Design: Fully mobile-responsive across all pages
- SEO Ready: Proper
<title>,<meta description>, and semantic HTML on every page
flowchart TD
Browser["π Browser (User)"]
Browser -->|"Public route (/)"|Landing["Landing Page\n(Server Component)"]
Browser -->|"Auth route (/login, /register)"|Auth["Auth Pages\n(Client Component)"]
Browser -->|"Protected route (/courses, /profileβ¦)"|Guard["Auth Guard\n(auth() check)"]
Auth -->|"signIn() / register()"|AuthJS["Auth.js v5\n(JWT Strategy)"]
AuthJS --> DB["Prisma 7\n+ Neon Postgres"]
Guard -->|"session valid"|AppPages["App Pages\n(Server Components)"]
Guard -->|"no session"|Auth
AppPages -->|"Server Actions\n(src/actions/*)"|DB
DB --> Models["User Β· Course Β· Lesson\nEnrollment Β· Progress\nPlan Β· Subscription"]
style Browser fill:#f3f4f6,stroke:#6b7280
style AuthJS fill:#8b5cf6,stroke:#6d28d9,color:#fff
style DB fill:#f59e0b,stroke:#b45309,color:#fff
style Guard fill:#ef4444,stroke:#991b1b,color:#fff
style AppPages fill:#3b82f6,stroke:#0369a1,color:#fff
| Route | Type | Auth Required |
|---|---|---|
/ |
Public landing page | No |
/login |
Sign in | No |
/register |
Sign up | No |
/courses |
Course directory | β Yes |
/courses/[slug] |
Course curriculum | β Yes |
/courses/[slug]/lessons/[id] |
Lesson player | β Yes (or preview) |
/profile |
Learner profile | β Yes |
/orders |
Order history | β Yes |
/memberships |
Membership status | β Yes |
/settings |
Account settings | β Yes |
erDiagram
User ||--o{ Account : "OAuth accounts"
User ||--o{ Subscription : has
User ||--o{ Enrollment : enrolled
User ||--o{ Progress : tracks
Course ||--o{ Lesson : contains
Course ||--o{ Enrollment : enrollments
Lesson ||--o{ Progress : tracked_in
Plan ||--o{ Subscription : defines
User {
string id PK
string name
string email UK
string password
Role role
datetime createdAt
}
Course {
string id PK
string title
string slug UK
string description
boolean is_published
}
Lesson {
string id PK
string courseId FK
string title
string video_url
boolean is_preview
int order
}
Enrollment {
string id PK
string userId FK
string courseId FK
datetime started_at
}
Progress {
string id PK
string userId FK
string lessonId FK
boolean completed
}
Plan {
string id PK
string name
int price_monthly
int price_yearly
string stripe_price_id
}
Subscription {
string id PK
string userId FK
string planId FK
string status
datetime current_period_end
string stripe_subscription_id
}
| Layer | Tech |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 + Vanilla CSS (CSS Variables) |
| Fonts | Plus Jakarta Sans, Inter (Google Fonts) |
| Icons | react-icons |
| Validation | Zod |
| Service | Tech |
|---|---|
| Authentication | Auth.js v5 (JWT, Credentials + Google OAuth) |
| ORM | Prisma 7 |
| Database | PostgreSQL via Neon (serverless) |
| Server Logic | Next.js Server Actions (src/actions/) |
| DB Adapter | @prisma/adapter-neon |
| Aspect | Solution |
|---|---|
| Hosting | Vercel |
| CI/CD | Vercel Auto-Deploy |
| Database | Neon Postgres (serverless) |
| Version Control | Git + GitHub |
src/
βββ app/
β βββ (auth)/ # Login & Register pages
β β βββ login/
β β βββ register/
β βββ (dashboard)/ # Authenticated user pages
β β βββ layout.tsx # Shared header + sidebar layout
β β βββ profile/
β β βββ orders/
β β βββ memberships/
β β βββ settings/
β βββ api/auth/ # Auth.js route handler
β βββ courses/
β β βββ page.tsx # Course directory
β β βββ [slug]/
β β βββ page.tsx # Course curriculum
β β βββ lessons/
β β βββ [lessonId]/page.tsx # Lesson player
β βββ page.tsx # Landing page
β βββ layout.tsx # Root layout
β βββ globals.css # Design tokens + Tailwind
βββ actions/
β βββ auth.actions.ts # login(), register()
β βββ course.actions.ts # getCourseBySlug(), getLessonById()β¦
βββ auth.ts # Auth.js (PrismaAdapter + JWT callbacks)
βββ auth.config.ts # Providers: Google + Credentials
βββ components/
β βββ course/ # CourseCard, CoursesList, LessonSidebar
β βββ dashboard/ # DashboardSidebar
β βββ layout/ # Navbar, Footer, ProfileDropdown
β βββ sections/ # Landing page sections
β βββ ui/ # Shadcn-based: Button, Input, Login1
βββ hooks/
β βββ useScrollReveal.ts
βββ lib/
βββ db.ts # Prisma singleton
βββ utils.ts # cn() utility
prisma/
βββ schema.prisma
βββ seed.ts
- Node.js 18+
- A PostgreSQL database (recommend Neon β free tier available)
- Google OAuth credentials (optional, for Google login)
1. Clone the repository
git clone https://github.com/wayphantomme/tech-with-phantom.git
cd tech-with-phantom2. Install dependencies
npm install3. Set up environment variables
cp .env.example .env
# Fill in your values (see Environment Variables section below)4. Push database schema
npx prisma db push5. Seed sample data (optional)
npx prisma db seed6. Start development server
npm run devCreate a .env file in the project root:
# Database (Neon Postgres)
DATABASE_URL="postgresql://..."
# Auth.js
AUTH_SECRET="your-secret-here" # generate: openssl rand -base64 32
# Google OAuth (optional)
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""npx prisma db push # Push schema to database (no migration files)
npx prisma migrate dev # Create & apply a new migration
npx prisma db seed # Run seed.ts to insert sample courses
npx prisma studio # Open visual database browserThe Prisma client is exposed as a singleton via src/lib/db.ts using the @prisma/adapter-neon for serverless-compatible connections.
- Push this repo to GitHub
- Import the project into Vercel
- Set all environment variables in Vercel's project settings
- Deploy β Vercel auto-detects Next.js
Important:
DATABASE_URLandAUTH_SECRETare required in production. For Google OAuth, also setGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET, and addhttps://your-domain.com/api/auth/callback/googleto your Google Cloud Console redirect URIs.
This project is open-source and available under the MIT License.
