# исходная архитектура потоков воркфлоу

Ниже — архитектура “минимально жизнеспособного” агент-бота в n8n для MAX → Voronka CRM → (OCR/документы) → Google Calendar → уведомления из CRM. Я опишу **какие workflow нужны**, **какие ноды в каждом**, **где хранить состояние**, и **как сделать подключение Google Calendar на пользователя** так, чтобы это масштабировалось (один бот, много пользователей/чатов).

---

## 0) Базовые принципы, чтобы система не развалилась

1. **LLM = только “интент + сущности + вопросы”**  
    Все реальные действия (создать клиента, создать встречу, прикрепить паспорт) выполняются **детерминированными нодами** (HTTP Request/DB/CRM API). Это стандартный мировой паттерн “LLM as router / extractor”.
2. **Состояние диалога хранится вне n8n**  
    n8n хорошо оркестрирует, но плохо хранит долгие “слоты” и контекст. Поэтому:
    
    
    - быстрые ожидания/TTL: **Redis**
    - долговременное: **Postgres** (у тебя уже есть)
3. **Один бот — много пользователей/чатов** ⇒ нужна таблица идентификации  
    Минимально: `max_user_id`, `chat_id`, `tenant_id / vclient`, `node_vpn_ip`, роли/права, токены Google.
4. **Файлы и паспорта**: всегда “сырьё” в MinIO + ссылкой дальше  
    Не гоняем большие байты через десяток нод. Сохранил → получил `s3://bucket/key` → передал дальше.

---

## 1) “Минимальный набор workflow” в n8n (на перспективу)

### WF-1. MAX Inbound Router (единая точка входа)

**Цель:** принять любое сообщение (текст/фото/файл), определить пользователя/чат, понять намерение и запустить нужную ветку.

Минимальные ноды:

