Платформа на Next.js и FastAPI — курсы с видео на HLS, оплата ЮKassa и родительское согласие по 152-ФЗ
Образовательные и wellbeing-продукты с платным контентом (курсы, практики), которым нужна не просто CMS с видео, а платформа — сайт, личный кабинет, админка и backend — с самого начала спроектированная под соответствие 152-ФЗ и работу с несовершеннолетними пользователями
Знакомая ситуация
Часть аудитории — несовершеннолетние, а по закону нельзя просто дать подростку зарегистрироваться и начать пользоваться сервисом без подтверждённого согласия законного представителя
Трекинг самочувствия, питания и активности — потенциально чувствительные данные: их нельзя хранить в базе обычным текстом и нельзя допустить, чтобы они «утекли» при инциденте так же легко, как логи
Видеокурсы нужно было защитить от скачивания и расшаривания прямой ссылкой, при этом хранить именно на российской инфраструктуре, а не в первом попавшемся облаке
AI-функции (коуч, ассистент) должны использовать только российские LLM-провайдеры и не передавать персональные данные пользователя во внешние сервисы — это ограничение архитектуры, а не «фича на будущее»
Доступ к оплаченному курсу должен открываться строго по факту подтверждённого платежа, а не по тому, вернулся ли пользователь на страницу успеха после оплаты
«Включись»
Задача
Команде «Включись» нужна была не CMS с курсами и не MVP «на быстро», а платформа, спроектированная вокруг двух требований сразу: часть аудитории — несовершеннолетние, а данные, которые собирает сервис (самочувствие, AI-диалоги, платежи), должны с первого дня соответствовать 152-ФЗ и 242-ФЗ — родительское согласие, локализация, шифрование чувствительных полей, — а не «дорабатываться» после запуска, когда пользователи уже есть.
Решение
Собрали платформу из сайта и backend: Next.js 14 (App Router) с гибридным рендерингом — SSG/ISR для контентных страниц ради скорости и SEO, CSR для админки и интерактивных экранов — и FastAPI поверх PostgreSQL с доменами контента, трекинга, платежей, геймификации и согласий. Видеоуроки хранятся в S3-совместимом хранилище в РФ и отдаются в формате HLS через backend с короткоживущим подписанным токеном на конкретный урок — прямой постоянной ссылки на видео не существует. Доступ к платному курсу открывается только по вебхуку payment.succeeded от ЮKassa, который дополнительно перепроверяется прямым запросом в API ЮKassa, а не по одному факту редиректа пользователя на success-страницу. Для несовершеннолетних реализовано родительское согласие через одноразовый код на email родителя: сам код хранится только как хэш, с ограничением по времени и числу попыток, а после подтверждения создаётся запись согласия с версионированным текстом документа и доказательствами в виде хэшей IP и User-Agent — не сырых данных. Чувствительные поля трекинга (самочувствие, заметки, питание) шифруются на уровне приложения (AES-GCM, field-level encryption), причём сервис в production принудительно откажется запускаться без мастер-ключа шифрования. AI-коуч и ассистент работают только через YandexGPT или GigaChat, с санитайзингом текста перед отправкой (маскирование email и телефонов) и логированием самого факта обращения без текста сообщения — в логах остаётся только обезличенный хэш пользователя.
Результаты
Платформа — контент, платные курсы, трекинг и родительские согласия — построена вокруг требований 152-ФЗ и 242-ФЗ с первого дня, а не как доработка после запуска
Инструменты и технологии
Не просто сайт с курсами — платформа с юридическими ограничениями внутри архитектуры
«Включись» — российская платформа нейропрактик и саморегуляции: сайт, приложение и книга с QR-кодами, объединённые вокруг коротких ежедневных практик для сна, фокуса и стресса. Часть аудитории — подростки, а значит требования 152-ФЗ и 242-ФЗ — не юридическая формальность на потом, а ограничения, которые должны быть в архитектуре с первого дня: родительское согласие, локализация данных, шифрование чувствительных полей, российские AI-провайдеры.
Видео, которое нельзя скачать, и оплата, которая не зависит от возврата на сайт
Видеоуроки курсов хранятся в S3-совместимом хранилище в РФ и отдаются в формате HLS: backend выдаёт короткоживущий подписанный токен на конкретный урок, плейлисты и сегменты проходят через сервер, а не отдаются напрямую из хранилища, — прямой постоянной ссылки на видео просто не существует. Доступ к платному курсу открывается по вебхуку об успешной оплате от ЮKassa, который backend дополнительно перепроверяет прямым запросом в API ЮKassa и сверяет сумму и валюту, — открытие доступа не зависит от того, вернулся ли пользователь на страницу успеха или закрыл вкладку раньше.
Родительское согласие — не чекбокс, а отдельный процесс с доказательствами
Для несовершеннолетних пользователей согласие законного представителя подтверждается одноразовым кодом, который уходит на email родителя, а не подростка. Код хранится только как хэш, с ограничением по времени жизни и числу попыток ввода. После подтверждения создаётся запись согласия — с версией текста документа и доказательствами в виде хэшей IP-адреса и User-Agent, а не сырых данных, — и только после этого пользователю открываются трекинг и связанные функции.
Трекинг самочувствия защищён шифрованием, а не только паролем от базы
Заметки, самочувствие, питание и активность — потенциально чувствительные данные, поэтому такие поля шифруются на уровне приложения (AES-GCM), а не полагаются только на то, что у базы есть пароль. Мастер-ключ шифрования обязателен в production: без него сервис принудительно откажется запускаться, а не тихо продолжит работать с незашифрованными полями. AI-коуч и ассистент работают только через российские провайдеры — YandexGPT или GigaChat, — с санитайзингом текста перед отправкой и логированием факта обращения без самого содержания сообщения.
Одна архитектура доступа на весь сайт
Состояния доступа — закрыто, нужно оплатить, доступ восстановлен — собраны в единый слой и переиспользуются в каталоге курсов, на странице маршрута и в QR-портале из книги, чтобы поведение не расходилось между разными точками входа в один и тот же платный контент. Роли на сайте (admin/manager) и scopes на backend (mobile/admin) разведены так, что отсутствие сессии и нехватка прав обрабатываются по-разному: в первом случае пользователя отправляют на логин, во втором — не разлогинивают, а просто не пускают в конкретное действие.