Перейти к содержимому
d.nikolaev
Все проекты
ФлагманПродукт

Навигатор карьеры

Агрегатор вакансий региона: миграция с легаси на Next.js с упором на SEO

Роль
Frontend-разработчик: миграция, SEO, новые фичи, поддержка
Период
июнь 2023 г. — по настоящее время
Команда
6 человек
Компания
LazurM

Платформа поиска работы: вакансии, резюме, отклики, чаты и карьерные мероприятия. Перевёл продукт с легаси-SPA на Next.js App Router и выстроил SEO-слой — от серверных метаданных до карты сайта, собираемой из API.

Что сделано

  • Миграция с легаси-SPA на Next.js App Router без остановки продуктовой разработки
  • Серверные метаданные на 15+ динамических разделах: вакансии, компании, соискатели, статьи, курсы, события
  • Карта сайта собирается из API по идентификаторам сущностей, а не поддерживается руками
  • Около 70 правил rewrite: человекопонятные URL для пользователя, латиница во внутренних роутах
  • Чаты на Mattermost с WebSocket-клиентом, отклики и уведомления
  • Авторизация по SMS и почте, регистрация через VK, единый профиль соискателя и работодателя

Контекст

Продукт

Региональный агрегатор вакансий: соискатели ведут резюме и откликаются, работодатели публикуют вакансии и разбирают отклики, поверх этого — карьерные мероприятия, статьи, курсы и карта событий.

К моменту моего подключения продукт уже работал, но был написан как классическое SPA: весь контент рисовался на клиенте, метаданные подставлялись через react-helmet, а поисковики видели пустую разметку.

Задача

Задача

Для агрегатора вакансий органический поиск — основной канал: страница каждой вакансии и каждой компании должна попадать в индекс. В легаси-версии этого не происходило вовсе.

Вторая проблема — скорость. Первый экран ждал загрузки бандла и цепочки клиентских запросов, а на слабых устройствах и мобильном интернете это давало заметную задержку.

Третья — поддерживаемость. Логика метаданных лежала в конфигах-объектах рядом с описанием страниц, canonical и noindex расставлялись вручную и легко терялись при доработках.

Решение

Решение

Перевёл приложение на App Router и сделал серверный рендер ключевых разделов: списки вакансий и резюме, карточки вакансии, компании и соискателя приходят готовой разметкой. Данные для метаданных берутся тем же серверным запросом, что и контент страницы.

Метаданные описал через generateMetadata: заголовок и описание собираются из реальных данных сущности — должность, вилка, город, количество открытых вакансий у работодателя. Для списков в описание подставляется актуальное число предложений, чтобы сниппет в выдаче не был шаблонным.

Карту сайта вынес в sitemap-роут, который запрашивает у API идентификаторы всех публичных сущностей и раскладывает их по разделам. Новая вакансия попадает в карту сайта автоматически, без ручной правки.

Публичные адреса сделал человекопонятными: для пользователя и поисковика это транслитерированные пути вида /vakansii и /soiskatel/:id, внутри приложения — латинские роуты. Соответствие описано правилами rewrite, которых набралось около семидесяти.

Из продуктовых фич сделал чаты на Mattermost с WebSocket-клиентом, отклики, авторизацию по SMS и почте, регистрацию через VK, лендинги карьерных островов для мероприятий и карту событий на Leaflet. Ошибки собираются в Sentry, поведение — в Яндекс.Метрику с вебвизором.

Результат

Результат

Страницы вакансий и компаний стали индексируемыми, а карта сайта перестала быть ручной работой. Первый экран приходит с сервера, поэтому основной контент виден до загрузки JavaScript.

Метаданные перестали быть россыпью настроек: они собираются в одном месте из данных сущности, и добавление нового раздела не требует помнить про десяток мелких полей.

Опыт этой миграции я перенёс в текущее портфолио: SEO-слой здесь построен так же, но с единой фабрикой метаданных, из которой невозможно забыть canonical или языковые альтернативы.

Интерфейс

Профиль соискателя: карьерная траектория и направление развития
Каталог приоритетных вакансий с поиском и фильтрами

Связанные проекты