Files
han-app/modules/sync-service-concept.md
T

141 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> Статус: исходный концепт и история обсуждения. Каноническая реализационная постановка после принятия решений — [`module-07-bitrix-sync.md`](module-07-bitrix-sync.md). При расхождении применяется module-07.
>
> Актуализация 2026-08-06: production-проверка reconciliation использует `crm.item.list`, `entityTypeId=3`, фильтры `>=updatedTime`, `opened=1`, `ufCrm_1778692456=1`. Указанные ниже ранние варианты `UF_CRM_6A70C275346A7`, `Y/N` и поиск по двум телефонным маскам сохранены только как история и не являются реализационным контрактом.
MCP Server Bitrix24 с документацией https://mcp-dev.bitrix24.tech/mcp
### 1. Границы релиза
1.1. Что входит в **первый** релиз sync:
`contact.map_or_create`, `contact.update`,
передача в Битрикс24 тэга о том, что пользователь зарегистрирован в приложении
webhook Bitrix→App при изменении данных у пользователей, зарегистрированных в приложении
обновление сведений о данных пользователя при изменении их в Битрик24,
ведение бизнес-логов с конфликтами и ошибкам, требующих внимания.
создание и отслеживание статуса alerts по конфликтам
1.2. Что явно **вне scope**:
Lead/Deal,
документы компании в профиль,
merge контактов,
ручной replay API
1.3. Можно ли выпускать без двусторонности (только App→Bitrix), или webhook обязателен сразу?
вебхук обязателен в первой сборке
### 2. Сущности и маппинг полей
2.1 Какие поля `ClientProfile` / `UserIdentity` синхронизируем (в скобках поле в битрикс24):
`full_name` ↔ name
`citizenship` ↔ ufCrm_1768493029,
`russian_phone` ↔ phone,
`email` ↔ email
Значение citizenship возвращается ИД. Справочник Битрикс можно загрузить
curl -sS -G 'https://<portal-name>/rest/<user-id>/<token>/crm.contact.userfield.list' \
--data-urlencode 'filter[FIELD_NAME]=uf_crm_1768493029'
При запросах важно соблюдать следующий принцип: сервис проектируется таким образом, чтобы запрашивать минимум необходимой информации.
Т.е.
а) если мы синхронизинуем 5 полей, то мы запрашиваем ровно 5 нужных полей. Не запрашиваем все данные по клиенту.
б) если нам надо синхронизировать контакт по телефону - мы ищем в Б24 контакт только по этому телефону. Не запрашиваем список контактов.
Второй момент, выявленный в ходе тестирования:
Номер телефона может храниться в двух форматах - "+7xxxxxxxxxx", "+7 (xxx) xxx-xxxx"
Соответственно, по каждому искомому телефону делаем запрос по двум маскам, указанным выше.
Также сервис следует проектировать с учетом ограничений Битрикс24 по кол-ву обращений к АПИ (генерируем очередь и делаем запросы по расписанию через batch).
Пример запроса требуемых данных для одного пользователя:
curl -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"entityTypeId":3,"select":["id","name","phone","ufCrm_1768493029","createdTime"],"filter":{"@phone":["+7xxxxxxxxxx","+7 (xxx) xxx-xxxx"],"opened":"Y"}}' \
https://<portal-name>/rest/<user-id>/<token>/crm.item.list
2.2. Нужен ли флаг «контакт зарегистрирован в приложении» в Bitrix, и в каком поле?
Нужен (поле UF_CRM_6A70C275346A7: Y/N).
### 3. Правила матчинга Contact
3.1. Ключ поиска: только телефон (как выше указывал телефон хранится по одной из двух масок; возможно в документации есть более стабильные методы поиска контакта по номеру телефона)
3.2. Управление конфликтами:
Для разбора конфликтов должны создаваться alert: задача в Б24 (смарт процесс "Конфликты синхронизации") и бизнес-лог в БД с типом проблемы, деталями, ссылкой на ИД задачи в Б24 и ее текущим статусом.
Жизненный цикл alert: alert создается СС, обработка alert осуществляется в Б24 через смарт процесс "Конфликты синхронизации", БД регулярно опрашивает статус задач. После успешного разбора конфликта, СС корректирует статус в БД на "Завершено". ИД alerts нумеруются сиквенсом и передаются в Б24 при постановке задачи.
Описанный механизм разбора конфликтов - используется для разбора бизнес-расхождений. Он не используется в случае технических сбоев или ошибок приложения.
3.3. Жизненный цикл пользователя приложения в контексте связи с контактом (на примере 1 пользователя):
а) Клиент зарегистрировался по номеру телефона.
СС запрашивает в Б24, есть ли клиенты с указанным номером телефона.
Варианты:
В0. 0 контактов. СС должен инициировать create, получить информацию об ИД нового пользователя, записать к себе ИД в Б24, в Б24 передать флаг привязки к Приложению.
В1.1. 1 контакт + контакт не имеет связи с приложением. СС должен записать к себе ИД в Б24, в Б24 передать флаг привязки к Приложению. Если при этом в приложении флаг уже был, нам не важно.
В1.2. 1 контакт + контакт уже привязан к другому активному пользователю приложения. СС должен инициировать create, получить информацию об ИД нового пользователя, записать к себе ИД в Б24, в Б24 передать флаг привязки к Приложению. Плюс СС создает alert об ошибке привязки.
В2.1. 2 и более. СС выбирает самый новый контакт по creationtime. Выбранный контакт не имеет связи с приложением. СС должен записать к себе ИД в Б24, в Б24 передать флаг привязки к Приложению. Плюс СС создает alert наличии дублей контактов: необходимо проверить актуальность контактов, корректность закрепления.
В2.2. 2 и более. СС выбирает самый новый контакт по creationtime. Выбранный контакт уже привязан к другому активному пользователю приложения. СС должен инициировать create, получить информацию об ИД нового пользователя, записать к себе ИД в Б24, в Б24 передать флаг привязки к Приложению. Плюс СС создает alert об ошибке привязки: с указанием деталей события (в том числе информация о наличии нескольких контактов).
б) Процесс обновления данных.
Сейчас реализовываем только движение Б24 -> Приложение.
Б24 отслеживает изменения данных контактов, у которых есть признак UF_CRM_6A70C275346A7 = 'Y'
При изменении Б24 направляет вебхук СС
СС при получении вебхука складывает в очередь задание на обновление данных соответствующего контакта.
По расписанию выполняется запрос данных контактов из Б24. И обновляются сведения. Если в ответ на запрос по контакту не найдены данные, формируется alert (Пользователь приложения привязан к несуществующему контакту).
в) Клиент удалил профиль из приложения.
Обновляем признак UF_CRM_6A70C275346A7 = 'N'. Деактивируем учетную запись.
Механизм изменения привязки ИД Битрикс24 к пользователю приложения - администратор вносит изменения напрямую в БД
### 4. Очередь и worker
4.1. Этот пункт - примерное видение. По нему можно смело предлагать улучшения, тк. получается несколько связанных асинхронных процессов.
В схеме han_app хранятся бизнесовые задачи на обновление данных. Должен быть воркер, который забирает эти задачи и стартует требуемые сценарии (map_or_create, update, delete, alert_create, alert_status_update).
Каждый сценарий предполагает набор действий и запросов в Б24. Обработчик сценария в рамках его исполнения формирует задачи на обмен данными с Б24 (один сценарий может предолагать несколько связанных задач). В следующем пункте расписал примерные запросы в Б24, которые могут возникать в ходе сценария. Тебе нужно более подробно сформулировать сценарий и действия.
Задачи на обмен с Б24 складываются в соответствующую таблицу в схеме sync. Обмен данными с Б24 осуществляется через механизм Батчей. Кроме операций синхронизации документов (не входят в текущую реализацию). Один вложенный в батч запрос должен относиться к одной задаче синхронизации.
Отправка запроса осуществляется по шедулеру (по умолчанию каждые 5 секунд). Для этого отдельный воркер собирает задачи, находящиеся в статусе pending + кол-во tryes <max_retries (не более 20 штук в один батч). Задачи отбираются по принципу fifo. Если задач меньше 20, то батч формируется из меньшего числа задач. Если задач 0, то батч не формируется, запрос в битрикс не отправляется.
Отобранные задачи переводятся в следующий статус (модель статусов предложи сам). После получения ответа успешные ответы переходят на следующий статус, неуспешные ответы, требующие retry, возвращаются в статус pending, кол-во tries + 1. Успешный ответ, касающийся задачи, сохраняем в таблице с задачами.
Триггер (или шедулер) проверяет наличие задач в статусе pending + кол-во tries >=max_retries. Если находит, переводит в статус fail + отбрасывает бизнес-лог для разбора (в Битрикс24 задача не создается).
Значения параметров прописываются в настройках сервиса в БД в схеме sync_service, изменения параметров в БД должны применяться сервисом без перезагрузки.
Какие у меня архитектурные сложности возникли, ограничивающие возможность полноценно поставить требования:
1) Битрикс24 допускает до 5 api запросов в секунду. По идее при высокой нагрузке это может означать что регулярность шедулера можно настроить до 0,2 секунд. Я не понимаю, нужно ли тут какой-то параллелиризм вводить? или БД с одним шедулером справится, тк Б24 достаточно быстро отвечает. Но что произойдет, если Б24 за 0.2 секунды не ответит? Тут нужна твоя экспертиза и варианты.
2) Как правильно организовать работу сценариев. Сценарий может содержать несколько последовательных действий, требующих обмена с Б24 и не требующих. Жизненный цикл отработки сценария начинается с момента, как я забрал задачу из han_app, или ее поставил сам СС. Держать в оперативной памяти сценарий на протяжении его жизненного цикла неправильно, тк очередь задач может забиться и либо все рухнет, либо сценарии перестанут запускаться - формируется точка отказа. Правильнее сценарий разделить на условно-атомарные операции, и раскладывать их в таблицу. И тогда какие-то воркеры могут быстро бегать по этой таблице, находить очередную операцию в рамках сценария, которая ждет исполнения, исполнять ее, переводить в статус "исполнена", чтобы активировать к возможности исполнения следующую задачу. Мне этот вариант кажется более отказоустойчивым и управляемым (плюс в любой момент, даже если грохнется сервис, можно запуститься с того места, где он грохнулся, и никакие сценарии не оборвутся). Но я не до конца понимаю, как тут управлять производительностью (можно ли много воркеров запускать, чтобы они параллельно работали, и в какой момент это нужно делать).
4.2. Виды запросов в Б24 с привязкой к сценариям:
Сценарий регистрации пользователя:
1: поиск контакта по номеру телефона
2: создание нового контакта либо
3: обновление сведений контактов (изменений флага UF_CRM_6A70C275346A7)
Сценарий обновления
4: запрос данных по контакту
Сценарий удаления профиля:
3: обновление сведений контактов (изменений флага UF_CRM_6A70C275346A7)
Сценарий обработки alerts:
5: поставить задачу в Б24
6: узнать статус задачи в Б24
... возможно еще понадобятся.
Используемые виды запросов хранятся в справочнике видов запросов и могут использоваться сервисом синхронизации в рамках запущенных процессов.
4.3. Сервис синхронизации должен ставить задачи на синхронизацию с использованием утвержденных видов запросов в Б24.
4.4. Готовы ли триггеры App DB и GRANT для `bitrix_sync_user` , или это часть той же постановки?
Триггеры 'contact.map_or_create' и 'contact.update' при создании и изменении данных в таблицах пользователей готовы и работают. Действующие триггеры необходимо проверить, что они не будут пытаться синхронизировать изменения, полученные от битрикс24 и залитые в БД. Процессов постановки задач на обновление данных пользователя из-за вебхука от Б24, нет.
### 5. Bitrix24: доступ и webhook
5.1. Способ доступа к CRM REST: я верно понимаю, что local-app безопаснее входящего вебхука? Т.к невозможно, даже зная токен, отправить запрос в Б24? Если это так, то логично создать в Б24 еще одно локальное приложение и получать данные через него. Для вебхуков от Б24 делаем соответствующую ссылку с секретом.
5.2. Кто настраивает робота в Bitrix (какие события/поля). Сформируй требования к роботу и исходящему вебхуку, я настрою робот.
5.3. Есть ли тестовый портал отдельно от prod. Нет, портал один. При этом для разделения теста и прода будут использоваться различные local-app. Чтобы не смешивать базу, набор тестовых пользователей будет задаваться маской "нелегитимных" номеров.
### 6. Надёжность, безопасность, ops
6.1. Rate limit / квоты Bitrix REST: политика при `QUERY_LIMIT_EXCEEDED`?
Кол-во попыток определено в п.4.1. Если не удалось - отбрасываем бизнес-логи. Правило универсально как для ошибок синхронизации, так и для QUERY_LIMIT_EXCEEDED. Можешь предложить вариант лучше, если есть идеи.
6.2. PII в логах/метриках: секреты в логах не допускаются. PII в логах маскируются: два первых читаемых и два последних читаемых символа поля отображаем как есть, остальные символы маскируем. Ошибки логируем как есть - т.к. сервис внутренний и недоступен пользователям.
6.3. Cutover: stub → full sync на уже накопленной очереди — replay всех pending или только новых? Управляем через .env: replay = true, значит replay всех pending. replay = false, значит все pending при раскатке сервиса переводим в статус "Cancelled".