Студенты бросают курсы, если не видят собственного прогресса. Простой счётчик «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%. Свяжитесь с нами для детального обсуждения вашего проекта.







