Skip to content

Repository files navigation

Lumina LMS

A modern, self-contained learning management system.

Courses, quizzes, SCORM, progress tracking, analytics and user management, built with Next.js (App Router), TypeScript, Tailwind CSS and SQLite. No external services required: the database is a local file, created and seeded automatically on first run.

The Lumina LMS landing page

Course catalogue Lesson player
Course catalogue with search and category filters Distraction-free lesson player with a course sidebar and completion ticks
Course builder Analytics and reports
Course curriculum builder with modules and inline lessons Analytics dashboard with trend charts and per-course engagement

Why it exists

Running a small course library usually means choosing between a hosted LMS — priced per active user, with your content in someone else's database — and one of the self-hosted veterans, which want a web server, a database server, a PHP runtime and a weekend to configure.

Lumina is one process and one SQLite file. npm install && npm run dev gives you a working LMS with demo content, and the Docker image needs nothing beside it. Back up one directory and you have backed up everything: the database, the extracted SCORM packages and the uploaded images.

It is batteries-included on purpose — courses, quizzes, SCORM, progress, analytics and user management are all in the box, with no plugins to hunt down.

What it does

For learners

  • Course catalogue — browse published courses with search and category filters. Each course page shows the full content outline, instructor and estimated time before you enrol.
  • Distraction-free lesson player — rich markdown lessons with code blocks, optional YouTube and Vimeo embeds, a course sidebar with completion ticks, mark-complete tracking, and previous/next navigation.
  • Auto-graded quizzes — multiple-choice checks per module with pass thresholds, per-question feedback and attempt history. Correct answers never leave the server before submission.
  • Personal dashboard — enrolled courses with progress bars, completion stats, and a "pick up where you left off" flow.

Course detail page with progress

For instructors

  • Course builder — create courses, structure them into modules, and add lessons and quizzes inline. Publish and unpublish with one click and view per-student progress. Course banners can be a solid colour or an uploaded image.
  • Markdown lesson editor — a formatting toolbar plus a live Preview tab that renders exactly like the lesson player, so what you write is what students see.
  • SCORM support — upload SCORM 1.2 or SCORM 2004 zip packages (Articulate, Captivate, iSpring and others) as lessons. The built-in runtime exposes the SCORM JavaScript API, persists the CMI data model (completion, score, suspend data) for resume, and mirrors completion into normal lesson progress.
  • SCORM library — upload a package once, attach it to any number of courses, see per-package usage, and safely delete unused packages. Deletion is blocked while lessons still reference a package.
  • Course review schedules — give each course a review period (3, 6, 12 or 24 months). A staff review dashboard flags what is overdue or due soon, tracks last-reviewed and last-updated timestamps, and offers one-click "Mark reviewed".
  • Enrolment policies — courses are either open to self-enrolment or "by allocation only": staff assign individual students or whole account groups, and allocation-only courses hide the enrol button behind an explanatory note.
  • Recycle bin — deleting a course soft-deletes it. Content and student progress are preserved, and courses can be restored or permanently purged later.
  • Staff preview — instructors and admins never enrol: every course on the platform is viewable directly in a clearly marked preview mode, while managing stays limited to the owning instructor or an admin.

Markdown lesson editor with a live preview tab

For admins

  • User management — create users, change roles, enable and disable accounts (live sessions end immediately), reset passwords, and organise users into account groups for bulk course allocation.
  • Analytics and reports — platform activity at a glance: active users, logins, lesson views, enrolments, completions, quiz pass rates, trend charts, and per-course engagement — each downloadable as CSV.

Admin dashboard with user management

Platform

  • Auth and roles — email and password accounts with HMAC-signed cookie sessions; student, instructor and admin roles enforced server-side.
  • Single-file database — SQLite via better-sqlite3, with schema migration and demo seeding handled automatically on first request.
  • No client-heavy stack — server components fetch data directly; small client components handle interactivity; a dependency-free markdown renderer displays lesson content.

Run it

With Docker (recommended)

The published image means you can deploy on any server with Docker — no source checkout, no local build. You need just two files side by side: compose.yaml and a .env holding your SESSION_SECRET.

curl -fsSL https://raw.githubusercontent.com/authorTom/lumina-lms/main/compose.yaml -o compose.yaml
printf 'SESSION_SECRET=%s\n' "$(openssl rand -base64 32)" > .env

docker compose pull
docker compose up -d

Open http://localhost:3000 and sign in with a demo account. Run docker compose ps — the container shows healthy once it is ready. The database is created and seeded on first request.

Deploying through a UI such as Dockge or Portainer? Paste the contents of compose.yaml into the stack editor and add SESSION_SECRET in the stack's environment field. The stack pulls ghcr.io/authortom/lumina-lms:latest directly — nothing is built on the server.

Updating:

docker compose pull && docker compose up -d

To build the image locally rather than pull it, comment out the image: line in compose.yaml, uncomment the build: block, then run from a full checkout:

cp .env.example .env          # then set SESSION_SECRET in .env
docker compose up -d --build

Or with plain Docker:

docker build -t lumina-lms .
docker run -d --name lumina \
  -p 3000:3000 \
  -e SESSION_SECRET="$(openssl rand -base64 32)" \
  -v lumina-data:/app/data \
  lumina-lms

The app ships as a self-contained image built from Next.js standalone output: a multi-stage build that compiles the native SQLite module, then copies only the runtime server, static assets and public/ into a slim Debian base running as an unprivileged user.

From source

npm install
npm run dev

Open http://localhost:3000. The SQLite database (data/lms.db) is created and seeded with demo courses and users on first request.

For production: npm run build && npm start.

Demo accounts

All demo accounts use the password password123:

Email Role
student@lms.dev Student (enrolled in two courses with some progress)
sarah@lms.dev Instructor (owns two courses)
james@lms.dev Instructor (owns two courses)
admin@lms.dev Admin

Configuration

Variable Default What it does
SESSION_SECRET Signs session cookies. Required in production
PORT 3000 Port the server listens on

SESSION_SECRET is required. In production (NODE_ENV=production) the app refuses to sign sessions without it — the container starts, but logging in throws. Generate one with openssl rand -base64 32, and keep the value stable across deploys, or all existing sessions are invalidated.

Uploads are capped at 200 MB (SCORM) via the server action body-size limit. Put a reverse proxy in front for TLS and its own request-size limits in production.

Everything else — courses, users, roles, review schedules, enrolment policies — is managed inside the app.

How it's built

  • lib/db.ts — SQLite connection, schema migration, and first-run seeding
  • lib/auth.ts — HMAC-signed cookie sessions and role guards
  • lib/data.ts — typed read queries
  • lib/actions.ts — server actions for every mutation (auth, enrolment, progress, quiz grading, authoring, admin)
  • app/ — App Router pages; server components fetch data directly, small client components handle interactivity
  • components/ — shared UI, including a dependency-free markdown renderer for lesson content

All state — the SQLite database, extracted SCORM packages and uploaded images — lives under /app/data, exposed as a volume so it survives container restarts and image upgrades.

Backing up

Back up the volume, not the container — everything persistent is in /app/data:

docker run --rm -v lumina-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/lumina-backup.tar.gz -C /data .

Licence

MIT — see LICENSE.

About

Lumina — a modern, self-contained learning management system built with Next.js, TypeScript, Tailwind, and SQLite

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages