Skip to content

Repository files navigation

Simple LMS

A small learning management system for non-profits that have to prove staff and volunteers completed required training.

For the learner: sign in, see what's due, click Start, finish, close the tab. No course catalogue, no profile, no gamification.

For the administrator: upload a SCORM package, put people in groups, assign training with a deadline and a renewal interval, and hand an auditor a report saying exactly who completed what and when.

It exists because the alternatives are either enterprise products priced per seat, or Moodle — which is a fine piece of software and vastly more than a small charity needs to record that eleven people did their safeguarding training.

Node 22.6+ · SQLite · no database server · no external services required

What it does

SCORM 1.2 A real runtime. Upload the .zip from Articulate Storyline or Rise, iSpring, Lectora, Captivate, or any SCORM 1.2 tool. The LMS reads imsmanifest.xml, serves the package, and records completion, score, bookmark and time from the course's own signals.
Completion isn't self-reported An administrator cannot mark someone complete. The record is written only when the course reports it. If a package declares a mastery score, a lower score is recorded as not passed.
Resume Close the tab mid-course and pick up where you left off. suspend_data and lesson_location are kept per person.
Groups Assign to everyone, to a group, or to one person.
Annual renewals Set training to repeat every 12 months. On completion the next cycle is scheduled and reappears 30 days before it's due. Each cycle is a separate dated record, so "completed annually for three years" is provable.
Email reminders People are emailed when training is assigned, again as the deadline nears, and chased while overdue — on a schedule set per assignment. Deduplicated in the database, so a restart can't send anything twice.
Audit report A compliance matrix on screen, a CSV export, and a printable report with per-course summaries, per-person detail, traceable record IDs and a signature line.
Activity log Append-only. Sign-ins, uploads, assignment changes, completions, report exports. Nothing in the app edits or deletes it.
Multi-tenant Every record scoped to an organization; one organization's administrators never see another's. A platform owner can switch between them — useful if you run training on behalf of several charities.
Self-service accounts People are emailed a one-time link to choose their own password. No administrator ever handles a password. Forgotten passwords reset by email.

Try it in two minutes

npm install
npm run seed          # creates the database and a demo organization
npm run dev           # http://localhost:3000

Sign in as admin@example.org / admin1234, or as a learner with maria@example.org / welcome1234.

No SCORM package to hand? npm run sample-course writes one — a valid SCORM 1.2 package with a question and a mastery score, so you can watch a pass and a fail flow through to the report.

Running it for real

DEPLOY.md covers Render (about $10/month, entirely in a browser), Docker, and bare Node, plus email, backups and configuration.

SECURITY.md — please read the first section before you let anyone upload a course. It matters more than anything else in this file.

Documentation

Both are Markdown so you can adapt the wording and send them as your own.

How it fits together

src/lib/
  db.ts             SQLite connection, schema and migrations
  auth.ts           scrypt passwords, signed session cookies, route guards
  tokens.ts         one-time links for setting and resetting passwords
  ratelimit.ts      sign-in throttling
  scorm.ts          zip extraction, imsmanifest.xml parsing, MIME types
  scorm-api.ts      the SCORM 1.2 runtime object — no React, no DOM, unit tested
  enrollments.ts    turns assignment rules into per-person enrollments, incl. renewals
  reporting.ts      the compliance matrix and its totals
  notify.ts         which reminder is due for whom, and sending it
  mail.ts           Resend, and the email templates
  audit.ts          append-only event log

src/app/
  page.tsx                    learner dashboard — the whole learner experience
  learn/[id]/                 full-screen player; installs window.API, then the iframe
  record/[id]/                printable certificate of completion
  api/scorm/[courseId]/...    serves package files (auth and enrollment checked)
  api/attempt/[id]/           receives runtime state; the only place completion is decided
  admin/                      courses, people, groups, assignments, reports, email, activity log

Data model. An assignment is a rule: this course, for these people, due in this many days, repeating every so often. syncEnrollments() turns rules into enrollments — one per person per course per cycle, each with its own due date and status. Each enrollment has one attempt holding the SCORM runtime state. Reports read the enrollment currently in force; older cycles remain as history.

Decisions worth knowing about

  • Stopping an assignment deletes only unfinished enrollments. Completed records are never removed, so past compliance stays provable.
  • Archiving a course keeps every completion attached to it.
  • Deactivating a person keeps their history and drops them from the compliance percentage.
  • Moving someone between organizations leaves their completed records with the organization where they were earned, and they still appear in that organization's report.
  • A scheduled future renewal doesn't count against your compliance rate until it opens.

Tests

npm test

Roughly 220 checks: the SCORM runtime against the spec's error codes and data model, backup and restore against a stand-in for Backblaze, sign-in and invitation flows driven the way a browser drives them, multi-tenant isolation, the reminder engine against a stand-in for Resend, and a few guards against mistakes already made once — a GET that changed state, a timestamp comparison that hid anything dated today, a button that swallowed its own form data.

Some tests need npm run build first and skip themselves without it.

Limits

  • SCORM 1.2 only. SCORM 2004 and xAPI/cmi5 packages won't run. Most compliance vendors still ship 1.2; ask for it.
  • Single SCO per package. Multi-SCO packages launch the first one; there's no sequencing.
  • Uploads over ~100 MB need object storage rather than a local disk, because most hosts cap request bodies around there.
  • SQLite suits a few hundred people per organization comfortably. Well past that, move to Postgres — the queries are plain SQL.
  • Due dates are computed in UTC, so "due today" can read a day off for users far from it.
  • No alerting if a nightly backup fails. It appears in the logs; nobody is told.

Contributing

Issues and pull requests welcome. npm test should pass, and please add a test alongside a fix — most of the suite exists because something broke in a way nobody noticed.

Licence

MIT — see LICENSE.

About

A small SCORM learning management system for non-profits that need to prove staff completed required training.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages