ReactNode.jsPostgreSQLHLS-стримингLMSАнтипиратство

Из закрытого TG‑канала — в собственную LMS‑платформу

У клиента был платный закрытый Telegram-канал с обучающим видео для квест-бизнеса. После замедления Telegram в России смотреть видео стало невозможно. Мы построили полноценную образовательную платформу с нуля: собственный видеоплеер, три слоя защиты от пиратства, система прогресса, admin-панель и авторизация через Telegram.

Стек

React + Node.js

База

PostgreSQL

Видео

HLS + S3

Тип

LMS / EdTech

Кейс за 60 секунд

Клиент продавал доступ к закрытому Telegram-каналу с видеокурсом — после замедления Telegram бизнес встал. Подняли его на своей LMS.

Клиент и боль

Обучающий контент для владельцев квест-бизнеса. После замедления Telegram в России подписчики не могли смотреть оплаченное видео: буферизация, обрывы. Плюс прежние проблемы закрытого канала — нет прогресса, нет аналитики, контент легко утекает.

Что построили

Своя образовательная платформа (LMS — система для онлайн-обучения): видеоплеер на HLS (сегментированный стриминг как у Netflix), 3 слоя водяных знаков для идентификации утечек, вход через Telegram без паролей, прогресс/заметки/чек-листы, 8 страниц админки, режим «День открытых дверей» для конверсии.

Кому подойдёт

Инфобизнес и онлайн-школы, чей контент застрял в Telegram-канале, GetCourse или конструкторе — и которым нужна своя платформа с защитой от пиратства.

React 19Node.js + ExpressPostgreSQLHLS.jsS3
Посмотреть: под NDA

Проблема

Telegram замедлили — бизнес встал

Клиент продавал доступ к закрытому Telegram-каналу с видеоуроками для владельцев квестов. Контент был ценный, аудитория — платящая. Но после замедления Telegram в России всё развалилось:

Видео не грузится

После замедления Telegram в России видео в закрытом канале стало невозможно смотреть. Буферизация, обрывы, вечная загрузка — подписчики платили за контент, который не могли потребить.

Нет прогресса

В Telegram нет понятия «прогресс обучения». Пользователь прокрутил ленту, посмотрел ролик — и забыл. Где остановился, что пропустил, сколько осталось — неизвестно.

Контент утекает

Закрытый канал — это иллюзия защиты. Любой участник может переслать видео, скачать его, поделиться ссылкой. Никакой привязки к конкретному человеку.

Нет аналитики

Владелец канала не знал, кто вообще смотрит контент. Сколько людей зашли, что популярно, кто платит, а кто просто сидит — полная темнота.

Решение

Собственная LMS с нуля — без конструкторов и компромиссов

Почему не GetCourse / Tilda

Готовые платформы — это шаблоны, ограничения и ежемесячная плата за чужие серверы. Нет контроля над видеоплеером, нельзя встроить свою защиту от пиратства, нельзя авторизовать через Telegram. И главное — контент по-прежнему легко украсть.

Что мы построили

Полноценную образовательную платформу: собственный видеоплеер с HLS-стримингом, три уровня антипиратской защиты, авторизация через Telegram, система прогресса и заметок, admin-панель с аналитикой, 5 ролей пользователей. Всё своё — от первой строки кода до последнего API-эндпоинта.

В цифрах

Масштаб платформы

15+
таблиц в базе данных
5
ролей пользователей
3
слоя антипиратства
50+
API-эндпоинтов
720p
адаптивный стриминг
8
страниц admin-панели

Видеоплеер

Собственный видеоплеер — не iframe, не embed

Не YouTube, не Vimeo, не чужой embed-код. Мы написали видеоплеер с нуля на HLS.js — том же протоколе, который используют Netflix и Apple TV. Видео хранится на S3-хранилище, разбито на сегменты по 6–10 секунд и стримится адаптивно.

HLS-стриминг

Видео не скачивается целиком — загружается сегментами по 6–10 секунд через протокол HTTP Live Streaming. Как Netflix или YouTube. Нельзя просто «скачать файл» — его нет в одном месте.

Адаптивный битрейт

Два варианта качества: 720p и 480p. Плеер автоматически переключается между ними в зависимости от скорости интернета. Плохая связь — не буферизация, а снижение качества.

Presigned URLs

Каждый сегмент видео запрашивает временную подписанную ссылку на S3-хранилище. Ссылка живёт 1 час, потом становится бесполезной. Даже если кто-то перехватит URL — через час он мёртв.

Управление скоростью

Переключение скорости воспроизведения: 1x → 1.25x → 1.5x → 2x. Настройка сохраняется между сессиями. Удобно для повторного просмотра или когда спикер говорит медленно.

Блокировка скачивания

Отключено контекстное меню на видео, убрана кнопка скачивания из стандартных контролов, заблокирован режим «картинка в картинке». Максимально усложнён путь к сохранению видео.

Режим превью

Для видео длиннее 20 минут — демо-версия. Пользователь видит случайный фрагмент с баннером «Демо-версия — вы смотрите случайный отрывок». В конце — призыв к действию.

Антипиратство

