Что было до нас: одна ссылка на всех

Наталья Чухреева, стилист из Петербурга, 15 лет в профессии. Учит мастеров кудрявому методу и стрижке по форме. Отдавать купленный курс было нечем: видеоуроки лежали одной общей папкой на Яндекс.Диске.

Такую ссылку пересылают. Одна оплата, дальше курс смотрит сколько угодно человек. Отозвать доступ нельзя вообще, ссылка живёт своей жизнью.

Готовые платформы закрывали вопрос доступа и открывали три новых: ежемесячная плата, чужой домен в адресной строке, чужой бренд поверх её собственного сайта. Отдельно болел блог: статьи были вписаны прямо в HTML лендинга, и ради одной запятой приходилось писать разработчику.

Кабинет, ключи от которого у владелицы

Сделали отдельное приложение на поддомене school.natali.hair. Основной сайт natali.hair не трогали.

Наталья заводит в админке почту ученицы и получает личный код вида NHR-XXXX-XXXX. Передаёт его после оплаты. Ученица входит по паре почта плюс код. Отзыв доступа, перевыпуск кода, удаление ученицы делаются одним кликом. Рядом видна дата последнего входа, поэтому сразу понятно, кто дошёл до уроков.

  • Сессия ученицы живёт 30 дней, сессия админки 12 часов: у владелицы доступ протухает в разы быстрее
  • Подбор кода ограничен: 8 попыток за 10 минут с одного адреса, для входа в админку лимит жёстче
  • Вариантов кода около 853 млрд: 8 символов из алфавита в 31 знак, похожие I, L, O, 0 и 1 убраны, чтобы ученица не ошиблась при вводе
!
Честная граница защиты

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

Что сделано с видео

Прямой ссылки на файл ученица не получает. Сервер сам забирает видео с Яндекс.Диска и переливает его потоком, исходный адрес в браузер не уходит. Служебная ссылка на файл живёт 3 минуты, дальше запрашивается заново.

В плеере убраны кнопка скачивания и правый клик. Поверх картинки полупрозрачно повторяется почта конкретной ученицы: 8 повторов под наклоном, прозрачность 10 процентов. В конспектах повторов 10.

Гейт стоит на всём содержимом. Уроки, конспекты и приложенные файлы отдаются только вошедшей. Прямых ссылок на файлы нет. Страницы кабинета закрыты от поисковиков.

Дальше Наталья ведёт школу сама

Курсы, уроки и материалы заводятся в админке. Обложка загружается перетаскиванием, сервер сам пересобирает её в webp по ширине 1600 пикселей и учитывает поворот камеры телефона. К уроку можно приложить файл: 17 форматов до 50 МБ, список закрытый, остальное отсекается.

Блог переехал из статики в ту же админку. Статьи пишутся простой разметкой с живым предпросмотром. Сейчас их 11, около 16 100 слов. Семь собраны из 151 поста её Telegram-канала: черновик писал один агент, факты проверял отдельный, с запретом выдумывать цифры. Он поймал реальные расхождения в исходниках, их вынесли списком вопросов к Наталье, вместо правдоподобного текста.

Разметка для поисковиков собирается на сервере из видимого текста статьи. Владелица правит вопрос в редакторе, разметка едет следом сама. Расхождение между тем, что читает человек, и тем, что видит поисковик, тут невозможно.

Грабли, которые встретили по дороге

Одно из модальных окон было объявлено как display:flex, и авторский стиль перебил браузерное правило прятать скрытый элемент. Окно осталось невидимым, растянутым на весь экран, и перехватывало клики. Форма входа для учениц просто перестала бы работать. Поймали автотестом в браузере до выката. Похожая история с декоративным градиентом: он рисовался поверх кликабельного элемента и съедал нажатия. В коде обе ошибки не видны, их находит только реальный браузер.

После одной из выкаток nginx около 12 минут отдавал старый CSS из своего кеша. Релиз выглядел не доехавшим, чуть не откатили нормально севшую версию. Теперь выкат проверяется только с обходом кеша.

Первая версия импорта статей заливала их по принципу «только если таблица пуста». Это затёрло бы правки, сделанные Натальей руками. Переделали: файл добавляет только те статьи, которых ещё нет, сверяясь по адресу.

Мелочь, на которой можно потерять полдня: Яндекс.Диск не отдаёт адрес для ссылки на папку, нужна ссылка на конкретный файл. Пока не упрёшься, это неочевидно.

Сроки, объём, обновления

Первый коммит 23 июля, последний 14 августа 2026 года, 16 коммитов. Рабочий каркас закрытого кабинета собрали за один день: вход по почте и коду, водяной знак, закрытая отдача материалов, контейнер и автовыкатка. Дальше слоями: редизайн под стиль основного сайта, админка курсов и уроков, ускорение сборки, блог-CMS, SEO-статьи, правки вёрстки.

Собственного кода 2552 строки, внешних библиотек 8. Лёгкий стек выбран намеренно: меньше кода, меньше поверхности для поломок и дыр, дешевле поддержка.

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

Частые вопросы

Можно ли защитить видеокурс от слива полностью?

Нет. Запись экрана заблокировать невозможно, и мы зафиксировали это прямо в коде вместо обещаний клиенту. Закрыли лёгкие пути: пересылку ссылки, кнопку скачивания, вход без оплаты. Против записи экрана работает водяной знак с почтой ученицы: 8 повторов под наклоном, прозрачность 10 процентов, поэтому утёкшая копия сама показывает, от кого она ушла.

Как отозвать доступ к онлайн-курсу у конкретной ученицы?

В админке отзыв доступа, перевыпуск кода и удаление ученицы делаются одним кликом. Рядом видна дата последнего входа, поэтому сразу понятно, кто дошёл до уроков. Сессия ученицы живёт 30 дней, сессия админки 12 часов.

Как ученицы заходят в кабинет и можно ли подобрать код доступа?

Вход по паре: почта плюс личный код вида NHR-XXXX-XXXX. Вариантов кода около 853 млрд: 8 символов из алфавита в 31 знак, похожие I, L, O, 0 и 1 убраны, чтобы ученица не ошиблась при вводе. Подбор ограничен 8 попытками за 10 минут с одного адреса, для входа в админку лимит жёстче.

Можно ли скачать видео из личного кабинета?

Прямой ссылки на файл ученица не получает. Сервер сам забирает видео с Яндекс.Диска и переливает потоком, исходный адрес в браузер не уходит, а служебная ссылка живёт 3 минуты. В плеере убраны кнопка скачивания и правый клик, страницы кабинета закрыты от поисковиков.

Сколько времени занимает свой кабинет для онлайн-школы вместо готовой платформы?

Рабочий каркас собрали за один день: вход по почте и коду, водяной знак, закрытая отдача материалов, автовыкатка. Вся школа заняла 3 недели: первый коммит 23 июля, последний 14 августа 2026 года, 16 коммитов. Своего кода 2552 строки, внешних библиотек 8. Обновления выкатываются примерно за 2 минуты после отправки кода в репозиторий.