Full-stack module for building Telegram chatbot scenarios in CRM. Backend (NestJS): - 6 Prisma models: TgBot, TgBotScenario, TgBotSubscriber, TgBotMessage, TgBotBroadcast, TgBotWebhook - JSON scenario engine with 6 node types: message, condition, action, input, delay, referral - Referral mechanics: deep links, invite tracking, friend routing - Broadcasts with 10 audience filters, batch sending with rate limiting - Outgoing webhooks: 9 event types, HMAC-SHA256 signing, retry - CRM integration: create deals from bot scenarios - Analytics: subscriber stats, referral metrics, funnel, daily growth - 12 services, 4 BullMQ processors, 7 controllers, ~35 REST endpoints Frontend (web-club-admin): - 8 pages: bot list, dashboard, subscribers, broadcasts, scenario editor, webhooks, analytics - Visual scenario editor with React Flow: 6 custom node types - Sidebar: module-aware visibility (Hide, Don't Block) Includes Powerhouse Gym referral scenario (24 nodes) and user docs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
36 KiB
Модуль "Telegram Bot Constructor" — План разработки
1. Концепция
Универсальный конструктор чат-бот сценариев в Telegram, встроенный в CRM. Админ клуба через UI собирает цепочку шагов (ноды), сценарий сохраняется в JSON, движок бота выполняет его в рантайме. Первый кейс — реферальный бот Powerhouse Gym.
Принцип: конструктор покрывает любой сценарий — от простого приветствия до многошаговой реферальной программы с ветвлениями, условиями и интеграциями.
2. Архитектура JSON-сценария
2.1 Структура сценария
{
"id": "uuid",
"version": 1,
"name": "Реферальный бот Powerhouse",
"startNodeId": "node_welcome",
"variables": {
"invited_count": { "type": "number", "default": 0 },
"selected_club": { "type": "string", "default": "" },
"bonus_granted": { "type": "boolean", "default": false },
"phone": { "type": "string", "default": "" },
"referrer_chat_id": { "type": "string", "default": "" }
},
"nodes": { ... },
"edges": [ ... ]
}
2.2 Типы нод
| Тип | Назначение |
|---|---|
message |
Отправить текст/фото с кнопками (inline/reply) |
condition |
Ветвление по переменной или выражению |
action |
Выполнить действие (webhook, set variable, API) |
input |
Ждать ввод от пользователя (текст, телефон) |
delay |
Пауза / таймер / напоминание |
referral |
Генерация реф-ссылки, подсчёт приглашённых |
broadcast |
Точка входа для рассылки (не часть основного flow) |
2.3 Пример ноды message
{
"id": "node_welcome",
"type": "message",
"data": {
"text": "👋 Привет! Это бот фитнес-клуба {{club_name}}.\n\nСейчас можем предложить вам **бесплатную персональную тренировку**!",
"image": null,
"buttons": [
{
"text": "🏋️ Как получить тренировку",
"action": "goto",
"target": "node_offer",
},
{
"text": "📍 О клубе",
"action": "goto",
"target": "node_about_club",
},
],
"buttonsLayout": "inline", // "inline" | "reply" | "remove"
},
"next": null, // null = ждём нажатия кнопки
}
2.4 Пример ноды condition
{
"id": "node_check_referrals",
"type": "condition",
"data": {
"rules": [
{
"condition": "invited_count >= 2",
"target": "node_bonus_granted",
},
{
"condition": "invited_count == 1",
"target": "node_one_more",
},
],
"default": "node_send_referral_link",
},
}
2.5 Пример ноды action
{
"id": "node_send_to_crm",
"type": "action",
"data": {
"actions": [
{
"type": "webhook",
"url": "{{webhook_url}}",
"method": "POST",
"body": {
"event": "bot.lead.created",
"phone": "{{phone}}",
"club": "{{selected_club}}",
"source": "telegram_bot",
"referrer": "{{referrer_chat_id}}",
},
},
{
"type": "set_variable",
"variable": "bonus_granted",
"value": true,
},
{
"type": "crm_deal",
"pipeline": "{{default_pipeline}}",
"fields": {
"name": "TG Bot: {{first_name}}",
"phone": "{{phone}}",
},
},
],
},
"next": "node_thank_you",
}
2.6 Пример ноды input
{
"id": "node_get_phone",
"type": "input",
"data": {
"prompt": "Оставьте номер телефона — менеджер предложит удобное время визита.",
"inputType": "phone", // "text" | "phone" | "email" | "choice"
"saveAs": "phone", // имя переменной
"requestContact": true, // кнопка "Поделиться контактом"
"validation": "^\\+?[0-9]{10,15}$",
"errorMessage": "Введите корректный номер телефона",
},
"next": "node_send_to_crm",
}
2.7 Пример ноды delay
{
"id": "node_reminder_30min",
"type": "delay",
"data": {
"duration": "30m", // "10m", "1h", "24h", "3d"
"cancelOn": "invited_count >= 2", // отмена при выполнении условия
"message": {
"text": "⏰ Пока никто из друзей не оставил заявку.\nПопробуйте отправить ссылку ещё одному другу!",
"buttons": [
{ "text": "📤 Отправить ещё раз", "action": "goto", "target": "node_send_referral_link" },
],
},
},
"next": "node_check_referrals",
}
2.8 Пример ноды referral
{
"id": "node_referral_setup",
"type": "referral",
"data": {
"generateLink": true,
"linkPrefix": "https://t.me/{{bot_username}}?start=ref_",
"trackVariable": "invited_count",
"targetCount": 2,
"onReach": "node_bonus_granted",
"friendStartNode": "node_friend_welcome", // куда попадает друг
},
"next": "node_send_referral_link",
}
3. Модели данных (Prisma)
3.1 Конфигурация бота
model TgBot {
id String @id @default(uuid())
clubId String
club Club @relation(fields: [clubId], references: [id])
name String // "Реферальный бот Powerhouse"
token String // Bot API token (encrypted)
username String? // @bot_username
isActive Boolean @default(false)
webhookUrl String? // Telegram webhook URL
scenarioId String?
scenario TgBotScenario? @relation(fields: [scenarioId], references: [id])
settings Json @default("{}") // { welcomeMessage, defaultLanguage, ... }
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
subscribers TgBotSubscriber[]
messages TgBotMessage[]
broadcasts TgBotBroadcast[]
webhooks TgBotWebhook[]
@@index([clubId])
}
3.2 Сценарий
model TgBotScenario {
id String @id @default(uuid())
clubId String
club Club @relation(fields: [clubId], references: [id])
botId String?
name String
description String?
scenario Json // Полный JSON сценария
version Int @default(1)
isPublished Boolean @default(false)
isDraft Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bots TgBot[]
@@index([clubId])
}
3.3 Подписчики (ключевая таблица)
model TgBotSubscriber {
id String @id @default(uuid())
clubId String
club Club @relation(fields: [clubId], references: [id])
botId String
bot TgBot @relation(fields: [botId], references: [id])
chatId String // Telegram chat ID
telegramUserId String? // Telegram user ID
username String? // @username
firstName String?
lastName String?
phone String? // номер телефона (если есть)
isRegistered Boolean @default(false) // зарегистрировался или нет
bonusGranted Boolean @default(false) // получал бонус или нет
mailingConsent Boolean @default(false) // давал согласие на рассылку
isSubscribed Boolean @default(true) // подписан сейчас или нет
referrerId String? // от кого пришёл (ID подписчика)
referrer TgBotSubscriber? @relation("Referrals", fields: [referrerId], references: [id])
referrals TgBotSubscriber[] @relation("Referrals")
invitedCount Int @default(0) // сколько пригласил
source String? // источник трафика (qr, social, website)
currentNodeId String? // текущая нода в сценарии
variables Json @default("{}") // переменные сессии бота
tags String[] @default([]) // теги для сегментации
registeredAt DateTime? // дата регистрации в боте
lastActiveAt DateTime?
blockedAt DateTime? // когда заблокировал бота
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
messages TgBotMessage[]
@@unique([botId, chatId])
@@index([clubId])
@@index([botId])
@@index([referrerId])
@@index([phone])
@@index([isSubscribed, mailingConsent])
}
3.4 История сообщений
model TgBotMessage {
id String @id @default(uuid())
botId String
bot TgBot @relation(fields: [botId], references: [id])
subscriberId String
subscriber TgBotSubscriber @relation(fields: [subscriberId], references: [id])
direction TgMessageDirection // IN | OUT
nodeId String? // из какой ноды сценария
text String?
payload Json? // кнопка, контакт, фото и т.д.
telegramMsgId Int? // ID сообщения в Telegram
createdAt DateTime @default(now())
@@index([botId, subscriberId])
@@index([createdAt])
}
enum TgMessageDirection {
IN
OUT
}
3.5 Рассылки
model TgBotBroadcast {
id String @id @default(uuid())
clubId String
club Club @relation(fields: [clubId], references: [id])
botId String
bot TgBot @relation(fields: [botId], references: [id])
name String
message Json // { text, image, buttons }
filters Json // фильтры аудитории (ниже)
status TgBroadcastStatus @default(DRAFT)
scheduledAt DateTime? // запланированная отправка
startedAt DateTime?
completedAt DateTime?
totalCount Int @default(0) // сколько подписчиков в выборке
sentCount Int @default(0)
failedCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([clubId])
@@index([botId])
}
enum TgBroadcastStatus {
DRAFT
SCHEDULED
SENDING
COMPLETED
CANCELLED
}
Формат фильтров рассылки:
{
"clubs": ["uuid1", "uuid2"], // фильтрация по клубам
"source": ["qr", "website"], // от кого пришёл
"isRegistered": true, // зарегистрировался
"bonusGranted": false, // получал/не получал бонус
"mailingConsent": true, // согласие на рассылку
"isSubscribed": true, // подписан сейчас
"invitedCountMin": 1, // сколько пригласил (от)
"invitedCountMax": null, // сколько пригласил (до)
"registeredAfter": "2026-01-01", // дата регистрации от
"registeredBefore": "2026-03-01", // дата регистрации до
"tags": ["vip", "active"], // по тегам
}
3.6 Вебхуки бота (уведомления на внешние URL)
model TgBotWebhook {
id String @id @default(uuid())
clubId String
botId String
bot TgBot @relation(fields: [botId], references: [id])
url String // URL для отправки
secret String // HMAC secret
events String[] // ["subscriber.created", "referral.completed", ...]
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([botId])
}
События для вебхуков:
subscriber.created— новый подписчикsubscriber.blocked— заблокировал ботаsubscriber.phone_shared— поделился телефономreferral.invited— пригласил другаreferral.completed— условие реферала выполненоbonus.granted— бонус начисленlead.created— заявка создана (выбрал клуб)broadcast.completed— рассылка завершенаscenario.completed— подписчик прошёл сценарий до конца
4. Архитектура модулей (API)
apps/api/src/modules/telegram-bot/
├── telegram-bot.module.ts # NestJS модуль
├── telegram-bot.controller.ts # REST API для управления ботами
├── scenario.controller.ts # CRUD сценариев
├── subscriber.controller.ts # Управление подписчиками
├── broadcast.controller.ts # Рассылки
├── webhook-input.controller.ts # Приём обновлений от Telegram API
├── dto/
│ ├── create-bot.dto.ts
│ ├── update-bot.dto.ts
│ ├── create-scenario.dto.ts
│ ├── update-scenario.dto.ts
│ ├── create-broadcast.dto.ts
│ ├── subscriber-filter.dto.ts
│ └── bot-webhook.dto.ts
├── services/
│ ├── bot-manager.service.ts # CRUD ботов, регистрация webhook в TG
│ ├── scenario.service.ts # CRUD и валидация сценариев JSON
│ ├── scenario-engine.service.ts # 🔑 Движок: выполняет JSON-сценарий
│ ├── subscriber.service.ts # CRUD подписчиков, фильтрация
│ ├── referral.service.ts # Реферальная механика
│ ├── broadcast.service.ts # Рассылки с фильтрами
│ ├── telegram-api.service.ts # Обёртка над Telegram Bot API
│ └── bot-webhook.service.ts # Отправка событий на внешние URL
├── processors/
│ ├── telegram-message.processor.ts # BullMQ: обработка входящих
│ ├── broadcast.processor.ts # BullMQ: отправка рассылок
│ ├── bot-webhook.processor.ts # BullMQ: доставка вебхуков
│ └── delay-node.processor.ts # BullMQ: отложенные ноды
└── interfaces/
├── scenario.interface.ts # Типы JSON-сценария
├── node.interface.ts # Типы нод
└── engine-context.interface.ts # Контекст выполнения
5. Ключевые компоненты
5.1 Scenario Engine (ядро)
Движок получает входящее событие (сообщение, callback, контакт) и:
- Находит подписчика по
chatId - Загружает сценарий бота
- Определяет текущую ноду (
subscriber.currentNodeId) - Выполняет ноду → получает следующую
- Рекурсивно проходит
actionиconditionноды (без ожидания ввода) - Останавливается на
message(ждём кнопку) илиinput(ждём текст) - Сохраняет
currentNodeId+variables
Входящее сообщение
→ telegram-message.processor (BullMQ)
→ scenario-engine.service
→ resolve current node
→ execute node chain (action → condition → message)
→ send Telegram message
→ save state (currentNodeId, variables)
→ emit events (webhook)
5.2 Referral Service
- Генерирует deep link:
https://t.me/bot?start=ref_{subscriberId} - При
/start ref_XXX— записываетreferrerIdновому подписчику - Инкрементит
invitedCountу реферера - Проверяет условие (достиг
targetCount) → переключает наonReachноду - Отправляет реферу промежуточные уведомления ("Осталось ещё 1 человек")
5.3 Broadcast Service
- Строит SQL-запрос по фильтрам из JSON
- Создаёт BullMQ job'ы пачками (50 сообщений/сек — лимит TG API)
- Rate limiter: 30 msg/sec per bot, очередь с задержкой
- Обновляет
sentCount/failedCountв реальном времени - Поддержка отмены рассылки (
CANCELLED)
6. API Endpoints
Боты
POST /telegram-bot/bots # Создать бота
GET /telegram-bot/bots # Список ботов клуба
GET /telegram-bot/bots/:id # Получить бота
PATCH /telegram-bot/bots/:id # Обновить бота
DELETE /telegram-bot/bots/:id # Удалить бота
POST /telegram-bot/bots/:id/activate # Активировать (set webhook)
POST /telegram-bot/bots/:id/deactivate # Деактивировать
Сценарии
POST /telegram-bot/scenarios # Создать сценарий
GET /telegram-bot/scenarios # Список сценариев
GET /telegram-bot/scenarios/:id # Получить сценарий (с JSON)
PATCH /telegram-bot/scenarios/:id # Обновить JSON сценария
POST /telegram-bot/scenarios/:id/publish # Опубликовать (isDraft=false)
POST /telegram-bot/scenarios/:id/validate # Валидация JSON (без сохранения)
POST /telegram-bot/scenarios/:id/duplicate # Дублировать сценарий
Подписчики
GET /telegram-bot/bots/:botId/subscribers # Таблица подписчиков
GET /telegram-bot/bots/:botId/subscribers/:id # Карточка подписчика
GET /telegram-bot/bots/:botId/subscribers/:id/messages # История переписки
GET /telegram-bot/bots/:botId/subscribers/stats # Статистика
PATCH /telegram-bot/bots/:botId/subscribers/:id # Редактировать (теги, заметки)
POST /telegram-bot/bots/:botId/subscribers/:id/reset # Сбросить сценарий
Рассылки
POST /telegram-bot/broadcasts # Создать рассылку
GET /telegram-bot/broadcasts # Список рассылок
GET /telegram-bot/broadcasts/:id # Статус рассылки
PATCH /telegram-bot/broadcasts/:id # Обновить (DRAFT only)
POST /telegram-bot/broadcasts/:id/send # Запустить
POST /telegram-bot/broadcasts/:id/cancel # Отменить
POST /telegram-bot/broadcasts/preview-count # Превью кол-ва получателей
Вебхуки бота
POST /telegram-bot/bots/:botId/webhooks # Создать подписку
GET /telegram-bot/bots/:botId/webhooks # Список подписок
PATCH /telegram-bot/bots/:botId/webhooks/:id # Обновить
DELETE /telegram-bot/bots/:botId/webhooks/:id # Удалить
POST /telegram-bot/bots/:botId/webhooks/:id/test # Тестовая отправка
Telegram Webhook Input (публичный)
POST /telegram-bot/webhook/:botId # Incoming updates от TG API
7. UI в админ-панелях
7.1 web-club-admin (Админ клуба)
Маршруты:
/telegram-bot # Список ботов
/telegram-bot/new # Создание бота
/telegram-bot/:id # Настройки бота
/telegram-bot/:id/scenario # Редактор сценария
/telegram-bot/:id/subscribers # Таблица подписчиков
/telegram-bot/:id/broadcasts # Рассылки
/telegram-bot/:id/broadcasts/new # Создание рассылки
/telegram-bot/:id/webhooks # Настройка вебхуков
/telegram-bot/:id/analytics # Аналитика бота
Экран "Редактор сценария" (ключевой):
- Визуальный редактор нод (drag & drop) на основе React Flow
- Панель свойств ноды справа
- Превью текста сообщения с подстановкой переменных
- Кнопки: Сохранить черновик / Опубликовать / Валидировать
- Импорт/экспорт JSON
Экран "Таблица подписчиков":
- Колонки: Chat ID, Имя, Телефон, Зарегистрирован, Бонус, Согласие, Подписан, Источник, Приглашено, Дата
- Фильтры по всем колонкам
- Экспорт в XLSX
- Клик → карточка подписчика с историей переписки
Экран "Рассылки":
- Форма: текст + кнопки + фильтры аудитории
- Превью количества получателей
- Статус отправки в реальном времени
7.2 web-platform-admin (Суперадмин)
- Обзор всех ботов по всем клубам
- Управление лимитами модуля (макс. подписчиков, рассылок/мес)
- Мониторинг активности
8. Спринты разработки
Спринт 1: Фундамент (5-7 дней)
Цель: Базовая инфраструктура модуля, бот отвечает на /start
| # | Задача | Слой |
|---|---|---|
| 1 | Prisma-модели: TgBot, TgBotScenario, TgBotSubscriber, TgBotMessage | Schema |
| 2 | Миграция БД | Schema |
| 3 | NestJS модуль telegram-bot со структурой |
API |
| 4 | TelegramApiService — обёртка над Telegram Bot API (sendMessage, setWebhook, getMe) |
API |
| 5 | BotManagerService — CRUD ботов, активация/деактивация |
API |
| 6 | webhook-input.controller.ts — приём updates от Telegram |
API |
| 7 | BullMQ очередь telegram-message + процессор |
API |
| 8 | SubscriberService — создание подписчика при /start |
API |
| 9 | REST контроллер ботов (CRUD) | API |
| 10 | @RequireModule('telegram-bot') + enum в shared-types |
API |
| 11 | Seed: тестовый бот для dev-окружения | API |
Definition of Done: Бот зарегистрирован, принимает /start, создаёт подписчика в БД.
Спринт 2: Движок сценариев (7-10 дней)
Цель: JSON-сценарий выполняется в рантайме
| # | Задача | Слой |
|---|---|---|
| 1 | TypeScript интерфейсы для JSON-сценария (все типы нод) | Types |
| 2 | ScenarioService — CRUD сценариев, валидация JSON |
API |
| 3 | ScenarioEngineService — ядро: загрузка, resolve, execute node chain |
API |
| 4 | Обработка ноды message — отправка текста + кнопки |
API |
| 5 | Обработка ноды condition — eval выражений на переменных |
API |
| 6 | Обработка ноды action — set_variable, webhook |
API |
| 7 | Обработка ноды input — ожидание текста, телефона, requestContact |
API |
| 8 | Обработка callback_query (inline-кнопки) | API |
| 9 | Сохранение состояния (currentNodeId, variables) в подписчике | API |
| 10 | Подстановка переменных в текст {{var_name}} |
API |
| 11 | REST контроллер сценариев | API |
| 12 | Тестовый JSON-сценарий приветствия (3-4 ноды) | Test |
Definition of Done: Простой сценарий (приветствие → кнопка → условие → ответ) работает в боте.
Спринт 3: Реферальная механика (5-7 дней)
Цель: Полный реферальный цикл из Miro-схемы
| # | Задача | Слой |
|---|---|---|
| 1 | ReferralService — генерация deep links, трекинг |
API |
| 2 | Обработка ноды referral в движке |
API |
| 3 | Обработка /start ref_XXX — привязка реферера |
API |
| 4 | Инкремент invitedCount, уведомления реферу |
API |
| 5 | Ветка друга — отдельный startNode из friendStartNode |
API |
| 6 | Обработка ноды delay — BullMQ delayed jobs |
API |
| 7 | delay-node.processor.ts — отправка напоминаний по таймеру |
API |
| 8 | Отмена delay при выполнении условия (cancelOn) |
API |
| 9 | JSON-сценарий Powerhouse Gym (полный по Miro-схеме) | Content |
| 10 | E2E тест реферального цикла | Test |
Definition of Done: Полный цикл: клиент → пригласил друга → друг зашёл → выбрал клуб → клиент получил бонус.
Спринт 4: Рассылки + Вебхуки (5-7 дней)
Цель: Отправка рассылок по фильтрам, события на внешние URL
| # | Задача | Слой |
|---|---|---|
| 1 | Prisma-модели: TgBotBroadcast, TgBotWebhook | Schema |
| 2 | Миграция БД | Schema |
| 3 | BroadcastService — создание, фильтрация, запуск |
API |
| 4 | broadcast.processor.ts — пакетная отправка с rate limit |
API |
| 5 | Фильтры: клуб, источник, приглашено, дата, согласие, подписка | API |
| 6 | preview-count endpoint — подсчёт аудитории без отправки |
API |
| 7 | BotWebhookService — CRUD подписок на события |
API |
| 8 | bot-webhook.processor.ts — доставка с HMAC, retry |
API |
| 9 | Эмиссия событий из движка и referral service | API |
| 10 | REST контроллеры рассылок и вебхуков | API |
Definition of Done: Рассылка с фильтрами отправляется, события бота уходят на внешний URL.
Спринт 5: UI — Управление ботами (7-10 дней)
Цель: Базовый UI в web-club-admin
| # | Задача | Слой |
|---|---|---|
| 1 | Sidebar item "Telegram-бот" (с RoleGate) | UI |
| 2 | Страница списка ботов | UI |
| 3 | Форма создания/редактирования бота (токен, имя) | UI |
| 4 | Таблица подписчиков с фильтрами и пагинацией | UI |
| 5 | Карточка подписчика + история переписки | UI |
| 6 | Экспорт подписчиков в XLSX | UI |
| 7 | Страница рассылок: список + форма создания | UI |
| 8 | Фильтры аудитории с превью количества | UI |
| 9 | Страница вебхуков: CRUD подписок | UI |
| 10 | Дашборд аналитики: подписчики, конверсия, рефералы | UI |
Definition of Done: Админ клуба может создать бота, видеть подписчиков, отправить рассылку через UI.
Спринт 6: UI — Редактор сценариев (10-14 дней)
Цель: Визуальный конструктор сценариев
| # | Задача | Слой |
|---|---|---|
| 1 | Интеграция React Flow (или @xyflow/react) | UI |
| 2 | Кастомные ноды: message, condition, action, input, delay, referral | UI |
| 3 | Drag & drop добавление нод | UI |
| 4 | Панель свойств ноды (правая sidebar) | UI |
| 5 | Редактор текста сообщения с переменными | UI |
| 6 | Редактор кнопок (inline/reply) | UI |
| 7 | Редактор условий (variable, operator, value) | UI |
| 8 | Редактор действий (webhook, set_variable, crm_deal) | UI |
| 9 | Конвертация React Flow ↔ JSON сценария | UI |
| 10 | Валидация графа (нет висячих нод, есть startNode) | UI |
| 11 | Превью / тест сценария (симулятор в UI) | UI |
| 12 | Импорт/экспорт JSON | UI |
| 13 | Черновик + публикация | UI |
Definition of Done: Админ собирает сценарий визуально, сохраняет, бот его выполняет.
Спринт 7: Интеграции + Полировка (5-7 дней)
Цель: Связь с CRM, аналитика, production-readiness
| # | Задача | Слой |
|---|---|---|
| 1 | Action crm_deal — создание сделки в CRM из сценария |
API |
| 2 | Action send_email — отправка email |
API |
| 3 | Action google_sheets — запись в таблицу |
API |
| 4 | Аналитика: воронка по нодам (сколько дошло до каждой) | API+UI |
| 5 | Аналитика: конверсия рефералов | API+UI |
| 6 | UI в web-platform-admin: обзор ботов по всем клубам | UI |
| 7 | Лимиты модуля: макс. подписчиков, рассылок/мес | API |
| 8 | Логирование и мониторинг | API |
| 9 | Документация API (Swagger) | Docs |
| 10 | Seed: полный сценарий Powerhouse Gym | Content |
Definition of Done: Модуль production-ready, сценарий Powerhouse Gym работает end-to-end.
9. Технические решения
| Вопрос | Решение |
|---|---|
| Telegram Bot API | HTTP напрямую (без grammY/Telegraf) — меньше зависимостей, полный контроль |
| Приём updates | Webhook mode (не long polling) — через публичный endpoint |
| Rate limiting | BullMQ rate limiter: 30 msg/sec per bot |
| Шифрование токена | AES-256 через env-ключ, хранение в БД |
| JSON-валидация | JSON Schema (ajv) для валидации сценария |
| Визуальный редактор | @xyflow/react (React Flow) — де-факто стандарт |
| Eval условий | Безопасный eval через new Function с whitelist переменных (без arbitrary code) |
| Multi-tenancy | clubId на всех таблицах, RLS, фильтрация как в остальной системе |
| Модуль | @RequireModule('telegram-bot'), ModuleId.TELEGRAM_BOT |
10. Оценка
| Спринт | Дни | Сложность |
|---|---|---|
| 1. Фундамент | 5-7 | Средняя |
| 2. Движок сценариев | 7-10 | Высокая |
| 3. Реферальная механика | 5-7 | Высокая |
| 4. Рассылки + Вебхуки | 5-7 | Средняя |
| 5. UI — Управление | 7-10 | Средняя |
| 6. UI — Редактор сценариев | 10-14 | Высокая |
| 7. Интеграции + Полировка | 5-7 | Средняя |
| Итого | 44-62 |