Skip to main content

Overview

EaseLMS is built on a modern, scalable architecture leveraging Next.js 16 with the App Router, TypeScript for type safety, and a monorepo structure managed by Turborepo. The system is designed to be self-hostable while maintaining cloud-native capabilities.

Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                        Client Layer                          │
│  Next.js App Router • React 19 • TanStack Query • Tailwind  │
└──────────────────┬──────────────────────────────────────────┘

┌──────────────────▼──────────────────────────────────────────┐
│                    Application Layer                         │
│  Server Components • API Routes • Server Actions • Middleware│
└──────────────────┬──────────────────────────────────────────┘

┌──────────────────▼──────────────────────────────────────────┐
│                     Service Layer                            │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ Supabase │  │   AWS    │  │ Payment  │  │  Email   │   │
│  │   Auth   │  │ S3/CDN   │  │ Gateways │  │ SendGrid │   │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘   │
└─────────────────────────────────────────────────────────────┘

┌──────────────────▼──────────────────────────────────────────┐
│                      Data Layer                              │
│            Supabase PostgreSQL with RLS                      │
└─────────────────────────────────────────────────────────────┘

Tech Stack

Frontend

  • Framework: Next.js 16 with App Router
  • Language: TypeScript 5.0+
  • UI Library: React 19
  • Styling: Tailwind CSS
  • Components: Radix UI + shadcn/ui
  • State Management: TanStack Query (React Query)
  • Forms: React Hook Form + Zod validation
  • Video Player: Media Chrome for HLS streaming

Backend

  • Runtime: Node.js 18.0+
  • Database: Supabase (PostgreSQL)
  • Authentication: Supabase Auth with Row Level Security (RLS)
  • File Storage: AWS S3 + CloudFront/Azure Front Door CDN
  • Video Processing: AWS MediaConvert for HLS transcoding
  • Payments: Stripe & Flutterwave
  • Email: SendGrid
  • PDF Generation: PDFKit with custom fonts

Infrastructure

  • Monorepo: Turborepo
  • Package Manager: npm 10.0+
  • Deployment: Vercel (recommended) or self-hosted
  • CDN: CloudFront or Azure Front Door

Monorepo Structure

EaseLMS uses Turborepo to manage a monorepo with multiple applications:
easelms/
├── apps/
│   ├── lms/                    # Main LMS application
│   │   ├── app/                # Next.js App Router
│   │   │   ├── admin/          # Admin dashboard
│   │   │   ├── learner/        # Learner interface
│   │   │   ├── api/            # API routes
│   │   │   └── auth/           # Authentication pages
│   │   ├── components/         # React components
│   │   ├── lib/                # Utilities and services
│   │   └── supabase/           # Database migrations
│   └── website/                # Marketing landing page
├── package.json                # Root workspace config
└── turbo.json                  # Turborepo configuration
easelms/ ├── apps/ │ ├── lms/ # Main LMS application │ │ ├── app/ # Next.js App Router │ │ │ ├── admin/ # Admin dashboard │ │ │ ├── learner/ # Learner interface │ │ │ ├── api/ # API routes │ │ │ └── auth/ # Authentication pages │ │ ├── components/ # React components │ │ ├── lib/ # Core libraries │ │ │ ├── aws/ # S3 & MediaConvert │ │ │ ├── supabase/ # Database & auth clients │ │ │ ├── payments/ # Payment integrations │ │ │ ├── certificates/ # PDF generation │ │ │ ├── email/ # Email service │ │ │ └── react-query/ # Query hooks & cache │ │ ├── hooks/ # Custom React hooks │ │ ├── utils/ # Utility functions │ │ ├── middleware.ts # Auth & CORS middleware │ │ └── supabase/ # Database migrations │ └── website/ # Marketing landing page ├── components/ # Shared components ├── package.json # Root workspace config └── turbo.json # Turborepo configuration

### Workspace Configuration

The monorepo uses npm workspaces with Turborepo for build optimization:

