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
┌──────────────────────────────────────────────┐
│ 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 theadmin_tokencookie. - Learner portal (
src/app/learner) and Instructor portal (src/app/instructor) — gated by themember_sessioncookie (onecustomersrow,account_typeofstudentorinstructor). - 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:
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.
┌──────────────────────────────── 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:
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) fromsrc/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 insrc/lib/vendor-schema.ts,src/lib/lms-schema.ts,scripts/init-db.ts, and per-add-onschema.tsfiles. - 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_connectionstable (channelSTORAGE), encrypted with AES-256-GCM, withR2_*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