Розробка системи прогресу навчання (Progress Tracking) для LMS
Студенти кидають курси, якщо не бачать власного прогресу. Простий лічильник «5 з 20 уроків» не мотивує і не дає викладачеві інформації, хто відстає. Ми розробляємо систему прогресу навчання, яка збирає дані на рівні секунд: скільки відео переглянуто, які завдання виконані, як часто студент заходить. Ці дані лягають в основу аналітики та алертів. За роки роботи ми реалізували такі системи для десяти освітніх платформ — від невеликих шкіл до корпоративних університетів. Наш досвід гарантує, що система працюватиме під навантаженням і не втратить жодної події. Економія часу викладачів — до 30% за рахунок автоматичних сповіщень.
Які проблеми вирішує трекінг прогресу
Неактивні студенти. Без автоматичних сповіщень викладач дізнається про відтік постфактум. Наша система прогресу надсилає алерти викладачам, якщо студент не заходив 7 днів при незавершеному курсі. Це дозволяє вчасно втрутитися.
Низька залученість студентів. Streak (кількість днів поспіль) — потужний мотиватор. Ми розраховуємо його автоматично і показуємо в особистому кабінеті. Якщо streak скинуто, студент бачить, що потрібно повернутися.
Відсутність аналітики навчання. Activity events показують, які уроки найскладніші і де студенти переглядають відео. Наприклад, якщо 70% студентів перемотують певний фрагмент — контент потрібно доопрацювати.
Чому streak важливий для утримання?
Streak мотивує на 30% ефективніше, ніж просто лічильник. Якщо студент пропустив день — streak скидається до 1 (не до 0), що психологічно дає шанс відновити звичку. Ми бачили, як впровадження streak збільшило повернення на 40% за короткий термін на одній з платформ.
Як ми відстежуємо прогрес відео?
Використовуємо стек: React на фронті, Laravel на бекенді, PostgreSQL для зберігання, Redis для кешу активності. Приклад трекера відео:
// Frontend: відправка прогресу відео class VideoProgressTracker { constructor(videoElement, lessonId) { this.video = videoElement; this.lessonId = lessonId; this.maxReached = 0; this.setupListeners(); } setupListeners() { // Відправляємо прогрес при паузі, не при кожному timeupdate this.video.addEventListener('pause', () => this.reportProgress()); this.video.addEventListener('ended', () => this.markCompleted()); // Трекінг максимально переглянутої точки (не рахуємо перемотку назад) this.video.addEventListener('timeupdate', () => { const pct = (this.video.currentTime / this.video.duration) * 100; if (pct > this.maxReached) this.maxReached = pct; }); } async reportProgress() { await api.post(`/lessons/${this.lessonId}/progress`, { videoProgress: this.maxReached, lastPosition: Math.floor(this.video.currentTime), timeSpentSec: Math.floor(this.video.currentTime), }); } async markCompleted() { if (this.maxReached >= 85) { // Вважаємо урок переглянутим при 85% await api.post(`/lessons/${this.lessonId}/complete`); } } } Цей код надсилає прогрес лише на паузі — не на кожен timeupdate, щоб не перевантажувати сервер. Урок вважається завершеним при 85% перегляду.
Технічна реалізація
Модель даних
-- Прогрес по уроках CREATE TABLE lesson_progress ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), student_id UUID REFERENCES users(id), lesson_id UUID REFERENCES lessons(id), course_id UUID REFERENCES courses(id), status VARCHAR(30) DEFAULT 'not_started', -- not_started, in_progress, completed started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, time_spent_sec INT DEFAULT 0, video_progress NUMERIC(5,2), -- % перегляду відео last_position INT, -- секунда відео при останньому перегляді UNIQUE(student_id, lesson_id) ); -- Прогрес по курсу (агрегат) CREATE TABLE course_progress ( student_id UUID REFERENCES users(id), course_id UUID REFERENCES courses(id), lessons_completed INT DEFAULT 0, lessons_total INT NOT NULL, percentage NUMERIC(5,2) DEFAULT 0, last_activity_at TIMESTAMPTZ, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, streak_days INT DEFAULT 0, PRIMARY KEY(student_id, course_id) ); -- Детальний лог активності для аналітики CREATE TABLE activity_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), student_id UUID REFERENCES users(id), event_type VARCHAR(100) NOT NULL, -- 'video_played', 'video_paused', 'lesson_completed' entity_type VARCHAR(50), entity_id UUID, metadata JSONB DEFAULT '{}', -- position, duration, device, etc. created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX ON activity_events (student_id, created_at DESC); CREATE INDEX ON activity_events (entity_id, event_type); Як розраховується streak
Streak — кількість днів поспіль, коли студент виконував хоча б одну дію. Алгоритм:
async function updateStreak(studentId, courseId) { const lastActivity = await db.courseProgress.findOne({ studentId, courseId }, 'last_activity_at'); const today = new Date().toDateString(); const yesterday = new Date(Date.now() - 86400000).toDateString(); const lastDate = new Date(lastActivity.lastActivityAt).toDateString(); let streakDelta = 0; if (lastDate === today) { streakDelta = 0; // Вже оновлено сьогодні } else if (lastDate === yesterday) { streakDelta = 1; // Продовження streak } else { // Streak скинуто — починаємо заново з 1 await db.courseProgress.update({ studentId, courseId }, { streakDays: 1 }); return; } if (streakDelta > 0) { await db.courseProgress.increment({ studentId, courseId }, 'streak_days', 1); } } Виявлення відстаючих
Автоматичні алерти для викладачів:
- Студент не заходив 7+ днів при незавершеному курсі.
- Прогрес < 20% через 2 тижні після запису.
- Різке уповільнення темпу: минулий тиждень — 5 уроків, цей — 0.
-- Студенти, неактивні 7+ днів SELECT cp.student_id, u.name, u.email, cp.percentage, cp.last_activity_at FROM course_progress cp JOIN users u ON u.id = cp.student_id WHERE cp.course_id = $1 AND cp.completed_at IS NULL AND cp.last_activity_at < NOW() - INTERVAL '7 days'; Рівні трекінгу: порівняння
| Рівень | Що відстежуємо | Технічна складність | Приблизний час впровадження |
|---|---|---|---|
| Базовий | Кількість завершених уроків | Низька | 2–3 дні |
| Середній | Прогрес відео, streak, час сесії | Середня | 4–5 днів |
| Просунутий | Activity events, cohorts, алерти | Висока | 7–10 днів |
Ми реалізуємо рівень, який потрібен під ваші задачі. Найчастіше достатньо середнього — він дає 80% цінності при 50% зусиль.
Типові помилки при впровадженні трекінгу
| Помилка | Наслідок | Як уникнути |
|---|---|---|
| Відправка прогресу на кожен timeupdate | Високе навантаження на сервер, втрата даних при паузах | Використовуйте відправку тільки на паузі / завершенні |
| Скидання streak при відсутності активності | Демотивація студентів | Починайте streak з 1 після пропуску, а не з 0 |
| Зберігання всіх подій без архівування | Ріст таблиць до терабайтів | Використовуйте партиціонування та TTL-індекси |
Ці помилки ми усуваємо на етапі проектування. Наші інженери з багаторічним досвідом в LMS заздалегідь передбачають вузькі місця.
Процес впровадження
- Аналітика. Вивчаємо вашу LMS, список курсів, вимоги до звітів.
- Проектування. Проектуємо модель даних, API ендпоінти, схему подій.
- Реалізація. Пишемо backend на Laravel, frontend на React, інтеграцію з відео-плеєром.
- Тестування. Перевіряємо коректність збору даних, навантажувальне тестування.
- Деплой. Розгортаємо на вашому сервері або хмарі. Надаємо документацію.
Що входить в роботу
- Модель даних (міграції, індекси)
- API для запису та читання прогресу
- Frontend-компоненти (індикатори, прогрес-бар)
- Алерти викладачам (email/telegram)
- Дашборди LMS аналітики (кількість активних студентів, відсоток завершення)
- Інструкція з експлуатації
- 6 місяців гарантії на код
Терміни та вартість
Базовий трекінг (уроки + курс) — 3–4 дні. Додавання відео-трекінгу та streak — ще 2–3 дні. Аналітика та алерти — 3–4 дні. Підсумкова вартість розраховується індивідуально після аудиту вашої LMS. Напишіть нам — оцінимо проект за один робочий день. Отримайте консультацію щодо оптимального рівня трекінгу.
Чому варто обрати нас
Багаторічний досвід у розробці освітніх платформ. Реалізували 10+ проектів, обслуговуємо понад 5000 студентів. Знаємо, як працювати з PostgreSQL на мільйонах записів і не просідати по продуктивності. Використовуємо готові патерни — Repository, BFF, — щоб код був підтримуваним. Наші клієнти скорочують витрати на навчання на 25% і збільшують LTV студента на 30%. Зв'яжіться з нами для детального обговорення вашого проекту.







