01 Что это за проект
PrimeTime — полноценный онлайн-кинотеатр (фильмы, сериалы, аниме) с каталогом на ~290 000 единиц контента, персональными рекомендациями на базе собственной двухбашенной нейросети, гибридным (текст + смысл) поиском, фасетным каталогом, системой аналитики просмотров и Telegram-рассылками.
Это не учебный CRUD: проект работает в продакшене, имеет реальных пользователей, непрерывную доставку (CI/CD через GitLab → Docker registry → VPS) и решает нетривиальные инженерные задачи — векторный поиск на 290k записей с укладкой в десятки миллисекунд, балансировку внешних API-провайдеров с circuit breaker, explainable-рекомендации в виде «полок».
Проект сознательно построен как полигон: автор обкатывает на нём современные веб- и ML-технологии (об этом прямо сказано в README фронтенда — «a super-duper pet project with which I play with different technologies»), но делает это на производственном уровне качества.
Продакшен: https://primetime.su/ · Автор: Фёдор Гаранин (yesfedor)
Масштаб кодовой базы (метрики)
| Репозиторий | Назначение | LOC | Ключевые числа |
|---|---|---|---|
core-web | Frontend (Nuxt 4 / Vue 3) | ~37 400 | 119 компонентов, 37 страниц, 34 composable, 57 API-обёрток |
core-api-grpc | Backend (NestJS / gRPC) | ~18 000 | 26 сервисов, 18 gRPC-контроллеров, 8 миграций |
ai-recommendation | ML-пайплайн (TensorFlow.js) | — | 7-шаговый пайплайн обучения Two-Tower |
content.proto | Контракт | 1 497 строк | 22 сервиса, 78 RPC-методов |
Только один backend-репозиторий — 206 коммитов, единственный автор, последняя активность в день анализа. Это длительная, последовательная работа одного инженера, а не разовый учебный проект.
02 Архитектура в целом
Ключевая архитектурная идея
Фронтенд и бэкенд связаны строго типизированным контрактом — единым proto-файлом (content.proto). Из него buf/protoc генерирует TypeScript-клиент для фронта и серверные интерфейсы для NestJS. Это даёт сквозную типобезопасность: изменил поле в proto → перегенерировал → TypeScript ломается там, где контракт нарушен. Никакого ручного REST-DTO-дрейфа.
Транспорт — gRPC-Web с бинарной сериализацией (не JSON). Браузер не умеет HTTP/2-gRPC напрямую, поэтому в цепочку добавлен Envoy как трансляционный прокси (gRPC-Web → gRPC). Это взрослое, «нетипичное для пет-проекта» решение.
03 Технологический стек
| Слой | Технологии |
|---|---|
| Frontend | Nuxt 4, Vue 3 (Composition API), TypeScript 5, Pinia, SCSS (7-1 pattern), VeeValidate + Yup, @connectrpc/connect-web, Bun |
| Backend | NestJS 10, TypeScript, gRPC (@grpc, ConnectRPC), Prisma 6, Passport JWT, Bull (очереди), @nestjs/schedule (cron) |
| БД | PostgreSQL 17 + расширения pgvector, pg_trgm, btree_gin, uuid-ossp; multi-schema (content, content-balancer) |
| Поиск | Elasticsearch 8.12 (BM25 + фасеты) + pgvector (kNN-семантика) |
| ML | TensorFlow.js (Node-биндинги), Two-Tower, in-batch sampled-softmax; эмбеддинги — Alibaba-NLP/gte-multilingual-base через Infinity Inference Server |
| LLM | Timeweb AI (deepseek-v4-flash) — оптимизация поисковых запросов |
| Инфра | Docker, Envoy, Redis, imgproxy, GitLab CI/CD, nginx-proxy, VPS |
| Внешние данные | Kinopoisk Unofficial / Dev API (контент), TMDB (студии/сети) |
04 Продакшен-инфраструктура (анализ запущенных контейнеров)
Список реально работающих в продакшене контейнеров и оценка качества их применения:
| Контейнер | Роль | Как используется — оценка |
|---|---|---|
core-api-grpc :50051 | gRPC backend | Ядро системы. Чистая модульная архитектура NestJS. Качественно. |
core-web :4503→3000 | Nuxt SSR frontend | SSR + гидрация, проксирование gRPC-Web. Качественно. |
pgvector/pgvector:pg17 :3338 | PostgreSQL + векторы | Хранит и контент, и 768/64-мерные векторы; HNSW-индексы. Используется по делу — векторный поиск прямо в SQL. Очень качественно. |
elasticsearch:8.12 :4801 | Полнотекст + фасеты | BM25-кандидаты для гибридного поиска, агрегации для фасетного каталога. Не «ES ради ES» — есть чёткое разделение ответственности с pgvector. Качественно. |
envoyproxy/envoy:v1.28 :4775 | gRPC-Web → gRPC | Обязательное звено для браузерного gRPC. Грамотный выбор вместо самописного прокси. Качественно. |
darthsim/imgproxy :4506 | On-the-fly ресайз постеров | Все постеры идут через imgproxy.primetime.su/insecure/rs:fill:.... Снимает нагрузку и нормализует размеры. Качественно. |
michaelf34/infinity :1919 | Embedding Inference Server | Генерация 768-мерных эмбеддингов (gte-multilingual-base) для семантики. Поднят отдельным сервисом (13 дней аптайма) — правильное разделение CPU-тяжёлой задачи. Качественно. |
redis:alpine :3435 | Кэш + rate-limit + локи | Кэш каталога/трендов (stale-while-revalidate), single-flight NX-локи, rate-limit токенов балансировщика. Используется на нескольких нетривиальных паттернах. Очень качественно. |
dpage/pgadmin4 :3340 | Админка БД | Вспомогательный инструмент. Нормально. |
wordpress :4025 | Блог | Контент-маркетинг отдельным сервисом. Прагматично. |
Вывод по инфраструктуре: каждый контейнер имеет ясную причину существования, нет «карго-культа». Связка Postgres+pgvector / Elasticsearch / Infinity / Redis — это осознанно спроектированная data-платформа, а не набор случайных зависимостей.
05 Функциональные подсистемы
- Аутентификация — JWT (access/refresh), вход по email и по Telegram-виджету, device-id через cookie, бесшовный refresh с дедупликацией (single-flight) на SSR.
- Каталог и контент — фасетный каталог через Elasticsearch (жанры, страны, студии, годы, рейтинги, длительность, возраст), карточки фильмов, персоны, студии/сети (из TMDB), связи (сиквелы/приквелы/спин-оффы).
- Поиск — гибридный: BM25 (Elasticsearch) + семантический kNN (pgvector) с Reciprocal Rank Fusion, байесовским взвешиванием популярности и LLM-нормализацией запроса.
- Рекомендации — двухбашенная нейросеть (Two-Tower); главная страница как лента объяснимых «полок» (shelves) с runtime k-means-кластеризацией вкусов.
- Аналитика просмотров — точный трекинг watch-сессий (хиты ≥30с, лимит 900с), агрегированная статистика, реалтайм-дашборды в админке.
- Балансировщик провайдеров — отказоустойчивый роутинг между источниками данных (Kinopoisk) с ротацией токенов, rate-limit и circuit breaker.
- Telegram-рассылки — кампании, тест-сообщения, авто-отписка при блокировке бота.
- Админ-панель — пользователи, рассылки, история просмотров, реалтайм-аналитика.
06 Сквозная оценка качества
Сильные стороны
- Сквозная типобезопасность через единый proto-контракт (frontend ↔ backend).
- Производительность как явная инженерная дисциплина — в коде есть комментарии с разбором
EXPLAIN, переход на двухстадийный HNSW-поиск,SET LOCAL hnsw.ef_search, sparse-маскирование в обучении. Это редкость даже в коммерческих проектах. - Чистая модульность на обоих концах (Nuxt feature-folders / NestJS-модули).
- Зрелые паттерны кэширования — stale-while-revalidate + single-flight на Redis.
- Грамотное разделение ответственности хранилищ: ES — текст и фасеты, pgvector — смысл, Redis — кэш/локи, PG — источник истины.
- Документация — каждая подсистема описана в
docs/*.mdс обоснованием решений.
Зоны риска / что отметила бы аттестационная комиссия
- Секреты в
.envлежат в репозитории (пароли БД, токены Telegram/TMDB, API-ключи). Для продакшена это уязвимость — нужен secret-manager / vault. (Замечание зафиксировано; в рамках задачи правки не вносятся.) - Местами «god-объекты» сервисов по 700+ строк (
recommendation,elastic-search,shelves) — читаемо, но просятся на декомпозицию. - Тестов немного (есть точечные на ML-кодек и загрузку башни); для дипломной работы это нормально, для дальнейшего роста — узкое место.
.env в репозитории — для продакшена это уязвимость безопасности: требуется перенос в secret-manager / vault.Итоговая оценка уровня автора — см. раздел 8 ниже и в каждом профильном файле.
07 Как читать остальные документы
- frontend.md — устройство Nuxt-приложения, фирменная liquid-вёрстка
1rem = 1px, плагины, gRPC-клиент с интерсепторами, auto-import API-слой, темизация, icon-модуль, примеры кода и оценка чистоты архитектуры. - backend.md — модули NestJS, gRPC-контракт, работа с Prisma и multi-schema PostgreSQL, Elasticsearch, pgvector, балансировщик, кэш-стратегии, «крутые решения» с разбором.
- ml.md — двухбашенная архитектура, признаки, 7-шаговый пайплайн, in-batch sampled-softmax с logQ-коррекцией, инференс и интеграция с бэкендом.
08 Краткий вердикт
Уровень исполнения — уверенный Senior (обоснование в профильных файлах).
Проект демонстрирует не только умение «собрать фичу», но и системное мышление: выбор транспорта, разделение хранилищ, профилирование запросов, отказоустойчивость, объяснимость рекомендаций и собственную ML-инфраструктуру end-to-end.