Привет! Меня зовут Игорь Росляков, я технический писатель. По приглашению руководителя направления «Маркет и интеграции» Сергея Вострикова готовлю цикл статей на тему ИИ-ассистированной разработки решений для Битрикс24.

Сегодня начинаем новую серию туториалов: будем работать с ИИ-агентами через платформу для вайбкодинга Битрикс24 Вайбкод и создавать полезные приложения почти полностью через интерфейс ИИ. В этой статье я использовал OpenAI Codex.

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

Что будет в этой статье:

Что делает платформа Битрикс24 Вайбкод

Обобщённо — это прослойка между агентом, порталом Битрикс24 и сервером приложения. Платформа выполняет несколько функций. 

Даёт API-ключи. Они нужны, чтобы агент мог обращаться к API: создавать приложение, сервер, смотреть статус и логи.

Даёт OAuth-приложение для Битрикс24. Это отдельный ключ vibe_app_..., через который приложение получает право читать данные портала в рамках установленных прав.

Регистрирует встройки в Битрикс24. Например, наше приложение появится как пункт в левом меню и как вкладка в карточке компании.

Хостит сервер приложения. Агент деплоит код на сервер Битрикс24 Вайбкод, и он становится доступен как приложение через URL.

Даёт доступ к данным Битрикс24 через API-обёртку. Приложение обращается к VibeCode Entity API и Batch, а платформа уже прокидывает запросы к порталу с нужной авторизацией.

Даёт инфраструктурные инструменты: создание сервера, деплой и просмотр логов.

Что сделаем и зачем это нужно

Чтобы собрать сводную информацию о компании, часто приходится вручную обходить вкладки с контактами и сделками, проверять завершённые и запланированные активности и искать дополнительный контекст.

Такой информации может быть много: только записей по звонкам и сделкам могут быть сотни. На поиск этой информации вручную уйдут часы.

Мы сделаем приложение «Паспорт клиента», которое будет делать всё за нас: собирать нужные данные в одном месте и выводить список всех компаний, по которым можно посмотреть информацию:

Паспорт клиента, фрагмент
Паспорт клиента, фрагмент

У нас будет отдельная страница с подробной информацией о компании и дополнительно — дашборд, который будет показывать список компаний-клиентов:

дашборд со всеми компаниями в портале
дашборд со всеми компаниями в портале

Что нужно для повторения нашего проекта

Для работы понадобится аккаунт в системе Битрикс24 с оплаченной подпиской, чтобы иметь разрешение на публикацию приложений.

Если мы уже зарегистрированы в системе Битрикс24, переходим в веб-приложение платформы vibecode.bitrix24.tech и нажимаем кнопку «Войти»:

Подключаемся к своему порталу в открывшемся окне и выдаём разрешение на работу с платформой:

Платформа соединяет наш портал и ИИ-инструмент. Для этой связи понадобится API-ключ. Получаем его на странице vibecode.bitrix24.tech/dashboard:

Что можно указать при создании ключа:

Название ключа будет отображаться в списке ключей после создания.

Режим доступа доступен в двух вариантах: Только чтение или Чтение и запись. Режим чтения нужен для безопасных интеграций, которые могут смотреть данные, но не могут ничего менять в портале. Режим Чтение и запись нужен, если приложение должно создавать или изменять данные, регистрировать бота и отправлять сообщения.

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

Вайбкод определяет доступ к разделам самой платформы, а не портала. 

Срок действия определяет время жизни ключа. 

Лимит запросов определяет, сколько обращений в секунду приложение может отправлять через этот ключ. Ограничение защищает портал от слишком высокой нагрузки, например если из-за ошибки приложение начнёт непрерывно повторять один и тот же запрос.

Белый список IP определяет, с каких IP-адресов разрешено использовать этот ключ. Если поле заполнить, платформа Битрикс24 Вайбкод и портал Битрикс24 будут принимать запросы с этим ключом только с указанных IP. С любых других IP ключ будет отклоняться.

Ключ лучше сохранить в .env-файл, где он будет храниться в переменной:

VIBECODE_API_KEY=vibe_api_... 

Тогда его не нужно пересылать агенту в чате.

После этого остаётся открыть рабочую директорию агента, с которым вы привыкли работать, попросить его взять ключ из .env-файла и дать ссылку на документацию платформы Битрикс24 Вайбкод: https://vibecode.bitrix24.tech/v1/me

Составляем план и условия работы

Чтобы повысить надёжность дальнейшей работы, я обрисовал агенту задачу и попросил составить план и сохранить его в .md-файл.

