исходная архитектура потоков воркфлоу
Ниже — архитектура “минимально жизнеспособного” агент-бота в n8n для MAX → Voronka CRM → (OCR/документы) → Google Calendar → уведомления из CRM. Я опишу какие workflow нужны, какие ноды в каждом, где хранить состояние, и как сделать подключение Google Calendar на пользователя так, чтобы это масштабировалось (один бот, много пользователей/чатов).
0) Базовые принципы, чтобы система не развалилась
-
LLM = только “интент + сущности + вопросы”
Все реальные действия (создать клиента, создать встречу, прикрепить паспорт) выполняются детерминированными нодами (HTTP Request/DB/CRM API). Это стандартный мировой паттерн “LLM as router / extractor”. -
Состояние диалога хранится вне n8n
n8n хорошо оркестрирует, но плохо хранит долгие “слоты” и контекст. Поэтому:-
быстрые ожидания/TTL: Redis
-
долговременное: Postgres (у тебя уже есть)
-
-
Один бот — много пользователей/чатов ⇒ нужна таблица идентификации
Минимально:max_user_id,chat_id,tenant_id / vclient,node_vpn_ip, роли/права, токены Google. -
Файлы и паспорта: всегда “сырьё” в MinIO + ссылкой дальше
Не гоняем большие байты через десяток нод. Сохранил → получилs3://bucket/key→ передал дальше.
1) “Минимальный набор workflow” в n8n (на перспективу)
WF-1. MAX Inbound Router (единая точка входа)
Цель: принять любое сообщение (текст/фото/файл), определить пользователя/чат, понять намерение и запустить нужную ветку.
Минимальные ноды:
-
Trigger: MAX Trigger (если используешь community node) или Webhook node
(MAX подписка на вебхуки: HTTPS, допустимые порты — у MAX это требование) (MAX для разработчиков) -
IF: проверка
x-max-bot-api-secret(как ты уже видишь в заголовках) -
Code/Set: нормализация входа в единый формат:
-
chat_id,max_user_id,message_id/mid,text,attachments[]
-
-
Postgres:
tenant_resolve(по max_user_id/chat_id найти vclient/node/права) -
Switch: по типу входа:
-
text→ в LLM-парсер -
attachments→ в файловый конвейер
-
-
LLM (DeepSeek): твой системный промт → вернуть JSON-команду
-
Parse JSON (Code): распарсить строку → объект
-
IF:
missing_fields? → ветка “уточнить” -
Switch по
action→ дергаем “WF-x исполнители” -
Отправка ответа в MAX (Send Message)
💡 Шаблон/пример для MAX-бота в n8n уже есть: “AI chatbot for Max Messenger …” (там ещё и voice) — можно импортировать и выкинуть лишнее. (n8n)
WF-2. File Ingest (фото/паспорт/PDF/DOCX/XLSX/txt)
Цель: скачать вложение, положить в MinIO, получить текст/данные (OCR/парсинг), вернуть в WF-1 “готовую сущность”.
Ноды:
-
HTTP Request: скачать файл по
payload.url -
MinIO/S3 node или HTTP: положить в bucket (например
crm-inbox-raw) -
Router по типу:
-
image → OCR microservice
-
pdf/docx/xlsx/txt → document parser microservice
-
-
HTTP Request: OCR/парсер → получить structured text
-
Return: упаковать результат как “input.text + input.file_ref” и передать обратно в LLM или сразу в действие
recognize_passport/create_client_from_passport/...
WF-3. CRM Action Executor (создать/найти/обновить клиента, прикрепить документы)
Цель: единый исполнитель действий с Voronka.pro (через API/вебхук), чтобы WF-1 не разрастался.
Ноды:
-
HTTP Request:
api.voronka.pro(resolver + маршрутизация на node1 по VPN) -
HTTP Request: вызов CRM API на конкретной ноде (внутренний VPN адрес)
-
Postgres: запись связок (например
client_id,passport_doc_id,source_mid) -
Return: результат (например номер клиента)
WF-4. Google Calendar Connect (OAuth-привязка календаря к пользователю)
Цель: дать пользователю ссылку, он авторизуется Google, и ты получаешь refresh token.
Почему отдельный WF: multi-user OAuth в n8n не “из коробки” удобен — это частая тема, люди делают “dynamic credentials / broker” подход. (n8n Community)
Ноды:
-
Trigger: из WF-1 (команда “подключить календарь”)
-
HTTP Request: к твоему Laravel
api.voronka.pro→ “создать OAuth-линк” (state = max_user_id + nonce) -
Send Message (MAX): отправить ссылку пользователю
-
Webhook (callback): (лучше пусть callback принимает Laravel, а не n8n)
Laravel сохранит refresh token и дернет внутренний webhook в n8n “calendar_connected” -
Send Message (MAX): “календарь подключен ✅”
(Можно и напрямую через n8n-credentials, но тогда ты либо вручную плодишь креды на каждого пользователя, либо строишь сложный обход — есть даже шаблон, который автоматизирует создание Google OAuth кредов в n8n, но это всё равно про n8n-credential storage. (n8n))
WF-5. Create Meeting (Google Calendar + запись в CRM по клиенту)
Цель: команда “создай встречу …” → событие в календаре пользователя → запись/комментарий/активность в CRM в карточке клиента.
Ноды:
-
Input: из WF-1 (action = schedule_meeting)
-
Postgres: взять “Google refresh token” пользователя
-
HTTP Request: к твоему “OAuth broker” (Laravel) → получить access token (или прокси-вызов календаря)
-
Google Calendar: Create Event (или HTTP Request в Calendar API)
-
HTTP Request: в CRM (создать Activity/Comment/Task с ссылкой на event/meet link)
-
Send Message (MAX): подтверждение + дата/время
WF-6. CRM → Bot Notifications (напоминания/чек-листы)
Цель: CRM по событию шлет webhook → n8n отправляет человеку/в группу задачи.
Ноды:
-
Webhook: входящий от CRM
-
Postgres: найти
chat_id/пользователей, кому слать -
Send Message (MAX): текст + кнопки (если используешь callbacks, MAX это поддерживает) (MAX для разработчиков)
WF-7. Error & Audit (чтобы не забивать логи, но видеть ошибки)
Цель: ошибки в любом workflow → в один канал (лог-таблица + уведомление админам).
Ноды:
-
Error Trigger (глобальный)
-
Postgres: записать кратко (workflow, node, error, mid, tenant)
-
Send Message (MAX) / Email: только критичные (по фильтру)
2) Что лучше “не писать с нуля”: готовые основы/шаблоны
-
MAX + AI-бот шаблон n8n
Есть готовый workflow именно под MAX (включая voice). Его можно взять как “скелет”, оставив только MAX Trigger/Send + твою бизнес-логику. (n8n) -
Шаблоны “бот + календарь/бронь”
У n8n много готовых booking-workflow под Google Calendar (проверка слотов, создание события, подтверждения). Их можно адаптировать под твою команду “создай встречу”. (n8n) -
Каталоги шаблонов (можно импортировать JSON и менять)
-
Community node для MAX
Чтобы не собирать руками HTTP-вызовы:n8n-nodes-max. (GitHub)
(И вообще n8n официально описывает установку community nodes и их режимы) (docs.n8n.io)
3) Первая “боёвая” настройка: подключение Google Calendar пользователем
Почему я предлагаю OAuth через твой Laravel (api.voronka.pro), а не “чисто n8n”
Потому что у тебя один бот и много пользователей, и каждому нужен свой Google доступ. В n8n это упирается в “dynamic credentials / multi-tenant OAuth” (у сообщества это отдельная боль, есть обсуждения и обходы). (n8n Community)
Laravel-broker решает это красиво: хранит refresh token на пользователя, а n8n всегда просто запрашивает “дай access token для max_user_id”.
Минимальный user-flow
-
Пользователь в MAX пишет: “Подключить календарь”
-
WF-1 распознаёт intent → вызывает WF-4
-
WF-4 запрашивает у
api.voronka.proссылку Google OAuth (с state = max_user_id + одноразовый nonce) -
Бот отправляет ссылку в чат
-
Пользователь проходит Google consent
-
Laravel сохраняет refresh token (привязка к max_user_id/tenant_id)
-
Laravel вызывает внутренний webhook n8n “calendar_connected”
-
n8n отправляет пользователю: “Google Calendar подключен ✅”
Что это даёт дальше
Когда пользователь попросит “создай встречу…”, WF-5:
-
берет refresh token по max_user_id
-
создаёт событие в календаре именно этого пользователя
-
фиксирует связку в CRM/у клиента
4) Как это ложится на твою инфраструктуру (центральный сервер + node1)
-
n8n на центральном: оркестрирует, хранит минимум, очереди/локи в Redis, аудиты в Postgres.
-
api.voronka.pro (Laravel/MySQL): идеальное место для:
-
tenant resolver (max_user_id → vclient/node)
-
OAuth broker (Google tokens per user)
-
политика доступа (кто что может)
-
-
node1 (CRM + базы клиентов): принимает только “чистые команды” от n8n (создать/найти/прикрепить документ/создать activity), по VPN адресу.
-
MinIO: raw-файлы/паспортные сканы/промежуточные результаты (с TTL/корзиной).
5) Что делаем прямо сейчас, чтобы “встреча в календаре” стала реальной
Без кода, только шагами:
-
В WF-1 добавляешь команду “подключить календарь” (можно через LLM или просто if по тексту).
-
Делаешь WF-4 “Google connect”:
-
нода HTTP Request →
api.voronka.proполучить auth_link -
Send Message → отдать ссылку в MAX
-
-
В Laravel добавляешь страницу OAuth (ты и так можешь, у тебя billing на Laravel) — она хранит refresh token и дергает n8n webhook.
-
После “подключено” — запускаем WF-5: команда “создай встречу …” → Create Event → ответ в MAX.
Если ты скажешь, как ты хочешь решать идентификацию пользователя с твоим tenant/vclient (например: “бот доступен только авторизованным в billing, привязка по email/коду”), я предложу самый короткий onboarding-флоу (2–3 сообщения в MAX) и какие таблицы минимально нужны, чтобы дальше спокойно прикручивать CRM и паспорта.