Frontend Engineer · Июль 2025 — 2026

UnitBox · Платформа

React · Next.js · TypeScript · Redux Toolkit · Nest.js · Puppeteer

Что это и что я делал

UnitBox — B2B-платформа для застройщиков Бали и их агентов. Застройщик ведёт свои проекты и юниты, агенты собирают из них предложения инвесторам. У каждого застройщика — свой поддомен вида tenant.unitbox.ai, со своими проектами, пользователями и правилами.

Это был наш стартап, и роли мы поделили: партнёр вёл продукт — исследование рынка, выбор сегмента, стратегию и визуальный дизайн; я вёл реализацию — фронтенд публичного портала и куски бэкенда на Nest. Дальше — как это устроено внутри, фича за фичей: что делает, как собрано, зачем нужно.

Как продавали до платформы

Застройщик почти никогда не продаёт сам — до 80% инвестиционных сделок идут через независимых агентов. А всё, из чего агент продаёт, лежит в папках застройщика: таблица юнитов, Google Drive с рендерами и планировками, PDF-презентация, финмодель в ещё одной таблице. Данные при этом устаревали: обновления застройщик рассылал в чатах, где они терялись.

Комплект продажника, как его получал агент: Excel со ссылками на Google Drive. Что доступно — держишь в голове.
Комплект продажника, как его получал агент: Excel со ссылками на Google Drive. Что доступно — держишь в голове.

Один источник правды

Вся платформа стоит на одной сущности — листинге юнитов застройщика. Одно место, где застройщик управляет каждым юнитом, и те же данные видят инвесторы, агенты и отдел продаж. Раньше у каждой группы была своя копия, и копии расходились. Теперь расходиться нечему: застройщик редактирует один раз, а обновляется каждая поверхность. Как держать листинг на 500 юнитов управляемым — отдельная история, она в кейсе про админку; здесь достаточно, что источник один.

Каталог и страница проекта

Поверх листинга — каталог: страница поиска с фильтрами (бюджет, район, срок сдачи) и отдельный каталог всех юнитов застройщика. На странице проекта — живая доступность, ключевые факты, инфраструктура, что вокруг и встроенная Google-карта.

Каталог проектов застройщика — фильтры и живая доступность

Карта — мелочь, которая отработала на реальных созвонах. Мы оставили весь инструментарий Google, вместе с панорамами: на Zoom агент открывает карту прямо на странице проекта и показывает инвестору вид на океан или рельеф, на котором стоит проект. Ровно те вопросы, которые всегда задаёт удалённый покупатель.

Каталог юнитов — статусы и цены

Живые статусы из CRM

Вопрос «юнит ещё свободен?» закрыли живые статусы. Очевидное решение — дать застройщику вести статусы у нас в админке — в жизни ломается: отдел продаж живёт в своей CRM и вторую систему вести не будет, и вторая система начинает врать. Поэтому источник правды остаётся в CRM: бронь там сама меняет цвет юнита здесь — статус приходит по вебхуку. Вопрос, который агенты весь день задавали менеджерам, просто перестал существовать.

Страница проекта — статусы продаж

Юнит: планировка и рассрочка

У каждого юнита — планировка, галерея, план оплат и своя финансовая модель, посчитанная из настроек застройщика. Никто ничего не считает руками. Агент может поменять входные данные прямо на созвоне и защищать цифры как свои. Сама модель выросла в самую глубокую систему платформы — про неё отдельный кейс; здесь важно, что на карточке юнита она уже живая.

Юнит — планировка и рассрочка

Движок офферов

Оффер — это презентация, по которой инвестор принимает решение, и работа, которую агенты делают чаще всего: несколько раз в неделю, кто-то каждый день. Раньше один оффер значил собрать четыре источника: финмодель в одном Excel, презентацию в PDF, рендеры в Drive, цены в ещё одной таблице. По-нормальному это занимало до пары часов, а назавтра оффер уже был неверным — цены двигаются, юниты продаются. Многие просто просили застройщика сделать готовый оффер и пересылали его.

Юнит добавляется в оффер

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

Что настраивается на странице оффера

  • язык и валюта под клиента, пересчёт автоматом
  • любой раздел включается или выключается: галерея, локация, планы оплат, прогноз доходности — одному инвестору модель нужна, другого она напугает
  • режим сравнения: юниты рядом в одной таблице, потому что главный вопрос инвестора — «какой из них?»
  • режим портфеля: несколько юнитов сведены в одну инвестицию с графиками распределения и роста стоимости
  • кнопка PDF для тех, кто просит файл
Живая страница оффера, которую получает инвестор

PDF на бэке через Puppeteer

