У нас есть телеграм бот в n8n, который умеет собирать сырые материалы в таблицу для дальнейшей публикации в соц сетях.
Давай подумаем как у нас будет работать: вокрфлоу Trigger Content Plan Orchestrator
Мне нужно чтобы он принимал разные источники входящего контента
- Отправленная вручную ссылка
- Rss лента
- новые файлы в папке
- и прочие варианты
Распределял их в контент-плане по каким-то условиям. Может какие-то настройки ему дать? Пока не знаю, Илья объясни как ты видишь)
Я бы видел Trigger Content Plan Orchestrator не как один большой “умный триггер”, а как центрального диспетчера, который принимает сырье из разных входов, приводит его к одному формату, оценивает, куда оно подходит, и аккуратно кладет в контент-план.
То есть логика такая:
Источник -> Нормализация -> Дедупликация -> Оценка/классификация -> Баланс плана -> Создание post_idea -> Производственный маршрут
Как это работает по шагам
- Разные входы дают события
Например:
- вручную отправили ссылку в Telegram;
- RSS принес новую статью;
- появился новый файл в папке;
- позже можно добавить YouTube-канал, сайт, Google Drive, Notion, Baserow-таблицу, webhook и т.д.
Но каждый источник не должен сразу сам решать, что делать. Он просто говорит orchestrator’у: “вот новый кусок контента”.
- Все приводится к единому объекту
source_eventНапример:
{ "tenant_row_id": 123, "source_type": "manual_link", "source_url": "https://example.com/article", "source_title": "Новая статья про рынок", "source_text": "...", "source_hash": "abc123", "published_at": "2026-04-18T10:00:00+03:00", "hints": { "priority": "high", "platform": "youtube", "pillar": "expert" } }Это важный момент. RSS, папка, ручная ссылка, файл, видео, документ — все превращается в один внутренний формат. Тогда дальше системе без разницы, откуда оно пришло.
- Дедупликация
Orchestrator проверяет: “мы уже видели эту ссылку/файл/заголовок?”
Для этого нужен
source_hash, например:tenant + source_type + url/file_id/guid/titleЕсли уже видели — пропускаем.
Если новое — идем дальше. - Оценка: что это за контент
Тут есть два уровня.
Простой уровень — правила:
если RSS из отраслевого СМИ -> expert если ссылка из TikTok/Instagram/Reels -> viral если файл из папки /cases -> sales если файл из папки /life -> lifestyleУмный уровень — AI-классификация:
тема: маркетинг pillar: expert формат: video угол: "3 ошибки..." срочность: medium подходит для: YouTube Shorts, Instagram, TikTokЯ бы сделал сначала правила, а AI подключал как второй слой, когда правило не уверено.
- Баланс контент-плана
Сейчас в orchestrator уже заложена хорошая идея: есть формула типа:
{ "viral": 40, "expert": 30, "lifestyle": 20, "sales": 10 }Orchestrator смотрит текущий план и понимает:
Нужно добрать: viral: 2 expert: 1 lifestyle: 0 sales: 1Потом из входящих событий выбирает не просто “все подряд”, а то, что закрывает дефицит.
Например:
- RSS принес 10 новостей;
- вручную отправили 2 ссылки;
- в папку добавили 3 файла.
Orchestrator выбирает максимум
max_new_units_per_run, например 3 штуки, и кладет те, которые лучше всего закрывают баланс. - Создание строки в
post_idea/ Content PlanВ Baserow создается единица плана:
title post_type post_format content_pillar status platforms tenant source_url source_payload production_routeЯ бы обязательно добавил/использовал поля:
Source TypeSource URLSource HashContent PillarProduction RoutePlanner MetaPriorityPlanned DateApproval Mode
- Маршрут производства
После создания идеи orchestrator решает, что делать дальше:
production_route = rss_video_avatar -> Worker Copywriting -> Worker Cover Design -> возможно Video Add to QueueИли:
production_route = manual_link_draft -> только создать идею -> показать пользователю на утверждениеТо есть не весь контент обязан сразу уходить в производство. Некоторые источники можно пускать автоматически, некоторые только через подтверждение.
Какие настройки ему нужны
Я бы дал настройки на уровне пользователя/тенанта. Примерно так:
{
"active": true,
"timezone": "Europe/Moscow",
"weekly_target": 10,
"max_new_units_per_run": 3,
"formula": {
"viral": 40,
"expert": 30,
"lifestyle": 20,
"sales": 10
},
"defaults": {
"platforms": {
"instagram": true,
"youtube": true,
"tiktok": true,
"vkontakte": false,
"rutube": true
},
"approval_required": true
},
"sources": [
{
"type": "rss",
"url": "https://example.com/rss",
"enabled": true,
"default_pillar": "expert",
"production_route": "rss_video_avatar",
"priority": 50
},
{
"type": "folder",
"path": "/content/inbox/cases",
"enabled": true,
"default_pillar": "sales",
"production_route": "file_to_post",
"priority": 70
},
{
"type": "manual_link",
"enabled": true,
"default_pillar": "auto",
"production_route": "manual_link_draft",
"priority": 100
}
],
"rules": [
{
"if": {
"source_type": "manual_link"
},
"then": {
"priority": 100,
"approval_required": true
}
},
{
"if": {
"source_type": "rss",
"keywords": ["AI", "автоматизация", "маркетинг"]
},
"then": {
"content_pillar": "expert",
"post_format": "Video"
}
}
],
"limits": {
"max_per_day": 3,
"max_from_same_source_per_week": 4,
"min_hours_between_same_pillar": 12
},
"blocklist": {
"domains": [],
"keywords": []
}
}
В текущем workflow уже есть часть этой идеи: CONTENT_PLAN_USERS, weekly_target, formula, rss, disk, max_new_units_per_run, platform defaults. Я бы развил именно это, но перенес бы со временем из env в Baserow-настройки, чтобы можно было управлять через интерфейс/Telegram.
Главная идея
Orchestrator должен отвечать не на вопрос:
“Что делать с RSS?”
А на вопрос:
“Какой контент сейчас нужен плану, и какой из входящих источников лучше всего закрывает этот дефицит?”
Тогда он станет не просто сборщиком ссылок, а именно планировщиком.
Я бы начал с минимальной версии:
- RSS + ручная ссылка + папка.
- Единый формат
source_event. - Дедупликация.
- Простые правила
source -> pillar/route. - Баланс по формуле
viral/expert/lifestyle/sales. - Создание
post_idea. - Режимы:
draft_onlyиauto_queue.
Потом уже добавил бы AI-классификацию, планирование по датам, умный скоринг и автопроизводство.
В идеале пользователь должен сам в настройках регулировать значения: { "viral": 40, "expert": 30, "lifestyle": 20, "sales": 10 }
В идеале, мыслить промежутками, например, контент план на 10 дней (тоже задается в настройках), а не опираться на 1 день.
И пользователь должен регулировать колво приемлемое для него кол-во публикаций в день (и еще время выбирать). Сейчас пока делаем по умолчанию 1 публикация в день в 9 утра. Но я бы хотел в будущем видеть более сложные комбинации: 1 карусель в день, на следующий день 1 пост с картинкой - в 9:00 утра. и при этом каждый день видео в 18:00 например. В общем нужна гибкая система.
В идеале видеть что вообще было опубликовано (но это высший пилотаж). Я вижу что опубликованная единица контента удаляется из таблицы post_idea и перемещается в таблицу history_content или published_content (со ссылками на публикацию), чтобы не мусорить основную таблицу предстоящего контента.
Да, вот тут я бы чуть перестроил мышление: планировать надо не “на день”, а на горизонт планирования и слоты публикаций.
То есть не так:
сегодня надо 1 пост, ищем 1 пост
А так:
у пользователя есть контент-план на 10 дней, внутри него есть 10/20/30 будущих слотов, и orchestrator должен заполнить эти слоты правильной смесью контента.
Ключевая модель
Пользователь задает:
{
"planning_horizon_days": 10,
"content_mix": {
"viral": 40,
"expert": 30,
"lifestyle": 20,
"sales": 10
},
"timezone": "Europe/Moscow"
}
И отдельно задает расписание публикаций.
Сейчас дефолт простой:
{
"rules": [
{
"type": "any_post",
"time": "09:00",
"cadence": "daily",
"count": 1
}
]
}
Это значит: на горизонте 10 дней система создает 10 будущих слотов.
Дальше формула применяется не к одному дню, а ко всем слотам:
10 слотов:
viral 40% -> 4 публикации
expert 30% -> 3 публикации
lifestyle 20% -> 2 публикации
sales 10% -> 1 публикация
Вот это уже намного здоровее. Не надо каждый день пытаться соблюсти идеальную пропорцию. Важно, чтобы баланс соблюдался на промежутке.
Будущая гибкая схема
То, что ты описал:
1 карусель в день, на следующий день 1 пост с картинкой в 9:00, и каждый день видео в 18:00
Я бы описывал не через “публикаций в день”, а через schedule rules:
{
"planning_horizon_days": 10,
"schedule_rules": [
{
"name": "Morning carousel",
"format": "carousel",
"time": "09:00",
"cadence": "every_2_days",
"start_offset_days": 0,
"platforms": ["instagram"]
},
{
"name": "Morning image post",
"format": "image_post",
"time": "09:00",
"cadence": "every_2_days",
"start_offset_days": 1,
"platforms": ["instagram", "vkontakte"]
},
{
"name": "Evening video",
"format": "video",
"time": "18:00",
"cadence": "daily",
"platforms": ["youtube", "tiktok", "rutube"]
}
]
}
На 10 дней это даст примерно:
День 1: 09:00 carousel, 18:00 video
День 2: 09:00 image_post, 18:00 video
День 3: 09:00 carousel, 18:00 video
День 4: 09:00 image_post, 18:00 video
...
То есть orchestrator сначала строит пустую сетку слотов, а потом думает, чем ее заполнить.
Как должен думать orchestrator
Я бы разделил его работу на 4 слоя:
- Собрать входящий контент
RSS, ручные ссылки, файлы, папки, будущие интеграции.
- Превратить все в кандидатов
Например:
{ "source_type": "rss", "title": "Новая статья", "source_url": "...", "suggested_pillar": "expert", "suggested_format": "video", "priority": 50 } - Построить будущие слоты
Например:
{ "planned_date": "2026-04-19", "planned_time": "09:00", "required_format": "image_post", "status": "empty" } - Заполнить слоты по балансу
Тут он смотрит:
- сколько всего слотов на 10 дней;
- какая нужна пропорция
viral/expert/lifestyle/sales; - что уже стоит в плане;
- какие кандидаты есть;
- какие форматы нужны в конкретных слотах.
И выбирает не просто “первое попавшееся”, а то, что закрывает дефицит.
Очень важная мысль
Формула viral/expert/lifestyle/sales должна применяться не к источникам и не к дням, а к заполненному плану на горизонт.
Например, если на 10 дней есть 20 слотов:
viral: 8
expert: 6
lifestyle: 4
sales: 2
Если в плане уже есть:
viral: 5
expert: 6
lifestyle: 1
sales: 0
То orchestrator понимает:
viral еще надо 3
expert уже достаточно
lifestyle надо 3
sales надо 2
И новые RSS/ссылки/файлы будет распределять в пользу lifestyle и sales, а не просто плодить expert, даже если RSS чаще всего экспертный.
Про настройки пользователя
Я бы в будущем сделал отдельный блок настроек контент-плана:
{
"enabled": true,
"planning_horizon_days": 10,
"approval_required": true,
"default_publication_time": "09:00",
"default_daily_publications": 1,
"content_mix": {
"viral": 40,
"expert": 30,
"lifestyle": 20,
"sales": 10
},
"schedule_rules": [],
"source_rules": [],
"default_platforms": {
"instagram": true,
"youtube": true,
"tiktok": true,
"vkontakte": false,
"rutube": true
}
}
Сейчас можно начать с простого UI:
Контент-план:
- Горизонт: 10 дней
- Публикаций в день: 1
- Время: 09:00
- Viral: 40%
- Expert: 30%
- Lifestyle: 20%
- Sales: 10%
А внутри уже хранить так, чтобы потом без боли перейти к сложным правилам.
Про таблицы
Я бы разделил данные так:
content_plan_settings
настройки пользователя: горизонт, формула, расписание, источники
source_events / content_inbox
сырые найденные материалы: RSS, ссылки, файлы, входящие идеи
post_idea / content_plan
предстоящий контент, который еще не опубликован
published_content / history_content
архив опубликованного контента со ссылками, датами, платформами и результатами
Мне больше нравится название published_content, если таблица именно про факт публикации.history_content шире: туда можно класть опубликованное, отмененное, архивное, неудачное. Но для аналитики лучше иметь явную таблицу published_content.
Что делать с опубликованной единицей
Да, я согласен: после публикации она не должна вечно лежать в post_idea.
Я бы делал так:
post_ideaсодержит только будущие и рабочие единицы:- draft
- approved
- queued
- scheduled
- publishing
- failed
- После успешной публикации создается запись в
published_content:{ "original_post_idea_id": 123, "tenant": 456, "title": "...", "content_pillar": "expert", "format": "video", "published_at": "2026-04-19T18:00:00+03:00", "platforms": ["youtube", "tiktok"], "publication_urls": { "youtube": "https://...", "tiktok": "https://..." }, "source_url": "...", "production_meta": {} } - Потом исходная строка из
post_idea:- либо удаляется;
- либо получает статус
published_archived; - либо переносится и удаляется.
Практически я бы на первом этапе не удалял сразу, а делал “move then delete”: сначала создать запись в published_content, убедиться, что она создана, потом удалить/архивировать post_idea. Так меньше риска потерять данные.
Как я вижу MVP
На ближайший этап я бы сделал так:
- Настройки:
planning_horizon_days, по умолчанию 10;content_mix, по умолчанию 40/30/20/10;daily_publications, по умолчанию 1;publication_time, по умолчанию 09:00.
- Orchestrator каждый день:
- смотрит план на следующие 10 дней;
- считает, сколько слотов должно быть;
- видит пустые места;
- смотрит баланс по pillar;
- добавляет недостающие идеи из источников.
- Каждая новая идея получает:
planned_date;planned_time;content_pillar;post_format;source_type;source_url;status = draftилиqueued_for_production.
- После публикации:
- запись переносится в
published_content; - в
published_contentсохраняются ссылки на публикации.
- запись переносится в
Главная архитектурная фраза
Orchestrator должен не “добавлять новые идеи”, а поддерживать заполненный контент-план на N дней вперед по правилам пользователя.
Вот это прям ядро. Тогда система становится гибкой: сегодня 1 пост в день в 09:00, завтра карусели через день, видео каждый вечер, разные платформы, разные форматы, разные правила. Всё это просто разные способы создавать будущие слоты.
А если единицы контента не достаточно?
в идеале конечно нужно чтобы мой контент-завод сам его сделал. 😀
Но он пока не умеет много. Допустим он умеет пока только видео из RSS ленты делать. А у него по формуле другойе сегодня публиковать.
По таблицам: content_plan_settings перенесем может в tenants? мне не принципиально, но не люблю много табличек. текущую таблицу post_idea можно тогда оставить под source_events / content_inbox а вот "content_plan" нужно будет сделать (а не текущую адаптировать).
Да, это как раз главный момент: контент-план должен уметь жить в условиях нехватки контента и ограниченного завода. Не пытаться магически выполнить невозможное, а честно управлять дефицитом.
Я бы разделил две сущности:
post_idea / content_inbox = сырье, входящие идеи, источники
content_plan = календарь обязательств, то есть что и когда должно выйти
Тогда проблема “сегодня по формуле нужен sales, а завод умеет только RSS-видео” решается не хаосом, а статусами и fallback-правилами.
Как мыслить
Контент-план состоит не из “идей”, а из слотов.
Например:
2026-04-19 09:00 | required_pillar: sales | required_format: image_post
2026-04-20 09:00 | required_pillar: viral | required_format: video
2026-04-21 09:00 | required_pillar: expert | required_format: video
А post_idea/content_inbox содержит кандидатов:
RSS статья -> expert video -> можно произвести
Ручная ссылка -> unknown -> нужно классифицировать
Файл из папки -> sales image_post -> пока нельзя произвести автоматически
Orchestrator пытается сопоставить слот и кандидата.
Если контента не хватает
Я бы ввел нормальные статусы для слота в content_plan:
empty
needs_source
source_found
production_not_supported
queued_for_production
ready
scheduled
publishing
published
failed
skipped
Пример:
Сегодня нужен sales image_post.
В inbox нет sales-кандидатов.
Завод не умеет сам делать sales image_post.
Тогда слот не заменяется молча RSS-видео. Он получает статус:
needs_source
И система может написать пользователю:
На 19 апреля 09:00 нужен sales-пост, но подходящего материала нет. Пришлите ссылку/файл или разрешите заменить на expert video.
Вот это важное отличие: orchestrator не должен ломать стратегию молча.
Fallback-уровни
Я бы дал пользователю/системе настройки fallback. Например:
{
"fallback_policy": {
"when_no_matching_content": "ask_user",
"allow_pillar_substitution": false,
"allow_format_substitution": false,
"allow_auto_factory_content": true,
"max_empty_slots": 3
}
}
Варианты поведения:
strict— ничего не подменять, слот остаетсяneeds_sourceask_user— спросить пользователя, чем заменитьrelaxed— можно заменить близким pillar/formatfactory_first— если завод умеет сделать хоть что-то подходящее, пусть делаетfill_anyway— лучше поставить любой готовый контент, чем оставить дырку
На MVP я бы выбрал:
ask_user + factory_first
То есть:
- если есть точное совпадение — ставим;
- если нет, но завод умеет сделать нужный формат из RSS — делаем;
- если не умеет — слот становится
needs_source, пользователь видит дефицит.
Матрица возможностей завода
Нужно явно описать, что завод умеет сейчас. Например:
{
"production_capabilities": [
{
"route": "rss_video_avatar",
"source_type": "rss",
"formats": ["video"],
"pillars": ["expert", "viral"],
"auto": true
}
]
}
Тогда orchestrator понимает:
expert video из RSS -> можно
viral video из RSS -> можно
sales carousel -> нельзя
lifestyle image_post -> нельзя
И не будет пытаться отправить неподходящий слот в несуществующий worker.
Про формулу
Формула остается целью, а не железным законом на каждый день.
Например на 10 дней и 10 слотов:
viral: 4
expert: 3
lifestyle: 2
sales: 1
Но если у нас реально есть только RSS expert/video, система может сделать так:
expert: 3 ready
viral: 2 ready
lifestyle: 2 needs_source
sales: 1 needs_source
viral: 2 needs_source или suggested_from_rss
То есть мы видим не только план, но и контентный долг:
Не хватает:
sales: 1
lifestyle: 2
viral: 2
Это очень полезно. Потом можно сделать экран “что нужно прислать”, и пользователь будет не просто кидать случайные материалы, а закрывать конкретные дырки.
Про таблицы
Да, я согласен с твоей мыслью.
content_plan_settings можно не делать отдельной таблицей, а положить в tenants.
Например в tenants добавить поля:
planning_horizon_days
daily_publications
default_publication_time
content_mix_json
schedule_rules_json
fallback_policy_json
source_rules_json
production_settings_json
Я тоже не люблю плодить таблицы без необходимости. Для настроек JSON-поля в tenants нормальны, особенно пока схема меняется.
Текущая post_idea
Да, ее можно оставить под source_events / content_inbox.
Я бы даже не переименовывал физически сразу, чтобы не ломать существующие workflow. Но концептуально считать так:
post_idea = inbox входящих идей и сырья
Там должны быть поля:
tenant
source_type
source_url
source_title
source_payload
source_hash
suggested_pillar
suggested_format
suggested_route
status
used_in_content_plan
Статусы:
new
classified
used
duplicate
rejected
expired
Важный нюанс: если post_idea становится inbox, то опубликованные единицы из нее не надо удалять как “контент-план”. Ее задача — хранить происхождение сырья. Можно просто ставить used.
Новая таблица content_plan
Вот ее лучше сделать с нуля. Это будет чистая таблица будущего календаря:
tenant
planned_at
planned_date
planned_time
timezone
slot_status
required_pillar
actual_pillar
required_format
actual_format
platforms
source_event/post_idea link
production_route
production_status
publication_status
title
caption
asset_url
approval_status
priority
content_plan отвечает на вопрос:
Что должно выйти, когда, в каком формате и в каком состоянии оно находится?
А post_idea отвечает:
Откуда взялся материал и можно ли его использовать?
После публикации
Я бы сделал отдельную таблицу:
published_content
Туда переносим факт публикации:
content_plan_id
source_event_id
tenant
published_at
platform
publication_url
title
pillar
format
metrics_json
Если один контент публикуется на 5 платформ, есть два варианта:
1 строка= единица контента, внутри JSON со ссылками по платформам1 строка= публикация на одной платформе
Для аналитики второй вариант лучше:
video X на YouTube
video X на TikTok
video X на Rutube
Но для MVP можно одной строкой с publication_urls_json.
Итоговая схема
Я бы зафиксировал так:
tenants
хранит настройки планирования, формулу, расписание, fallback
post_idea
становится inbox/source_events: сырье, ссылки, RSS, файлы, идеи
content_plan
новая таблица: календарь будущих слотов и производственный статус
published_content
история фактических публикаций и ссылки
А orchestrator делает не “создать идею”, а:
- Построить слоты на N дней вперед.
- Посчитать нужный баланс.
- Найти подходящие source_events.
- Проверить, умеет ли завод это произвести.
- Заполнить слот или пометить как
needs_source/production_not_supported. - Если можно, отправить в производство.
Самая правильная фраза для этой системы:
Контент-завод не обязан уметь делать всё сразу, но orchestrator должен знать, что он умеет, и показывать, где стратегия не закрыта ресурсами.
Это даст тебе управляемую систему: даже когда автоматизация пока слабая, план уже будет зрелым.
