# OkoCRM: привязка Telegram-чата к контакту

## Целевой сценарий

1. Клиент запускает Telegram-бота ThaiForTravel.
2. Клиент делится своим номером телефона.
3. Backend находит существующий контакт OkoCRM по Telegram ID и
   подтверждённому номеру либо создаёт новый контакт.
4. Текущий Telegram-диалог прикрепляется к найденному контакту вместе со
   всей предыдущей историей.
5. Backend не создаёт сделку на этом этапе.
6. Сделка создаётся и связывается с этим контактом только после отправки
   экскурсии, трансфера или плана отдыха из Mini App.

Существующий робот OkoCRM не отключается этой интеграцией. Если робот настроен
создавать сделку на `/start`, это отдельное поведение OkoCRM, которое нужно
изменять в настройках робота после отдельной проверки.

## Официальный API

Поддержка OkoCRM подтвердила публичный метод «Входящие лиды / Прикрепить
диалог к контакту»:

```text
POST https://api.okocrm.com/v2/unsorted/attach/
Authorization: Bearer <API token>
```

Параметры:

- `client_id` — обязательный идентификатор диалога во входящих лидах;
- `contact_id` — идентификатор контакта;
- `phone_id` — альтернативный идентификатор конкретного телефона контакта.

Backend использует `client_id + contact_id`. Внутренний маршрут интерфейса
`/backend/ajax/v1/chat/attach` и веб-сессия OkoCRM больше не нужны для рабочего
сценария.

## Webhook `client_message`

Поддержка OkoCRM подтвердила два состояния сообщения:

- до привязки OkoCRM присылает `client_id`;
- после привязки OkoCRM присылает `contact_messenger_id`.

Webhook регистрируется в OkoCRM на адрес:

```text
https://api.thaifortravel.ru/webhook/okocrm?token=<OKOCRM_WEBHOOK_TOKEN>
```

Токен генерируется отдельно, хранится только в production ENV и скрывается из
HTTP-журналов. Оригинальный payload сохраняется в `CrmWebhookEvent`, чтобы
обработчик не терял событие при перезапуске и мог повторить привязку.

## Безопасное сопоставление

Backend прикрепляет чат только при однозначном сопоставлении:

1. уже сохранённый `client_id` или `contact_messenger_id`;
2. для нового диалога — единственное точное совпадение текста и времени с
   локальным сообщением, которое backend действительно поставил в relay;
3. Telegram ID и номер из webhook, если они присутствуют, обязаны совпасть с
   пользователем найденного локального сообщения.

Имя, username, телефон из формы заявки и текст без отметки локального relay не
используются как самостоятельное основание. Каждое локальное сообщение может
подтвердить только одну первичную привязку. Если совпадение неоднозначно,
событие остаётся в очереди; чужой чат автоматически не прикрепляется.

Контакт OkoCRM выбирается по следующим правилам:

- совпадение Telegram ID и телефона имеет приоритет;
- совпадение Telegram ID допустимо самостоятельно;
- единственный контакт по подтверждённому Telegram номеру можно дополнить
  Telegram ID, только если у него ещё нет другого Telegram ID;
- при отсутствии безопасного совпадения создаётся новый контакт;
- конфликтующий номер другого Telegram-контакта не перезаписывается.

## История сообщений

После официальной привязки OkoCRM переносит диалог из входящих лидов в канал
контакта. Админка ThaiForTravel читает историю через:

```text
GET https://api.okocrm.com/v2/messages/?contact_id=<id>&setting_id=<id>
```

И импортирует её в локальный чат без дублей. `client_id`,
`contact_messenger_id`, `contact_id` и `setting_id` сохраняются в
`Conversation`.

## Проверка

1. Отправить 2–3 сообщения с тестового Telegram-аккаунта до передачи номера.
2. Поделиться собственным контактом.
3. Проверить, что появился или обновился ровно один контакт OkoCRM.
4. Проверить, что диалог исчез из «Входящих лидов» и вся ранняя история
   отображается в контакте.
5. Убедиться, что backend на этом этапе не создал сделку.
6. Отправить заявку Mini App и проверить появление ровно одной сделки,
   связанной с тем же контактом.
7. Повторить `/start` и убедиться, что контакт и чат не задвоились.
