# Доработки визуального редактора Telegram-бот — План ## Итерация 1: Критичные фиксы + Backend (2-3 дня) ### 1.1. Обработка /stop (п.4, п.9) **Backend:** - В `telegram-incoming.processor.ts` — при получении `/stop`: - Пометить подписчика `isSubscribed = false`, `blockedAt = now()` - Отправить прощальное сообщение (настраивается в settings бота) - НЕ отправлять больше сообщений (проверка в engine перед sendMessage) - В `scenario-engine.service.ts` — перед каждым `sendMessage` проверять `isSubscribed` - В `broadcast.processor.ts` — уже есть проверка, ок - При повторном `/start` — `isSubscribed = true`, `blockedAt = null` (уже работает) **Аналитика:** - В stats добавить `unsubscribed` (blockedAt != null, отдельно от telegram-блокировки) - Отображать на дашборде: подписаны / отписались (/stop) / заблокировали (telegram) ### 1.2. Защита от перехода по своей реф-ссылке (п.10) **Backend:** - В `telegram-incoming.processor.ts` — при `/start ref_XXX`: - Если `ref_XXX` === текущий subscriberId → не создавать реферал - Отправить сообщение: "Это ваша реферальная ссылка — отправьте её другу!" - Показать кнопку "Поделиться ссылкой" ### 1.3. Сохранение позиций блоков (п.8 второй) **Backend:** - Добавить поле `layoutPositions Json?` в модель `TgBotScenario` - Формат: `{ "nodeId": { "x": 100, "y": 200 }, ... }` - API: при сохранении сценария принимать `positions` отдельно от `scenario` - Загружать позиции при открытии и применять к React Flow **Frontend:** - При перемещении ноды — сохранять `node.position` в локальный state - При нажатии "Сохранить" — отправлять и `scenario` и `positions` - При загрузке — если есть `positions`, применять их вместо авто-layout --- ## Итерация 2: Визуальный редактор v2 — Layout + Кнопки (3-5 дней) ### 2.1. Рендеринг сверху вниз (п.1) **Изменения:** - React Flow `direction: 'TB'` (top-to-bottom) вместо LR - Handles: `Position.Top` (target) и `Position.Bottom` (source) - `scenarioToFlow` — пересчёт layout вертикально (дерево сверху вниз) - Dagre layout library для автоматического расположения (`@dagrejs/dagre`) ### 2.2. Кнопки как визуальные элементы (п.1) **Архитектура:** - Кнопки рендерятся внутри message-ноды как кликабельные блоки - Каждая кнопка имеет свой выходной handle (source) - Из каждой кнопки идёт связь вниз к целевой ноде - Кнопки расположены горизонтально на одном уровне под сообщением **UI ноды `message`:** ``` ┌──────────────────────────┐ │ 📝 Сообщение │ │ Привет! Выбери действие: │ │ │ │ [+ Кнопка] │ │ ┌─────────┐ ┌─────────┐ │ │ │ Узнать │ │ О клубах│ │ │ │ ● │ │ ● │ │ ← выходные handles │ └─────────┘ └─────────┘ │ └──────────────────────────┘ ``` **Для каждой кнопки:** - Текст (редактируемый inline) - Тип: goto / url / share_contact - Кнопки [X] удалить, [↑↓] переместить - Drag handle для связи с целевой нодой ### 2.3. Управление кнопками (п.1) - [+ Кнопка] — добавить новую кнопку в сообщение - Клик по кнопке → inline-редактирование текста - Правый клик / иконка → popup: тип (goto/url/contact), target - [x] — удалить кнопку - Drag & drop для сортировки кнопок внутри ноды --- ## Итерация 3: Визуальные редакторы свойств (3-5 дней) ### 3.1. Редактор сообщений в стиле Telegram (п.3) **Компонент `TelegramMessageEditor`:** - WYSIWYG-подобный редактор текста - Toolbar: **Bold**, _Italic_, ~~Strikethrough~~, `Code`, ||Spoiler|| - Генерирует HTML: ``, ``, ``, ``, `` - Emoji picker (популярные emoji для бизнеса) - Превью сообщения в стиле Telegram (пузырь) - Подстановка переменных: кнопка `{{x}}` → выпадающий список переменных сценария ### 3.2. Картинки в сообщениях (п.2) - Кнопка "Добавить картинку" в ноде message - Upload изображения → сохранение на сервере (или URL) - Превью картинки в ноде - Кнопка [X] для удаления картинки - Backend: `sendPhoto` вместо `sendMessage` когда есть `image` ### 3.3. Визуальный блок «Действие» (п.5) **Вместо JSON — UI форма:** ``` ┌──────────────────────────────┐ │ ⚡ Действие │ │ │ │ [+ Добавить действие] │ │ │ │ 1. 📌 Установить переменную │ │ bonus_granted = true [X] │ │ │ │ 2. 🎁 Начислить бонус [X] │ │ │ │ 3. 📋 Создать сделку CRM [X] │ │ Имя: {{user_name}} │ │ Тел: {{phone}} │ └──────────────────────────────┘ ``` **Каждый тип действия — своя мини-форма:** - `set_variable` → dropdown переменных + input значения - `grant_bonus` → просто галочка, без параметров - `set_consent` → toggle вкл/выкл - `webhook` → URL + метод + body (JSON) - `crm_deal` → поля: имя, телефон, pipeline (dropdown) ### 3.4. Визуальный блок «Условие» (п.7) **Вместо JSON — UI с ветвлениями:** ``` ┌────────────────────────────────┐ │ 🔀 Условие │ │ │ │ [+ Добавить правило] │ │ │ │ Если [invited_count ▼] [>= ▼] │ │ [2 ] → ● │ ← handle к целевой ноде │ │ │ Если [invited_count ▼] [== ▼] │ │ [1 ] → ● │ │ │ │ Иначе → ● │ ← default handle └────────────────────────────────┘ ``` **Каждое правило:** - Dropdown: выбор переменной (из variables сценария) - Dropdown: оператор (==, !=, >=, <=, >, <) - Input: значение - Выходной handle справа/снизу ### 3.5. Визуальное условие в задержке (п.8 первый) **Блок delay с визуальным cancelOn:** ``` ┌───────────────────────────┐ │ ⏰ Задержка: 30m │ │ │ │ Отменить если: │ │ [invited_count ▼] [>= ▼] │ │ [2 ] │ │ │ │ Напоминание: "Пока..." │ └───────────────────────────┘ ``` --- ## Зависимости и порядок ``` Итерация 1 (backend фиксы) ├── /stop обработка ├── Защита от своей реф-ссылки └── Сохранение позиций │ Итерация 2 (layout + кнопки) ├── Dagre layout (TB) ├── Кнопки как handles └── CRUD кнопок в ноде │ Итерация 3 (визуальные редакторы) ├── Telegram message editor ├── Картинки ├── Action builder ├── Condition builder └── Delay condition builder ``` ## Технические решения | Задача | Библиотека/подход | | ------------------ | ----------------------------------------------------------------- | | TB layout | `@dagrejs/dagre` — автоматическое расположение графа | | Кнопки как handles | React Flow dynamic handles (`Handle` с уникальными id per button) | | Текстовый редактор | `tiptap` (lightweight) или custom contentEditable с toolbar | | Emoji picker | `emoji-mart` или встроенный через Unicode | | Картинки | Upload на `/api/upload` → URL, или base64 inline | | Позиции | JSON поле в TgBotScenario, sync при drag-end | ## Оценка | Итерация | Дни | Приоритет | | ----------------------- | -------- | --------- | | 1. Backend фиксы | 2-3 | Высокий | | 2. Layout + кнопки | 3-5 | Высокий | | 3. Визуальные редакторы | 3-5 | Средний | | **Итого** | **8-13** | |