PDF собирается на бэкенде. Puppeteer открывает ту же самую страницу оффера в режиме печати — то есть PDF и веб-версия это один макет, ничего не дублируется. В проде браузер не поднимается на каждый запрос, а подключается к общему Chrome по вебсокету.

Главная возня — вес. Оффер часто тащит оригиналы на 24–50 мегапикселей; на полном разрешении PDF раздувается до сотен мегабайт, и генерация отваливается по таймауту. Поэтому каждую картинку я перехватываю и уменьшаю через sharp до 1600px, прежде чем Chrome её вставит, а сами загрузки идут через ограничитель одновременности — иначе всплеск под сотню-другую картинок ловит рейт-лимит у хоста, и часть картинок просто пропадает. Печатается один непрерывный лист, без разбивки на страницы, иначе фото и карточки резались бы пополам. В итоге PDF остаётся лёгким даже когда в оффере много юнитов и фотографий.

«Я с клиентом» и кнопки скачивания

Две детали решают, переживёт ли всё это живой созвон. Режим «интерфейс клиента» прячет комиссию агента и контакты застройщика, пока агент шарит экран. А у планировки и модели свои кнопки скачивания — чтобы ответить на один вопрос клиента не значило собирать целый оффер.

Инвестор открыл оффер — пуш агенту

Одну работу мы придумали с нуля. Когда инвестор открывает оффер, агенту прилетает уведомление в Telegram — с кнопкой сразу открыть этот оффер. На бэке это просто: страницу открывает неавторизованный посетитель, мы засчитываем просмотр, пишем время первого и последнего открытия и шлём пуш. Раньше единственным сигналом был ответ, который мог и не прийти; агент перезванивал через день-три, когда инвестор уже говорил с другим. Теперь звонит, пока клиент ещё внутри. Мгновенная обратная связь стала одной из самых ценных фич платформы.

Мультивалюта: все валюты мира

Проект может быть в любой валюте мира — застройщик задаёт дефолтную, и она прокидывается везде, где есть цена. Но при любой записи цена всегда пересчитывается и хранится ещё и в USD. Курсы тянет крон из внешнего API по расписанию, база — USD; высокая точность не нужна, финальную цену застройщик всё равно согласует с клиентом лично.

USD-нормализация нужна ради скорости. Платформа показывает и фильтрует в одной валюте, поэтому фильтры и сортировка по десяткам проектов в разных валютах работают быстро — не надо на каждый запрос пересчитывать «много валют в много». А при смене валюты проекта цены пересчитываются каскадно, не меняя реальную стоимость. Здесь легко всё сломать: перепутать пересчёт — и $100k превращаются в 100k IDR, в тысячи раз дешевле, по всему каталогу разом. Поэтому именно эти расчёты я закрыл unit-тестами — точечно, там, где ошибка недопустима.

Интерактивные фасады

На созвоне клиент спрашивает: какой корпус, какой этаж, куда окна. На платформе это интерактивный фасад: клиент кликает от мастер-плана в корпус, этаж и юнит, и цвета всегда показывают сегодняшнюю доступность — статусы те же, из CRM. Иерархию корпусов, этажей и юнитов застройщик размечает поверх своих картинок сам, в админке. На фронте это рисуется своим SVG-слоем поверх изображения — чтобы держать сотни полигонов на фасаде без лагов. То, что застройщики раньше заказывали как отдельную услугу и перерисовывали при каждой смене нумерации, стало часом настройки.

Прийти туда, где люди работают

Хороший инструмент по умолчанию проигрывает привычке. Работа уже жила в Telegram, WhatsApp и CRM — поэтому платформу принесли туда, где люди уже есть. Telegram-бот несёт важные моменты: пуш об открытии оффера и подтверждение агентов — новый агент просит доступ, застройщик жмёт кнопку прямо в чате, готово. Для отделов продаж каталог рендерится внутри их CRM — карточки проектов и юнитов в amoCRM и Kommo. А каталог каждого застройщика живёт на своём поддомене, с его логотипом и именем: для него это его портал, не наш, поэтому он его и наполняет.

Доступ и видимость

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

Что получилось

Движок офферов закрыл главную работу на платформе. Оффер уходит ссылкой или PDF, не устаревает, язык и валюта — под клиента, а агент узнаёт момент, когда инвестор его открыл, и звонит, пока интерес горячий.

~2 мин вместо часовОффер
около 3000Собрано офферов
под каждого клиентаЯзык и валюта
живьём из CRMСтатусы юнитов

Через движок офферов прошло около трёх тысяч предложений, и за каждым — своя аналитика в админке. Всё это стоит на одном листинге, живёт на поддомене застройщика и встречает продажников там, где они уже работают.