Модель данных
Промо-баннер — одна запись с содержимым, правилами доступности и журналом показов.
Обязательны только заголовок и описание — всё остальное имеет значение по умолчанию или может быть пустым. Порядок сортировки у баннеров не задан.
Журнал показов и чёрный список живут внутри записи баннера, а не в данных компании. Это значит, что действия сотрудников разных компаний (отметки о прочтении) пишутся в одну и ту же строку одной общей таблицы.
Что уходит в интерфейс
Наружу отдаётся только содержательная часть баннера: идентификатор, заголовок, описание, промокод, иконка, ссылка, изображение и анимация. Периодичность показа, журнал показов, чёрный список компаний и флаг активности остаются внутренними — интерфейс их не видит и не может самостоятельно решить, пора ли показывать баннер. Вся логика «показывать или нет» находится на стороне сервера.Логика выбора баннера
Запрос за баннером доступен только авторизованному пользователю; кроме того, общий контур доступа пропускает к этому разделу лишь сотрудника выбранной компании (либо сотрудника платформы). Сервер берёт две координаты — текущую компанию и текущего пользователя — и подбирает один баннер.Шаги подбора
- Отбираются все включённые баннеры.
- Из них исключаются те, в чей чёрный список входит текущая компания.
- Оставшиеся перебираются по очереди. Для каждого сервер смотрит в журнал показов: сначала находит раздел текущей компании, внутри него — отметку по текущему пользователю.
- Отметки нет — баннер этому человеку в этой компании ещё не показывали, он и возвращается, перебор прекращается.
- Отметка есть — сравнивается, сколько времени прошло с последнего показа. Если прошло не меньше, чем указано в периодичности (в часах), баннер возвращается. Если меньше — сервер переходит к следующему баннеру, а не прекращает поиск.
- Отметку не удалось разобрать — если сохранённое время записано строкой в неожиданном формате или без часового пояса, баннер считается непоказанным и возвращается.
- Если ни один баннер не подошёл, ответ пустой — со статусом «нет содержимого», без тела.
Сравнение идёт по правилу «прошло не меньше заданной периодичности». При периодичности 24 часа баннер повторно доступен ровно через сутки после последнего отмеченного показа. Периодичность 0 (или отрицательная) означает, что баннер подходит всегда, при каждом запросе — нижней границы у этого значения нет.
Что означает «первый подходящий»
Перебор идёт в том порядке, в котором записи отдаёт база: явная сортировка не задана ни в описании данных, ни в запросе. Пока активен один баннер, это не имеет значения. Как только активных баннеров несколько и человек подходит под условия сразу нескольких, предсказать, какой из них покажется, нельзя. Практический способ управлять очерёдностью — держать включённым один баннер за раз.Отметка о прочтении
Сама выдача баннера ничего не записывает. Журнал пополняется только отдельным вызовом, который интерфейс делает по номеру баннера — обычно в момент, когда баннер реально показан пользователю или закрыт им. Что происходит при этом вызове:- Баннер ищется по номеру. Если такого нет — ответ «не найдено».
- В журнале берётся (или создаётся) раздел текущей компании.
- В нём по ключу текущего пользователя записывается текущее время.
- Запись баннера сохраняется целиком.
Отметка не проверяет ни активность баннера, ни чёрный список — она принимает любой существующий номер. Отметить «прочитанным» можно и выключенный баннер, и тот, который данной компании вообще не показывается.
Разделение по компаниям и пользователям
Ключ в журнале двойной: сначала компания, затем пользователь. Отсюда несколько следствий, которые обычно вызывают вопросы:- Один и тот же сотрудник, работающий в двух компаниях, увидит баннер дважды — по разу в каждой компании, и отметки будут независимыми.
- Чёрный список исключает компанию целиком. Скрыть баннер от конкретного человека, не скрывая от его коллег, нельзя.
- Записи в журнале не удаляются: ни ручной очистки, ни фоновой уборки не предусмотрено. Со временем журнал накапливает по одной отметке на каждую пару «компания — пользователь», которой баннер когда-либо показывали.
- Чтобы показать баннер заново всем, недостаточно поменять его содержимое: нужно либо очистить журнал вручную, либо завести новый баннер.
Управление в административной панели
Баннеры создаются и отключаются на отдельной странице платформенной админки.- Список показывает заголовок и признак активности.
- Поиск работает по заголовку, описанию, промокоду и ссылке.
- Фильтр — по признаку активности.
Как это используется
Типовой сценарий работы интерфейса:- При входе в рабочее пространство фронтенд запрашивает баннер.
- Если ответ пустой — ничего не показывается.
- Если баннер пришёл — он отрисовывается по полученным полям: заголовок, описание, картинка или анимация, иконка, промокод и ссылка перехода.
- Сразу после показа (или при закрытии) интерфейс вызывает отметку о прочтении с номером этого баннера — иначе баннер вернётся снова.
Подводные камни
- Отметка о прочтении принимает любой существующий номер баннера: ни активность, ни чёрный список компании при этом не проверяются, а тело запроса не читается и не валидируется.
- Если сохранённое время последнего показа записано строкой в неразборчивом формате или без часового пояса, баннер считается непоказанным и выдаётся снова — такая ошибка в журнале приводит к бесконечному показу, а не к его прекращению.
- Если журнал испорчен грубее — вместо строки со временем записано число либо раздел компании перестал быть структурой «ключ-значение», — запрос за баннером завершится ошибкой сервера, а не мягким пропуском записи.
- Периодичность показа не ограничена снизу: значение 0 или отрицательное означает, что баннер подходит при каждом запросе.
- Чёрный список исключает компанию целиком; скрыть баннер от отдельного пользователя внутри компании невозможно.
- Изображение и анимация складываются в одну и ту же папку файлового хранилища, причём анимация загружается как произвольный файл без проверки того, что это картинка.
- Когда показывать нечего, ответ приходит со статусом «нет содержимого» и пустым телом, а не пустым объектом — интерфейс должен корректно обрабатывать этот статус.
- Журнал показов растёт бесконечно: отметки по каждой паре «компания — пользователь» никогда не удаляются и хранятся внутри самой записи баннера; ни фоновой уборки, ни отдельного инструмента очистки нет.
- Один и тот же человек, работающий в двух компаниях, получает баннер отдельно в каждой из них, потому что ключ журнала составной — сначала компания, затем пользователь.
- Наружу не отдаются периодичность, журнал показов, чёрный список и флаг активности, поэтому интерфейс не может самостоятельно решить, пора ли показывать баннер.
- Подбор баннера не кэшируется и на каждый запрос вычитывает включённые баннеры с их журналами, разбирая их в памяти приложения, а не в базе.
- В административной панели нет отдельных инструментов для чёрного списка и журнала показов: список содержит только заголовок и признак активности, фильтр — только по активности, а обе структуры правятся как обычные поля формы.
- Страница баннеров, в отличие от соседней страницы настроек таблиц, не ограничена дополнительно правами суперпользователя — редактировать баннеры может любой сотрудник платформы с обычными правами админки на эту запись.
- У промо-баннера, в отличие от остальных настроек, нет поля компании вовсе; у прочих записей раздела ссылка на компанию есть и может быть пустой — это означает общую платформенную заготовку.
Связанные страницы
Глоссарий: Промо-баннеры
Полный перечень полей баннера, журнала показов и правил подбора.
Настройки компании
Обзорная страница модуля: из чего состоят настройки компании и как они связаны между собой.
Реестр настроек компании
Полный перечень параметров компании: что можно включить или выключить, какие значения стоят по умолчанию и как настройки читаются и сохраняются.
Хранение и кэш настроек
Как значение настройки попадает в базу, как оно кэшируется по компаниям и почему изменение настройки сбрасывает кэш целиком.
Дополнительные поля
Собственные поля компании для клиентов, инвентаря, аренд и других справочников: типы, обязательность, отображение в таблице и фильтрах.
Переименование сущностей
Как компания меняет названия разделов и статусов под свою нишу, включая формы слова по падежам и числам.
Настройки таблиц
Сохранённый состав, порядок и ширина колонок для таблиц интерфейса — отдельно по каждой таблице компании.
Сквозная автонумерация
Общий счётчик компании, из которого берутся номера клиентов, артикулы создаваемых единиц инвентаря и номера документов.
Настройки в админ-панели
Служебный экран платформы для просмотра и правки настроек конкретной компании со сбросом значений к умолчанию.