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







