Tech Path Finder
Платформа подготовки IT-специалистов: 65 курсов с квизами и три AI-тренажёра, где спорит автор PR, торгуется оппонент на переговорах и оценивается ответ на собеседовании
Оглавление
О проекте
Tech Path Finder это платформа подготовки IT-специалистов к карьерному росту. Начиналась она как курсы с квизами, а за последний год выросла в другое: к теории и вопросам добавились три тренажёра, в которых на той стороне сидит не форма с вариантами ответа, а собеседник со своими интересами.
Проблема, которую платформа решает, простая. Разработчик не знает, что именно учить для перехода на следующий уровень, и тратит время на хаотичное потребление материала без обратной связи о реальных пробелах. Квиз показывает, что он знает. Тренажёр показывает, как он себя ведёт, когда с ним спорят.
Ключевая идея это персонализация через данные: система строит профиль компетентности с учётом времени. Знания, которые не применяются, постепенно деградируют, и платформа напоминает об этом раньше, чем это станет проблемой на собеседовании.
Что внутри
Обучение и оценка знаний
65 курсов по категориям: Agile/Scrum, Python, Django, FastAPI, Kubernetes, Docker, AWS, System Design, LLM/RAG, ClickHouse, Kafka, Playwright, LeetCode и другие. В сумме 940 тем, 941 теоретическая статья и 8457 вопросов в квизах. Каждый курс содержит:
- Теорию в Markdown с диаграммами и глоссарием терминов
- Квизы трёх уровней сложности (junior / middle / senior) с детальными объяснениями
- Экзамены по 20 детерминированных вопросов на вариант, с историей сдач
- Прогресс по завершению тем и точности ответов
Алгоритм деградации знаний
Proficiency-score каждой темы снижается со временем, если пользователь не возвращается к материалу:
proficiency = accuracy × recency_factor × 100
recency_factor = max(0.3, 1 - days_since_last_answer / 30)Темы автоматически попадают в «критичные» (< 40%), «слабые» (40–65%) или «не начатые», и система строит персональную очередь для повторения.
Мок-интервью с AI-оценкой
Структурированные сессии по языкам и уровням, 1236 вопросов в базе. Ответы оцениваются моделью через OpenRouter, на выходе итоговый скор и разбор по каждому ответу. Формат express или полный, стоимость 10 кредитов за сессию.
Code Review Arena
Самое сложное из добавленного за год. Пользователю дают проблемный PR, он пишет свободные замечания, а автор кода отвечает и спорит. Обычный квиз по коду для этого не годился: там достаточно узнать баг, а здесь надо ещё и настоять на своём.
Домен code_review_arena собран из отдельных частей: генерация сценариев, синхронизация сидов, оценка детекции нулевого раунда, диалог с автором, финализация с судьёй, модерация. В библиотеке 133 сценария. Подробный разбор в посте «Code Review Arena».
Тренажёр переговоров
78 сценариев сложных разговоров. На той стороне ролевой персонаж со скрытой карточкой: интересы, страхи, условия, при которых он раскрывается и идёт на уступки. Персонаж отвечает в роли, а параллельно с диалогом идёт разбор, которого сам персонаж не видит.
На выходе главный результат переговоров, профиль по шести параметрам процесса и PDF-отчёт с цитатами из разговора. Есть голосовой режим. Разбор в посте «Тренажёр переговоров».
Code Review как упражнения
Практические задания с реальным кодом на Python, Go, Java, Ruby и других языках. Пользователь находит баги и нарушения, система сравнивает с эталоном по трёхбалльной шкале (0 / 0.5 / 1.0). Есть ежедневный челлендж и отслеживание слабых типов ошибок по языкам.
Геймификация
XP-система с событиями-триггерами (завершение темы +50, экзамен +100, стрики +25/100), достижения по милестонам, ежедневные стрики, дашборд с тепловой картой активности и историей экзаменов.
Архитектурные решения
Backend: Domain-Driven Design
14 независимых доменов, каждый со своими api.py, service.py, models.py, schemas.py. За год их стало на семь больше, и это лучший показатель того, куда двигался проект:
| Домен | Ответственность |
|---|---|
| auth | JWT, OAuth (Google/Yandex/GitHub), восстановление пароля |
| users | Профили, достижения, XP, настройки |
| content | Квизы, экзамены, прогресс, рекомендации |
| interview | Мок-интервью, AI-оценка, расход кредитов |
| code_review | Упражнения с кодом, ежедневные челленджи |
| code_review_arena | Сценарии PR, диалог с автором, судья, модерация сидов |
| negotiations | Ролевой персонаж, разбор реплик, голос, PDF-отчёты |
| billing | Кредитная система, промокоды, рефанды |
| admin | Аналитика, управление пользователями, модерация |
| seo | Wordstat, аудит, скоринг, цели, диагностика, бэкфилл |
| media | Загрузка, обработка и хранение медиа |
| comments | Комментарии с лайками |
| notifications | Email-рассылки, отчёты |
| feedback | Обратная связь |
Всего около 54 000 строк Python в app/ и 92 миграции.
Frontend: Feature-Sliced Design
Next.js 16.2.12 (App Router) и React 19.2.3, 75 страниц, три route group'а:
(main)для аутентифицированных страниц с навигацией(auth)для публичных: вход, регистрация, восстановление(admin)для панели администратора
Все API-вызовы идут через Server Actions с 'use server'. Токены читаются из httpOnly cookies исключительно на сервере, ни один токен не достигает клиентского кода.
Контент как код
Курсы версионируются в Git как JSON и Markdown в content/data/:
content/data/
agile/
ceremonies.json # Вопросы подтемы с объяснениями
ceremonies.md # Теоретическая статья
glossary.json # Глоссарий терминов
exam.json # 20 детерминированных вопросовОбновление контента это коммит в Git и редеплой. Никакой CMS, никакой БД для контента. Рядом так же лежат 133 сценария арены, 78 сценариев переговоров и 1236 вопросов мок-интервью.
Инфраструктура
nginx → next.js (:3000) + fastapi (:8000)
├── postgres # Основная БД
├── redis # Сессии, rate limiting, кэш
├── kafka # Event streaming, аудит-лог
├── celery # Фоновые задачи, email
├── jaeger # Distributed tracing
└── plausible # Privacy-first аналитикаТехнические вызовы и решения
Ролевой персонаж, который не подглядывает в разбор
Проблема: в тренажёре переговоров одна и та же LLM должна одновременно играть оппонента и оценивать реплики пользователя. Если оба режима живут в одном диалоге, персонаж начинает подыгрывать: он видит разбор и сам подстраивается под правильный ответ.
Решение: протокол разведён. Персонаж отвечает в роли по внутренней логике скрытой карточки (интересы, страхи, условия раскрытия и уступок), разбор идёт параллельным потоком, и персонажу он не виден. LLM-ядро переиспользуется из домена interview, а протокол поверх него свой.
Healthcheck, который уронил celery через SIGBUS
Проблема: проверка здоровья контейнера трое суток копила mmap-файлы prometheus_client, забила tmpfs, форки celery начали умирать с SIGBUS, задачи с acks_late закружились в очереди и за полторы минуты выбрали дневную квоту писем.
Решение: unset PROMETHEUS_MULTIPROC_DIR для команды healthcheck, tmpfs с запасом, счёт писем после SMTP вместо счёта до, отдельный алерт на смерть исполнителя. Полный разбор с хронологией и пунктами в постмортеме.
Тасование ответов без утечки правильного индекса
Проблема: если тасовать варианты только на фронтенде, пользователь запоминает позицию правильного варианта в исходном массиве.
Решение: Fisher-Yates выполняется на сервере при каждом запросе. Клиент отправляет индекс в пространстве перетасованных вариантов, сервер переводит его обратно для валидации.
Rate limiting через Lua и Redis
Проблема: защита чувствительных endpoint'ов от брутфорса без внешних зависимостей.
Решение: атомарный sliding window через Lua-скрипт в Redis, INCR и EXPIRE в одной транзакции. Свои лимиты на каждый endpoint:
POST /auth/login → 5 / 15 минут / IP
POST /auth/register → 3 / час / IP
POST /auth/forgot-pw → 3 / час / IPКредитный биллинг без гонок
Проблема: атомарное списание кредитов при параллельных запросах без двойного расхода.
Решение: ledger-паттерн, append-only таблица CreditTransaction плюс денормализованный кэш User.credits_balance, атомарное обновление через SELECT FOR UPDATE. Сессии мок-интервью идемпотентны по ключу.
Refresh-токены без race condition
Проблема: при одновременных запросах с истёкшим токеном оба могут попытаться обновить, и один получит инвалидированный.
Решение: атомарный GETDEL из Redis при обновлении. Токен читается и удаляется в одной операции, второй запрос получает None и идёт на /auth/refresh снова.
Observability с нуля
Полный стек наблюдаемости без vendor lock-in:
- Tracing: FastAPI, SQLAlchemy и Redis инструментированы через OpenTelemetry в Jaeger
- Metrics: Prometheus и кастомные метрики (регистрации, XP, завершения тем, потерянные воркеры)
- Health checks:
/healthи/health/readyс проверкой БД и Redis - Graceful shutdown: дренаж in-flight запросов с 30-секундным таймаутом
Безопасность
- Пароли: bcrypt с 12 раундами
- JWT: HS256, access на 30 минут и refresh на 7 дней в httpOnly cookies
- OAuth: state-параметр верифицируется через Redis (TTL 1 час) против CSRF
- Чувствительные поля: Fernet-шифрование при наличии
APP_ENCRYPTION_KEY - SQL: параметризованные запросы через SQLAlchemy
- Linting: Bandit и Ruff в pre-commit hooks
Результаты
9693 вопроса это 8457 в квизах курсов и 1236 в мок-интервью. Тесты: 643 штуки в 87 файлах. Коммитов в репозитории 1062.
Что получилось построить
- Полноценный SaaS с нуля, от архитектуры до деплоя
- Алгоритм деградации знаний, дающий персонализацию без ML-оверхеда
- Три AI-тренажёра, в которых оценивается не выбор варианта, а поведение в диалоге
- Контент как код: 65 курсов и 211 сценариев обновляются через Git без CMS
- Продакшн-стек с трейсингом, метриками и graceful shutdown
Извлечённые уроки
Контент как код работает лучше CMS для технических курсов: версионирование, code review контента и откат изменений достаются из Git бесплатно.
Алгоритм деградации знаний оказался неочевидно простым решением. Полноценный spaced repetition с планировщиком не понадобился, хватило time-decay функции, чтобы рекомендации стали ощутимо лучше.
DDD-разбиение оправдалось с первого месяца и особенно за последний год: семь новых доменов приросли, не тронув старые. Арена и переговоры переиспользуют LLM-ядро интервью, но живут своей жизнью.
Тренажёр отличается от квиза не интерфейсом, а тем, что на той стороне есть интерес. Автор PR спорит, оппонент на переговорах торгуется и что-то скрывает. Как только у собеседника появились свои цели, задача перестала быть про проверку знания и стала про поведение, и это оказалась совсем другая инженерная работа.
JWT в httpOnly cookies через Server Actions решает проблему токенов на фронтенде: клиентский код никогда их не видит, и XSS их не похитит.
Похожие материалы
Проекты с похожими технологиями и задачами
AI Builders: открытый учебник о LLM в backend и разобранные системы
Платформа на ai.potapov.me для инженеров, которые встраивают LLM в работающие системы. Открытый учебник на 10 частей и 58 глав, под ним разобранные системы с числами и списком пропусков. Бесплатно, без регистрации.
- Python
- FastAPI
- Django
- Pydantic
- Celery
- +4
Code Review Arena: живое ревью pull request с ИИ-автором
Тренажёр code review: проблемный PR, построчные замечания и диалог с автором, который спорит и правит код. Часть Tech Path Finder.
- Python
- FastAPI
- PostgreSQL
- Celery
- OpenRouter
- +1
Тренажёр переговоров: разговор с персонажем, у которого есть скрытая карта
Симуляция сложных разговоров: у собеседника мотивы и условия уступки, которых вы не знаете заранее. В конце отчёт с вашими цитатами. Часть Tech Path Finder.
- Python
- FastAPI
- PostgreSQL
- Celery
- OpenRouter
- +2