Три слоя защиты — невидимые водяные знаки

Главная боль инфобизнеса — пиратство. Кто-то записывает экран, делает скриншот, пересылает видео. Мы встроили три уровня водяных знаков прямо в видеоплеер. Каждый привязан к конкретному аккаунту. Утечка = мгновенная идентификация.

1

Видимый водяной знак

Левый верхний угол

Полупрозрачная надпись с @username пользователя. Всегда на экране, но не мешает просмотру. Если кто-то записывает экран — его Telegram-никнейм будет на записи.

2

Скрытый водяной знак

Правый нижний угол

Практически невидимый при просмотре видео. Но стоит сделать скриншот — и при JPEG-сжатии он проявляется. Встроен на уровне, который камера или запись экрана обязательно захватит.

3

Призрачный водяной знак

Случайная позиция

Меняет положение при каждом открытии видео. Настолько прозрачный, что глаз его не замечает. Но при сильном сжатии (пересылка через мессенджер, загрузка на торрент) — проступает. Экспертиза покажет, чей аккаунт.

VideoPlayer.jsx — watermark layers
/* Слой 1: Видимый */.watermark-visible {
  position: absolute;
  top: 12px; left: 16px;
  opacity: 0.35;
  color: #1a1a1a;
}
/* Слой 2: Проявляется на скриншотах */.watermark-subtle {
  position: absolute;
  bottom: 8px; right: 12px;
  opacity: 0.02; /* невидим глазу */
}
/* Слой 3: Призрак — случайная позиция */.watermark-ghost {
  position: absolute;
  /* top/left вычисляется рандомно */
  opacity: 0.008; /* практически 0 */
}

LMS

Полноценная система обучения — не просто «смотри видео»

В Telegram-канале пользователь — пассивный зритель. В нашей LMS — активный ученик. Прогресс, заметки, чек-листы, рейтинги, избранное. Каждый инструмент повышает вовлечённость и завершаемость курса.

Продолжить с места остановки

Система запоминает, на какой секунде пользователь остановился. Вернулся через неделю — видео начинается ровно с того места. Heartbeat-пинги каждые несколько секунд фиксируют позицию.

Отметка «Просмотрено»

Видео автоматически помечается как просмотренное, когда пользователь досмотрел 90%+. Можно отметить вручную — если пересматривать не планируешь. Прогресс виден по каждой категории.

Рейтинги уроков

1–5 звёзд + текстовый комментарий к каждому уроку. Владелец видит, какой контент ценят, а какой нужно переработать. Средний балл агрегируется в admin-панели.

Личные заметки

К каждому уроку можно написать заметку — конспект, идеи, вопросы. Заметки привязаны к пользователю и уроку. Никто кроме автора их не видит.

Избранное

Сохраняй уроки в избранное одним кликом. Отдельная страница со всеми сохранёнными материалами — как плейлист, только для обучения.

Чек-листы

К урокам можно прикреплять чек-листы с заданиями. Пользователь отмечает пункты — прогресс сохраняется. Практические задания, а не просто «посмотрел и забыл».

Авторизация

Вход через Telegram — без паролей и регистраций

Аудитория клиента живёт в Telegram. Поэтому авторизация — через Telegram Login Widget. Одна кнопка, два клика — и пользователь внутри. Никаких паролей, email-подтверждений и «забыл пароль». JWT-токены, httpOnly-cookies, автообновление сессии.

Безопасность

JWT + Refresh tokens

Access-токен живёт 15 минут, refresh — 30 дней в httpOnly cookie. XSS-атака не даст украсть сессию. Ротация: новый refresh-токен при каждом обновлении.

Удобство

Stub-пользователи

Админ заранее создаёт запись по @username с нужной ролью. Когда человек впервые входит через Telegram — система автоматически привязывает его к заготовке. Не нужно потом вручную выдавать доступ.

Верификация

Подпись Telegram

Каждый вход верифицируется криптографической подписью от Telegram. Невозможно подделать авторизацию — данные подписаны ботом, сервер проверяет хэш.

Роли

5 ролей — от гостя до администратора

Не все пользователи равны. У кого-то гостевой доступ, кто-то — платный подписчик, кто-то — владелец франшизы с командой. Для каждого — свой уровень доступа и свои инструменты.

1

Admin

Полный доступ: управление контентом, пользователями, аналитика, инсайты. 8 страниц admin-панели.

2

Manager

Доступ к контенту и базовой аналитике. Может управлять пользователями без изменения ролей.

3

Employee

Полный доступ к контенту, заметкам, чек-листам и рейтингам. Основной тип для платных подписчиков.

4

Guest

Видит только бесплатный контент и превью платных видео. Мотивация к покупке доступа.

5

Blocked

Заблокированный пользователь. Авторизация проходит, но контент недоступен. Для нарушителей.

Для владельцев

Дашборд владельца — контроль команды

Владелец квест-бизнеса покупает доступ не только для себя, но и для команды. Owner-дашборд показывает прогресс каждого сотрудника: кто учится, кто забил, кто завершил курс. Мотивация через прозрачность.

