27 KiB
Закрыто 21.07-27.07
MVP frontend: один чат с компанией без истории диалогов; пункт «Чат» открывает текущий активный диалог или создаёт его при отсутствии
При создании пользователя номер телефона копировать в профиль Russian_Phone
Убрать хеширование устройства клиента в devise_json - хочу видеть его параметры.
Добавить параметр, ограничивающих кол-во неуспешных попыток ввода смс.
Поправить чтение сообщений от Битрикса. Сейчас они выглядят так: "[b]Антон Пичугин:[/b] [br]опять ты?" Надо убрать из текста сообщения Отправителя в битриксе
Если неавторизованный пользователь вводит сообщение, после отправки идет на регистрацию, после окончания регистрации его сообщение пропадает. Надо чтобы сохранялось и отправлялось (по аналогии с нажатием на кнопку из раздела "Популярные вопросы")
Изменение в БД по аудитам (заполнение IP, сквозное заполнение UserSession)
Яндекс.капчу добавить
Формы согласий поправить (Согласие на обработку ПД + Политика, Пользовательское соглашение, Реклама)
При повторном запросе OTP кода при авторизации не нужно указывать ошибку "Новый код заказан. Предыдущий код больше не действует."
Интеграция с СМС-провайдером — спецификация и план rollout зафиксированы в modules/module-11-idgtl-sms.md; пункт не закрыт до реализации sms-service/worker, Keycloak lifecycle, schema sms, callback/nginx, env validation, observability и общего DoD. Production prerequisites: согласованные sender/template, Direct TOKEN_1, callback credentials/подтверждённый source IP и статический egress IP.
Моделирование уведомлений — постановка v6 синхронизирована с functional_blocks (business logic)/notification-requirements.md, arch-00…05 и module-01/03/07. Зафиксированы: instruction только в новой вкладке; TTL только при отсутствии date_expired; первое скачивание любого связанного документа скрывает; producer_test только для smoke, secret/hash раздельно.
Кнопка "Позвонить оператору" (ссылка tel:+74999591007)
На главном экране две кнопки: чат и звонок оператору. На кнопке с чатом уведомление при наличии непрочитанных сообщений.
Закрыто 28.07-03.08
#MONITORING Подключить OTLP-провайдер (Signoz)
#UI Отправлять на UI информацию разные ошибки при попытках авторизации в зависимости от события: код неверен, истёк или уже использован; превышен лимит попыток авторизации, попробуйте через 24 часа (в случаях превышения otp.phone.max_send_attempts_per_24h); превышен лимит неуспешных авторизаций, начните процедуру заново (в случае превышения otp.phone.max_verify_attempts).
#UI При отрицательном результате проверки сообщения через message-safety, если сообщение отправлялось с главного экрана, то пользователь не переводится в чат, ему под окном главного экрана выпадает сообщение об ошибке. Не на всех устройствах это видно. Воспринимается как UX-дефект. Как надо: вне зависимости от решения message-safety, если пользователь отправил сообщение, то он переводится на экран с чатом. Далее, сейчас отрицательный результат message-safety выводится пользователю как техническая ошибка (красным цветом под полем ввода сообщения) и опять же воспринимается не как бизнес-логика, а как техническая ошибка. Это поведение нужно поменять. Если сообщение пользователя не прошло проверку, нужно ему в окне чата прислать ответ: Для сообщений: К сожалению, ваше сообщение не соответствует правилам данного чата и не может быть отправлено. Попробуйте переформулировать. Для документов: К сожалению, ваш документ не прошел проверку и не может быть доставлен.
UX-дефект: frontend показывает «Не удалось завершить вход» при ошибке отправки отложенного сообщения, хотя вход завершён. Это следует исправить: завершать экран авторизации после bootstrap, а ошибку Bitrix показывать уже в чате (если сообщение отклонено сервисом message-safety, учесть реализацию предыдущего пункта)
#UI Ограничить кол-во символов в сообщении на фронте. Показывать в моменте счетчик: n/max, где n сколько символов уже напечатано, max сколько может быть отправлено. Максимальное кол-во символов - положить в app_settings.
#UI Убрать с экрана ввода номера телефона тексты согласий внизу экрана: Нажимая «Получить код», вы соглашаетесь с условиями использования и политикой конфиденциальности. Согласия пользователь дает ранее на отдельном экране.
#BACK_SECURE Перенести секреты из .env в KM Selectel.
#BACK_SECURE Провести аудит безопасности вм
#UI Унифицированы гостевые экраны Центра уведомлений, Профиля и Чата: единый стиль сообщения о необходимости входа и кнопка «Авторизоваться».
#BACK_BUSINESS Архитектурное решение принято: message-safety и bitrix-sync выносятся на самостоятельную ВМ2 с одним root Compose/nginx; Message Safety доступен privately, CRM webhook приходит напрямую на отдельный public host ВМ2; реализация/cutover остаются в задачах 16–17.
#BACK_SECURE Разработан архитектурный стандарт по безопасному деплою и размещению сервисов на ВМ.
Закрыто 04.08-10.08
#BACK_DEFECT Исправлены дублирующиеся триггеры на создание контакта для сервиса синхронизации. Исправлено создание в БД лишних задач на обновление контакта (каждый бустрап пользователя вызывал задачу на обновление контакта)
Закрыто 18.08-24.08
#INFRASTRUCTURE Зарегистрировать Conteiner registry Selectel
#BACK_DEFECT Автопродление TLS падает при перезагрузке nginx; сертификат действует до 14.10.2026. (Исправить reload внутри контейнера и проверить systemctl start an-chat-ssl-renew.service до успешного завершения.)
#BACK_BUSINESS Разработка Message Safety v2 по module-05, §18 DoR/DoD и cutover gates module-10-vm2:
- API/OpenAPI v2, versioned `message_safety.config_versions`, configuration activation/validation и schema migrations;
- PostgreSQL queue/lease/fencing/deadline + Redis hot cache/rate/wakeup;
- Unicode normalization и versioned text rule bundle/corpus;
- local-only URL parser/IDNA/DNS/IP policy и cache split;
- immutable S3 version flow, file detectors и technical matrix;
- ClamAV/freshclam, signature rollback и EICAR tests;
- api-backend integration: `202` polling, M8, `safety.chat.blocked`, conditional promote;
- VM2 internal nginx/TLS/egress/collector/dashboards + root-owned emergency MOCK helper/alert;
- contract/security/failure/load acceptance и S3 negative gate;
- controlled v1→v2 cutover, rollback rehearsal и удаление stub references.
#BACK_BUSINESS Разработка sync-service
#INFRASTRUCTURE Перераскатить сервисы от деплоя
В разработку:
1 #BACK_SECURE После интеграции с смс провайдером, реализовать debounce механизм при авторизации - каждая след. смс можно отправить через все большее окно. (сейчас есть Фиксированный cooldownmin_seconds_between_attempts)
2. #MONITORING Настроить мониторинг в Signoz
3. #BACK_BUSINESS Хранить историю устройств, с которых пользователь входил в ЛК (Ид юзера, идентификатор устройства, дата последнего входа, способ входа - веб\приложение)
4. #BACK_BUSINESS Веб-пуши для PWA
5. #UI На кнопке Чат отображать значок наличия непрочитанных уведомлений. Требуется синхронизация между устройствами (решение, например через Dialog.client_last_opened_at)
6. #BACK_BUSINESS Описание бизнес сущностей: Пользователь
7. #BACK_BUSINESS Описание бизнес сущностей: Сообщение
8. #UI Сделать страницу с инструкцией по установке приложения
9. #LEGAL Написать пользовательское соглашение.
13. #INFRASTRUCTURE Поднять второй контур для продакшн
14. #INFRASTRUCTURE Спрятать сеть за балансировщиком нагрузки
15. #UI Добавить подсказку по разрешенным типам файлов
16. #INFRASTRUCTURE WireGuard-only SSH.
17. #LEGAL Обновить документы по ПД - модель угроз и меры защиты.
18. #LEGAL Уведомление в РКН по БД обработки ПД.
19. #MONITORING Добавить логи (Для Python-сервисов добавить OTLP Log Exporter: api-backend; sms-service; sms-worker. Подключить LoggerProvider, BatchLogRecordProcessor и bounded queue. Передавать resource attributes: service.name; service.version; deployment.environment; service.namespace=han-chat.) Экспортировать структурированные поля request_id, trace_id, span_id, severity и event name. Оставить stdout как аварийный локальный журнал. Добавить canary-тесты, запрещающие экспорт токенов, cookie, телефонов, email, текстов сообщений, SQL и object keys.).
20. #MONITORING Nginx metrics/tracing в signoz
21. #BACK_SECURE Сформулировать требования для обработки персональных данных
23. #BACK_BUSINESS Разработка notification-service
24. #BACK_BUSINESS Store-review вход: точечный bypass в Keycloak OTP SPI по номеру из .env (STORE_REVIEW_ENABLED / STORE_REVIEW_PHONE / STORE_REVIEW_OTP) — для этого телефона SMS не шлётся, verify принимает фиксированный OTP; остальные номера идут обычным OTP/SMS. Не путать с глобальным KEYCLOAK_OTP_MOCK_*. Учётные данные только в Review Notes стора (не в бинарнике/UI); пользователь с демо-контентом; в production включать только на время ревью.
25. #UI Реализация мнемоник: Определение итогового перечня мнемоник, перевод фронтенда на мнемоники, seed заливка мнемоник в БД (?)
26. #INFRASTRUCTURE Развернуть Гит в облаке
27. #BACK_BUSINESS Синхронизация документов из битрикс24 в Приложение.
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 схлапывание контактов. Подробности реализации ниже (на подумать)
36. #INFRASTRUCTURE положить в облако секреты ВМ
Критично для релиза:
1. Разработка message-safety
2. Разработка sync-service
3. Пользовательское соглашение
4. Подключить OTLP-провайдер
5. Починить UI баги
6. Второй контур для продакшн
-
details Комплексный алгоритм:
-
Нормализовать номер приложения
P. -
Если active mapping существует:
- Contact принадлежит текущему
user_id— обновить служебные поля и app-телефон; user_idпуст — восстановить служебные поля;- указан чужой
user_id— ничего не перезаписывать, создать alertmapping_identity_mismatch; - Contact отсутствует — пометить mapping broken и создать alert.
- Contact принадлежит текущему
-
Если mapping отсутствует, собрать объединённый список Contact:
- найденные по текущему
user_id; - найденные по новому полю app-телефона
P; - найденные через
duplicate.findbycommпо стандартномуPHONE.
- найденные по текущему
-
Загрузить все карточки и классифицировать:
- принадлежат текущему пользователю;
- свободны —
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-телефоном нельзя автоматически привязывать.
- кандидатами считаются Contact с app-телефоном
-
Один кандидат свободен:
- записать
user_id, registration flag и app-телефон; - создать mapping.
- записать
-
Несколько кандидатов:
- выбрать самый новый по
CREATED_TIME, затем по числовому ID; - если выбранный свободен — привязать его и создать
duplicate_contacts; - если выбранный принадлежит другому пользователю — создать новый Contact и alert
contact_owned_by_other_user; - в
contactIdsalert передать все старые ID и ID нового Contact.
- выбрать самый новый по
-
Совпадения есть только по стандартному
PHONE, но у них указан другой app-телефон:- не считать их Contact текущего пользователя;
- создать новый Contact;
- создать alert о совпадении общего номера.
-
Совпадений нет:
- создать новый Contact без alert.
Дополнительные правила:
- app-телефон — App-master: изменения этого поля в Б24 не меняют номер авторизации.
- При смене номера приложение обновляет app-телефон и гарантирует наличие нового номера в стандартном
PHONE, но не удаляет остальные номера Contact. - Перед повторным
contact.addпосле timeout необходимо повторно искать поuser_idи app-телефону, чтобы не создать дубль. - Mapping создаётся только после успешной записи служебных полей.
- Все конфликтные ветки должны иметь отдельные регрессионные тесты до реализации.
- details
Изменение стандартного
PHONEв Битрикс24 не должно автоматически менять номер авторизации в приложении. Иначе сотрудник с доступом к CRM сможет случайно или намеренно передать чужой аккаунт другому номеру.
Рекомендуемый процесс:
- Сотрудник меняет стандартный номер в карточке.
- Webhook фиксирует расхождение с полем «Номер телефона в приложении».
- Система создаёт отдельный запрос/смарт-процесс «Смена номера приложения».
- Сотрудник явно выбирает, какой из номеров Contact является новым номером приложения.
- Выполняются проверки:
- нормализация E.164;
- новый номер не занят другим пользователем;
- Contact действительно связан с нужным
user_id; - нет другого активного запроса.
- Клиент подтверждает смену:
- OTP на новый номер;
- подтверждение в активной сессии приложения;
- желательно OTP на старый номер, если он доступен.
- Если старый номер недоступен — отдельный усиленный сценарий идентификации сотрудником с обязательным аудитом и, желательно, дополнительным согласованием.
- После подтверждения App меняет номер в своём источнике истины — БД приложения/Keycloak.
- Через outbox создаётся задача синхронизации.
- Bitrix Sync обновляет:
- поле «Номер телефона в приложении»;
- служебные поля связи;
- при необходимости добавляет новый номер в стандартный
PHONE; - закрывает запрос на смену номера.
Важные правила:
- Обычное редактирование
PHONEтолько создаёт предложение на смену, но не меняет логин. - Поле «Номер телефона в приложении» остаётся read-only для сотрудников.
- Старые дополнительные номера Contact автоматически не удаляются.
- Нужны срок действия запроса, ограничение попыток OTP, журнал сотрудника и времени операции.
- Повторный запрос должен быть идемпотентным.
Так сохраняется удобство работы через Б24, но CRM не становится небезопасным источником истины для номера авторизации.
- details
Здесь нужно объединять не только карточки Битрикс24, но прежде всего два аккаунта приложения. Простое слияние Contact оставит данные личного кабинета привязанными к старому
user_id.
Рекомендуемый сценарий account merge.
-
Создать заявку на объединение:
- старый
user_idи старый Contact; - новый
user_idи новый Contact; - результат комплайенса;
- оператор и подтверждающий сотрудник;
- причина и audit trail.
- старый
-
Выбрать канонический аккаунт. Обычно это старый аккаунт, содержащий историю и данные. Новый пустой аккаунт становится поглощаемым.
-
На время операции заблокировать изменения обоих аккаунтов и повторные merge-заявки.
-
Проверить конфликты:
- заказы, документы, согласия;
- бонусы, баланс и другие финансовые данные;
- активные процессы;
- наличие данных в новом аккаунте;
- отсутствие третьего аккаунта с новым номером.
-
На стороне приложения:
- привязать новый номер к каноническому старому аккаунту;
- старый номер сделать неактивным либо историческим;
- перенести допустимые данные нового аккаунта;
- отметить новый
user_idкакmerged_into=<canonical_user_id>; - запретить дальнейшее использование поглощённого аккаунта;
- обновить Keycloak/механизм авторизации;
- отозвать старые сессии и потребовать повторный вход.
-
Только после успешного App merge обработать Битрикс:
- старый Contact выбрать каноническим;
- записать в него канонический
user_id; - поле «Номер телефона в приложении» установить в новый номер;
- объединить стандартные номера обоих Contact;
- создать active mapping канонического пользователя на канонический Contact;
- у второго Contact очистить app-телефон,
user_idи registration flag; - затем объединить его с каноническим Contact штатным механизмом Б24 либо архивировать как поглощённый.
-
Закрыть старые mapping со специальной причиной
account_merge, но сохранить историю. -
Завершить заявку только после проверок:
- вход по новому номеру открывает старый личный кабинет;
- существует один active App user;
- существует один active mapping;
- только один Contact содержит app-телефон и registration flag;
- поглощённый аккаунт больше не создаёт задачи синхронизации.
Ключевой принцип: сначала объединение аккаунтов приложения, затем CRM. Если сначала слить карточки Б24, это не вернёт пользователю данные.
Для устойчивой реализации потребуется отдельная audited-процедура наподобие:
request_account_merge(
canonical_user_id,
absorbed_user_id,
canonical_contact_id,
absorbed_contact_id,
reason,
operator_id,
compliance_case_id
)
Операция должна быть идемпотентной, поэтапной и восстанавливаемой после сбоя. Для финансовых или юридически значимых данных автоматический перенос без отдельных правил недопустим.