# RFC по теггированию пользователей [TOC] ## Описание решаемой задачи Нужна возможность определить группу пользователей на основании произвольных критериев, чтобы выполнить с этими пользователями некое однотипоное действие. В нашей практике таких действий несколько: * сделать рассылку (или показать topline) по пользователям принадлежащим группе. Когда рассылка относится к конкретной предметной области (например, нацелена на агенства недвижимости), мы не хотим "спамить" клиентов занимающихся предпринимательской деятельностью в других разделах, и уж тем более всех наших пользователей. Примеры задач: * BZR-26014 – [Сделать рассылку о закрытии Фармастера через админские сообщения](https://jira.farpost.net/browse/BZR-26014) * BZR-25976 – [Сделать рассылку админских сообщений с опросом про Почту России](https://jira.farpost.net/browse/BZR-25976) * BZR-25553 – [Эксперимент: новый вариант письма о давно не обновлявшемся резюме](https://jira.farpost.net/browse/BZR-25553) * BZR-25258 – [Поменять текст рассылки пользователям контактирующим с наказуемым при блокировке за мошенничество](https://jira.farpost.net/browse/BZR-25258) * BZR-16106 – [Уведомлять пользователя о том, что деньги закончатся](https://jira.farpost.net/browse/BZR-16106) * BZR-24523 – [Изменить текст нотификации о давно не обновлявшемся резюме](https://jira.farpost.net/browse/BZR-24523) * при анализе поведения или проблем пользователей может понадобится ограничить домен анализа только пользователями относящимися к конкретной группе. Пример: * BZR-26432 – [Возможность выбирать фидбэки из базы по признаку Автор - продавец шин](https://jira.farpost.net/browse/BZR-26432) * показать промо фичи интересной для узкого круга пользователей: * BZR-28341 - [Показать промо для подключения HR мультикабинетов](https://jira.farpost.net/browse/BZR-28341). Показывать промо нужно только работодателям. В конкретной задаче работодатель — пользователю имеющий хотябы одну актуальную вакансию. * BZR-25169 - [Назначать диалоги и сделки на дочерние кабинеты в зависимости от прайса](https://jira.farpost.net/browse/BZR-25169). Промо фичи показывается пользователям у которых есть прайс и больше 10 новых диалогов по товарам из прайсов в сутки в среднем за последние 30 дней. * BZR-24134 - [Промо для многопользовательского режима](https://jira.farpost.net/browse/BZR-24134). Критерий аналогичен тому, что приведен выше + магазины на ЗС. ## Описание решения Фоновый сервис периодически строит *полное* представление всех групп пользователей и обновляет БД. В БД записана информация к каким группам какие пользователи относятся. Если при расчете состояния группы, пользователь отсутствует в списке, соответствующая пометка пользователя должна пропасть из БД. БД должна быть оптимизирована под эффективное обслуживание следующих сценариев: * проверить относится ли пользователь к конкретной группе. *Пример: мы рисуем страницу личного кабинета и хотим проверить относится ли пользователь к группе "Продавцы спецтехники" и нужно ли показывать уведомление об изменении цен в этом разделе*; * извлечь все идентификаторы пользователей с указанной пометкой. *Пример: мы хотим разослать письмо с "Call to Action" пользователям у которых есть резюме на сайте, но они его не обновляли в течении 3 месяцев.* ## Ограничения использования ### Отсутствие оперативности Подразумевается что состояние группы пересчитывается относительно редко: 1 раз в час или реже. Это ограничивает область применения задачами в которых приемлемо действовать на основании неоперативного состояния группы. Примеры задач, которые требуют оперативности, и их решение неуместно в рамках предлагаемой схемы: * у пользователя появилось новое сообщение в переписке. Мы хотим уведомить его об этом; * продавец пополнил счет. Мы хотим вернуть на платное размещение ранее снятые с публикации товары продавца; ### Требуется хранение отметки было ли действие выполнено для конкретного пользователя Если с группой выполняются периодические действия необходимо дополнительно реализовывать защиту от повторного выполнения операции. **Пример.** > Мы хотим стимулировать пользователей ищущих работу периодически обновлять информацию в собственных резюме. > > При наличии группы *пользователи, которые 3 месяца не обновляли свое резюме*, легко сделать периодическую рассылку по всей группе. Но скрипт рассылки должен отслеживать каким пользователям уже отправлены нотификации, чтобы не раздражать пользователей повторными сообщениями. Хранение подобного рода информации выходит за пределы предлагаемого решения. ### Тег не хранит никакой дополнительной информации о пользователе **Пример** > Если пользователь в течении дня просматривает более 10 предложений по аренде квартир в одном и том же доме (с одинаковым адресом), мы автоматически создаем за пользователя подписку на предложения по этому адресу. Этот пример труднореализуем в рамках предложенного подхода. При добавлении аккаунта в группу *пользователи просмотревшие 10+ предложений по одному адресу*, у нас нет возможности сохранить сам адрес, что затрудняет реализацию сценария. ## Возможности дальнейшего развития ### Отслеживание добавления пользователя в группу Возможно реализовать отслеживание добавления пользователя в группу, а также удаление из группы. Это требует хранения раунда на котором был создан тег (с технической точки зрения это может быть временная метка). Тогда после сохранения полного состояния группы в БД мы можем отследить какие пользователи были добавлены на текущем раунде (новые) и какие в текущем раунде отсутствуют (удаленные) В этом случае, тривиальных сценариях становится не актуально ограничение описанное в "**Периодические действия с группами требуют хранения дополнительной информации**". Так происходит потому что мы можем организовывать отсылку не периодически, а только только при добавлении пользователя в группу. ### Оперативное добавление пользователя в группу Технически возможно сделать API для оперативного добавления пользователя в группу (например, в ответ на событие). Это в свою очередь позволяет не писать код вычисляющий полное состояние группы и наполнять группу пользователями событийно. :::warning **Риск** Состояние группы в этом случае становится не воспроизводимо. Отсутствует универсальный способ привести группу в согласованное состояние после изменения ее инварианта (например, из за ошибки). ::: ## Тезарус Группа : множество пользователей объединенных по общему критерию (инварианту). Предполагается что целевое дейстие, для которого мы создаем группу (рассылка) должно быть выполнено для каждого пользователя группы. Термины *группа*, *пометка* и *тег* используются взаимозаменяемо. Инвариант (критерий) группы : условие при выполнении которого пользователь попадает в группу. Например группа "*пользователи давно не менявшие пароль*" может иметь инвариант "*авторизованный пользователь пользовавшийся сайтом хотя бы раз за последний месяц **И** последний раз менявший пароль более 3-х месяцев назад*". Раунд : очередное периодическое выполнение фонового сервиса, который перестраивает полное состояние групп