После этого добавил базовые инженерные условия:

  • Использовать максимально доступную типизацию: основной код пишем на TypeScript, включаем строгий режим и избегаем any, кроме явно изолированных адаптеров внешнего API.

  • Подключать минимум зависимостей: каждая новая runtime-зависимость должна быть нужна для конкретной функции приложения. Если задачу можно безопасно решить стандартными возможностями платформы, зависимость не добавляем.

  • Тесты добавлять по максимуму: покрываем адаптер VibeCode API, нормализацию данных, агрегатор паспорта, расчёты метрик, обработку частичных ошибок, UI-состояния и smoke-проверки backend routes.

  • Подключить coverage-проверку после каждого шага: начиная с появления тестового раннера, каждый отчёт должен содержать команду тестов и текущие проценты покрытия. 

План агент составил подробный, но неравномерный:

  1. Составить безопасную базу: создать в папке репозиторий, завести .env, .gitignore и .env.example, проверить VibeCode API, документацию и прямой портал.

  2. Подробно изучить нужные разделы документации и составить архитектурную схему реализации приложения, карту по типу «раздел паспорта → endpoint → фильтр → связь → fallback». После этого проверить все доступы к нужным источникам и зафиксировать инженерные ограничения: минимальные зависимости, обязательные тесты и coverage-отчёт.

  3. Реализовать приложение и запустить его локально для теста.

  4. Провести финальный деплой.

Чтобы следить за исполнением работы, я добавил в план чёткое правило останавливаться после каждого шага и давать подробный отчёт о том, что сделано.

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

Проверки:
  Секреты: ключ не найден нигде кроме .env.
  Тесты: пока не запускались.
  Coverage: N/A, потому что scaffold приложения ещё не создан.
  VibeCode API: работает.
  Документация VibeCode: работает.
  Прямой доступ к порталу Битрикс24: всё ещё не работает, DNS/resolve timeout.
  Продолжать можно через VibeCode wrapper/API.

Реализация

Теперь разбираем по шагам, как агент собирал решение, и что у него получалось сразу, а что нужно было исправлять.

1 — Проектирование структуры проекта

Основную реализацию агент сделал в один заход, и после этого мы вносили правки. 

ИИ учёл требования и сделал приложение на TypeScript со строгой типизацией через tsconfig.json. Runtime-зависимости полностью отсутствовали. Для тестов агент сначала пробовал Vitest, но он оказался тяжеловат и капризен под текущий Node, поэтому заменил на более минимальный стек: встроенный node:test и c8 для coverage.

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

Технически проект делится на несколько слоёв:

  • http.ts — маршруты, placement-контекст, ответы сервера.

  • passport.ts — бизнес-логика паспорта клиента.

  • vibe.ts — клиент VibeCode API.

  • ui/pages.ts — HTML-интерфейс.

  • Отдельные тесты для конфигурации, HTTP, VibeCode-клиента, паспорта и UI.

Это помогло создать аккуратное разделение: отдельно лежат сбор данных, рендеринг, работа с API.

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

2 — Создание интерфейса и полей на портале

Агент зарегистрировал два места встраивания в интерфейс Битрикс24:

  • В панели слева появилась кнопка, по которой должен быть открываться общий дашборд со всеми компаниями.

  • В карточке компании открывался паспорт конкретной компании.

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

Ключевая логика на этом этапе простая: что приложение смотрит, откуда его открыли. Если это карточка компании, оно достаёт ID компании из placement-контекста. Если это левое меню, показывает общий дашборд.

В коде src/http.ts это место выглядит так:

// создаём объект url из входящего запроса
// это нужно, чтобы одинаково работать и с обычными get-параметрами, и с параметрами placement
const url = createRequestUrl(rawUrl, rawBody)

// проверяем, что пользователь открыл корень приложения
// именно на корень обычно приходит запуск из placement Битрикс24
if (url.pathname === '/') {
  // читаем тип placement из параметров запроса
  // по нему понимаем, приложение открыли из левого меню или из карточки компании
  const placement = getParam(url, 'placement')

  // если placement равен CRM_COMPANY_DETAIL_TAB, значит приложение открыто как вкладка в карточке компании
  if (placement === 'CRM_COMPANY_DETAIL_TAB') {
    // достаём id текущей компании из placement_options
    // это главный контекст: вокруг этой компании дальше строится паспорт
    const companyId = extractPlacementCompanyId(url)

    // собираем паспорт конкретной компании и отдаём html-страницу встройки
    return htmlResponse(200, renderCompanyCardPage({
      passport: await loadClientPassport(
        companyId ?? 'не передан',
        createVibeClient(context.auth)
      )
    }))
  }

  // если это не вкладка компании, считаем, что открыт общий вход в приложение
  // в этом случае показываем общий дашборд со списком компаний
  return htmlResponse(200, renderDashboardPage({
    data: await loadDashboardData(createVibeClient(context.auth))
  }))
}

