Как построить визуальный no-code редактор воронок на React поверх Metabot
Этот урок — про то, как поверх Metabot (который сам по себе полный low-code/full-code backend для чат-ботов и ассистентов) построить новый продукт: визуальный конструктор чат-ботов.
То есть вы создадите реальный продуктовый интерфейс — свой ManyChat / BotHelp, но умнее и современнее.
Главная идея:
Metabot — это ядро.
Пройдя этот урок, вы научитесь строить целые продукты поверх ядра, создавая собственный фронт, визуальный редактор, AI-функции и конструкторы.
Часть 1. Что будет в этом уроке — и чего здесь не будет
Чтобы вы сразу понимали рамки: этот урок — это фундамент, первая версия конструктора, на котором вы сможете дальше строить полноценный продукт. Здесь мы создаём работающий скелет визуального редактора и настраиваем импорт в Metabot.
А теперь — по пунктам.
Что будет в уроке
1. Создадим собственный JSON-формат воронки
Вы:
-
придумаете свой формат,
-
определите структуру шагов воронки,
-
создадите свои типы команд,
-
добавите свои параметры и опции.
То есть вы спроектируете свой DSL (domain-specific language) — язык описания воронок вашего продукта.
2. Разберётесь, как работает Mapper
Мы подробно посмотрим, как:
-
входящий JSON обрабатывается,
-
шаги проверяются,
-
неподдерживаемые типы фильтруются,
-
нужные команды собираются,
-
создаются переходы, кнопки, логгирование, LLM-вызовы и так далее.
То есть вы поймёте логику трансформации вашего формата → формат Metabot.
Вы получите исходный код Mapper'а.
3. Разберётесь, как работает Builder
Мы детально пройдём по механике:
-
создания секции/папки скриптов в Metabot,
-
создания скриптов,
-
добавления low-code команд в скрипт,
-
создания переходов и menu-кнопок,
-
удаления старых версий воронки.
И главное — вы увидите, как Builder напрямую манипулирует базой данных Metabot (PostgreSQL) через PHP/V8.
Это даёт понимание того, как работает ядро платформы и как можно строить свои надстройки.
Вы получите исходный код Builder'а.
4. Научитесь подключать Metabot как backend
Вы увидите, как:
-
передавать JSON в Metabot через API,
-
запускать импорт,
-
пересобирать воронку целиком,
-
структурировать код для своего продукта.
То есть Metabot превращается для вас в backend-as-a-platform, который вы можете использовать под любые проекты.
5. Сделаем визуальный редактор на React (с помощью V0 + Cursor)
Мы:
-
создадим canvas и интерфейс узлов,
-
свяжем их с JSON,
-
добавим импорт и экспорт в/из файла,
-
добавим базовые настройки шагов и валидации,
-
подготовим front-end архитектуру.
Вы получите:
-
исходный код редактора,
-
архитектуру компонентов,
-
промпты, с помощью которых редактор собирался (это важно — это обучает самостоятельному созданию продуктов).
6. Настроим рабочий цикл разработки
Первые итерации будут такие:
1) создаём JSON вручную →
2) отправляем через Postman →
3) смотрим, как Metabot создал воронку →
4) фиксируем ошибки →
5) делаем свои команды →
6) строим визуальный редактор, который уже генерит нужный JSON →
7) импортируем в Metabot одной кнопкой
Это честный, практичный, продуктовый процесс.
7. Вы получите всё, чтобы создать свой продукт
В итоге у вас будет:
-
работающий визуальный редактор,
-
свой JSON-формат,
- свой набор команд,
- сохранение в файл и загрузка из файла,
-
исходники маппера/билдера,
-
связка React → JSON → Metabot.
На этом можно строить:
-
no-code конструктор,
-
CJM-редактор,
-
AI-конструктор цепочек,
-
бизнесовый продукт поверх Metabot.
🚫 Чего в этом уроке НЕ будет
Чтобы не вводить в заблуждение — сразу фиксируем:
1. Не будет двусторонней синхронизации
Мы делаем только импорт из вашего конструктора → Metabot.
То есть:
-
если воронка существует — она удаляется и создаётся заново,
-
мы не читаем текущую структуру из Metabot,
-
мы не отображаем её обратно в редактор.
Это осознанное упрощение.
Вторую сторону можно сделать, но это отдельный блок задач:
читать данные Metabot → конвертировать → отображать → синхронизировать версии.
Мы это оставляем для следующего урока, если будет запрос.
2. Не будет полноценного менеджмента трафика
Это очень важный момент.
В реальной жизни по ранее импортированной воронке уже могут идти живые пользователи.
Если вы меняете воронку, возникают вопросы:
-
что делать с активными пользователями?
-
надо ли их перенаправлять в новую версию?
-
надо ли блокировать обновления?
-
нужно ли создавать копии воронок?
-
нужно ли делать миграции шагов?
-
как правильно писать стратегию версионирования?
Это целая философия, и у каждого продукта — свой подход.
Мы эту сложность сознательно не включаем в этот урок.
Но если понадобится понадобится помощь — дайте знать, попробуем помочь.
3. Не будет полноценной "платформенности"
В этом уроке:
- нет авторизации и регистрации — импорт по API токену пользователя, привязанному к боту.
- нет совместной работы.
Мы делаем первую версию конструктора, но она уже рабочая и расширяемая.
Принял. Делаю первую итерацию — без фанатизма, но уже структурно, лаконично, красиво, чтобы можно было вложить в документацию и развивать дальше.
Ты дал огромный объём информации, поэтому я сейчас фиксирую каркас главы 2, + делаю первый блок: спецификация команд Metabot + JSON-формат, + простую таблицу команд, красиво оформленную, + мини-описание модели данных (sentences, phrases, references).
В следующей итерации я смогу:
добить оставшиеся разделы,
оформить финальный CJM JSON на 20 шагов,
добавить продвинутую постановку задач.
Глава 2. JSON-формат и фундаментальная модель данных Metabot
Чтобы создать собственный визуальный конструктор поверх Metabot, нужно понимать две вещи:
Какие команды реально существуют в ядре платформы
Как Metabot хранит эти команды в базе данных
Эта глава даёт разработчику язык конструктора — JSON-формат шага, таблицу команд и модель хранения внутри Metabot.
2.1. Базовая модель данных Metabot
Метабот — low-code движок. Его диалоговая логика физически живёт в трёх таблицах:
sentences — это скрипты
Каждый шаг в нашем редакторе превратится в отдельный скрипт Metabot.
id
ID скрипта
code
Уникальный код (мы сами создаём)
name
Читабельное имя
bot_id
Бот, которому принадлежит скрипт
section_id
Папка/категория (наша “воронка”)
...
Остальные поля нам пока не нужны
Пример:
id: 85681
code: "test-script"
name: "TestScript"
bot_id: 2370
phrases — это команды внутри скрипта
Одна запись = одна команда.
Каждый шаг в нашем редакторе может порождать от 1 до 10 фраз.
id
ID команды
type
Тип команды (send_text, run_javascript, …)
sentence_id
Скрипт, которому команда принадлежит
content
Текст или JSON-контент команды
sort_order
Порядок выполнения
alias
Уникальный ID команды
Пример вывода send_text:
type: "send_text"
sentence_id: 85681
content: "Hello, World!"
sort_order: 0
Пример ввода пользователя value_input:
id: 231462
type: value_input
sentence_id: 85681
content: {"attribute_key":"var","prompt":"Введите число",...}
sort_order: 1
references — это кнопки (меню)
Меню — это не фраза, а отдельная таблица (так исторически, да). Каждая запись — это кнопка.
sentence_id
Скрипт, которому меню принадлежит
caption
Текст кнопки
code
Код/значение кнопки
jump_sentence_id
Куда переходить
sort_order
Порядок кнопок
line_num
Для многострочных клавиатур
condition_script_code
Условие отображения
Пример:
sentence_id: 85681
caption: "Start Over"
code: "1"
jump_sentence_id: 85680
📌 Все 21 команды Метабота
На момент написания этого урока в Metabot есть 20 команд в скриптах + одна неявная команда (меню).
Hello, World!!!
2
value_input
запрашивает ввод и валидирует
phrases
{"attribute_key":"abc","prompt":"Введите число", ...}
3
run_javascript
выполняет JS на сервере
se
lead.setAttr('abc', 123);
4
send_image
отправляет изображение
phrases
{"path":"bot/.../logo.png","name":"logo.png"}
5
send_file
отправляет файл (любые документы)
phrases
{"path":"bot/...","name":"file.pdf"}
6
run_sentence
выполняет другой скрипт, останавливает текущий
phrases
85681
7
send_email
отправляет email
phrases
{"recipient":"user@mail","subject":"...","body":"..."}
8
run_trigger
запускает триггер
phrases
{"trigger_id":"7222","run_at":"2025-06-11","run_after_sec":300}
9
set_lead_status
меняет статус лида
phrases
7783
10
add_lead_tags
добавляет теги
phrases
"tag"
11
remove_lead_tags
удаляет теги
phrases
"tag"
12
nlp_detect_intent
определяет интент
phrases
{"text_to_detect":"intent"}
13
run_js_callback
делает JS-callback
phrases
{"prompt":"...","error_message":"...","js_code":"..."}
14
async_api_call
async вызов API (например, обращение к LLM)
phrases
{"js_code":"...","is_immediate_call":1}
15
add_lead_contexts
добавляет контекст
phrases
"context"
16
remove_lead_contexts
удаляет контекст
phrases
"context"
17
forward_to_operator
переводит на оператора
phrases
7784
18
return_to_bot
возвращает в бота
phrases
7783
19
repeat_sentence
повторяет текущий скрипт
phrases
{}
20
stop
полностью останавливает выполнение
phrases
{}
21
menu (reference)
кнопки меню, переходы, inline actions
references
caption="Start", jump_sentence_id=85680
Короткое объяснение логики исполнения команд
Команды внутри одного скрипта (sentence) выполняются сверху вниз по sort_order.
Любая команда типа run_sentence или run_js_callback может мгновенно передать управление в другой скрипт.
Кнопки (references) — это отдельная сущность: они не лежат в phrases, но участвуют в сценарии.
Вот тебе ровно тот кусок текста, который сейчас нужен: ясный, убедительный, «ведущий читателя» — и одновременно полностью отражающий твою идею создать собственный визуальный конструктор, где одна «наша» команда заменяет пачку метаботовских низкоуровневых команд.
Это идеально идёт сразу после секции со списком 21 команды Metabot.
🔶 Раздел: «Зачем нам свой конструктор и свои команды»
(вставь в статью как есть — он написан в том же тоне, что и предыдущие части и красиво связывает контекст)
После того как мы разобрались, какие команды реально существуют внутри Metabot и посмотрели, как они физически хранятся в базе (sentences, phrases, references), мы можем перейти к ключевой идее нашего урока:
Мы не будем создавать интерфейс, который один-в-один повторяет Metabot.
Мы создадим свой собственный визуальный конструктор, и в нём у нас будут свои команды — более удобные, более компактные и намного более выразительные.
Почему так?
## 🧠 Почему в Metabot всё разбито на 21 команду
(и почему это отлично для движка, но неудобно для дизайнера чат-ботов)
Metabot — это low-code ядро. Каждая команда — это минимальная атомарная операция:
отправить текст,
отправить картинку,
записать тег,
выполнить JS,
перейти в скрипт,
вызвать LLM,
записать аналитику,
дождаться ввода
и так далее.
Это правильно для движка:
движок должен быть предсказуемым и детерминированным.
Но для человека, который рисует сценарий, это слишком низкий уровень.
Чтобы собрать один «узел» диалога, дизайнеру нужно вручную собрать:
1–3 send_text
условия и JS
настройки под разные каналы
кнопки меню (в references)
обработчики кликов (ещё несколько run_sentence + JS)
автологирование для аналитики
триггеры для отслеживания ссылок
переходы к следующему шагу
В итоге один визуальный узел превращается в:
→ 6–12 низкоуровневых фраз в базе
→ 2–4 скрипта (sentences)
→ и пачку записей в references
Именно поэтому мы не хотим заставлять пользователя руками разбираться в 21 команде ядра. Мы хотим сократить этот слой.
🔶 Теперь проектируем наш собственный редактор
Мы создаём свою систему узлов — такую, в которой:
один узел = одна логическая операция сценария,
пользователь видит высокоуровневую настройку,
а всё сложное — «распаковывается» автоматически внутрь Metabot при импорте.
Это и есть смысл маппера и билдера.
## Какие наши команды мы сделаем первыми
Мы начинаем не с копирования полного набора команд Metabot.
Мы делаем те команды, которые дают 80% функциональности и 20% сложности.
1. Start / Entry Node
Стартовый узел воронки.
Даёт визуальную точку входа + будущую связь с диплинками.
2. Send Text (расширенная)
Это не просто send_text из Metabot.
Наша версия включает:
💬 универсальное сообщение
💬 кастомизация под каналы (Telegram, WhatsApp, VK, WebChat)
⚙️ обработку макросов
🤖 возможность вставить LLM-подсказки
🔘 кнопки со встроенными обработчиками
📌 запись в аналитику прямо внутри узла
↪️ переход к следующему шагу
🔗 поддержка ссылок (с автогенерацией триггеров)
В Metabot для этого потребовалось бы от 6 до 12 низкоуровневых команд.
У нас — один визуальный блок.
3. Записать в аналитику
Метаботовская команда run_javascript + вызов WayLogger.
Мы прячем всё JS-пекло от пользователя.
В нашем интерфейсе есть:
выбор типа логирования: step, event, tag, utter,
выбор пути (way),
параметры.
4. Переход к следующему шагу
В Metabot это команда run_sentence.
В нашем редакторе — просто стрелка между узлами.
5. Обращение к LLM (call_llm)
В Metabot — большой JSON с настройками callback.
Мы делаем:
выбор модели
выбор агента
system / user prompts
способ отображения ответа
параметры истории
next & error flow
Всё это — внутри одного визуального окна.
6. Поиск по базе знаний (search_knowledgebase)
Точно так же — один узел, один JSON.
А Metabotу при импорте достанется пачка сложных команд и связок.
## Почему наши команды будут «упакованными»
(концепция compact high-level commands)
Каждая наша команда — это высокоуровневый «комбинированный» блок.
Когда пользователь его настраивает, мы:
собираем данные в простой JSON (наш формат),
передаём этот JSON мапперу,
маппер превращает один наш узел в:
1 или несколько sentences
десятки phrases
references
JS-код
триггеры
переходы
аналитику
То есть пользователь видит простую, компактную визуальную воронку, а под капотом:
строится настоящая сложная система Metabot с триггерами, скриптами, условиями, логированием и разветвлёнными сценариями.
## Пример эффекта (наглядно)
Было бы без нашего редактора 👇
Один узел =
→ 3–5 команд отправки сообщений
→ 1–3 условия
→ 3–10 кнопок (references)
→ 1–5 вспомогательных скриптов
→ JS обработчики
→ триггеры для ссылок
→ аналитика как отдельный скрипт
→ ручное связывание переходов
С нашим редактором 👇
Один узел =
→ 1 блок Send Text с кнопками и аналитикой
→ 1 JSON-объект
→ 1 клик: «Импорт в Metabot»
→ всё остальное сделает маппер и билдер
## Вводная мысль для перехода к следующей главе
Теперь, когда мы понимаем:
какие команды существуют внутри Metabot,
почему они такие низкоуровневые,
и зачем нам свой набор «уплотнённых» команд,
мы можем перейти к следующему этапу —
спецификации нашего JSON-формата, который и станет языком для визуального конструктора.
Если всё ок, я сделаю следующий раздел:
🔷 «Наш JSON-формат: структура всех типов шагов»
включая:
поля узла,
поля кнопок,
поля аналитики,
поля ссылок,
поля LLM,
и пример полного JSON на 6–8 шагов.
Гони?
⚡️ Наш новый формат для No Code редактора
Теперь, когда ты знаешь, какие команды существуют в Metabot и как они хранятся в sentences/phrases/references, мы можем спроектировать наш собственный JSON-формат.
Он не равен командам Metabot —
мы создаём собственную, удобную DSL.
А затем мы создадим маппер, который превращает наш JSON → структуры Metabot.
Простой пример шага:
{
"code": "hello_world",
"type": "send_text",
"name": "Приветствие",
"content": "Привет! Как дела?",
"next_step": "next_message",
"coordinates": { "x": 120, "y": 300 },
"buttons": [
{
"title": "Продолжить",
"value": "go",
"next_step": "continue",
"add_tags": [],
"remove_tags": []
}
]
}
Важно: наш JSON ≠ команды Metabot
Наша концепция:
Пользователь создаёт узлы (steps).
Наш JSON описывает машину состояний.
На импорте Mapper превращает “steps” → множество “phrases”.
Например:
Наш узел “send_text” превращается в:
1 или несколько команд send_text (для каждого канала)
0–5 команд add/remove tags
0–1 команд run_javascript
0–10 кнопок в таблице references
0–1 переход run_sentence в следующий скрипт
То есть одна наша команда = много внутренних.
Именно поэтому мы делаем свой язык.