Админ-панель агрегатора вакансий
Около сорока сущностей под управлением: вакансии, компании, статьи, мероприятия, конструкторы форм
- React
- TypeScript
- MobX
- Formik + Yup
- +3
Агрегатор вакансий региона: миграция с легаси на Next.js с упором на SEO
Платформа поиска работы: вакансии, резюме, отклики, чаты и карьерные мероприятия. Перевёл продукт с легаси-SPA на Next.js App Router и выстроил SEO-слой — от серверных метаданных до карты сайта, собираемой из API.
Контекст
Региональный агрегатор вакансий: соискатели ведут резюме и откликаются, работодатели публикуют вакансии и разбирают отклики, поверх этого — карьерные мероприятия, статьи, курсы и карта событий.
К моменту моего подключения продукт уже работал, но был написан как классическое SPA: весь контент рисовался на клиенте, метаданные подставлялись через react-helmet, а поисковики видели пустую разметку.
Задача
Для агрегатора вакансий органический поиск — основной канал: страница каждой вакансии и каждой компании должна попадать в индекс. В легаси-версии этого не происходило вовсе.
Вторая проблема — скорость. Первый экран ждал загрузки бандла и цепочки клиентских запросов, а на слабых устройствах и мобильном интернете это давало заметную задержку.
Третья — поддерживаемость. Логика метаданных лежала в конфигах-объектах рядом с описанием страниц, canonical и noindex расставлялись вручную и легко терялись при доработках.
Решение
Перевёл приложение на App Router и сделал серверный рендер ключевых разделов: списки вакансий и резюме, карточки вакансии, компании и соискателя приходят готовой разметкой. Данные для метаданных берутся тем же серверным запросом, что и контент страницы.
Метаданные описал через generateMetadata: заголовок и описание собираются из реальных данных сущности — должность, вилка, город, количество открытых вакансий у работодателя. Для списков в описание подставляется актуальное число предложений, чтобы сниппет в выдаче не был шаблонным.
Карту сайта вынес в sitemap-роут, который запрашивает у API идентификаторы всех публичных сущностей и раскладывает их по разделам. Новая вакансия попадает в карту сайта автоматически, без ручной правки.
Публичные адреса сделал человекопонятными: для пользователя и поисковика это транслитерированные пути вида /vakansii и /soiskatel/:id, внутри приложения — латинские роуты. Соответствие описано правилами rewrite, которых набралось около семидесяти.
Из продуктовых фич сделал чаты на Mattermost с WebSocket-клиентом, отклики, авторизацию по SMS и почте, регистрацию через VK, лендинги карьерных островов для мероприятий и карту событий на Leaflet. Ошибки собираются в Sentry, поведение — в Яндекс.Метрику с вебвизором.
Результат
Страницы вакансий и компаний стали индексируемыми, а карта сайта перестала быть ручной работой. Первый экран приходит с сервера, поэтому основной контент виден до загрузки JavaScript.
Метаданные перестали быть россыпью настроек: они собираются в одном месте из данных сущности, и добавление нового раздела не требует помнить про десяток мелких полей.
Опыт этой миграции я перенёс в текущее портфолио: SEO-слой здесь построен так же, но с единой фабрикой метаданных, из которой невозможно забыть canonical или языковые альтернативы.


Около сорока сущностей под управлением: вакансии, компании, статьи, мероприятия, конструкторы форм
Портал аренды и покупки жилья с нуля на Next.js: карта, геокодер, бронирование, ипотека
Модерация объявлений, управление объектами агентства и ипотечными программами