исходная архитектура потоков воркфлоу Ниже — архитектура “минимально жизнеспособного” агент-бота в n8n для MAX → Voronka CRM → (OCR/документы) → Google Calendar → уведомления из CRM. Я опишу какие workflow нужны, какие ноды в каждом, где хранить состояние, и как сделать подключение Google Calendar на пользователя так, чтобы это масштабировалось (один бот, много пользователей/чатов). 0) Базовые принципы, чтобы система не развалилась LLM = только “интент + сущности + вопросы”Все реальные действия (создать клиента, создать встречу, прикрепить паспорт) выполняются детерминированными нодами (HTTP Request/DB/CRM API). Это стандартный мировой паттерн “LLM as router / extractor”. Состояние диалога хранится вне n8nn8n хорошо оркестрирует, но плохо хранит долгие “слоты” и контекст. Поэтому: быстрые ожидания/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 и менять) Категория “AI Chatbot” в n8n (сотни шаблонов) (n8n) awesome-n8n-templates (огромный набор JSON) (GitHub) архив официальных n8n workflows (удобно версионировать/таскать оффлайн) (GitHub) 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 и паспорта.