1. **Trigger**: MAX Trigger (если используешь community node) *или* Webhook node  
    (MAX подписка на вебхуки: HTTPS, допустимые порты — у MAX это требование) ([MAX для разработчиков](https://dev.max.ru/docs-api/methods/POST/subscriptions?utm_source=chatgpt.com "POST Подписка на обновления - MAX для разработчиков"))
2. **IF**: проверка `x-max-bot-api-secret` (как ты уже видишь в заголовках)
3. **Code/Set**: нормализация входа в единый формат:
    
    
    - `chat_id`, `max_user_id`, `message_id/mid`, `text`, `attachments[]`
4. **Postgres**: `tenant_resolve` (по max\_user\_id/chat\_id найти vclient/node/права)
5. **Switch**: по типу входа:
    
    
    - `text` → в LLM-парсер
    - `attachments` → в файловый конвейер
6. **LLM (DeepSeek)**: твой системный промт → вернуть JSON-команду
7. **Parse JSON** (Code): распарсить строку → объект
8. **IF**: `missing_fields`? → ветка “уточнить”
9. **Switch** по `action` → дергаем “WF-x исполнители”
10. **Отправка ответа в MAX** (Send Message)

💡 Шаблон/пример для MAX-бота в n8n уже есть: “AI chatbot for Max Messenger …” (там ещё и voice) — можно импортировать и выкинуть лишнее. ([n8n](https://n8n.io/workflows/12022-ai-chatbot-for-max-messenger-with-voice-recognition-gigachat-salutespeech/?utm_source=chatgpt.com "AI chatbot for Max Messenger with voice recognition ..."))

---

### WF-2. File Ingest (фото/паспорт/PDF/DOCX/XLSX/txt)

**Цель:** скачать вложение, положить в MinIO, получить текст/данные (OCR/парсинг), вернуть в WF-1 “готовую сущность”.

Ноды:

1. **HTTP Request**: скачать файл по `payload.url`
2. **MinIO/S3 node или HTTP**: положить в bucket (например `crm-inbox-raw`)
3. **Router по типу**:
    
    
    - image → OCR microservice
    - pdf/docx/xlsx/txt → document parser microservice
4. **HTTP Request**: OCR/парсер → получить structured text
5. **Return**: упаковать результат как “input.text + input.file\_ref” и передать обратно в LLM или сразу в действие `recognize_passport/create_client_from_passport/...`

---

### WF-3. CRM Action Executor (создать/найти/обновить клиента, прикрепить документы)

**Цель:** единый исполнитель действий с Voronka.pro (через API/вебхук), чтобы WF-1 не разрастался.

Ноды:

1. **HTTP Request**: `api.voronka.pro` (resolver + маршрутизация на node1 по VPN)
2. **HTTP Request**: вызов CRM API на конкретной ноде (внутренний VPN адрес)
3. **Postgres**: запись связок (например `client_id`, `passport_doc_id`, `source_mid`)
4. **Return**: результат (например номер клиента)

---

### WF-4. Google Calendar Connect (OAuth-привязка календаря к пользователю)

**Цель:** дать пользователю ссылку, он авторизуется Google, и ты получаешь refresh token.

Почему отдельный WF: multi-user OAuth в n8n **не “из коробки”** удобен — это частая тема, люди делают “dynamic credentials / broker” подход. ([n8n Community](https://community.n8n.io/t/multi-tenant-saas-google-nodes-how-to-use-per-user-oauth-tokens-dynamic-credentials/247612?utm_source=chatgpt.com "how to use per-user OAuth tokens (dynamic credentials)?"))

Ноды:

1. **Trigger**: из WF-1 (команда “подключить календарь”)
2. **HTTP Request**: к твоему Laravel `api.voronka.pro` → “создать OAuth-линк” (state = max\_user\_id + nonce)
3. **Send Message (MAX)**: отправить ссылку пользователю
4. **Webhook (callback)**: (лучше пусть callback принимает Laravel, а не n8n)  
    Laravel сохранит refresh token и дернет **внутренний webhook** в n8n “calendar\_connected”
5. **Send Message (MAX)**: “календарь подключен ✅”

(Можно и напрямую через n8n-credentials, но тогда ты либо вручную плодишь креды на каждого пользователя, либо строишь сложный обход — есть даже шаблон, который автоматизирует создание Google OAuth кредов в n8n, но это всё равно про n8n-credential storage. ([n8n](https://n8n.io/workflows/2909-automate-google-oauth2-credential-creation-in-n8n/?utm_source=chatgpt.com "Automate Google OAuth2 credential creation in n8n")))

---

### WF-5. Create Meeting (Google Calendar + запись в CRM по клиенту)

**Цель:** команда “создай встречу …” → событие в календаре пользователя → запись/комментарий/активность в CRM в карточке клиента.

Ноды:

1. **Input**: из WF-1 (action = schedule\_meeting)
2. **Postgres**: взять “Google refresh token” пользователя
3. **HTTP Request**: к твоему “OAuth broker” (Laravel) → получить access token (или прокси-вызов календаря)
4. **Google Calendar**: Create Event (или HTTP Request в Calendar API)
5. **HTTP Request**: в CRM (создать Activity/Comment/Task с ссылкой на event/meet link)
6. **Send Message (MAX)**: подтверждение + дата/время

---

### WF-6. CRM → Bot Notifications (напоминания/чек-листы)

**Цель:** CRM по событию шлет webhook → n8n отправляет человеку/в группу задачи.

Ноды:

1. **Webhook**: входящий от CRM
2. **Postgres**: найти `chat_id`/пользователей, кому слать
3. **Send Message (MAX)**: текст + кнопки (если используешь callbacks, MAX это поддерживает) ([MAX для разработчиков](https://dev.max.ru/docs-api/methods/POST/answers?utm_source=chatgpt.com "POST Ответ на callback - MAX для разработчиков"))

---

### WF-7. Error &amp; Audit (чтобы не забивать логи, но видеть ошибки)

**Цель:** ошибки в любом workflow → в один канал (лог-таблица + уведомление админам).

Ноды:

1. **Error Trigger** (глобальный)
2. **Postgres**: записать кратко (workflow, node, error, mid, tenant)
3. **Send Message (MAX) / Email**: только критичные (по фильтру)

---

## 2) Что лучше “не писать с нуля”: готовые основы/шаблоны

1. **MAX + AI-бот шаблон n8n**  
    Есть готовый workflow именно под MAX (включая voice). Его можно взять как “скелет”, оставив только MAX Trigger/Send + твою бизнес-логику. ([n8n](https://n8n.io/workflows/12022-ai-chatbot-for-max-messenger-with-voice-recognition-gigachat-salutespeech/?utm_source=chatgpt.com "AI chatbot for Max Messenger with voice recognition ..."))
2. **Шаблоны “бот + календарь/бронь”**  
    У n8n много готовых booking-workflow под Google Calendar (проверка слотов, создание события, подтверждения). Их можно адаптировать под твою команду “создай встречу”. ([n8n](https://n8n.io/workflows/8635-complete-booking-system-with-google-calendar-business-hours-and-rest-api/?utm_source=chatgpt.com "Complete booking system with Google Calendar, business ..."))
3. **Каталоги шаблонов (можно импортировать JSON и менять)**
    
    
    - Категория “AI Chatbot” в n8n (сотни шаблонов) ([n8n](https://n8n.io/workflows/categories/ai-chatbot/?utm_source=chatgpt.com "Top 899 AI Chatbot automation workflows"))
    - `awesome-n8n-templates` (огромный набор JSON) ([GitHub](https://github.com/enescingoz/awesome-n8n-templates?utm_source=chatgpt.com "enescingoz/awesome-n8n-templates"))
    - архив официальных n8n workflows (удобно версионировать/таскать оффлайн) ([GitHub](https://github.com/nusquama/n8nworkflows.xyz?utm_source=chatgpt.com "nusquama/n8nworkflows.xyz: N8N Workflows Catalog"))
4. **Community node для MAX**  
    Чтобы не собирать руками HTTP-вызовы: `n8n-nodes-max`. ([GitHub](https://github.com/pfrankov/n8n-nodes-max?utm_source=chatgpt.com "pfrankov/n8n-nodes-max: n8n-нода для мессенджера Max"))  
    (И вообще n8n официально описывает установку community nodes и их режимы) ([docs.n8n.io](https://docs.n8n.io/integrations/community-nodes/installation/verified-install/?utm_source=chatgpt.com "Install verified community nodes"))

---

## 3) Первая “боёвая” настройка: подключение Google Calendar пользователем

### Почему я предлагаю OAuth через твой Laravel (api.voronka.pro), а не “чисто n8n”

Потому что у тебя **один бот и много пользователей**, и каждому нужен **свой** Google доступ. В n8n это упирается в “dynamic credentials / multi-tenant OAuth” (у сообщества это отдельная боль, есть обсуждения и обходы). ([n8n Community](https://community.n8n.io/t/multi-tenant-saas-google-nodes-how-to-use-per-user-oauth-tokens-dynamic-credentials/247612?utm_source=chatgpt.com "how to use per-user OAuth tokens (dynamic credentials)?"))  
Laravel-broker решает это красиво: **хранит refresh token на пользователя**, а n8n всегда просто запрашивает “дай access token для max\_user\_id”.

### Минимальный user-flow

1. Пользователь в MAX пишет: **“Подключить календарь”**
2. WF-1 распознаёт intent → вызывает WF-4
3. WF-4 запрашивает у `api.voronka.pro` ссылку Google OAuth (с state = max\_user\_id + одноразовый nonce)
4. Бот отправляет ссылку в чат
5. Пользователь проходит Google consent
6. Laravel сохраняет refresh token (привязка к max\_user\_id/tenant\_id)
7. Laravel вызывает внутренний webhook n8n “calendar\_connected”
8. 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) Что делаем прямо сейчас, чтобы “встреча в календаре” стала реальной

Без кода, только шагами:

1. В WF-1 добавляешь команду **“подключить календарь”** (можно через LLM или просто if по тексту).
2. Делаешь WF-4 “Google connect”:
    
    
    - нода HTTP Request → `api.voronka.pro` получить auth\_link
    - Send Message → отдать ссылку в MAX
3. В Laravel добавляешь страницу OAuth (ты и так можешь, у тебя billing на Laravel) — она хранит refresh token и дергает n8n webhook.
4. После “подключено” — запускаем WF-5: команда “создай встречу …” → Create Event → ответ в MAX.

---

Если ты скажешь, как ты хочешь решать **идентификацию пользователя с твоим tenant/vclient** (например: “бот доступен только авторизованным в billing, привязка по email/коду”), я предложу самый короткий onboarding-флоу (2–3 сообщения в MAX) и какие таблицы минимально нужны, чтобы дальше спокойно прикручивать CRM и паспорта.