3 — Сбор данных через Entity API и Batch

По ID компании приложение формирует пять batch-команд: отдельно запрашивает саму компанию, связанные контакты, сделки, лиды и активности.

Вместо 5 отдельных запросов мы собираем команды в Batch. Это хорошо показывает экономию, потому что раньше эксперт раньше открывал всё руками, а приложение одним пакетом запрашивает нужные сущности.

Как это записано в коде в src/passport.ts:

// функция формирует первый набор batch-команд для паспорта клиента
// на вход приходит id компании, которую пользователь открыл в Битрикс24
function createPrimaryCalls(companyId: string): readonly BatchCall[] {
  // пробуем привести id компании к числу
  // для некоторых get-запросов entityId удобнее передавать числом
  const id = Number(companyId)

  // возвращаем массив команд, который потом уйдёт в VibeCode Batch API
  return [
    // получаем саму карточку компании
    // это базовая сущность паспорта: название, телефон, отрасль, выручка, последняя активность
    {
      id: 'company',
      entity: 'companies',
      action: 'get',
      entityId: Number.isFinite(id) ? id : companyId
    },

    // получаем контакты, связанные именно с этой компанией
    // фильтр companyId не даёт забрать все контакты портала, только релевантные текущей карточке
    {
      id: 'contacts',
      entity: 'contacts',
      action: 'list',
      params: {
        filter: { companyId },
        limit: 50
      }
    },

    // получаем сделки компании
    // по ним считаются статусы: в процессе, выиграны, проиграны, а также сумма сделок
    {
      id: 'deals',
      entity: 'deals',
      action: 'list',
      params: {
        filter: { companyId },
        limit: 50
      }
    },

    // получаем лиды, связанные с компанией
    // если лидов нет, приложение покажет пустой источник
    {
      id: 'leads',
      entity: 'leads',
      action: 'list',
      params: {
        filter: { companyId },
        limit: 50
      }
    },

    // получаем активности, привязанные напрямую к компании
    // ownerTypeId = 4 в нашей модели означает crm-компанию
    {
      id: 'companyActivities',
      entity: 'activities',
      action: 'list',
      params: {
        filter: {
          ownerTypeId: COMPANY_ENTITY_TYPE_ID,
          ownerId: companyId
        },
        limit: 50
      }
    }
  ]
}

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

src/passport.ts, функция loadDealActivities(client, deals):

// функция догружает активности по найденным сделкам
// это второй batch-проход после того, как мы уже получили список сделок компании
async function loadDealActivities(
  client: VibeClient,
  deals: readonly DealSummary[]
): Promise<{
  readonly activities: readonly ActivitySummary[]
  readonly errors: readonly string[]
}> {
  // если сделок нет, то и активности по сделкам искать негде
  // возвращаем пустой результат без ошибки
  if (deals.length === 0) return { activities: [], errors: [] }

  // собираем batch-команды для активностей каждой сделки
  // ограничиваемся первыми 20 сделками, чтобы не раздувать пакет бесконечно
  const calls: BatchCall[] = deals.slice(0, 20).map((deal) => ({
    // задаём уникальный id результата, чтобы потом понимать, к какой сделке относится ответ
    id: dealActivities_${deal.id},

    // работаем с сущностью activities
    entity: 'activities',

    // запрашиваем список активностей
    action: 'list',

    // фильтруем активности по сделке
    // ownerTypeId = 2 означает crm-сделку
    params: {
      filter: {
        ownerTypeId: DEAL_ENTITY_TYPE_ID,
        ownerId: deal.id
      },
      limit: 20
    }
  }))

  // отправляем второй batch-запрос через VibeCode API
  const batch = await client.batch(calls)

  // ответы приходят сгруппированными по id команд
  // разворачиваем все списки активностей в один общий массив
  const activities = Object.values(batch.results).flatMap((value) =>
    asArray(value).map(normalizeActivity)
  )

  // возвращаем найденные активности и отдельно список ошибок api, если они были
  return {
    activities,
    errors: formatBatchErrors(batch.errors)
  }
}

4 — Деплой на сервер Вайбкод и проверка в портале

После локальной реализации приложение нужно было сделать рабочим снаружи. Мы подняли сервер на VibeCode, задеплоили Node-приложение, привязали его к OAuth-приложению и зарегистрировали встройки.