Статистика команды

  • Количество сотрудников с доступом
  • Активные за последнюю неделю
  • Средний процент завершения курса
  • Общее время просмотра по каждому
  • Последняя активность сотрудника
  • Количество написанных заметок

Профиль сотрудника

  • Детальный прогресс по категориям
  • Список просмотренных уроков
  • Время просмотра и завершённость
  • Оценки и комментарии к урокам
  • Написанные заметки (приватные)
  • Роль и дата последнего входа

Admin

8 страниц admin-панели — полный контроль

Владелец платформы управляет всем из браузера: контент, пользователи, аналитика, права. Без SSH, без терминала, без разработчика. Всё — через удобный интерфейс.

Дашборд

6 карточек статистики: пользователи, контент, категории, просмотры, активные пользователи, завершённые уроки. Таблица последних зарегистрированных.

Контент

CRUD для всех типов: видео, статьи, чек-листы, файлы. Фильтрация по категории и типу. Авто-генерация slug из русского заголовка (транслитерация).

Категории

Создание и редактирование разделов. Управление видимостью, иконками, сортировкой. Тип категории: стандартный или витрина (для отзывов).

Пользователи

Поиск, назначение ролей, привязка к компании, просмотр истории: что смотрел, что оценил, какие заметки оставил.

Аналитика

Трендовый контент, метрики вовлечённости, распределение просмотров по времени. Данные для принятия решений.

Инсайты

Глубокий анализ: поведение пользователей, эффективность контента, паттерны потребления. BI-уровень аналитики.

Права доступа

Матрица ролей и возможностей. Массовые операции: выдать доступ всей команде, заблокировать группу.

Stub-пользователи

Заранее создай пользователя по @username. Когда он войдёт через Telegram — система автоматически привяжет его к заготовке с нужной ролью.

Маркетинг

«День открытых дверей» — маркетинговый инструмент

Встроенный режим Open House: администратор задаёт дату начала и окончания — и на это время весь контент становится доступным для всех зарегистрированных пользователей. Гости видят полную библиотеку, пробуют, вовлекаются — и покупают доступ, когда окно закрывается.

1
Задай даты

Администратор указывает OPEN_HOUSE_START и OPEN_HOUSE_END. Активация — автоматическая, по серверному времени.

2
Все видят всё

Гости и бесплатные пользователи получают полный доступ к библиотеке. Замки на контенте исчезают. Превью заменяется полным видео.

3
Конверсия

Когда окно закрывается — пользователь уже знает ценность контента. Конверсия в покупку кратно выше, чем с холодного трафика.

Поиск

Полнотекстовый поиск — на русском и английском

В Telegram «найти что-то в канале» — это боль. Мы встроили PostgreSQL Full-Text Search с весами: заголовок весит больше описания, описание — больше категории. Поиск понимает русский язык, подсвечивает совпадения и показывает контекст. Для аббревиатур — fallback на ILIKE.

search query — weighted FTS
-- Веса: A = заголовок, B = описание, C = категория
ts_rank(
  setweight(to_tsvector('russian', title), 'A') ||
  setweight(to_tsvector('russian', description), 'B') ||
  setweight(to_tsvector('russian', category), 'C'),
  plainto_tsquery('russian', :query)
) AS rank

Технический стек

Что внутри

Frontend

  • React 19 + Vite (быстрая сборка)
  • React Router DOM 7 (маршрутизация)
  • HLS.js (видеостриминг)
  • DOMPurify (санитизация HTML)
  • Lucide React (иконки)
  • CSS Variables + адаптивная вёрстка

Backend

  • Node.js + Express 5
  • PostgreSQL 8+ (15+ таблиц)
  • JWT + httpOnly cookies (авторизация)
  • Zod (валидация данных)
  • Winston (структурированные логи)
  • node-cron (очистка сессий в 3:00)

Безопасность

  • Helmet.js (CSP, security headers)
  • Rate limiting на /api
  • HMAC-SHA256 верификация Telegram
  • Presigned URLs с экспирацией
  • Path traversal защита
  • CORS + CSRF middleware

Инфраструктура

  • AWS S3 / Yandex Cloud (видеохранилище)
  • HLS: 720p + 480p адаптивный стриминг
  • Multer (загрузка файлов)
  • Graceful shutdown (корректное завершение)
  • Автоочистка просроченных сессий
  • Транслитерация slug из русского

Итог

Из «видео не грузится» — в полноценную образовательную платформу

Клиент пришёл с проблемой: «Telegram замедлили, подписчики не могут смотреть видео». Мы могли бы просто перенести видео на сайт. Но вместо этого построили платформу, которая решает все проблемы инфобизнеса: защита контента, аналитика, прогресс, командный доступ.

Результат — продукт, который стоит дороже, чем «закрытый канал в Telegram». Потому что это уже не канал. Это образовательная платформа с собственным видеоплеером, антипиратской защитой и admin-панелью. Своя LMS — без ежемесячных платежей за GetCourse.

Нужна своя LMS или образовательная платформа?

Расскажите задачу — мы спроектируем решение. Если ваш контент застрял в Telegram, мессенджере или на конструкторе — мы перенесём его в собственную платформу с защитой и аналитикой.

Написать в Telegram