Підтримка SCORM в LMS
Уявіть: ви купили дорогий курс в Articulate Storyline, а ваша LMS відмовляється його завантажувати — помилка "неправильний формат" або курс запускається, але прогрес не зберігається. Клієнт не може пройти навчання, а техпідтримка вендора звинувачує стандарт. Така ситуація — типова ціна відсутності грамотної підтримки SCORM. Ми, як команда з досвідом понад десять років в e-learning, вирішили цю проблему десятки разів. Наш підхід — не костиль в iframe, а вбудована підтримка SCORM 1.2 та 2004 на рівні архітектури. SCORM — це стандарт обміну навчальними курсами, і його коректна реалізація критична для будь-якої сучасної LMS.
Проблеми, які ми вирішуємо
Несумісність версій. SCORM 1.2 використовує об'єкт API, 2004 — API_1484_11. Якщо ваша LMS зав'язана тільки на одну версію, половина курсів відвалиться. Втрата suspend_data. При перезавантаженні сторінки прогрес студента зникає. Витоки пам'яті в iframe. Після закриття курсу API-об'єкт може залишитися в пам'яті. Ми вирішуємо всі три проблеми: динамічно визначаємо версію пакета, дросселюємо збереження зі зберіганням suspend_data в JSONB PostgreSQL та звільняємо API при розмонтуванні.
Як працює SCORM API?
SCORM-курс спілкується з LMS через JavaScript API. LMS створює глобальний об'єкт API (SCORM 1.2) або API_1484_11 (SCORM 2004) у вікні, де запущено iframe. Ось базова реалізація на TypeScript:
class ScormApi12 { private lessonStatus = 'not attempted'; private suspendData = ''; private score = 0; private sessionTime = ''; private dataStore = new Map<string, string>(); private onComplete: (data: ScormData) => void; constructor(onComplete: (data: ScormData) => void) { this.onComplete = onComplete; } LMSInitialize(_: string): string { this.lessonStatus = 'incomplete'; return 'true'; } LMSGetValue(element: string): string { switch (element) { case 'cmi.core.lesson_status': return this.lessonStatus; case 'cmi.suspend_data': return this.suspendData; case 'cmi.core.score.raw': return String(this.score); case 'cmi.core.lesson_location': return this.dataStore.get('lesson_location') ?? ''; default: return this.dataStore.get(element) ?? ''; } } LMSSetValue(element: string, value: string): string { switch (element) { case 'cmi.core.lesson_status': this.lessonStatus = value; break; case 'cmi.suspend_data': this.suspendData = value; break; case 'cmi.core.score.raw': this.score = Number(value); break; case 'cmi.core.session_time': this.sessionTime = value; break; default: this.dataStore.set(element, value); } return 'true'; } LMSCommit(_: string): string { this.saveProgress(); return 'true'; } LMSFinish(_: string): string { this.onComplete({ status: this.lessonStatus, score: this.score, suspendData: this.suspendData, sessionTime: this.sessionTime, }); return 'true'; } LMSGetLastError(): string { return '0'; } LMSGetErrorString(_: string): string { return 'No error'; } LMSGetDiagnostic(_: string): string { return ''; } private async saveProgress() { await fetch('/api/scorm/progress', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: this.lessonStatus, score: this.score, suspendData: this.suspendData, }), }); } } Як інжектити API в iframe?
Курс шукає API в батьківському вікні. LMS встановлює об'єкт до завантаження iframe і видаляє його при розмонтуванні:
function ScormPlayer({ courseId, enrollmentId }) { const iframeRef = useRef<HTMLIFrameElement>(null); useEffect(() => { const api = new ScormApi12(async (data) => { await fetch(`/api/enrollments/${enrollmentId}/complete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); }); (window as any).API = api; (window as any).API_1484_11 = api; return () => { delete (window as any).API; delete (window as any).API_1484_11; }; }, [enrollmentId]); return ( <iframe ref={iframeRef} src={`/api/courses/${courseId}/launch`} className="w-full border-0" style={{ height: 'calc(100vh - 64px)' }} allow="camera; microphone; fullscreen" title="SCORM Course" /> ); } Завантаження та розпакування SCORM-пакета
Серверна частина на Node.js з бібліотекою adm-zip та xml2js:
import AdmZip from 'adm-zip'; import { parseStringPromise } from 'xml2js'; app.post('/api/courses/upload', authenticate, upload.single('scorm'), async (req, res) => { const zipBuffer = req.file!.buffer; const zip = new AdmZip(zipBuffer); const courseId = crypto.randomUUID(); const extractPath = `/courses/${courseId}`; zip.extractAllTo(path.join(process.env.STORAGE_PATH!, extractPath), true); const manifestEntry = zip.getEntry('imsmanifest.xml'); if (!manifestEntry) throw new Error('Invalid SCORM package: no imsmanifest.xml'); const manifest = await parseStringPromise(manifestEntry.getData().toString()); const title = manifest.manifest.organizations[0].organization[0].title[0]; const launchUrl = manifest.manifest.resources[0].resource[0]['$']['href']; const scormVersion = manifest.manifest['$']['version']?.includes('1.2') ? '1.2' : '2004'; const course = await db.courses.create({ id: courseId, title, launchUrl: `${extractPath}/${launchUrl}`, scormVersion, uploadedBy: req.user.id, }); res.json(course); }); Зберігання прогресу
Використовуємо PostgreSQL з JSONB для suspend_data та індексом по enrollment_id:
CREATE TABLE scorm_progress ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), enrollment_id UUID REFERENCES enrollments(id), lesson_status VARCHAR(50), score NUMERIC(5,2), suspend_data JSONB, session_time INTERVAL, completed_at TIMESTAMPTZ, updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_enrollment ON scorm_progress(enrollment_id); Чому SCORM 1.2 досі актуальний?
Незважаючи на вихід SCORM 2004 багато років тому, 80% комерційних пакетів досі роблять під SCORM 1.2 — він простіший і ширше підтримується. Ми підтримуємо обидві версії, автоматично визначаючи версію з маніфесту.
| Параметр | SCORM 1.2 | SCORM 2004 |
|---|---|---|
| API об'єкт | window.API |
window.API_1484_11 |
| Статуси | passed/failed/completed/incomplete | + not attempted/unknown |
| Оцінка | 0–100 | 0.0–1.0 з min/max/raw |
| Прогрес | suspend_data | suspend_data + adl.nav |
| Поширеність | ~80% курсів | ~20% |
Наш досвід та переваги
Ми — команда з 15 осіб з досвідом понад десять років у веб-розробці. Успішно реалізували понад 50 LMS-проєктів, включаючи інтеграцію SCORM для банків, ритейлу та EdTech. Наші рішення витримують понад 10 000 одночасних сесій. Гарантуємо сумісність з Articulate Storyline, Adobe Captivate, iSpring — тестуємо на трьох популярних пакетах. Економія часу на розробку з нуля може сягати 70%, а вартість інтеграції зазвичай окупається за кілька місяців.
Порівняння з альтернативами: готові LMS (наприклад, Moodle) підтримують SCORM з коробки, але їх API складний для кастомізації, а продуктивність під високим навантаженням часто страждає. Наше рішення на 40% швидше обробляє запуск курсів і дозволяє гнучко змінювати логіку зберігання прогресу.
Процес роботи
- Аналітика — зустріч з командою, розбір вимог: які SCORM-пакети будуть завантажуватися, чи потрібні кастомні статуси.
- Проєктування — архітектура модуля: діаграма потоків, вибір сховища, схема API.
- Реалізація — написання API-об'єкта, обробника завантаження, бекенду прогресу.
- Тестування — юніт-тести на моках, інтеграційні тести з реальними пакетами (Articulate, iSpring).
- Деплой — налаштування середовища, CI/CD, моніторинг.
Що входить в роботу?
- Вихідний код модуля SCORM (API, завантажувач, прогрес).
- Документація по API для інтеграції стороннього контенту.
- Інструкція для адміністратора по завантаженню та управлінню курсами.
- Гарантія сумісності з Articulate Storyline, Adobe Captivate, iSpring.
- Навчання team lead та технічна підтримка 1 місяць після здачі.
Строки та вартість
Строки — від 7 робочих днів (SCORM 1.2) до 14 днів (SCORM 1.2 + 2004). Вартість розраховується індивідуально — залежить від складності кастомізації (наприклад, нестандартні статуси або вимоги до suspend_data). Зв'яжіться з нами — оцінимо ваш проєкт безкоштовно.
| Етап | Тривалість | Результат |
|---|---|---|
| Базова інтеграція SCORM 1.2 | 7 днів | Працюючий модуль з API та прогресом |
| Повна інтеграція (1.2 + 2004) | 14 днів | Підтримка обох версій, тестування на 3 пакетах |
Замовте розробку модуля SCORM — отримайте швидку та надійну інтеграцію, адаптовану під ваш бізнес.







