Frontend Engineer · Июль 2025 — 2026
UnitBox · Платформа
React · Next.js · TypeScript · Redux Toolkit · Nest.js · Puppeteer
Что это и что я делал
UnitBox — B2B-платформа для застройщиков Бали и их агентов. Застройщик ведёт свои проекты и юниты, агенты собирают из них предложения инвесторам. У каждого застройщика — свой поддомен вида tenant.unitbox.ai, со своими проектами, пользователями и правилами.
Это был наш стартап, и роли мы поделили: партнёр вёл продукт — исследование рынка, выбор сегмента, стратегию и визуальный дизайн; я вёл реализацию — фронтенд публичного портала и куски бэкенда на Nest. Дальше — как это устроено внутри, фича за фичей: что делает, как собрано, зачем нужно.
Как продавали до платформы
Застройщик почти никогда не продаёт сам — до 80% инвестиционных сделок идут через независимых агентов. А всё, из чего агент продаёт, лежит в папках застройщика: таблица юнитов, Google Drive с рендерами и планировками, PDF-презентация, финмодель в ещё одной таблице. Данные при этом устаревали: обновления застройщик рассылал в чатах, где они терялись.

Один источник правды
Вся платформа стоит на одной сущности — листинге юнитов застройщика. Одно место, где застройщик управляет каждым юнитом, и те же данные видят инвесторы, агенты и отдел продаж. Раньше у каждой группы была своя копия, и копии расходились. Теперь расходиться нечему: застройщик редактирует один раз, а обновляется каждая поверхность. Как держать листинг на 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, не устаревает, язык и валюта — под клиента, а агент узнаёт момент, когда инвестор его открыл, и звонит, пока интерес горячий.
Через движок офферов прошло около трёх тысяч предложений, и за каждым — своя аналитика в админке. Всё это стоит на одном листинге, живёт на поддомене застройщика и встречает продажников там, где они уже работают.