# Доработки визуального редактора 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: `<b>`, `<i>`, `<s>`, `<code>`, `<tg-spoiler>`
- 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** |           |
