Как построить визуальный no-code редактор воронок и AI пайплайнов на React поверх low-code ядра Metabot
Этот урок — про то, как поверх Metabot (который сам по себе полный low-code/full-code backend для чат-ботов и ассистентов) построить новый продукт: визуальный конструктор чат-ботов.
То есть вы создадите реальный продуктовый интерфейс — свой ManyChat / BotHelp, но умнее и современнее.
Главная идея:
Metabot — это low-code/full-code ядро.
Пройдя этот урок, вы научитесь строить целые продукты поверх ядра, создавая собственный фронт, визуальный редактор, 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 команд в скриптах + одна неявная команда (меню).
| № | Команда | Что делает | Где хранится | Пример content в БД |
|---|---|---|---|---|
| 1 | send_text | отправляет текстовое сообщение | phrases | Hello, World!!! |
| 2 | value_input | запрашивает ввод и валидирует | phrases | {"attribute_key":"abc","prompt":"Введите число", ...} |
| 3 | run_javascript | выполняет JS на сервере | phrases | 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_javascriptможет мгновенно передать управление в другой скрипт. -
Кнопки (
references) — это отдельная сущность: они не лежат вphrases, но участвуют в сценарии. В интерфейсе меню расположено внизу скрипта, после списка команд.
«Зачем нам свой конструктор и свои команды»
После того как мы разобрались, какие команды реально существуют внутри Metabot и посмотрели, как они физически хранятся в базе (sentences, phrases, references), мы можем перейти к ключевой идее нашего урока:
Мы не будем создавать интерфейс, который один-в-один повторяет Metabot.
Мы создадим свой собственный визуальный конструктор, и в нём у нас будут свои команды — более удобные, более компактные и намного более выразительные.
Почему так?
Почему в Metabot всё разбито на 21 команду
(и почему это отлично для движка, но неудобно для дизайнера чат-ботов)
Metabot — это low-code ядро. Каждая команда — это минимальная атомарная операция:
-
отправить текст,
-
отправить картинку,
-
записать тег,
-
выполнить JS,
-
перейти в скрипт,
- дождаться ввода
и так далее.
Это правильно для движка:
движок должен быть предсказуемым и детерминированным.
Но для человека, который рисует сценарий, это слишком низкий уровень.
Чтобы собрать один «узел» диалога, дизайнеру нужно вручную собрать:
-
1–3
send_text-
условия и JS
-
настройки под разные каналы
-
кнопки меню (в
references)
-
обработчики кликов (ещё несколько
run_sentence+ JS)
-
JS для логирования для аналитики
-
триггеры для отслеживания ссылок
-
переходы к следующему шагу
-
В итоге один визуальный узел превращается в:
→ 6–12 низкоуровневых фраз в базе
→ 2–4 скрипта (sentences)
→ и пачку записей в references
Именно поэтому мы не хотим заставлять пользователя руками разбираться в 21 команде ядра. Мы хотим сократить этот слой.
Теперь проектируем наш собственный редактор
Мы создаём свою систему узлов — такую, в которой:
-
один узел = одна логическая операция сценария,
-
пользователь видит высокоуровневую настройку,
-
а всё сложное — «распаковывается» автоматически внутрь Metabot при импорте.
Это и есть смысл маппера и билдера.
Какие наши команды мы сделаем первыми
1. Start / Entry Node
Стартовый узел воронки.
Даёт визуальную точку входа + будущую связь с диплинками.
Вход в воронку возможен как из других воронок / сценариев, так и снаружи при переходе в мессенджер из приложений или из контента в Интернет.
2. Send Text (расширенная)
Это не просто send_text из Metabot.
Наша версия включает:
-
💬 универсальное сообщение
-
💬 кастомизация сообщения под каналы (Telegram, WhatsApp, VK, WebChat и так далее)
- 🔘 поддержка кнопок
- ⚙️ обработчики событий нажатия на кнопку
-
📌 запись в аналитику прямо внутри узла
- 🔗 поддержка ссылок (с автогенерацией триггеров)
В Metabot для этого потребовалось бы от 6 до 12 низкоуровневых команд.
У нас — один визуальный блок.
Пример шага в новом no code редакторе:
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 в следующий скрипт
То есть одна наша команда = много внутренних.
Именно поэтому мы делаем свой язык.



