Умный движок обучения для платформы теории вождения
Клиент создавал приложение для подготовки к теоретическому экзамену по вождению на рынке Центральной Азии — речь о миллионах потенциальных пользователей в регионе, где сдача теории становится реальным препятствием на пути к водительскому удостоверению. Существующие способы подготовки сводились к PDF-файлам с устаревшими билетами и нескольким приложениям, как будто собранным в 2012 году. Задача была простой: построить обучающий движок, который реально помогает сдать экзамен, честно отслеживает прогресс и работает на русском и узбекском с первого дня.
движок по темам и билеты
Ядро того, что мы построили, — это система обучения по темам, дополненная полноценным движком симуляции экзамена. Пользователи изучают вопросы, сгруппированные по темам ПДД — дорожные знаки, приоритет проезда, действия в нештатных ситуациях, — а затем проверяют себя на экзаменационных билетах. Каждый билет — это рандомизированный набор вопросов, но «рандомизированный» здесь не значит «вытащить из шапки». Реальный экзамен подчиняется строгому распределению: фиксированное число вопросов по каждой теме с приоритетом на те области, что важнее всего для безопасности на дороге. Мы повторили эту логику в точности, чтобы тренировочные билеты были неотличимы от настоящих. Алгоритм генерации берёт вопросы из банка через взвешенный случайный выбор по тематическим корзинам, и он достаточно быстр, чтобы выдавать свежий билет на каждый запрос без кеширования самих комбинаций.
прогресс без перегрузки БД
Отслеживание прогресса оказалось самой интересной — и при наивной реализации самой дорогой — частью. Каждый ответ пользователя обновляет его профиль: счётчики верных/неверных ответов по темам, время на вопрос, скользящие тренды точности, кривые улучшения за последнюю неделю. Умножьте это на тысячи одновременных пользователей — и вы получите write-heavy нагрузку, которая легко положит базу. Мы решили это двухуровневым подходом: события отдельных ответов уходят в лёгкий append-only лог, а агрегированная статистика пересчитывается асинхронно пакетными запросами по расписанию. Пользователь видит почти реальные цифры, а база не задыхается под потоком UPDATE по горячим строкам. Cachetools закрывает сторону чтения — статистика по темам кешируется на пользователя с коротким TTL, поэтому один и тот же запрос дашборда не бьёт в базу дважды в течение нескольких секунд.
целостность двуязычного контента
Двуязычная задача оказалась тоньше, чем кажется. Каждый вопрос, каждый вариант ответа, каждое пояснение существует и на русском, и на узбекском. Это не просто слой перевода — это задача целостности. Когда вопрос обновляется (потому что меняются ПДД), обе языковые версии должны обновиться атомарно. Мы заложили это на уровне базы: контент вопроса хранится в парной структуре, где обе версии перевода разделяют общий счётчик версий. Если русский текст отредактировали, а узбекский ещё не подтянули, система помечает его как «pending review», а не отдаёт устаревший контент. Мелочь — но в области, где одно неверное слово в вопросе способно перевернуть правильный ответ, точность критична.
stateful-сессии экзамена
Сама симуляция экзамена работает с таймером обратного отсчёта, навигацией по вопросам, возможностью пометить вопросы для повторной проверки и подробной разбивкой результатов в конце — по темам, с конкретным указанием областей, требующих доработки. Мы сделали это как stateful-сессию на бэкенде, а не полагались на клиент, поэтому закрытие приложения посреди экзамена не теряет прогресс. Сессия живёт в PostgreSQL с TTL, и пользователь может вернуться к ней в пределах временного окна.
результаты и выводы
Результат — обучающий движок, который закрывает полный цикл от первого знакомства до уверенной готовности к экзамену. Пользователи, прошедшие в приложении хотя бы 80% банка вопросов, сдают настоящий экзамен заметно чаще — клиент начал отслеживать это через опросы после экзамена. Честный вывод по проекту: самой сложной частью оказались не алгоритмы и не оптимизация базы, а целостность двуязычного контента. Технический долг в переводах копится молча — вы не замечаете рассогласованный вопрос, пока его не заметит пользователь, а к этому моменту доверие уже подорвано. Если бы начинали заново, мы бы построили пайплайн ревью переводов до обучающего движка, а не после.