Architecture Diagram

This document gives a high-level view of how EduNest LMS fits together: the browser, the single Next.js application (pages and API), the serverless PostgreSQL database, object storage, the license server, and integration providers. EduNest is one deployable Next.js 16 app — there is no separate API server, no ORM, and no message broker.

System Diagram

TEXT
                          ┌──────────────────────────────────────────────┐
                          │                  BROWSER                      │
                          │  Public site · Admin panel · Learner portal · │
                          │  Instructor portal · Course player · Installer│
                          └───────────────────────┬──────────────────────┘
                                                  │  HTTPS (page loads + fetch /api/v1/*)
                                                  ▼
        ┌───────────────────────────────────────────────────────────────────────┐
        │                    NEXT.JS 16 APP  (App Router, React 19)              │
        │                                                                       │
        │   src/app                                                             │
        │   ├─ (site)        public website + storefront + checkout             │
        │   ├─ (auth)        learner / instructor account auth                  │
        │   ├─ admin/(panel) admin dashboard      (cookie: admin_token)         │
        │   ├─ learner       learner portal       (cookie: member_session)      │
        │   ├─ instructor    instructor portal    (cookie: member_session)      │
        │   ├─ learn/[slug]  course player                                      │
        │   ├─ install       first-run setup wizard                            │
        │   └─ api/v1/*      ROUTE HANDLERS = the API (256 route.ts files)      │
        │                                                                       │
        │   each handler →  ensure<Table>()  →  auth/permission  →  raw SQL     │
        │                                                                       │
        │   src/lib   db · auth · customer-auth · r2 · secrets · license        │
        │   src/core + src/product   channels · plugins · payments · adapters   │
        │                            (93 built-in add-ons)                      │
        └───┬───────────────┬────────────────┬────────────────┬────────────────┘
            │ SQL (HTTPS)   │ S3 API         │ HTTPS          │ HTTPS / SMTP
            ▼               ▼                ▼                ▼
     ┌────────────┐  ┌─────────────┐  ┌──────────────┐  ┌─────────────────────┐
     │ PostgreSQL │  │ Cloudflare  │  │   License    │  │  Integration         │
     │  (Neon,    │  │  R2 / S3    │  │   server     │  │  providers           │
     │ serverless)│  │  storage    │  │ (CreativeCape│  │  (payments / email / │
     │            │  │             │  │  RS256, off- │  │  sms / video / chat /│
     │ raw SQL,   │  │ uploads,    │  │  line verify)│  │  analytics / captcha)│
     │ no ORM     │  │ media       │  │              │  │  via add-ons         │
     └────────────┘  └─────────────┘  └──────────────┘  └─────────────────────┘

Client

The browser is served four experiences from the same application, separated by App Router route groups (and gated by their respective cookies):

  • Public site / storefront (src/app/(site)) — home, course catalog, course detail, bundles, blog, pages, cart, checkout, membership.
  • Admin panel (src/app/admin/(panel)) — dashboard, courses, customers, orders, blogs, settings, learning content, marketing, revenue, plugins. Gated by the admin_token cookie.
  • Learner portal (src/app/learner) and Instructor portal (src/app/instructor) — gated by the member_session cookie (one customers row, account_type of student or instructor).
  • Course player (src/app/learn/[slug]) and installer (src/app/install).

There is no separate single-page app or mobile-only client in this repository; all UI is rendered by Next.js server and client components, and all data access goes through /api/v1/*.

API

The API is route handlers, not a standalone server. Every route.ts under src/app/api is an endpoint; the repository contains 256 of them. The primary surface is versioned under /api/v1, with /api/install and /api/license outside the version prefix and an OpenAPI document at /api/openapi.json.

Representative /api/v1 resource segments:

TEXT
admin · analytics · blogs · brand · calendar-config · captcha · chat · chatbot ·
checkout · countries · coupons · course-categories · courses · cron · exams · faqs ·
forms · gallery · gift-cards · hero-slides · i18n · instructor · languages · learn ·
livechat · locations · pages · plugins · portal · tax-config · testimonials · video

Each handler typically (1) calls the relevant ensure*() schema function, (2) checks auth (getSession() for admin, getCustomerId() for portal) and per-route permissions on admin routes, (3) runs raw SQL, and (4) returns JSON.

Layer Diagram — Core vs Product

The extensibility system splits stable framework code (src/core) from swappable add-ons (src/product). Add-ons are aggregated at build time into generated index files, which the core registries import.

TEXT
┌──────────────────────────────── src/core (stable contracts + registries) ───────────────┐
│                                                                                          │
│  channels/registry.ts  → CHANNELS  = mergeChannels(                                      │
│       email (FREE: SMTP), payments (FREE: COD/Bank/PayPal), storage (FREE: S3/R2/GCS),   │
│       analytics (FREE: GA4), video (FREE: YouTube/Vimeo),  …ADDON_CHANNELS )             │
│                                                                                          │
│  plugins/registry.ts   → FEATURES  = [ …ADDON_FEATURES ]      (FeaturePlugin contract:   │
│       nav · admin/learner/public pages · api · hooks · ensureSchema · settings)          │
│                                                                                          │
│  payments/registry.ts  → PAYMENT_DRIVERS = [ cod, bank, paypal, …serverAdapters(payment)]│
│                                                                                          │
│  adapters/client.ts·server.ts → clientAdapters(kind) / serverAdapters(kind)              │
│       resolve a provider implementation by kind + provider at runtime                    │
└───────────────────────────────────────────▲────────────────────────────────────────────┘
                                             │ imports the GENERATED indexes
┌────────────────────────── src/product (add-ons + generated aggregation) ─────────────────┐
│                                                                                          │
│  addons/<id>/   (93 folders)   addon.json  +  index.ts  (+ schema.ts / api.ts / *.tsx)   │
│     feature add-ons  → certificates, gamification, exams, assignments, forums, …         │
│     provider add-ons → payments-stripe, payments-razorpay, email-sendgrid,               │
│                        analytics-clarity, video-mux, calendar-google_calendar, …         │
│                                                                                          │
│  addons/index.ts            [GENERATED] → ADDON_CHANNELS                                  │
│  features/index.ts          [GENERATED] → ADDON_FEATURES                                 │
│  adapters-server/index.ts   [GENERATED] → ADDON_SERVER_ADAPTERS  (by kind)               │
│  adapters-client/index.ts   [GENERATED] → ADDON_CLIENT_ADAPTERS  (by kind)               │
│                          (produced by scripts/bundle-addons.mjs — do not hand-edit)      │
└──────────────────────────────────────────────────────────────────────────────────────────┘

The same relationships expressed as a Mermaid graph:

MERMAID
graph TD
  B[Browser] -->|HTTPS| APP[Next.js 16 App]
  subgraph APP[Next.js 16 App Router]
    SITE["(site) storefront"]
    ADMIN["admin/(panel)"]
    LEARN[learner portal]
    INST[instructor portal]
    API["api/v1/* route handlers"]
    CORE[src/core registries]
    PROD[src/product add-ons]
  end
  PROD -->|generated indexes| CORE
  API -->|raw SQL| DB[(PostgreSQL / Neon)]
  API -->|S3 SDK| R2[(Cloudflare R2 / S3)]
  APP -->|offline RS256 verify + heartbeat| LIC[License server]
  API -->|via add-ons| INTG[Payments / Email / SMS / Video / Analytics]

Database

  • Engine: PostgreSQL, hosted on Neon, reached through @neondatabase/serverless (HTTP-based driver) from src/lib/db.ts.
  • No ORM, no migration tool. Tables are created and evolved by idempotent ensure*() functions (CREATE TABLE IF NOT EXISTS + ALTER TABLE … ADD COLUMN IF NOT EXISTS) defined in src/lib/vendor-schema.ts, src/lib/lms-schema.ts, scripts/init-db.ts, and per-add-on schema.ts files.
  • The model covers the LMS domain (courses → sections → lessons, enrollments, lesson progress, instructors, bundles, quizzes, surveys, certificates) plus commerce (transactions, instructor earnings, payouts, coupons, gift cards) and a CMS (blogs, pages, FAQs, hero slides, testimonials). See the Database Documentation.

Storage

  • File uploads are sent to Cloudflare R2 (or any S3-compatible bucket) through the AWS S3 SDK in src/lib/r2.ts.
  • The active storage provider and credentials are read from the integration_connections table (channel STORAGE), encrypted with AES-256-GCM, with R2_* environment variables as a fallback.
  • Images can be transformed with sharp (configurable thumbnail dimensions/format) before upload. Clients receive the public object URL.

Third-Party Services

Provider Used for
Neon Managed serverless PostgreSQL
Cloudflare R2 / S3-compatible Object storage (course media, images, attachments)
CreativeCape license server Domain license activation + heartbeat (RS256, verified offline)
SMTP / email providers Transactional email (verification, OTP, notifications)
Payment gateways Course/bundle checkout (COD, Bank, PayPal free; Stripe, Razorpay… as add-ons)
SMS / WhatsApp OTP + notifications (Twilio, Msg91, WA Cloud — add-ons)
Video hosts Lesson video (YouTube/Vimeo free; Bunny, Cloudflare Stream, Mux — add-ons)
Analytics / pixels GA4 (free); Clarity, GTM, Meta Pixel, PostHog, TikTok — add-ons
Captcha / live chat / chatbot reCAPTCHA, Crisp/Intercom/Tawk…, OpenAI/Anthropic/OpenRouter — add-ons

Which providers are active is resolved at runtime from admin-configured integration_connections, and provider code ships in the corresponding add-on — so integrations activate without changing core code. Secrets are stored encrypted and never returned to the client in plaintext.


© CreativeCape Solutions · creative-cape.com · support@creative-cape.com