```json title="package.json"
{
  "name": "easelms-monorepo",
  "private": true,
  "workspaces": ["apps/*"],
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "lint": "turbo run lint"
  }
}

Turborepo Pipeline

turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

Application Architecture

Middleware Layer

The middleware handles authentication, session management, and CORS:
apps/lms/middleware.ts
import { updateSession } from "@/lib/supabase/middleware"
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"

export async function middleware(request: NextRequest) {
  // Handle CORS for API routes
  if (request.nextUrl.pathname.startsWith('/api/')) {
    const allowedOrigin = process.env.NEXT_PUBLIC_WEBSITE_URL || '*'
    
    if (request.method === 'OPTIONS') {
      return new NextResponse(null, {
        status: 200,
        headers: {
          'Access-Control-Allow-Origin': allowedOrigin,
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
        },
      })
    }
  }
  
  // Update Supabase session
  return await updateSession(request)
}

Route Protection

Routes are protected based on user type (admin, instructor, learner):
  • Public routes: /auth/*, /forgot-password
  • Admin routes: /admin/* (requires user_type = 'admin')
  • Learner routes: /learner/* (requires authenticated user)

Data Flow

  1. Client Request → Server Component/API Route
  2. Authentication → Supabase Auth validates session
  3. Authorization → Row Level Security (RLS) enforces permissions
  4. Data Fetching → TanStack Query with cache management
  5. Response → Server-rendered or JSON response

Database Schema

EaseLMS uses Supabase PostgreSQL with Row Level Security (RLS) policies:

Core Tables

  • profiles - User profiles with role-based access
  • courses - Course metadata and settings
  • lessons - Course content with video/resources
  • enrollments - Student course enrollments
  • progress - Lesson completion tracking
  • payments - Payment records
  • certificates - Generated certificates
  • quiz_questions, quiz_attempts, quiz_results - Assessment system
  • platform_settings - Branding and configuration

Row Level Security

All tables use RLS policies to enforce:
  • Admins can access all data
  • Instructors can access their courses
  • Learners can only access enrolled courses
  • Public can view published course listings

Caching Strategy

TanStack Query manages client-side caching with configurable stale times:
lib/react-query/cache-config.ts
export const CACHE_TIMES = {
  COURSES: 5 * 60 * 1000,      // 5 minutes
  LESSONS: 10 * 60 * 1000,     // 10 minutes
  PROFILE: 30 * 60 * 1000,     // 30 minutes
  SETTINGS: 60 * 60 * 1000,    // 1 hour
}

Cache Invalidation

  • Mutations automatically invalidate related queries
  • Realtime subscriptions update cache on data changes
  • Manual invalidation for critical updates

Deployment Architecture

┌──────────────┐
│   Vercel     │ ← Next.js App (SSR + API Routes)
└──────┬───────┘

       ├─────→ Supabase (Database + Auth)
       ├─────→ AWS S3 (File Storage)
       ├─────→ CloudFront/Azure FD (CDN)
       ├─────→ AWS MediaConvert (Video Processing)
       ├─────→ Stripe/Flutterwave (Payments)
       └─────→ SendGrid (Emails)

Scaling Considerations

  • Horizontal scaling: Next.js serverless functions auto-scale
  • Database: Supabase connection pooling
  • CDN: Global edge caching for video/assets
  • Video processing: Async job queue with MediaConvert

Performance Optimizations

  1. Server Components: Reduce client-side JavaScript
  2. HLS Streaming: Adaptive bitrate video delivery
  3. Image Optimization: Next.js automatic image optimization
  4. Code Splitting: Dynamic imports for heavy components
  5. Database Indexes: Optimized queries on frequently accessed tables
  6. CDN Caching: Static assets served from edge locations

Security Features

  • Authentication: Supabase Auth with email/password
  • Authorization: Row Level Security (RLS) policies
  • CORS: Configured middleware for cross-origin requests
  • Environment Variables: Secrets managed securely
  • Input Validation: Zod schemas for all forms
  • SQL Injection Protection: Parameterized queries via Supabase client

Development Workflow

# Install dependencies
npm install

# Start development servers (both apps)
npm run dev

# Build for production
npm run build

# Lint code
npm run lint

Environment Setup

Each app requires its own .env.local file:
apps/lms/.env.local
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_key
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key

Next Steps

Authentication

Learn about Supabase authentication implementation

File Storage

Explore AWS S3 and CDN integration

Video Processing

Understand video upload and HLS streaming

Build docs developers (and LLMs) love