Финальная стабильная реализация
This commit is contained in:
@@ -77,6 +77,9 @@
|
||||
30. #INFRASTRUCTURE перевести взаимодействие с signoz на TLS (сейчас OTEL_REMOTE_TLS_INSECURE=true)
|
||||
31. #BACK_BUSINESS VM1 -> VM2: `curl -sS --cacert /etc/han/ca/vm2-internal-ca.crt "https://processing.internal:8443/internal/safety/status" | python3 -m json.tool` В коде захардкожен Redis в components = "degraded". Надо реализовать реальную проверку вместо костыля.
|
||||
32. #BACK_BUSINESS Решить проблему с обновлением сигнатур CLAMAV.
|
||||
33. #BACK_BUSINESS Создать поле "Номер телефона в приложении". Подробности реализации ниже (на подумать)
|
||||
34. #BACK_BUSINESS реализация смены номера телефона. Подробности реализации ниже (на подумать)
|
||||
35. #BACK_BUSINESS схлапывание контактов. Подробности реализации ниже (на подумать)
|
||||
|
||||
# Критично для релиза:
|
||||
~~1. Разработка message-safety~~
|
||||
@@ -85,3 +88,170 @@
|
||||
~~4. Подключить OTLP-провайдер~~
|
||||
~~5. Починить UI баги~~
|
||||
6. Второй контур для продакшн
|
||||
|
||||
|
||||
33. details
|
||||
Комплексный алгоритм:
|
||||
|
||||
1. Нормализовать номер приложения `P`.
|
||||
2. Если active mapping существует:
|
||||
- Contact принадлежит текущему `user_id` — обновить служебные поля и app-телефон;
|
||||
- `user_id` пуст — восстановить служебные поля;
|
||||
- указан чужой `user_id` — ничего не перезаписывать, создать alert `mapping_identity_mismatch`;
|
||||
- Contact отсутствует — пометить mapping broken и создать alert.
|
||||
3. Если mapping отсутствует, собрать объединённый список Contact:
|
||||
- найденные по текущему `user_id`;
|
||||
- найденные по новому полю app-телефона `P`;
|
||||
- найденные через `duplicate.findbycomm` по стандартному `PHONE`.
|
||||
4. Загрузить все карточки и классифицировать:
|
||||
- принадлежат текущему пользователю;
|
||||
- свободны — `user_id` пуст;
|
||||
- принадлежат другому пользователю;
|
||||
- app-телефон равен `P`;
|
||||
- app-телефон пуст — legacy-контакт;
|
||||
- app-телефон отличается от `P`.
|
||||
|
||||
Дальнейшие ветки:
|
||||
|
||||
- Найден Contact с тем же `user_id`:
|
||||
- выбрать самый новый среди таких Contact;
|
||||
- восстановить mapping;
|
||||
- записать `P` в app-телефон;
|
||||
- если таких Contact несколько или есть другие совпадения — создать duplicate alert со всеми ID.
|
||||
|
||||
- Контактов с тем же `user_id` нет:
|
||||
- кандидатами считаются Contact с app-телефоном `P`;
|
||||
- также допускаются legacy-контакты с пустым app-телефоном, найденные по стандартному `PHONE`;
|
||||
- Contact с другим непустым app-телефоном нельзя автоматически привязывать.
|
||||
|
||||
- Один кандидат свободен:
|
||||
- записать `user_id`, registration flag и app-телефон;
|
||||
- создать mapping.
|
||||
|
||||
- Несколько кандидатов:
|
||||
- выбрать самый новый по `CREATED_TIME`, затем по числовому ID;
|
||||
- если выбранный свободен — привязать его и создать `duplicate_contacts`;
|
||||
- если выбранный принадлежит другому пользователю — создать новый Contact и alert `contact_owned_by_other_user`;
|
||||
- в `contactIds` alert передать все старые ID и ID нового Contact.
|
||||
|
||||
- Совпадения есть только по стандартному `PHONE`, но у них указан другой app-телефон:
|
||||
- не считать их Contact текущего пользователя;
|
||||
- создать новый Contact;
|
||||
- создать alert о совпадении общего номера.
|
||||
|
||||
- Совпадений нет:
|
||||
- создать новый Contact без alert.
|
||||
|
||||
Дополнительные правила:
|
||||
|
||||
- app-телефон — App-master: изменения этого поля в Б24 не меняют номер авторизации.
|
||||
- При смене номера приложение обновляет app-телефон и гарантирует наличие нового номера в стандартном `PHONE`, но не удаляет остальные номера Contact.
|
||||
- Перед повторным `contact.add` после timeout необходимо повторно искать по `user_id` и app-телефону, чтобы не создать дубль.
|
||||
- Mapping создаётся только после успешной записи служебных полей.
|
||||
- Все конфликтные ветки должны иметь отдельные регрессионные тесты до реализации.
|
||||
|
||||
|
||||
34. details
|
||||
Изменение стандартного `PHONE` в Битрикс24 не должно автоматически менять номер авторизации в приложении. Иначе сотрудник с доступом к CRM сможет случайно или намеренно передать чужой аккаунт другому номеру.
|
||||
|
||||
Рекомендуемый процесс:
|
||||
|
||||
1. Сотрудник меняет стандартный номер в карточке.
|
||||
2. Webhook фиксирует расхождение с полем «Номер телефона в приложении».
|
||||
3. Система создаёт отдельный запрос/смарт-процесс «Смена номера приложения».
|
||||
4. Сотрудник явно выбирает, какой из номеров Contact является новым номером приложения.
|
||||
5. Выполняются проверки:
|
||||
- нормализация E.164;
|
||||
- новый номер не занят другим пользователем;
|
||||
- Contact действительно связан с нужным `user_id`;
|
||||
- нет другого активного запроса.
|
||||
6. Клиент подтверждает смену:
|
||||
- OTP на новый номер;
|
||||
- подтверждение в активной сессии приложения;
|
||||
- желательно OTP на старый номер, если он доступен.
|
||||
7. Если старый номер недоступен — отдельный усиленный сценарий идентификации сотрудником с обязательным аудитом и, желательно, дополнительным согласованием.
|
||||
8. После подтверждения App меняет номер в своём источнике истины — БД приложения/Keycloak.
|
||||
9. Через outbox создаётся задача синхронизации.
|
||||
10. Bitrix Sync обновляет:
|
||||
- поле «Номер телефона в приложении»;
|
||||
- служебные поля связи;
|
||||
- при необходимости добавляет новый номер в стандартный `PHONE`;
|
||||
- закрывает запрос на смену номера.
|
||||
|
||||
Важные правила:
|
||||
|
||||
- Обычное редактирование `PHONE` только создаёт предложение на смену, но не меняет логин.
|
||||
- Поле «Номер телефона в приложении» остаётся read-only для сотрудников.
|
||||
- Старые дополнительные номера Contact автоматически не удаляются.
|
||||
- Нужны срок действия запроса, ограничение попыток OTP, журнал сотрудника и времени операции.
|
||||
- Повторный запрос должен быть идемпотентным.
|
||||
|
||||
Так сохраняется удобство работы через Б24, но CRM не становится небезопасным источником истины для номера авторизации.
|
||||
|
||||
35. details
|
||||
Здесь нужно объединять не только карточки Битрикс24, но прежде всего два аккаунта приложения. Простое слияние Contact оставит данные личного кабинета привязанными к старому `user_id`.
|
||||
|
||||
Рекомендуемый сценарий account merge.
|
||||
|
||||
1. Создать заявку на объединение:
|
||||
- старый `user_id` и старый Contact;
|
||||
- новый `user_id` и новый Contact;
|
||||
- результат комплайенса;
|
||||
- оператор и подтверждающий сотрудник;
|
||||
- причина и audit trail.
|
||||
|
||||
2. Выбрать канонический аккаунт. Обычно это старый аккаунт, содержащий историю и данные. Новый пустой аккаунт становится поглощаемым.
|
||||
|
||||
3. На время операции заблокировать изменения обоих аккаунтов и повторные merge-заявки.
|
||||
|
||||
4. Проверить конфликты:
|
||||
- заказы, документы, согласия;
|
||||
- бонусы, баланс и другие финансовые данные;
|
||||
- активные процессы;
|
||||
- наличие данных в новом аккаунте;
|
||||
- отсутствие третьего аккаунта с новым номером.
|
||||
|
||||
5. На стороне приложения:
|
||||
- привязать новый номер к каноническому старому аккаунту;
|
||||
- старый номер сделать неактивным либо историческим;
|
||||
- перенести допустимые данные нового аккаунта;
|
||||
- отметить новый `user_id` как `merged_into=<canonical_user_id>`;
|
||||
- запретить дальнейшее использование поглощённого аккаунта;
|
||||
- обновить Keycloak/механизм авторизации;
|
||||
- отозвать старые сессии и потребовать повторный вход.
|
||||
|
||||
6. Только после успешного App merge обработать Битрикс:
|
||||
- старый Contact выбрать каноническим;
|
||||
- записать в него канонический `user_id`;
|
||||
- поле «Номер телефона в приложении» установить в новый номер;
|
||||
- объединить стандартные номера обоих Contact;
|
||||
- создать active mapping канонического пользователя на канонический Contact;
|
||||
- у второго Contact очистить app-телефон, `user_id` и registration flag;
|
||||
- затем объединить его с каноническим Contact штатным механизмом Б24 либо архивировать как поглощённый.
|
||||
|
||||
7. Закрыть старые mapping со специальной причиной `account_merge`, но сохранить историю.
|
||||
|
||||
8. Завершить заявку только после проверок:
|
||||
- вход по новому номеру открывает старый личный кабинет;
|
||||
- существует один active App user;
|
||||
- существует один active mapping;
|
||||
- только один Contact содержит app-телефон и registration flag;
|
||||
- поглощённый аккаунт больше не создаёт задачи синхронизации.
|
||||
|
||||
Ключевой принцип: сначала объединение аккаунтов приложения, затем CRM. Если сначала слить карточки Б24, это не вернёт пользователю данные.
|
||||
|
||||
Для устойчивой реализации потребуется отдельная audited-процедура наподобие:
|
||||
|
||||
```text
|
||||
request_account_merge(
|
||||
canonical_user_id,
|
||||
absorbed_user_id,
|
||||
canonical_contact_id,
|
||||
absorbed_contact_id,
|
||||
reason,
|
||||
operator_id,
|
||||
compliance_case_id
|
||||
)
|
||||
```
|
||||
|
||||
Операция должна быть идемпотентной, поэтапной и восстанавливаемой после сбоя. Для финансовых или юридически значимых данных автоматический перенос без отдельных правил недопустим.
|
||||
Reference in New Issue
Block a user