Назад в блог

Фронт деплоится за 3 минуты, бэк — за 40: как мы это решали в headless-проекте

Мы перешли на headless. Фронт стал деплоиться за 3 минуты. Бэк — нет.

Первые два месяца мы жили в режиме: фича в Next.js готова, а Bitrix API ещё нет. Или наоборот — бэк обновился, фронт не знает об этом. Продакшн вроде бы зелёный, а сайт не работает как надо. Это не баг архитектуры headless. Это управленческая задача, о которой почти никто не пишет.

В headless деплой — не одна операция, а две

В монолите у вас один репозиторий, один деплой, одна точка синхронизации. Фронт и бэк выходят вместе. Это неудобно, но хотя бы предсказуемо.

В headless у вас два независимых стека с разной скоростью доставки кода в продакшн. Теоретически это свобода. На практике — асимметрия, которую надо уметь контролировать.

Next.js за 3 минуты, Bitrix за 40: что под капотом

Наш стек: IvanPin/ivanpin.com работает на Next.js + PM2 на том же сервере. Деплой — это git pull, npm run build, pm2 restart. Обычно 2–3 минуты. Если что-то сломалось — откатили предыдущий pm2 снапшот за секунды.

Бэкенд IvanPin/wgp_backend — это Bitrix. Деплой PHP-эндпоинтов идёт через FTP (скрипт deploy_ivanpin_api.py). Последовательность: заливка файлов, сброс OPcache через HTTP-вызов на проде, проверка что эндпоинты отвечают. Реалистичное время с переключением контекста и ручными проверками — 30–40 минут.

Разрыв 10–13x. Это не трагедия, если вы управляете им сознательно.

Три паттерна рассинхрона, которые убивают итерации

  1. Фича в Next.js готова, тесты проходят. Вы деплоите фронт — и пользователи видят пустое место, потому что бэк ещё не знает об этом поле в API. Если вы не держите совместимость в API по умолчанию, этот паттерн будет повторяться снова и снова.
  1. Вы обновляете формат ответа в Bitrix-эндпоинте. В тестовой среде всё хорошо. На проде Next.js начинает получать другой JSON и тихо ломается — без 500-ки, просто данные отображаются не так. Вы узнаёте об этом через несколько часов.
  1. Самый болезненный для нашего конкретного стека: wgp_backend обслуживает одновременно ivanpin.com и webgoodpeople.com. Изменение API для одного сайта может задеть второй. Деплой бэка — не изолированная операция, а риск для нескольких потребителей сразу.

API-контракты как способ развязать стеки

Первое, что помогло — это зафиксировать контракт. У нас есть X-WGP-Token и фиксированный набор эндпоинтов в /api/ivanpin/services/. Это уже зачаток контракта: Next.js знает, что будет в ответе, а Bitrix знает, какой формат не менять.

Практическое правило, которое мы ввели: никакие сломанные изменения API не деплоятся без одновременного обновления фронта. Если изменение не обратно совместимо — вводим версионирование или промежуточный адаптер на стороне Next.js.

Это не сложная архитектура. Это договорённость, которую надо сделать явной.

Feature-флаги: где держать состояние

Следующий вопрос: вы добавляете новую фичу. Когда её «включать» — на стороне фронта или бэка?

Мы разделили это так: если фича зависит от данных бэка — флаг на стороне бэка. Это может быть поле в API-ответе (feature_enabled: true/false), или просто отсутствие/наличие endpoint'а в /api/. Next.js проверяет перед рендером. Если бэк не готов — фича не показывается.

Если фича чисто фронтовая (UI, переключение компонента) — флаг в Next.js, в переменных среды или в конфиге. Деплоится без участия Bitrix.

Это разделение убрало большую часть проблем рассинхрона для нас.

Что мы поменяли в процессе деплоя

Раньше деплой бэка был: «сейчас возьму и обновлю». Теперь — чеклист из 4 шагов:

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

Второе — для любого изменения API проверяю обратную совместимость. Если ломаю формат — обновляю фронт первым.

Третье — после деплоя Bitrix прогоняю смоук-тест на обоих сайтах. Один HTTP-запрос к /api/ivanpin/services/blog/ и один к /api/services/wgp/ — убеждаюсь, что оба отвечают корректно.

Четвёртое — фиксирую в deploy_ivanpin_api.py какие именно файлы были изменены. Это позволяет откатиться к предыдущей версии за 5 минут, если что-то пошло не так.

Что не работает

Я не автоматизировал деплой Bitrix и не буду это делать ближайшее время. Причина проста: бэк живёт на общем сервере с несколькими проектами, ошибка в автоматическом деплое может задеть продакшн клиентского проекта. Ручной деплой с чеклистом дороже по времени, но дешевле по рискам.

Это не оправдание. Это осознанный выбор в пользу надёжности.

Итог

Переход на headless не решает проблему деплоя — он её переформулирует. Вместо «мы деплоимся вместе» вы получаете «мы деплоимся независимо, но должны координироваться».

Если ваш Next.js уходит в прод за 3 минуты, а Bitrix — за 40, это не повод отказываться от headless. Это повод выработать правила: что деплоится первым, где живут флаги, как вы проверяете совместимость.

Управляемая асимметрия лучше, чем кажущаяся синхронность.

→ Подробнее о том, почему я выбрал headless именно для этого проекта — в статье Headless — это не про скорость. Это про то, чтобы Bitrix не ронял фронт.

→ Как я принимал решение отказаться от переписывания Bitrix — Я отказался от $40K-контракта, чтобы не переписывать Bitrix