Направление работ: Back Код раздела: 1.3 Аккаунты и пользователи > Клиенты Статус: Готов Ответственный: Панкова Л.А. Версия: 0.2 Обновлено: 24.07.26
1. Назначение
Раздел описывает Карточку клиента как сущность для хранения персональной информации об аккаунте и истории его взаимодействий с партнерами.
Карточка клиента создается и привязывается к аккаунту при регистрации, бронировании или добавлении сотрудника.
В текущем документе фиксируются состояния Карточки клиента и состав ее персональных, технических и партнерских данных.
2. Ключевые понятия
Клиент — базовая пользовательская характеристика аккаунта МАРТ, которая присваивается при регистрации путем создания и привязки Карточки клиента.
Карточка клиента — сущность для хранения персональной информации об аккаунте и истории его взаимоотношений с партнерами в качестве получателя услуг.
Карточка зарегистрированного пользователя — Карточка клиента, которую может изменять только пользователь, которому она принадлежит.
Карточка незарегистрированного пользователя — Карточка клиента, которую может изменять только партнер или сотрудник партнера.
Параметры и данные Карточки клиента — персональные данные, технические данные и данные по партнерам.
3. Scope
Входит
S1: Карточка клиента: создание, хранение персональных данных и связь с аккаунтом
S2: Состояния карточки клиента: карточка зарегистрированного пользователя и карточка незарегистрированного пользователя, включая правило, кто может изменять карточку в каждом состоянии.
S3: Параметры и данные карточки клиента: персональные данные, технические данные и данные по партнерам, включая перечень связанных сущностей без раскрытия их внутренней логики.
Не входит
-
Аккаунты, учетные данные и связь аккаунта с карточкой клиента: Back 1.1
-
Доступы, клиентская зона, тарифы и подписки: Back 1.2 / Back 1.3.1 / Back 1.3.4 / Back 8.3.4
-
Характеристики клиента, группы клиентов и группы деятельности: Back 1.3.2 / Back 1.3.3 / Back 8.2.1
-
Партнеры, партнерские зоны и сотрудники партнеров: Back 1.4
-
Заказы, штрафы, скидки и условия оплаты: Back 2.4 / Back 2.7.1 / Back 3.2 / Back 3.2.1
-
Платежные документы, сохраненные карты, уведомления, устройство и статистика: Back 5.4 / Back 5.5 / Back 7.2.1 / Back 9.1 / Back 9.4.1
-
UI и фронтовые сценарии карточки клиента: AdmLk 3.2 / AdmLk 3.2.1 / WebLk 6.4.1
4. Требования
Правила и ограничения бизнеса на уровне данных, источник истины в системе
| ID | Требование | Комментарий | Тип требования | Вес | Статус |
|---|---|---|---|---|---|
| S1: BR1.3-1 | Клиент присваивается аккаунту МАРТ через создание и привязку Карточки клиента | Бизнес | 1 | Частично \ #OQ1.3-1 | |
| S1: BR1.3-2 | Карточка клиента должна хранить персональную информацию об аккаунте и историю его взаимоотношений с партнерами | • Фамилия • Имя (обязательный) • Отчество • Телефон (обязательный) • Почтовый адрес • Публичное имя пользователя (латиница) • Дата рождения • Фотография • Пол • О себе • Страница в ВК • Профиль в Instagram • Канал Telegram — ссылка на группу в Телеграмм • Город • Группы клиента ( https://wiki.yandex.ru/homepage/d750da42741c/putevoditel-po-jekosisteme/guidebook/akkaunty-i-dostup/klienty/ad6842153a20/ ) • Группы деятельности ( https://wiki.yandex.ru/homepage/d750da42741c/putevoditel-po-jekosisteme/guidebook/administrirovanie-servisa/6d764dd604ff/17168a199436/ ) Нормы имени: минимум 2 буквы, максимум 50 букв, цифры запрещены. | Бизнес | 1 | Частично \ #OQ1.3-2 \ #OQ1.3-3 \ #OQ1.3-4 |
| S1: BR1.3-3 | Все заказы в системе должны привязываться к Карточке клиента за исключением заказов без статуса (Статус: PreReserv) | Бизнес | 1 | Частично \ #OQ1.3-5 | |
| S2: BR1.3-4 | Карточка клиента может быть создана при регистрации аккаунта, бронировании в виджет без регистрации или добавлении сотрудника или клиента | Способ создания определяет состояние Карточки клиента | Системное | 1 | Частично \ #OQ1.3-10 \ #OQ1.3-11 |
| S2: BR1.3-5 | Карточка клиента может находиться только в допустимых состояниях | Допустимые состояния: карточка зарегистрированного пользователя и карточка незарегистрированного пользователя | Бизнес | 1 | Не реализовано \ #OQ1.3-6 |
| S2: BR1.3-6 | Право изменения Карточки клиента зависит от ее состояния | Карточку зарегистрированного пользователя может изменять только пользователь, которому она принадлежит. Карточку незарегистрированного пользователя может изменять только партнер или сотрудник партнера | Бизнес | 1 | Не реализовано \ #OQ1.3-7 |
| S2: BR1.3-7 | Карточка зарегистрированного пользователя является источником прав доступа для связанного аккаунта | К таким карточкам всегда привязан хотя бы один клиентский тариф, он же Подписка (см. 1.3.1 Клиентская зона доступа). | Бизнес | 1 | Не реализовано \ #OQ1.3-8 |
| S3: BR1.3-8 | Правила заполнения и редактирования персональных данных зависят от состояния Карточки клиента | Персональные данные заполняются клиентом или партнером. Телефон и почтовый адрес после завершения регистрации редактируются только через аккаунт. Публичное имя пользователя до регистрации недоступно, после ее завершения переносится значение логина | Системное | 1 | Не реализовано \ #OQ1.3-12 \ #OQ1.3-13 |
| S3: BR1.3-9 | Технические данные Карточки клиента должны заполняться автоматически вследствие системного процессинга | Состав: кем создано, аккаунт, уведомления, подписки, автопродление тарифа, сферы, заказы, платежные документы, избранное, сохраненные карты, данные об устройстве | Системное | 1 | Частично \ #OQ1.3-14 |
| S3: BR1.3-10 | Данные по партнерам должны заполняться каждым партнером в рамках одной партнерской зоны и группироваться в общий список характеристик клиента | Состав: скидки клиента, штрафы, признак блокировки партнерами, условия оплаты, группы деятельности, сообщения по клиенту. Партнерские группы добавляются вручную партнерами | Бизнес | 1 | Частично \ #OQ1.3-9 |
| S3: BR1.3-11 | Сообщения по клиенту должны хранить ограничение доступа на просмотр | Допустимые значения: только я, сотрудники, все. | Системное | 2 | Частично \ #OQ1.3-15 \ #OQ1.3-16 \ #OQ1.3-17 |
| S3: BR1.3-12 | Система должна поддерживать фильтрацию Карточек клиентов по источнику создания (после релиза реализация) | Системное | 3 |
5. Открытые вопросы
| ID | Источник | Вопрос | Кому | Статус | Рекомендации | Итоговое решение |
|---|---|---|---|---|---|---|
| #OQ1.3-1 | Код BR1.3-1 | Требование говорит: клиент привязывается к аккаунту связью один-к-одному. В коде отдельной связи нет — карточка и аккаунт считаются связанными по совпадению идентификаторов (ID карточки при создании берётся равным ID аккаунта), сама карточка создаётся асинхронно по событию регистрации. Отдельной колонки-ссылки и запрета «один аккаунт — одна карточка» в базе нет — инвариант держится только на соглашении «ID равны» и на проверке при регистрации. \ ClientAggregate.cs:131,148; AccountCreatedClientConsumer.cs:46,76 | Бизнес/Разработка | Open | В гайдбуке 1.3 связь описана как «создание и привязка карточки к аккаунту», но способ гарантии (равенство ID / внешний ключ / уникальное ограничение) не оговорён — подтвердить нечем. (А) зафиксировать в BRD, что связь реализована равенством идентификаторов, и добавить защиту инварианта «один аккаунт — одна карточка» на уровне базы/процесса; (Б) оставить как есть, отметив отсутствие строгой связи в базе как осознанный компромисс. Гарантия на уровне базы — решает бизнес/архитектура. | Нужно подтвердить, считаем ли связь аккаунта и карточки клиента через одинаковый ID достаточной. Если да, фиксируем это в BRD как текущую модель связи. Если нужна строгая гарантия «один аккаунт — одна карточка», разработке нужно добавить явную защиту на уровне базы или процесса создания карточки. |
| #OQ1.3-2 | Код BR1.3-2 | Требование говорит: Имя и Телефон — обязательные поля. В коде оба поля необязательные: доменной проверки на обязательность нет, при сборке имя подставляется пустой строкой — карточку можно сохранить без имени и телефона. \ Client.cs:30-31,60-61; ClientMapping.cs:24 | Разработка | Закрывает PM | Гайдбук 1.3 прямо помечает Имя и Телефон как обязательные — значит это баг, а не спорный вопрос. Закрываю сам: включить проверку обязательности при создании/обновлении → тикет в Bitrix. Оговорка для реализации: сверить путь создания из виджета (партнёр бронирует без данных клиента); гайдбук исключения не даёт, поэтому по умолчанию обязательность применяется ко всем путям. | Имя и телефон должны быть обязательными полями карточки клиента. Разработке нужно добавить проверку при создании и обновлении карточки, чтобы карточка не сохранялась без этих данных. Отдельно проверить сценарий создания из виджета без регистрации: если там допускается создание без имени или телефона, это исключение нужно явно описать в BRD. |
| #OQ1.3-3 | Код BR1.3-2 | Требование говорит: карточка хранит Почтовый адрес, Публичное имя (латиница), О себе, Профиль в Instagram, Город. В коде этих полей нет вообще — ни столбцов базы, ни в доменной модели. Из контактных ссылок есть только ВК и Telegram. \ Client.cs:30-145 | Бизнес/Разработка | Open | Гайдбук 1.3 эти поля перечисляет — по спецификации они нужны. Но фактически их нет, и выбор «строить пять полей сейчас или урезать состав карточки» меняет продукт. (А) привести код к BRD — завести недостающие поля; (Б) привести BRD к коду — оставить фактический состав, недостающие вынести в явный список «планируется / не реализовано». Продуктовое решение о составе карточки. Связать с OQ1.3-13 (публичное имя нужно и для правил заполнения). | Нужно подтвердить состав персональных данных карточки клиента. Сейчас в коде нет полей «почтовый адрес», «публичное имя», «о себе», «Instagram» и «город». Если эти поля нужны пользователю и должны быть частью карточки, разработке нужно добавить их в модель, базу и API. Если они не нужны или относятся к другому разделу, нужно скорректировать BRD и убрать их из состава карточки клиента. |
| #OQ1.3-4 | Код BR1.3-2 | Требование говорит: карточка хранит Фотографию. В коде столбца «фото» в карточке нет — фото подтягивается на чтение из внешнего сервиса Resources по gRPC. Функционально фото у карточки есть, но хранится не в ней. \ ImageService.cs:17,27-30; GetClientInfoByAccountIdHandler.cs:28-41 | Разработка | Закрывает PM | Гайдбук 1.3 перечисляет фото как поле, но не требует хранить его именно в карточке — функциональная потребность закрыта (фото доступно из Resources). Продуктового выбора нет, вопрос в формулировке. Закрываю сам: уточнить в BRD, что фото отображается из сервиса Resources, а не хранится в карточке → правка формулировки BR1.3-2. | Фотография клиента не хранится в самой карточке, а отображается из сервиса Resources при запросе данных карточки. Функционально фото доступно пользователю, поэтому доработка кода не требуется. Нужно уточнить BRD: фотография относится к отображаемым данным карточки клиента, но хранится во внешнем сервисе Resources. |
| #OQ1.3-5 | Код BR1.3-3 | Требование говорит: все заказы привязываются к карточке клиента, кроме заказов без статуса (PreReserv). В коде привязка гарантирована не всегда: у одиночного заказа поле клиента необязательное, строго обязательно оно только у групп заказов. То есть отдельный заказ может существовать без клиента. \ OrderAggregate.cs:122; OrderModelConfiguration.cs:41; ProcessingOrderGroup.cs:23,35 | Бизнес (Герман) | Open | Гайдбук 1.3 подтверждает правило («все заказы привязываются к карточкам»), но не описывает, бывают ли легитимные заказы без клиента (служебные/гостевые), кроме уже названного PreReserv. (А) сделать поле клиента обязательным и для одиночных заказов после выхода из PreReserv; (Б) уточнить в BRD, какие заказы без клиента допустимы. Решает бизнес; затрагивает разделы заказов (2.4 / 3.2). | |
| #OQ1.3-6 | Код BR1.3-5 | Требование говорит: карточка может быть только в одном из допустимых состояний — зарегистрированного или незарегистрированного пользователя. В коде явного состояния (поля или перечисления) нет. Косвенные признаки ненадёжны: ID аккаунта проставляется всегда (в т.ч. пустой GUID для карточек из виджета), а флаг «профиль заполнен» отражает заполненность, а не регистрацию. \ ClientAggregate.cs:107,114,131,148,166; Client.cs:24-25,143-144 | Бизнес/Разработка | Open | Гайдбук 1.3 явно вводит два состояния и разные права изменения для них — требование реально, спорить не о чем. Но состояние в домене не выражено, поэтому и правило доступа проверить нечем. (А, рекоменд.) ввести явное состояние карточки и на нём строить право изменения; (Б) если разграничение обеспечивается выше (шлюз / личные кабинеты) — описать это как внешний механизм и снять требование с сервиса карточки (сейчас такого разграничения не найдено нигде). Ключевое продукт+архитектура решение, разблокирует OQ1.3-7, OQ1.3-11, OQ1.3-12, OQ1.3-13. | Нужно подтвердить, должно ли состояние карточки клиента явно храниться в системе: «зарегистрированный пользователь» или «незарегистрированный пользователь». Сейчас такого состояния в коде нет, поэтому система не может надежно отличать эти два случая. Если правило остается в BRD, разработке нужно добавить явное состояние карточки и использовать его в связанных проверках: кто может редактировать карточку и какие поля доступны после регистрации. Если состояние определяется вне этого сервиса, нужно описать этот внешний механизм в BRD. |
| #OQ1.3-7 | Код BR1.3-6 | Требование говорит: карточку зарегистрированного меняет только её владелец, карточку незарегистрированного — только партнёр или сотрудник партнёра. В коде разграничения нет вообще: ID вызывающего используется лишь чтобы записать «кем обновлено», сравнения с владельцем нет, на шлюзе проверка бинарная «должен быть авторизован». Фактически любой авторизованный может изменить любую карточку по её ID. \ UpdateClientCommandHandler.cs:39-44,83; ClientAggregate.cs:210-214; RpcAnonByRouteAuthorization.cs:48-57 | Разработка (Влад) | Open | Гайдбук 1.3 право доступа по состоянию подтверждает — правило реально, и это дыра в безопасности (любой правит любую карточку). Реализация зависит от наличия состояния (OQ1.3-6). Вопрос к Владу: где живёт проверка (домен карточки / шлюз / кабинеты) и как её ввести после появления состояния. Связать с OQ1.3-6. | Нужно определить место, где будет применяться правило изменения карточки клиента. Сейчас в слое авторизации доступ в целом проверяется по permissions, но отдельного правила для изменения карточки с учетом ее состояния и владельца не найдено. Как вариант, можно поставить требованию вес 3 и дождаться полной реализации ABAC, после чего добавить отдельный permission/правило, которое будет отвечать за изменение карточки клиента: владелец редактирует зарегистрированную карточку, партнер или сотрудник партнера — незарегистрированную. |
| #OQ1.3-8 | Код BR1.3-7 | Требование говорит: к зарегистрированной карточке всегда привязан хотя бы один клиентский тариф (Подписка), при создании/привязке карточки привязывается подписка «По умолчанию». В коде автопривязки нет: признак «по умолчанию» у тарифа задаётся вручную и относится к каталогу тарифов (у тарифа нет привязки к клиенту), обработчик создания клиента и consumer регистрации тариф не привязывают — в сервисе авторизации TODO-заглушка. Гарантии «хотя бы один тариф» нет. \ ClientTariffAggregate.cs:13,64; CreateClientCommandHandler.cs:19-52; AccountCreatedClientConsumer.cs:93-131; RegistrationMobileEndCommandHandler.cs:122 | Бизнес/Разработка | Open | Гайдбук 1.3 и 1.3.1 прямо говорят: базовая подписка активируется при создании карточки, подписка «По умолчанию» привязывается — правило реально, это недоделка. По скоупу инвариант авто-привязки живёт в 1.3.1 / 8.3.4, в 1.3 требование BR1.3-7 остаётся ссылкой; чинить и заводить недоработку — в 1.3.1. (А, рекоменд.) реализовать автопривязку подписки «По умолчанию» при создании/привязке (снять TODO); (Б) оставить в 1.3 только ссылку, требование держать в 1.3.1. Координация с 1.3.1 и 8.3.4. | Нужно подтвердить, где должна выполняться автоматическая привязка подписки «По умолчанию» при создании или привязке карточки клиента: в сервисе карточек клиента или в разделе подписок/клиентской зоны доступа. Сейчас в коде такой автопривязки нет, поэтому у зарегистрированной карточки не гарантируется наличие хотя бы одного тарифа. Если правило остается обязательным, разработке нужно реализовать автопривязку подписки в согласованном сервисе, а в BRD 1.3 оставить ссылку на раздел 1.3.1, где описывается логика подписок. |
| #OQ1.3-9 | Код BR1.3-10 | Требование говорит: данные по партнёрам заполняются в рамках одной партнёрской зоны; в состав входят в т.ч. скидки клиента и группы деятельности. В коде зонирование неоднородно: блокировка, штраф, условия оплаты и сообщения привязаны к партнёрской зоне (верно), а скидки клиента и группы деятельности — нет (поля зоны в их моделях нет, хранятся на уровне клиента целиком). \ ClientPartAggregate.cs:13,15-17; ClientMessageAggregate.cs:11; ClientDiscount.cs; ClientServiceGroupEntity.cs | Бизнес/Разработка | Open | Гайдбук разводит два пункта по-разному, ответ раздельный. (1) Группы деятельности — гайдбук 1.3 относит их к персональным данным (см. 8.2.5), а не к данным по партнёрам → код верен, ошибка в BRD → убрать группы деятельности из состава BR1.3-10 (закрывается правкой BRD). (2) Скидки клиента — гайдбук 1.3.2 даёт скидке поле «Партнёрская зона» → скидки должны быть в рамках зоны → код привести к спецификации. По скоупу состав скидки — в 1.3.2, сущность скидки — в 2.7.1; зонирование согласовать там, в 1.3 не дублировать. | Нужно разделить данные по партнерам. Блокировки, штрафы, условия оплаты и сообщения уже привязаны к партнерской зоне. Группы деятельности не нужно относить к партнерским данным, их следует перенести в персональные данные карточки клиента. По скидкам нужно подтвердить бизнес-правило: скидка должна быть общей для клиента или отдельной в рамках партнерской зоны. Если скидки должны зависеть от партнерской зоны, разработке нужно добавить такую привязку в модель скидок; если скидки общие, нужно уточнить это в BRD. |
| #OQ1.3-10 | Код BR1.3-4 | Требование говорит: карточка может быть создана при бронировании в виджете без регистрации. В коде сценарий реализован, но как отдельный вызываемый метод API (источник фиксируется как «виджет», ID аккаунта — пустой GUID). При этом ни один обработчик событий заказа карточку не создаёт (consumer закрытия/отмены заказа выходит, если клиента нет). То есть «при бронировании» зависит от того, вызовет ли метод сторона виджета — внутри сервиса карточки такого триггера нет. \ CreateClientFromWidgetCommandHandler.cs:36-50; OrderClosedClientConsumer.cs:41-45 | Разработка (Влад) | Open | Гайдбук 1.3 подтверждает, что карточка создаётся при бронировании, но не оговаривает механизм (событие заказа vs явный вызов). Вопрос к Владу: где в архитектуре живёт виджет-флоу — (А) зафиксировать, что карточку создаёт сторона виджета явным вызовом (описать в BRD/контракте, кто и когда вызывает); (Б) создавать карточку в обработчике события бронирования. | Автоматическое создание карточки клиента при бронировании из виджета сейчас не подтверждено кодом. В коде есть отдельные методы CreateClientFromWidget / CreateClientFromWidgetMobile, но они помечены как unused, не найдены среди вызываемых методов и не открыты для анонимного доступа виджета на gateway. Нужно выбрать целевую механику: либо виджет сначала отдельным доступным вызовом создает карточку клиента и затем передает clientId в заказ, либо карточка создается автоматически внутри сценария CreateOrderWidget. Для автоматического создания потребуется расширить контракт CreateOrderWidget, потому что сейчас в заказ из виджета не передаются ФИО/телефон/email клиента. |
| #OQ1.3-11 | Код BR1.3-4 | Требование говорит: способ создания карточки определяет её состояние. В коде способ создания фиксируется (Web / виджет / партнёрский Web), но никакого состояния из него не выводится — поля состояния нет (см. OQ1.3-6). Связь «способ → состояние» не реализована. \ EventSourceMapper.cs:14-25; ClientAggregate.cs | Разработка | Open | Гайдбук подтверждает «исходя из способа определяется состояние». Проблема — производная от отсутствия поля состояния. Рекомендация: отдельного решения не требует — как только появится состояние (OQ1.3-6), способ создания в него отображается. Пока — описать в BRD, что источник фиксирует канал, но состояние из него не выводится. Связать с OQ1.3-6. | Способ создания карточки сейчас фиксируется как источник создания, но не определяет состояние карточки. Реализация зависит от OQ1.3-6: после добавления явного состояния карточки разработке нужно настроить правило, какое состояние присваивается при каждом способе создания. До этого в BRD нужно указать, что текущий источник создания показывает только канал, через который создана карточка, но не является состоянием карточки. |
| #OQ1.3-12 | Код BR1.3-8 | Требование говорит: телефон и почтовый адрес после завершения регистрации редактируются только через аккаунт (правила заполнения зависят от состояния карточки). В коде ограничения нет: обновление карточки безусловно перезаписывает телефон и email независимо от состояния, почтового адреса в модели нет вовсе, понятия «после регистрации» не существует. \ ClientAggregate.cs:204-205; UpdateClientCommandHandler.cs:83 | Бизнес/Разработка | Open | Гайдбук 1.3 правило подтверждает дословно. Но реализация упирается в отсутствие состояния (OQ1.3-6) и отсутствующий почтовый адрес (OQ1.3-3), плюс вопрос, где живёт правило — в 1.3 или в аккаунте 1.1. (А) реализовать гейтинг после появления состояния; (Б) если редактирование контактов через аккаунт обеспечивается разделом 1.1 — перенести правило туда. Связать с OQ1.3-6, OQ1.3-3. | Нужно подтвердить, где должно выполняться правило редактирования контактов после регистрации: в карточке клиента или в аккаунте. Сейчас карточка может напрямую обновить телефон и email, а почтового адреса в модели нет. Если после регистрации контакты должны меняться только через аккаунт, разработке нужно запретить прямое изменение этих полей в карточке клиента и связать проверку с состоянием карточки из OQ1.3-6. Если это правило относится к разделу аккаунтов, его нужно перенести в BRD 1.1, а в 1.3 оставить ссылку. |
| #OQ1.3-13 | Код BR1.3-8 | Требование говорит: публичное имя пользователя до регистрации недоступно, после завершения регистрации в него переносится значение логина. В коде поля «публичное имя» нет, переноса логина после регистрации тоже нет — правило не реализовано. \ ClientAggregate.cs; Client.cs | Бизнес/Разработка | Open | Гайдбук 1.3 правило описывает явно. Но оно завязано на отсутствующее поле (публичное имя — см. OQ1.3-3) и на состояние (OQ1.3-6). (А) завести поле и реализовать перенос логина после регистрации; (Б) если поле исключается из состава карточки (решение по OQ1.3-3) — снять и это правило. Связать с OQ1.3-3, OQ1.3-6. | Нужно подтвердить, остается ли «публичное имя пользователя» частью карточки клиента. Сейчас такого поля в коде нет, поэтому логин после регистрации некуда переносить. Если публичное имя нужно, разработке нужно добавить поле и реализовать заполнение значением логина после завершения регистрации. Если поле не требуется, нужно убрать из BRD правило про публичное имя и перенос логина. Решение связано с OQ1.3-3 и OQ1.3-6. |
| #OQ1.3-14 | Код BR1.3-9 | Требование говорит: технические данные заполняются автоматически; состав — кем создано, аккаунт, уведомления, подписки, автопродление, сферы, заказы, платёжные документы, избранное, сохранённые карты, устройство. В коде часть состава отсутствует (уведомления, сохранённые карты, устройство не хранятся), заказы и платёжные документы живут в других сервисах и попадают как производные, подписка/тариф на основном методе карточки отдаётся как null (TODO). Подтверждено рабочими: кем создано, аккаунт, автопродление, сферы, избранное. \ Client.cs:30-145; GetClientInfoByAccountIdResponse.cs:31; GetClientInfoByAccountIdHandler.cs:45 | Бизнес/Разработка | Open | Гайдбук 1.3 сам ссылается на внешние разделы: уведомления (7.2.1), заказы (9.4.1), платёжные документы (5.4), сохранённые карты (5.5), устройство (9.1), подписки/автопродление (1.3.1) — эти данные по замыслу живут не в карточке. (Б, рекоменд.) уточнить BRD: такие данные описать как «отображается из сервиса X», а не «хранится в карточке»; перечислить, что заполняется фактически и что отдаётся как null; (А) добавить реально отсутствующее (уведомления/устройство/карты или ссылки). Подписка null — связать с OQ1.3-8 (живёт в 1.3.1). Состав согласовать с продуктом. | Нужно уточнить состав технических данных карточки клиента. Сейчас карточка хранит не все перечисленные данные: часть данных находится в других сервисах и должна только отображаться в карточке. В BRD нужно разделить данные на две группы: что реально хранится в карточке клиента, и что отображается из других разделов/сервисов. Если какие-то данные должны именно храниться в карточке, разработке нужно добавить их в модель и API. Отдельно нужно связать вопрос подписки с OQ1.3-8 и разделом 1.3.1. |
| #OQ1.3-15 | Код BR1.3-11 | Требование говорит: сообщения по клиенту хранят ограничение доступа на просмотр со значениями «только я / сотрудники / все» (три значения). В коде перечисление содержит четыре значения: EmployeesAndMe, OnlyMe, OnlyService, OtherPartners. Сопоставление приблизительное: «сотрудники» ≈ EmployeesAndMe (включает автора, ограничено зоной), «все» ≈ OtherPartners; чистого «все» нет, а OnlyService в гайдбуке не описано. \ ClientMessageAdmissionEnum.cs:5-8 | Бизнес/Разработка | Open | Гайдбук 1.3 называет ровно три значения. (А, рекоменд.) свести к трём (только я / сотрудники / все) — OnlyService/OtherPartners убрать или отобразить на три; (Б) задокументировать все четыре и их семантику, уточнив, что «сотрудники» ограничены партнёрской зоной. В любом варианте закрыть дыру с непокрытым OnlyService (OQ1.3-16). Связать с OQ1.3-16. | Нужно подтвердить модель доступа к сообщениям по клиенту. В BRD указаны три варианта: «только я», «сотрудники», «все», а в коде сейчас четыре: EmployeesAndMe, OnlyMe, OnlyService, OtherPartners. Если правильна модель из BRD, разработке нужно привести код к трем значениям или корректно сопоставить текущие значения с ними. Если нужны все четыре варианта, нужно описать их в BRD понятными названиями и правилами видимости. Решение связано с OQ1.3-16, потому что одно из текущих значений сейчас не обрабатывается при чтении. |
| #OQ1.3-16 | Код BR1.3-11 | Проблема: фильтр видимости на чтении обрабатывает только 3 из 4 значений; значение OnlyService не покрыто ни одной веткой — такие сообщения не вернутся никогда (тихо невидимы, данные теряются на чтении). Плюс «только я» трактуется как «только автор-сотрудник», а не клиент. \ ClientMessagesReadRepository.cs:25-30; GetClientMessagesHandler.cs:29-33 | Разработка (Влад) | Open | Тихая потеря данных на чтении — дыру закрыть обязательно, независимо от модели значений. Но какую ветку добавлять (или убрать OnlyService) зависит от решения по составу значений (OQ1.3-15). Вопрос к Владу: после выбора модели — либо добавить ветку для OnlyService, либо убрать значение и мигрировать данные. Связать с OQ1.3-15. | Нужно устранить ситуацию, при которой сообщения с доступом OnlyService не возвращаются при чтении. После решения по OQ1.3-15 разработке нужно либо добавить корректную обработку OnlyService в фильтр видимости, либо убрать это значение и мигрировать существующие данные на поддерживаемые варианты доступа. Также нужно явно зафиксировать, что «только я» означает автора сообщения, а не клиента. |
| #OQ1.3-17 | Код BR1.3-11 | Проблема: ограничение доступа применяется только на чтение. На запись (редактирование / удаление / архивацию сообщения) проверки прав нет — любой авторизованный может изменить или удалить любое сообщение по его ID независимо от значения ограничения. \ UpdateClientMessageHandler.cs:22-27; ArchiveClientMessageHandler.cs; DeleteClientMessageHandler.cs | Бизнес (Герман) | Open | Гайдбук 1.3 говорит только про ограничение на просмотр — про запись ничего нет, додумывать не за что. Но открытая на запись механика приватных заметок партнёров о клиенте — смежная дыра в безопасности. Решение бизнеса: нужно ли симметрично ограничивать запись (автор или сотрудник зоны). Рекомендация — да, ограничить; если сознательно нет — отметить в BRD, что ограничение только на просмотр. | |
| #OQ1.3-18 | Код вне BRD | Что нашли: на карточке клиента лежит целая подсистема — баллы лояльности, кешбэк, лимиты, штрафы. В требованиях 1.3 как состав это не описано. \ Client.cs:108-109; ClientAggregate.cs:109,289 | Разработка | Закрывает PM | Дом у всех частей есть по скоупу: кешбэк и лимиты активных заказов — гайдбук 1.3.1 (подписки), штрафы — 1.3.2 / BR1.3-10, баллы — 8.4.2 (Настройки балльной системы) / 2.7.3 (Скидки баллами). Закрываю сам: «Не входит → 1.3.1, 1.3.2, 8.4.2 / 2.7.3». Если баллы физически хранятся на карточке — максимум одна строка в технических данных со ссылкой на 8.4.2, правила не дублировать. | Доработка кода не требуется. Баллы, кешбэк, лимиты и штрафы не нужно подробно описывать в разделе 1.3 как отдельную логику карточки клиента. Эти правила относятся к смежным разделам: подписки и лимиты — к 1.3.1, штрафы — к 1.3.2, баллы и кешбэк — к разделам про балльную систему и скидки. В 1.3 можно оставить только краткое упоминание, что такие данные могут отображаться на карточке клиента из связанных разделов. |
| #OQ1.3-19 | Код вне BRD | Что нашли: на карточке есть скрытая стейт-машина заполненности профиля — флаг «профиль заполнен» и процент заполненности (0–100), защёлкивается при 100%. В требованиях 1.3 не описано. \ Client.cs:117-118,143-144; ClientAggregate.cs:298-307 | Бизнес (Герман) | Open | В гайдбуке 1.3 (и смежных 1.3.1 / 1.3.2) про признак заполненности профиля и процент ничего нет — дома находке не нашлось, подтвердить нечем. Решение бизнеса: это осознанное бизнес-правило (напр. для онбординга / фронта) — тогда завести требование (в 1.3 или в разделе профиля фронта); или это внутренняя техническая деталь — тогда сознательно не описывать. Не додумываю за гайдбук. | |
| #OQ1.3-20 | Код вне BRD | Что нашли: при создании/обновлении карточки проверяется, что дата рождения не в будущем. В требованиях 1.3 инвариант не описан. \ AdditionalClientInfo.cs:13-16 | Разработка | Закрывает PM | Безобидный инвариант на поле карточки (дата рождения — поле 1.3 по гайдбуку), продуктового выбора нет. Закрываю сам: зафиксировать как техническую валидацию — комментарием к BR1.3-2 или отдельным техническим требованием. Тикета на код не требуется (уже работает), только документирование. | Доработка кода не требуется. Проверка даты рождения уже реализована: дата рождения клиента не может быть в будущем. Нужно зафиксировать это в BRD как техническую валидацию поля «Дата рождения» в составе персональных данных карточки клиента. |
| #OQ1.3-21 | Код вне BRD | Что нашли: в коде есть операции над карточкой, не описанные в составе 1.3: архивация/восстановление (мягкое удаление), привязка аккаунта к существующей карточке, бан/разбан в рамках зоны, избранные комнаты, ресинк скидок. \ ArchiveClientCommand.cs:7; AttachAccountToClientCommand.cs:8; ChangeClientBanStatusCommand.cs:11; AddRoomToFavouriteCommand.cs:13; ResyncClientDiscountsCommand.cs:9 | Бизнес (Герман) | Open | Часть операций уже имеет дом: бан/разбан — BR1.3-10 и гайдбук 1.3.2 (Блокировки), избранное — технические данные BR1.3-9. Не описаны нигде: архивация/восстановление, привязка аккаунта, ресинк скидок. Решение бизнеса: какие из неописанных операций внести в scope 1.3 требованиями (создание/архивация/восстановление ожидаются методологией Back в разделе операций), какие сознательно оставить вне. Гайдбук 1.3 про эти операции молчит. | |
| #OQ1.3-22 | Код вне BRD | Что нашли: сервисные признаки клиента сверх «сфер» — должности, уровни навыка, музыкальные жанры, инструменты, танцевальные стили. Помечено Владом как «сверх BRD». \ ClientServicesTypesEnum.cs:11-31; GetClientInfoByAccountIdResponse.cs:24-28 | Разработка | Закрывает PM | На деле это не «сверх BRD»: гайдбук 1.3 перечисляет их как состав Групп деятельности (уровень навыков, музыкальный инструмент, стиль танца, музыкальный жанр — см. 8.2.5). Закрываю сам: отнести к данным «Группы деятельности» (BR1.3-2), сослаться на 8.2.5; отдельным вопросом не является. «Должности» — сверить с 8.2.5, там же «виды деятельности». | Доработка кода не требуется. Должности, уровни навыка, музыкальные жанры, инструменты и танцевальные стили нужно относить к «Группам деятельности» в составе персональных данных карточки клиента. Это уже связано с BR1.3-2 и смежным разделом про группы деятельности, поэтому отдельное требование в 1.3 заводить не нужно. |
| #OQ1.3-23 | Код вне BRD | Что нашли: признак подтверждения email подтягивается в карточку из внешнего сервиса Identity на чтении. В составе 1.3 не описан. \ GetClientInfoByAccountIdResponse.cs:9; GetClientInfoByAccountIdHandler.cs:31,43 | Разработка | Закрывает PM | Подтверждение email — зона аккаунта/авторизации (1.1), карточка лишь отображает признак из Identity на чтении (как фото из Resources в OQ1.3-4). Закрываю сам: «Не входит → 1.1» либо одна строка «отображается из Identity» в технических данных; правила подтверждения email не дублировать. | Доработка кода не требуется. Признак подтверждения email не хранится и не изменяется в карточке клиента, а отображается из сервиса Identity при чтении карточки. Правила подтверждения email относятся к разделу аккаунтов/авторизации, поэтому в 1.3 достаточно указать, что этот признак отображается из внешнего сервиса. |
Подстраницы
- 1.3.1 Клиентская зона доступа
- 1.3.2 Характеристики клиента
- 1.3.3 Группы деятельности
- 1.3.4 Расширение клиентских прав доступа через подписки
Вопросы по сверке с кодом
BRD 1.3 v0.1 · booking-monorepo · commit 9e19870 / dev/cms-conflict-warning · 2026-06-30 · якорь src/services/booking.clients (+ кросс-проверка src/services/booking.authentication) Сводка: 18 вопросов (бизнесовых 9, программных 9); подтверждено без вопросов 0; отрезано находок обратного прохода 4
Бизнесовые
| № | Связано с | Что в BRD | Что в коде | Где в коде |
|---|---|---|---|---|
| Б1 | BR1.3-1 | Клиент присваивается аккаунту через создание и привязку Карточки клиента (связь аккаунт↔карточка) | Связь реализована как совпадение идентификаторов: при создании ID карточки берётся равным ID аккаунта (clientId = accountId ?? Guid.NewGuid(), далее AccountId = new AccountId(clientId)), то есть ClientId == AccountId. Карточка создаётся асинхронно по событию AccountCreatedEvent через consumer. Отдельной колонки account_id со строгой связью в базе нет — связь держится только на соглашении «ID равны». — нужно решение: считать ли «равенство ID» достаточной моделью связи 1:1 | ClientAggregate.cs:131,148; AccountCreatedClientConsumer.cs:46,76; Account.cs:85 |
| Б2 | BR1.3-2 | Имя и Телефон помечены как обязательные | В коде оба поля необязательные: first_name и phone_number допускают пустое значение, доменной проверки на обязательность нет (при сборке имя подставляется как пустая строка) | Client.cs:30-31,60-61; ClientMapping.cs:24 |
| Б3 | BR1.3-2 | Карточка хранит поля: Почтовый адрес, Публичное имя пользователя (латиница), О себе, Профиль в Instagram, Город | Этих полей в карточке нет ни как столбцов базы, ни в доменной модели (поиск по address/postal, public_name/username/login, about/bio, instagram, city — пусто). Из контактных ссылок есть только ВК и Telegram. — нужно решение: нужны ли эти поля карточке или часть из них исключается из состава | Client.cs:30-145 (поля отсутствуют) |
| Б4 | BR1.3-2 | Карточка хранит Фотографию | Столбца «фото» в карточке нет. Фотография и файлы подтягиваются на чтение из внешнего сервиса Resources по gRPC в момент запроса, в самой карточке не хранятся. — нужно решение: считать ли это «хранением в карточке» по смыслу BRD | ImageService.cs:17,27-30; GetClientInfoByAccountIdHandler.cs:28-41 |
| Б5 | BR1.3-3 | Все заказы должны привязываться к Карточке клиента за исключением заказов без статуса (Статус: PreReserv) | Привязка гарантирована не для всех заказов: у одиночного заказа client_id допускает пустое значение (необязательный столбец), а строго обязателен он только у групп заказов (processing group). То есть отдельный заказ может существовать без клиента | OrderAggregate.cs:122; OrderModelConfiguration.cs:41; ProcessingOrderGroup.cs:23,35 |
| Б6 | BR1.3-5 | Карточка может находиться только в допустимых состояниях: зарегистрированного / незарегистрированного пользователя | Явного состояния (поля или перечисления «зарегистрирован / не зарегистрирован») в коде нет. Косвенные признаки ненадёжны: ID аккаунта проставляется всегда (в т.ч. для карточек из виджета — там подставляется пустой GUID), а флаг AlreadyFilled отражает заполненность профиля, а не регистрацию. — нужно решение: моделировать ли состояние явно | ClientAggregate.cs:107,114,131,148,166; Client.cs:24-25,143-144 |
| Б7 | BR1.3-6 | Карточку зарегистрированного может менять только её владелец; карточку незарегистрированного — только партнёр или сотрудник партнёра | Никакого разграничения по состоянию карточки и роли вызывающего нет. ID аккаунта в команде обновления используется только чтобы записать «кем обновлено», сравнения с владельцем карточки нет. На шлюзе проверка бинарная — «должен быть авторизован», без ролей / владельца / партнёра. Фактически любой авторизованный может изменить любую карточку по её ID | UpdateClientCommandHandler.cs:39-44,83; ClientAggregate.cs:210-214; RpcAnonByRouteAuthorization.cs:48-57 |
| Б8 | BR1.3-7 | При создании или привязке карточки к аккаунту к ней привязывается Подписка с признаком «По умолчанию»; у зарегистрированной карточки всегда есть хотя бы один клиентский тариф | Признак «по умолчанию» (IsDefault) у тарифа есть, но он задаётся вручную при создании тарифа партнёром и относится к каталогу тарифов (у ClientTariff нет привязки к клиенту). Автоматической привязки тарифа или подписки при создании карточки нет — обработчик создания клиента и consumer регистрации тариф не привязывают (в сервисе авторизации на этот счёт стоит TODO-заглушка). Гарантии «хотя бы один тариф всегда привязан» в коде нет | ClientTariffAggregate.cs:13,64; CreateClientCommandHandler.cs:19-52; AccountCreatedClientConsumer.cs:93-131; RegistrationMobileEndCommandHandler.cs:122 |
| Б9 | BR1.3-10 | Данные по партнёрам заполняются каждым партнёром в рамках одной партнёрской зоны (скидки, штрафы, блокировка, условия оплаты, группы деятельности, сообщения) | Часть данных действительно привязана к партнёрской зоне (блокировка, штраф, условия оплаты — на ClientPart с PartnerZoneId; сообщения — с PartnerZoneId). Но скидки клиента и группы деятельности НЕ разрезаны по партнёрской зоне: в их моделях нет поля партнёрской зоны, они хранятся на уровне клиента целиком. — нужно решение: должны ли скидки и группы деятельности быть в рамках зоны | ClientPartAggregate.cs:13,15-17; ClientMessageAggregate.cs:11; ClientDiscount.cs (нет PartnerZoneId); ClientServiceGroupEntity.cs (нет PartnerZoneId) |
Рекомендация / варианты решения
- Связь аккаунт↔карточка 1:1 (Б1). Вариант А (рекоменд.): зафиксировать в BRD, что связь реализована равенством идентификаторов (ClientId == AccountId), и добавить требование на защиту инварианта «один аккаунт — одна карточка» в базе или в процессе; сейчас он держится только на соглашении и на pre-check при регистрации. Вариант Б: оставить как есть, явно отметив отсутствие строгой связи в базе как осознанный компромисс. Нужна ли гарантия на уровне базы — решает бизнес / архитектура.
- Обязательность Имени и Телефона (Б2). Вариант А (рекоменд.): привести код к BRD — добавить проверку обязательности при создании и обновлении, иначе требование декларативно. Вариант Б: привести BRD к коду — признать оба поля необязательными (например, при создании из виджета телефон может быть единственным контактом, а имя — отсутствовать). Согласовать с продуктом, какой минимальный набор обязателен в каждом сценарии создания.
- Состав персональных полей: адрес, публичное имя, о себе, Instagram, город, фото (Б3, Б4). Вариант А: привести код к BRD — завести недостающие поля и решить, хранить ли фото в карточке или продолжать брать из Resources. Вариант Б (рекоменд.): привести BRD к коду — оставить фактический состав (ФИО, дата рождения, пол, email, телефон, ВК, Telegram + фото из Resources), а недостающие поля вынести в явный список «планируется / не реализовано». По существу это продуктовое решение о составе карточки.
- Привязка всех заказов к клиенту (Б5). Вариант А (рекоменд.): привести код к BRD — сделать
client_idобязательным и для одиночных заказов (как уже сделано для групп). Вариант Б: уточнить в BRD, что заказ без карточки клиента допустим (напр. служебные / гостевые заказы), и описать эти случаи. Зависит от того, бывают ли легитимные заказы без клиента. - Состояние карточки «зарегистрированный / незарегистрированный» (Б6) и право изменения по состоянию (Б7). Общая первопричина — состояние карточки в домене не выражено, поэтому и правило доступа по состоянию проверить нечем. Вариант А (рекоменд.): привести код к BRD — ввести явное состояние карточки и на его основе разграничить право изменения (владелец vs партнёр / сотрудник). Вариант Б: привести BRD к коду — если разграничение доступа по правилам BRD на самом деле обеспечивается выше (на шлюзе / в личных кабинетах), описать это как внешний механизм и снять требование с этого сервиса; но сейчас такого разграничения не найдено нигде. Это ключевое продуктовое и архитектурное решение, разблокирует Б6/Б7.
- Подписка «по умолчанию» при создании карточки (Б8). Вариант А (рекоменд.): привести код к BRD — реализовать автопривязку тарифа-подписки с признаком «по умолчанию» при создании или привязке карточки (сейчас стоит TODO-заглушка). Вариант Б: привести BRD к коду — если «подписка по умолчанию» относится к разделу 1.3.1 и здесь лишь упоминается, перенести требование туда и убрать из карточки. Решает продукт совместно с разделом 1.3.1.
- Партнёрское разрезание скидок и групп деятельности (Б9). Вариант А: привести код к BRD — добавить партнёрскую зону в модель скидок и групп деятельности. Вариант Б (рекоменд.): уточнить BRD — если скидки и группы деятельности по замыслу общеклиентские (а к зоне привязаны только блокировка, штрафы, оплата, сообщения), скорректировать формулировку «в рамках одной партнёрской зоны» для этих двух пунктов. Согласовать с продуктом фактическую модель видимости.
Программные
| № | Связано с | Что в BRD | Что в коде | Где в коде |
|---|---|---|---|---|
| П1 | BR1.3-4 | Карточка может быть создана при бронировании в виджет без регистрации | Сценарий «создание из виджета без регистрации» реализован, но как отдельный вызываемый метод API (CreateClientFromWidgetCommand, источник фиксируется как Widget, ID аккаунта — пустой GUID). При этом ни один обработчик событий заказа карточку не создаёт (consumer закрытия / отмены заказа выходит, если клиента нет). То есть «при бронировании» зависит от того, вызовет ли этот метод сторона виджета — внутри booking.clients такой триггер не найден | CreateClientFromWidgetCommandHandler.cs:36-50; OrderClosedClientConsumer.cs:41-45 |
| П2 | BR1.3-4 | Способ создания определяет состояние Карточки клиента | Способ создания фиксируется как SourceId (Web / Widget / партнёрский Web), но никакого «состояния карточки» из него не выводится — поля состояния нет (см. Б6). Связь «способ → состояние» в коде не реализована | EventSourceMapper.cs:14-25; ClientAggregate.cs (нет поля состояния) |
| П3 | BR1.3-8 | Телефон и почтовый адрес после завершения регистрации редактируются только через аккаунт | Ограничения нет: обновление карточки безусловно перезаписывает телефон и email независимо от состояния регистрации; почтового адреса в модели нет вовсе. Признака «после регистрации» в логике редактирования не существует | ClientAggregate.cs:204-205; UpdateClientCommandHandler.cs:83 |
| П4 | BR1.3-8 | Публичное имя пользователя до регистрации недоступно, после регистрации в него переносится значение логина | Поля «публичное имя пользователя» в карточке нет, переноса логина после регистрации тоже нет (поиск по publicname / login / username — пусто). Правило не реализовано | (поле и логика отсутствуют; ClientAggregate.cs, Client.cs) |
| П5 | BR1.3-9 | Технические данные карточки заполняются автоматически. Состав: кем создано, аккаунт, уведомления, подписки, автопродление тарифа, сферы, заказы, платёжные документы, избранное, сохранённые карты, данные об устройстве | Часть состава отсутствует: «уведомления», «сохранённые карты», «данные об устройстве» в сервисе карточки не хранятся (поиск по device, saved_card, notification_settings — пусто). «Заказы» и «платёжные документы» живут в других сервисах и попадают в карточку лишь как производные (счётчик заказов, события). Подписка / тариф на основном методе карточки сейчас отдаётся как null (TODO) | Client.cs:30-145; GetClientInfoByAccountIdResponse.cs:31; GetClientInfoByAccountIdHandler.cs:45 |
| П6 | BR1.3-9 | Технические данные: кем создано, аккаунт, автопродление тарифа, сферы, избранное | Эта часть подтверждается: «кем создано» (created_by), «аккаунт» (account_id), автопродление (AutoRenewal / IsAutoRenewal), сферы (через client_services, тип SphereActivity), избранное (favorite_rooms) — присутствуют. Расхождение только в неполноте состава (см. П5), сами эти поля заполняются | Client.cs:24,90; ClientTariffAggregate.cs:23; ClientServicesTypesEnum.cs:36; ClientAggregate.cs:68-69 |
| П7 | BR1.3-11 | Сообщения хранят ограничение доступа на просмотр. Допустимые значения: только я, сотрудники, все | В коде перечисление содержит ЧЕТЫРЕ значения, а не три: EmployeesAndMe=0, OnlyMe=1, OnlyService=2, OtherPartners=3. Сопоставление с BRD приблизительное: «сотрудники» ≈ EmployeesAndMe (включает автора и ограничено партнёрской зоной), «все» ≈ OtherPartners; чистого значения «все» нет, а значение OnlyService в BRD не описано | ClientMessageAdmissionEnum.cs:5-8 |
| П8 | BR1.3-11 | Ограничение доступа должно соблюдаться (значение «только я / сотрудники / все» определяет видимость) | Фильтрация на чтении реально применяется на стороне сервера, НО обрабатывает только 3 из 4 значений: OtherPartners (видно всем), EmployeesAndMe + совпадение партнёрской зоны, OnlyMe + совпадение автора. Значение OnlyService=2 не покрыто ни одной веткой — такие сообщения не вернутся никогда (тихо невидимы). «Только я» = только автор-сотрудник (CreatedBy), а не клиент | ClientMessagesReadRepository.cs:25-30; GetClientMessagesHandler.cs:29-33 |
| П9 | BR1.3-11 | Ограничение доступа на ПРОСМОТР сообщений | Ограничение применяется только на чтение. На запись (редактирование / удаление / архивацию сообщения) проверки прав нет — любой авторизованный может изменить или удалить любое сообщение по его ID независимо от значения ограничения. BRD прямо про запись не говорит, но это смежный пробел в той же механике | UpdateClientMessageHandler.cs:22-27; ArchiveClientMessageHandler.cs; DeleteClientMessageHandler.cs |
Рекомендация / варианты решения
- Триггер создания карточки из виджета «при бронировании» (П1). Вариант А (рекоменд.): уточнить BRD / контракт — явно зафиксировать, что карточка из виджета создаётся отдельным вызовом стороны виджета, а не как следствие события заказа; описать, кто и когда его вызывает. Вариант Б: привести код к BRD — создавать карточку в обработчике события бронирования. Зависит от того, где в архитектуре живёт виджет-флоу.
- Связь «способ создания → состояние карточки» (П2). Завязано на отсутствие поля состояния (см. рекомендацию по Б6/Б7). Отдельного программного решения не требует: появится состояние —
SourceIdможно в него отображать. Пока — описать в BRD, чтоSourceIdфиксирует канал, но состояние из него не выводится. - Гейтинг телефона / адреса и перенос логина в публичное имя (П3, П4). Общая первопричина — нет понятия «после регистрации» и нет полей публичного имени и адреса. Вариант А (рекоменд.): привести код к BRD — реализовать поля и правила (после регистрации телефон / адрес правятся только через аккаунт; публичное имя = логин). Вариант Б: привести BRD к коду — если редактирование контактов через аккаунт обеспечивается разделом 1.1, перенести правило туда; пункт про публичное имя снять или перенести, раз поля нет. Решение продуктовое, затем реализация.
- Полнота состава технических данных (П5, П6). Вариант А: привести код к BRD — добавить недостающее (уведомления / устройство / сохранённые карты или ссылки на них) и снять TODO с подписки на методе карточки. Вариант Б (рекоменд.): уточнить BRD — для данных из других сервисов (заказы, платёжные документы, сохранённые карты, устройство) описать их как «отображается из сервиса X», а не «хранится в карточке»; перечислить, что заполняется фактически (П6) и что отдаётся как
null. Согласовать ожидаемый состав с продуктом. - Модель значений ограничения доступа к сообщениям (П7, П8). Общая первопричина — перечисление из 4 значений не совпадает с тремя из BRD, и одно значение «мертво» на чтении. Вариант А (рекоменд.): привести код к BRD — свести к трём значениям (только я / сотрудники / все), убрать или задействовать
OnlyService, добавив для него ветку в фильтр чтения, чтобы не было тихо невидимых сообщений. Вариант Б: привести BRD к коду — задокументировать все четыре значения и их семантику (включая «только этот сервис» и «другие партнёры»), уточнить, что «сотрудники» ограничены партнёрской зоной. В любом варианте обязательно закрыть дыру с непокрытымOnlyService(иначе данные теряются на чтении). - Отсутствие проверки прав на запись сообщений (П9). Вариант А (рекоменд.): привести код к BRD по духу — добавить проверку прав на редактирование / удаление / архивацию сообщения (автор или сотрудник зоны), симметрично чтению. Вариант Б: оставить как есть и явно отметить в BRD, что ограничение распространяется только на просмотр. Так как речь о приватных заметках партнёров о клиенте, рекомендована защита записи.
Приложение. Находки обратного прохода (код сверх BRD). Ниже — поведение и данные, найденные в коде, но не упомянутые в BRD 1.3. Показаны как кандидаты на требования (бизнес-значимые); мелкий плумбинг отрезан. Отрезано находок: 4 (служебные: предвычисленный столбец полнотекстового поиска
search_column; неиспользуемый в доступеSourceId; инфраструктурные настройки кэша; внутренний расчётFillFactorдублируется двумя формулами).
| № | Связано с | Что в коде (нет в BRD) | Где в коде | Куда отнести |
|---|---|---|---|---|
| Д1 | вне BRD | Баллы лояльности клиента (Points) и целая подсистема баллов / кешбэка / лимитов / штрафов на карточке клиента | Client.cs:108-109; ClientAggregate.cs:109,289 | бизнес-правило |
| Д2 | вне BRD | Признак «профиль заполнен» (AlreadyFilled) и процент заполненности (FillFactor, 0–100) — латентная стейт-машина профиля, защёлкивается при 100% | Client.cs:117-118,143-144; ClientAggregate.cs:298-307 | бизнес-правило |
| Д3 | вне BRD | Проверка «дата рождения не в будущем» при создании / обновлении карточки | AdditionalClientInfo.cs:13-16 | программное (инвариант) |
| Д4 | вне BRD | Архивация / восстановление карточки (мягкое удаление), привязка аккаунта к существующей карточке (AttachAccount), бан / разбан в рамках зоны, избранные комнаты, ресинк скидок — операции есть, в составе раздела не описаны | ArchiveClientCommand.cs:7; AttachAccountToClientCommand.cs:8; ChangeClientBanStatusCommand.cs:11; AddRoomToFavouriteCommand.cs:13; ResyncClientDiscountsCommand.cs:9 | программное |
| Д5 | вне BRD | Сервисные признаки клиента сверх «сфер»: должности, уровни навыка, музыкальные жанры, инструменты, танцевальные стили (типы 1–5) | ClientServicesTypesEnum.cs:11-31; GetClientInfoByAccountIdResponse.cs:24-28 | бизнес-правило |
| Д6 | вне BRD | Признак подтверждения email (EmailVerified) подтягивается в карточку из внешнего сервиса Identity на чтении | GetClientInfoByAccountIdResponse.cs:9; GetClientInfoByAccountIdHandler.cs:31,43 | программное |