Это оказалось самой сложной частью проекта для ИИ-разработки.

Сначала агент решил, что публикация приложения должна идти через обычный мастер Битрикс24 Вайбкод: выбрать сервер, выбрать места показа, нажать кнопку Опубликовать. Из-за этого ИИ раз за разом давал инструкции по работе с UI: где выбрать левое меню, где вкладку компании, какой сервер указать. Это было неверное направление для задачи, потому что смысл проекта был именно в том, что агент должен довести приложение до финальной работы самостоятельно.

Потом выяснилось, что агент запутался между несколькими сущностями в интерфейсе публикации: API-ключом, OAuth-приложением, сервером, каталогом приложений, placement-встройками и Black Hole сервером. Я отправлял в Codex скриншоты, на которых он видел, что приложение как ключ авторизации существует, серверы существуют, но в каталоге приложений приложение не появляется. При публикации через стандартный путь платформа хотела создать или выбрать сервер и пройти настройку через мастер настройки UI:

Некоторое время агент ошибочно воспринимал это как обязательный путь. 

Реальная проблема была в том, что «публикация в каталог» и «регистрация встраиваний в портал» оказались не одним и тем же. Для задачи не обязательно было публиковать приложение в каталог. Нужно было, чтобы оно стало видно в интерфейсе Битрикс24: в левом меню и во вкладке карточки компании. Это решается через placement bind.

Понять это мешали проблемы с доступом: из среды агента мой бизнес-портал был недоступен и возвращал DNS timeout. Поэтому ИИ не мог открыть портал и проверить, что происходит после каждого действия.

В конце концов агент нашёл решение и сделал регистрацию через API Битрикс24 Вайбкод.

Фактически решение было таким:

  1. Создать и использовать OAuth-приложение Вайбкод. То есть у нас появилось приложение «Паспорт клиента» с app key вида vibe_app_....

  2. Задеплоить сервер приложения. Агент собрал проект, загрузил его на VibeCode Black Hole server и настроил старт:
    npm ci --omit=dev
    npm run start

  3. Указать приложению VIBE_APP_KEY. На сервере приложение получило ключ OAuth-приложения, чтобы запросы к Entity API шли от имени установленного приложения, а не от личного API-ключа.

  4. Зарегистрировать placements напрямую. Это был главный инсайт для ИИ: вместо прохода публикации через UI агент использовал API-привязку placements.

Нужны были два placement:

LEFT_MENU
CRM_COMPANY_DETAIL_TAB

И handler:

https://vibecode.bitrix24.tech/v1/bitrix-handler

Это именно handler Вайбкода, не прямой URL сервера. Это важно, потому что handler прокидывает gateway-авторизацию и открывает приложение корректно внутри портала.

После этого приложение появилось в левом меню как Паспорт клиента и во вкладке карточки компании:

Кнопка приложения на главной панели слева
Кнопка приложения на главной панели слева
Кнопка приложения в карточке компании
Кнопка приложения в карточке компании

Во время деплоя агент оперативно реагирует на происходящее и держит в курсе процесса, это приятно:

На всякий случай скажу, что посмотреть и настроить свои серверы можно в меню платформы:

5 — Исправление ошибок после реальной проверки

После деплоя и запуска первой версии в портале осталось внести небольшие правки: например, иногда при переходе между общим дашбордом и паспортом конкретной компании терялась авторизация:

Для сохранения авторизации агент начал сохранять авторизацию в подписанную HttpOnly cookie. Для этого понадобились 2 правки в src/http.ts. Сначала — место, где используется авторизация:

// при обработке запроса сначала пытаемся взять свежую авторизацию из заголовка gateway
// если заголовка уже нет, пробуем восстановить авторизацию из подписанной cookie
authorization:
  getHeader(request, 'x-vibe-authorization') ??
  readSignedAuthCookie(request, config.vibeAppKey)

Потом — место, где создаётся cookie:

// функция создаёт cookie только если есть и авторизация, и ключ приложения
// без этих данных сохранять нечего
export function createSignedAuthCookie(
  authorization: string | null,
  appKey: string | null
): string | null {
  // если авторизации нет, возвращаем null
  // это защищает от установки пустой или бессмысленной cookie
  if (!authorization || !appKey) return null

  // кодируем значение авторизации в base64url
  // так его безопаснее положить в cookie как строку
  const value = Buffer.from(authorization, 'utf8').toString('base64url')

  // подписываем значение через hmac
  // подпись нужна, чтобы пользователь не мог подменить cookie вручную
  const signature = signCookieValue(value, appKey)

  // возвращаем защищённую cookie
  // httponly не даёт читать её из javascript
  // secure требует https
  // samesite=none нужен, потому что приложение работает внутри iframe/placement
  return ${AUTH_COOKIE_NAME}=${value}.${signature}; Path=/; Max-Age=3600; HttpOnly; Secure; SameSite=None
}

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

Некоторые недочёты стали видны только после тестирования на реальных сценариях — например, сумма сделок считалась некорректно:

const totalDealAmount = deals.reduce((sum, deal) => sum + deal.amount, 0)

const currency = deals.find((deal) => deal.currency)?.currency ?? null

Получался такой алгоритм: 

  1. Взять все сделки компании.

  2. Сложить amount каждой сделки в одно число.

  3. Найти первую сделку, у которой есть валюта.

  4. Показать всю сумму в этой первой валюте.

Готовая структура проекта

Итоговый состав приложения выглядит так:

VKVVPart1Passport/
├─ src/
│  ├─ server.ts
│  ├─ http.ts
│  ├─ config.ts
│  ├─ vibe.ts
│  ├─ passport.ts
│  ├─ ui/
│  │  └─ pages.ts
│  ├─ config.test.ts
│  ├─ http.test.ts
│  ├─ vibe.test.ts
│  ├─ passport.test.ts
│  └─ ui/
│     └─ pages.test.ts
│
├─ docs/
│  ├─ DEPLOYMENT_STATUS.md
│  ├─ ENGINEERING_STANDARDS.md
│  ├─ INVENTORY.md
│  └─ TEST_DATA_SCENARIO.md
│
├─ dist/
├─ coverage/
├─ node_modules/
├─ package.json
├─ package-lock.json
├─ tsconfig.json
├─ PLAN.md
├─ .env
├─ .env.example
└─ .gitignore

Основные составляющие проекта:

  • src/server.ts — точка входа приложения, которая запускает HTTP-сервер на нужном порту.

  • src/http.ts — HTTP-слой маршрутизации, который отвечает на несколько вопросов: какой URL открыл пользователь, открыл ли он общий дашборд или карточку компании, какой HTML или JSON вернуть.

  • src/passport.ts — главный бизнес-слой, где живёт логика приложения. Этот скрипт понимает, какие сущности нужны, как собрать Batch-запрос, как считать метрики и нормализовывать ответы. При добавлении новых функций основная работа будет здесь.

  • src/vibe.ts — клиент VibeCode API. Он знает, куда отправлять Batch, какие заголовки авторизации нужны, как распарсить ответ. Весь контакт с внешним API изолирован в одном месте. Благодаря этому, если поменяется формат ответа или endpoint, не придётся переписывать весь проект. 

  • src/ui/pages.ts — серверный HTML-рендеринг. Здесь хранятся общий дашборд, карточка компании, таблицы, метрики, стили. Агент сознательно не стал использовать React/Vue, потому что на этапе первой версии это было бы лишней зависимостью. Нам нужен был быстрый, типизированный и минимальный проект, который можно легко задеплоить на VibeCode-сервер.

  • src/*.test.ts — тесты, которые проверяют конфиг, HTTP-роутинг, Вайбкод-клиент, сбор паспорта и HTML-рендеринг.

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

Общий процесс выглядит так:

Что сделаем дальше

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

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

Комментарии (1)


  1. mia123
    01.07.2026 09:22

    Ждем официальную библиотеку Bitrix UI для платформы вайбкодинга и чёткие инструкции для агента по авторизации. Все путаются , как у вас , так и у нас разные агенты разных вендоров, наталкиваются на одно и тоже препятствие в авторизации. По задумке одного ключа должно быть достаточно для всего. А получается , что нет , и количество вариаций зашкаливает в таком случае. Необходимо чёткое разделение в документации видов приложений в зависимости от видов их использования и видов планируемой авторизации.
    не знаю как у остальных, у нас 99% приложений это встройка в интерфейс Битрикс. Но чёткого алгоритма создания такой встройки не описано. Даже у вас описано, что агент запутался.

    так же на пример на презентации вайб платформы, был упомянута возможность создавать внешнее приложение со своей авторизацией логин/пароль без привязки к битрикс паспорту и без регистрации на портале, это влечёт за собой кучу инфраструктурных решений, хранение и администрирование этих учёток, ролевая модель прав, ну и связь с информацией из портала, на пример покупатель войдя в "личный кабинет" мог видеть связанные с ним сделки в нашем формате.

    в документации я такой возможности не нашёл, а агенты тем более.