Роли, права и доступ по магазинам с полным аудитом
Доступы в AIERP построены на трёх связанных слоях. Базовый слой — промышленная система ролей и прав. Каждое право — отдельная запись с системным и человекочитаемым названием (например, «Топ товаров — просмотр»). Поверх плоского списка работают группы прав с полями «системное имя, отображаемое название, описание, категория, порядок, активна ли». Группы привязываются к ролям или напрямую к пользователям; выдача группы роли даёт роли все её права; отзыв группы отзывает только те права, что не входят в другие группы этой же роли — права не теряются случайно. Параллельный слой — автоматический фильтр по магазинам: на любой выборке система прозрачно отсекает данные тех магазинов, к которым у пользователя нет доступа. Доступ к магазинам определяется объединением основного магазина пользователя и магазинов из карточки сотрудника. Специальное право для админа сети полностью отключает фильтрацию. Аудит действий — полный журнал с автором, событием и разбивкой изменений «было/стало».
Что получает бизнес от модуля
Промышленная система ролей и прав
В основе — зрелая, проверенная индустрией модель ролей и прав. У пользователя есть набор ролей; у роли — набор прав. Проверка «есть ли право» (например, «может смотреть отчёт по топу товаров») идёт без обращения к базе — список прав закэширован на запрос.
Иерархия прав через группы
Поверх плоского списка прав работают группы с полями «системное имя, отображаемое название, описание, категория, порядок, активна ли». Права привязываются к группам. На сводке права — не плоский список из 100+ строк, а структура «Заказы», «Финансы», «Отчёты» с подгруппами. Поддерживаются фильтры: только активные, по категории, по порядку.
Группы → роли → пользователи
Выдача группы роли добавляет связь и даёт роли все её права. Отзыв группы у роли отзывает связь и только те права, которых нет в других группах этой же роли. Выдача и отзыв прямо пользователю работают аналогично. Никаких «случайно потерял право».
Доступные магазины пользователя
У пользователя два источника доступа: основной магазин и магазины из карточки сотрудника. Система объединяет оба списка, убирает дубли. Если у пользователя есть право обхода — возвращается пустой список как признак «доступ ко всем магазинам». Этот список используется автоматическим фильтром по магазинам.
Право обхода ограничений
Если у пользователя есть специальное право, фильтрация по магазинам отключается — директор сети видит всё. Если права нет — применяется фильтр по доступным магазинам. Одно право переключает режим «свой магазин vs все».
Автоматический фильтр по магазинам
Подключается к моделям с настраиваемой колонкой магазина (по умолчанию «магазин», у финансов — переопределена). На любой выборке прозрачно отсекает данные магазинов вне доступа. Если у пользователя нет доступных магазинов — выборка возвращает пустой результат. Если у модели несколько колонок магазина (заказы — магазин клиента и магазин получателя), фильтрация раскладывается по всем.
10 операций над группами прав
Связь пользователя с группами, выдача одной группы, выдача нескольких, отзыв одной, отзыв нескольких, синхронизация (применить разницу), проверки «есть ли группа», «есть ли хотя бы одна», «есть ли все», получение плоского списка всех прав через все группы. Каждая операция принимает группу объектом, по идентификатору или по имени.
Кэширование прав
Список прав пользователя загружается один раз за запрос, проверки идут по памяти. При изменении ролей или прав кэш сбрасывается. Если хранилище кэша не поддерживает теги — сбрасывается целиком.
Журнал действий и аудит
Каждое изменение фиксируется в журнале действий: кто, какой объект, какое событие (создание/обновление/удаление/восстановление), разбивка «было/стало», момент времени. У каждого пользователя есть его лента действий. Аудит основных сущностей включается одной строкой.
Что входит в Доступы
- 01
Роль с уникальным идентификатором
У роли есть имя и стабильный уникальный идентификатор, который генерируется при создании. Поддерживаются фильтры в списке ролей. Пользователи связаны с ролями через стандартную связку.
- 02
Право — системное и отображаемое название
Каждое право хранит системное название (например, «отчёт по топу товаров — просмотр», «финансы — создание», «заказ — обновление», «может видеть свою ЗП», «обход ограничений по магазинам») и человекочитаемое название для сводки. Защита маршрутов проверяет право по системному имени — без него доступ блокируется.
- 03
Группы прав
Поля: системное имя, отображаемое название, описание, категория (для группировки на сводке — например, «Управление», «Магазин», «Финансы»), порядок (сортировка внутри категории), активна ли, даты. Связи многие-ко-многим с правами, ролями, пользователями.
- 04
Выдача группы роли
Шаги: если связи ещё нет — создать; собрать имена всех прав группы; выдать роли права пакетом. Полностью идемпотентно — повторный вызов не дублирует и не удаляет существующие права.
- 05
Отзыв группы у роли
Шаги: убрать связь группы и роли; собрать имена прав этой группы; собрать имена прав из ДРУГИХ групп этой же роли; вычислить разницу — права для отзыва (не используются другими группами); отозвать пакетом. Безопасно — если право входит в несколько групп, оно остаётся при отзыве одной из них.
- 06
Выдача и отзыв напрямую пользователю
Аналогичные операции для прямой выдачи группы пользователю (минуя роль). Связь хранится в отдельной таблице. Используется для редких исключений: «этому конкретному сотруднику нужны дополнительные права, не вкладываясь в новую роль». Выдача и отзыв прав напрямую пользователю работают так же, как на роли.
- 07
Прокатить обновлённый состав группы
Массовое применение прав группы ко всем ролям и пользователям, привязанным к ней. Полезно после изменения состава прав в группе — например, добавили новое право «отчёт по складу» в группу «Менеджер по закупкам», запустили обновление, все 5 менеджеров и роль «Закупщик» получили право.
- 08
Подключение к пользователю и роли
Один и тот же набор операций над группами прав подключается и к пользователю, и к роли. Связи хранятся в соответствующих таблицах, выбор автоматический. 10 операций: выдать / отозвать / синхронизировать / проверить наличие / получить плоский список прав. Каждая операция принимает группу объектом, по идентификатору или по имени.
- 09
Синхронизация групп прав
Аналог обычной синхронизации ролей, но для групп прав. Получает массив групп (объекты, идентификаторы или имена), разворачивает каждую. Вычисляет разницу: какие группы убрать (есть сейчас, нет в новом списке) и какие добавить (есть в новом, нет сейчас). Удаляет старые, добавляет новые. Идемпотентно.
- 10
Доступные магазины пользователя
Возвращает список идентификаторов магазинов. Начинает с основного магазина пользователя. Если карточка сотрудника уже подгружена — добавляет привязанные к ней магазины. Иначе подгружает их отдельным запросом. Убирает дубли. Если результат не пустой — возвращает его. Если пустой и есть право обхода — возвращает пустой список как признак «доступ ко всему». Иначе — пустой список без доступа.
- 11
Проверка доступа к магазину и режима
Проверка доступа к конкретному магазину: сначала смотрит право обхода — если есть, доступ есть. Иначе проверяет, входит ли магазин в список доступных. Признак «нужно ли вообще фильтровать»: проверка отсутствия права обхода. Это два разных вопроса: «должны ли мы фильтровать вообще» и «может ли этот пользователь видеть этот конкретный магазин».
- 12
Право обхода ограничений по магазинам
Специальное право, отключающее фильтрацию по магазинам. Назначается ролям «Директор сети», «Финансовый директор УК», «Системный администратор». Пользователь с этим правом видит данные всех магазинов и юрлиц без явного перечисления. При отзыве этого права автоматически включается фильтрация по доступным магазинам.
- 13
Автоматический фильтр по доступным магазинам
Шаги: 1) взять текущего пользователя, 2) если не авторизован — пустой результат, 3) если у пользователя не определены доступные магазины — пропустить фильтр (модель не предполагает фильтрацию по магазинам), 4) если есть право обхода — пропустить (полный доступ), 5) получить список доступных магазинов, если пусто — пустой результат, 6) иначе фильтр «магазин в списке доступных».
- 14
Фильтр по запрошенным магазинам с пересечением
Принимает явный список магазинов от запроса (например, фильтр на сводке «показать только эти 3 магазина») и пересекает с доступными пользователю. Шаги: 1) если есть право обхода — применить только переданный список, 2) иначе пересечь с доступными, 3) если пересечение пусто — пустой результат, 4) иначе фильтр по пересечению. Защита от обхода через параметр запроса.
- 15
Переопределение в многоколоночных моделях
У заказа две колонки магазина (где оформлен и где получают), у финансовой операции три (где учитывается, через какую кассу, кто согласовал). Модель переопределяет фильтр: вместо одного условия — несколько по каждой колонке через «или». Любая запись, где у пользователя есть доступ хотя бы к одной из этих точек, видна.
- 16
Набор операций над ролями
Проверки «есть ли роль», «есть ли хотя бы одна», «есть ли все», присвоение, снятие, синхронизация ролей. Проверки прав, выдача, отзыв, синхронизация прав. Списки прямых прав, прав через роли, всех прав суммарно. Покрывает 95% сценариев напрямую. Дополнительно группы прав дают удобное группирование для сводки.
- 17
Журнал действий
Каждая запись журнала: имя журнала, описание, объект (любая сущность системы), автор (пользователь), разбивка «было/стало» по изменённым полям, идентификатор пакета изменений (для группировки изменений в одной транзакции), момент времени. У каждого пользователя есть его лента действий. На моделях аудит включается одной строкой с настройкой, какие поля логировать.
- 18
Базовый наблюдатель аудита
Базовый компонент, наследуется конкретными по каждой основной сущности. На события «создано / обновлено / удалено / восстановлено» пишет запись в журнал с автором (текущий пользователь), объектом (сама сущность), разбивкой по изменённым полям. Полный аудит без явного кода на каждой модели — подключил и забыл.
- 19
Управление ролями
Список с фильтрами, создание, просмотр, обновление, клонирование роли со всеми правами (удобно для «такая же, как X, но с одной правкой»), удаление. Права роли управляются через смежные операции управления правами.
- 20
Управление правами
Список, создание, просмотр, обновление, удаление прав. Отдельная операция массового присвоения ролей пользователю. На сводке — список с группировкой по категориям, флажками и поиском.
Как это выглядит в системе
Частые вопросы
Это собственная модель ролей или готовый продукт?
В основе — промышленная, проверенная индустрией система ролей и прав. Поверх добавлен слой групп прав для группировки по категориям и удобной выдачи на сводке. Автоматический фильтр по магазинам — собственный механизм. Журнал действий — отдельный промышленный пакет.
Что такое группа прав?
Сущность поверх стандартного списка прав. Поля: системное имя, отображаемое название, описание, категория (для группировки на сводке — «Заказы», «Финансы», «Отчёты»), порядок (сортировка внутри категории), активна ли. Связи многие-ко-многим: с правами, с ролями, с пользователями. Поддерживаются фильтры «только активные», «по категории», «по порядку».
Зачем нужны группы прав, если есть роли?
Роль — это «должность» (Менеджер, Закупщик, Директор). Группа прав — это «набор связанных прав» (например, «Управление заказами» = просмотр, создание, обновление, удаление заказов). На одну роль можно повесить несколько групп. При добавлении нового права в группу — оно автоматически появляется у всех ролей с этой группой через синхронизацию. Это удобнее, чем перебирать роли вручную.
Что делает выдача группы роли?
Шаги: 1) если связи группы с ролью ещё нет — создать её, 2) собрать имена всех прав группы, 3) выдать роли права пакетом. Связи прав и ролей сохраняются в стандартных таблицах. Идемпотентно — повторный вызов не дублирует.
А если право в нескольких группах?
Отзыв группы у роли аккуратно отзывает только те права из этой группы, которых нет в других группах этой же роли. Шаги: 1) убрать связь группы и роли, 2) собрать имена прав этой группы, 3) собрать имена прав из ДРУГИХ групп этой роли, 4) вычислить разницу — права для отзыва, 5) отозвать пакетом. Право не теряется, если оно входит в другую группу роли.
Что такое автоматический фильтр по магазинам?
Собственный механизм, который подключается к моделям с настраиваемой колонкой магазина (по умолчанию «магазин»). Даёт две операции: автоматический фильтр по доступным пользователю магазинам и фильтр по явному списку с пересечением с доступными. Без него — нужно вручную писать условие «магазин в списке» во всех контроллерах.
Как фильтр определяет доступные магазины?
Берёт у пользователя два источника: основной магазин (например, кассир привязан к одной точке) и магазины из карточки сотрудника (менеджер может быть приписан к нескольким). Объединяет, убирает дубли. Если есть право обхода — возвращает пустой список как признак «доступ ко всему».
Что такое признак ограничения?
Признак «нужно ли вообще фильтровать» — это отсутствие у пользователя права обхода. Для всех, у кого нет права обхода, ограничения применяются. Для админов сети и финансового директора УК с правом обхода ограничения отключаются. Автоматический фильтр проверяет этот признак перед применением.
Можно ли иметь несколько колонок с магазинами в одной модели?
Да. Например, заказ имеет «магазин клиента» и «магазин получателя». Финансовая операция имеет три: «магазин учёта», «магазин кассы», «магазин согласования». Модель переопределяет фильтр: вместо одного условия — несколько по каждой колонке через «или». Запись видна, если хотя бы одна колонка попадает в доступные магазины.
Что если у пользователя нет ни одного доступного магазина?
Список доступных магазинов пустой. Фильтр гарантированно возвращает пустой результат. Пользователь видит абсолютно пустые списки везде, где работает фильтр. Это безопасное поведение: при ошибочной настройке доступов пользователь не получает доступ к чужим данным.
Что такое фильтр по запрошенным магазинам?
Принимает явный список магазинов (например, из фильтра на сводке «показать только эти 3 магазина»). Шаги: 1) если есть право обхода — применить только переданный список, 2) иначе пересечь с доступными, 3) если пересечение пусто — пустой результат, 4) иначе фильтр по пересечению. Защищает от попытки увидеть «не свой» магазин через подмену параметра запроса — даже если попросил конкретный магазин, увидит только если есть доступ.
Какие операции есть над группами прав?
10 операций. Список связанных групп. Выдача одной группы. Выдача нескольких. Отзыв одной. Отзыв нескольких. Синхронизация (применить разницу). Проверки «есть ли группа», «есть ли хотя бы одна», «есть ли все». Получение плоского списка всех прав через все группы. Подключается одинаково к пользователю и к роли — таблица связей выбирается автоматически.
Что делает синхронизация групп прав?
Аналог обычной синхронизации ролей, но для групп прав. Принимает массив групп (объекты, идентификаторы или имена). Разворачивает каждую. Вычисляет разницу: какие группы убрать (есть сейчас, нет в новом списке) — отзывает; какие добавить (есть в новом, нет сейчас) — выдаёт. Идемпотентно: повторный вызов с тем же массивом ничего не меняет.
Можно ли дать пользователю права в обход роли?
Да. Те же операции над группами работают и на пользователе, и на роли. Выдача группы пользователю создаёт связь и выдаёт права напрямую. Это редкий сценарий «у этого конкретного сотрудника нужны дополнительные права без создания новой роли». Видимость — через списки прав через группы и прямых прав.
Как обновить набор прав в группе?
Группа умеет «прокатить» обновлённый список прав по всем ролям и пользователям, к которым она привязана. Полезно после изменения состава прав группы — например, добавили «отчёт по складу» в группу «Менеджер по закупкам», запустили обновление, все 5 менеджеров и роль «Закупщик» получили новое право автоматически.
Как именуются права?
Системное имя у каждого права короткое и стабильное — оно используется в защите маршрутов. Отображаемое имя — человекочитаемое, видно на сводке. Левая часть имени — модуль или сущность, правая — действие. Например: «отчёт по топу товаров — просмотр», «маржинальность — просмотр», «финансы — создание», «заказ — обновление», «фискализация платежа», «может видеть свою ЗП», «обход ограничений по магазинам».
Можно ли клонировать роль?
Да, есть отдельная операция дублирования. Создаёт новую роль с тем же набором прав и тем же списком групп. Удобно при создании «почти такой же роли»: «Менеджер B2B» = «Менеджер» + 2 дополнительных права. Дублируем, потом правим, не настраивая с нуля 20+ прав.
Где аудит изменений?
В журнале действий, который ведёт промышленный пакет. Каждая запись: имя журнала, описание, объект (любая сущность системы), автор (пользователь), разбивка «было/стало» по изменённым полям, идентификатор пакета изменений (для группировки изменений в одной транзакции), момент времени. У каждого пользователя есть его лента действий. Базовый наблюдатель пишет автоматически.
Что попадает в журнал?
Все ключевые сущности проекта (займы, документы, позиции, заказы, движения склада, товары, финансовые операции, платежи и т.д.) имеют свои наблюдатели, наследующие базовый. На каждое событие (создание / обновление / удаление / восстановление) пишется запись с разбивкой «было/стало». На карточке любого объекта — кнопка «История», открывает таймлайн всех изменений с автором и временем.
А двухфакторная авторизация и единый вход?
В текущей реализации нет встроенной двухфакторной аутентификации (одноразовые коды, СМС) и нет коннекторов единого входа (SAML, OIDC, AD/LDAP, Keycloak, Google Workspace). Эти функции реализуемы как новый функционал поверх существующей системы — отдельная разработка по запросу. Не обещаем фичу, которой нет.
Кэширование прав?
Список прав пользователя загружается один раз за запрос. Все проверки идут по памяти без обращения к базе. При изменении ролей или прав кэш сбрасывается. Это критично для производительности: в одном запросе может быть 20+ проверок прав.
Можно ли посмотреть все права роли?
У роли есть прямые права и права через группы. Один вызов даёт плоский список всех прав через все группы. Объединение с прямыми правами даёт полный список. На сводке карточки роли отображается дерево «Группы → права».
Как проверяются права в коде?
Несколькими равноценными способами: проверка роли по имени, проверка права по системному имени, защита маршрута требованием конкретного права, защита элементов на сводке. Все опираются на одни и те же данные и кэш — никаких ручных запросов в базу.
Что если поменяли роли пользователя — нужен ли перевход?
Нет. Права кэшируются на запрос, а не в сессии. После изменения ролей следующий запрос пользователя автоматически получит новые права. Можно даже принудительно сбросить кэш — пригодится при массовой правке ролей скриптом.
Что меняется на реальной сети
- Было
- У каждого юрлица свой набор магазинов. Кассир ТТ-7 «случайно» видел заказы и финансы ТТ-1, потому что в коде не было фильтра по доступным магазинам. Аудит ИБ нашёл утечку, требовалось закрыть быстро.
- Сделали
- Подключили автоматический фильтр по магазинам ко всем ключевым моделям с указанием колонки магазина. У пользователя список доступных магазинов объединяет основной магазин и магазины из карточки сотрудника. Фильтр отсекает чужие данные автоматически. Для админов сети дали право обхода — признак ограничения становится отрицательным, фильтр отключается.
- Стало
- Кассир ТТ-7 видит только свои заказы, финансы своей кассы, своих клиентов. Менеджер 3 точек видит только свои 3. Финдир УК с правом обхода видит всю сеть. Аудит ИБ закрыл найденное расхождение, утечки больше нет — защита на уровне выборки, а не контроллера.
- Было
- Менеджер по KPI вёл табличку «кому какие права», правил вручную через сводку после каждого изменения регламентов. На 12 ролей × 50 прав = 600+ галочек, ошибки находили постфактум: «продавец видит то, что не должен».
- Сделали
- Перешли с плоского списка прав на группы. Группы по категориям: «Заказы», «Финансы», «Отчёты», «Управление». В каждой группе — связанные права. На роль вешается набор групп, не отдельные права. Выдача группы массово назначает права; отзыв группы отзывает только те, что не входят в другие группы роли.
- Стало
- Управление правами стало понятным: 12 ролей × 6 групп = 72 галочки, не 600. Добавление нового права в группу автоматически разводит его по ролям через единое обновление. Менеджер по KPI разбирается в правах за минуты, не за полдня. Случайные «не те права» не появляются.
- Было
- У регионального директора 5 магазинов в его регионе, у его коллеги — другие 5. Основной магазин — это только тот, где сидит сам директор, но фактически он работает с 5 точками. Без поддержки связи «директор × несколько магазинов» приходилось дублировать аккаунты или давать право обхода (что слишком широко).
- Сделали
- Список доступных магазинов объединяет основной магазин и магазины из карточки сотрудника. У карточки сотрудника — список магазинов, к которым он приписан. Региональный директор приписан к 5 магазинам — получает их все. Автоматический фильтр на любой выборке отсекает чужое.
- Стало
- Региональный директор видит все 5 своих магазинов одним аккаунтом, не нужно переключаться. Каждый региональный получает доступ только к своим точкам. При увольнении менеджера — снимаем привязку к магазинам, доступ закрывается без удаления учётки.
- Было
- Каждый квартал коммерческий директор уточнял регламенты: «бухгалтеру дополнительно дать отчёт X, у директоров магазинов забрать право Y». Менеджер по KPI открывал 12 ролей и руками каждую правил. Ошибки попадали в прод, замечали через 2-3 недели.
- Сделали
- Права организованы в группы по тематикам. Изменение регламента = правка состава 1-2 групп, не правка 12 ролей. Одна операция массово применяет изменённый состав ко всем ролям и пользователям, привязанным к этой группе. Один вызов — все 12 ролей обновлены.
- Стало
- Квартальная переписка регламентов — 15 минут вместо полдня. После обновления новый состав применился ко всем сразу. Ошибок «забыл правку в роли X» нет — система применяет везде одинаково.
- Было
- После каждого инцидента «кто отредактировал цены SKU X в субботу 23 числа» отделу безопасности приходилось вручную проверять логи приложения и сопоставлять с активностью. Уходил день на одно расследование.
- Сделали
- Журнал действий настроен на ключевые сущности через базовый наблюдатель аудита. Каждое событие «создано / обновлено / удалено» пишет: автор, объект, разбивку «было/стало», момент времени. У каждого пользователя есть его лента действий. Поиск по типу и идентификатору объекта даёт всю историю объекта.
- Стало
- Расследование инцидента — 5 минут. Открыл карточку товара, нажал «История», увидел: «Петров (менеджер), 23 ноября 15:42, цена: 12 400 → 11 900». Аудит ИБ удовлетворён, безопасность сети повышена.
- Было
- Создание новой роли (например, «Старший менеджер B2B») — это копипаст из существующей роли с правками. В UI это означает 50+ кликов: открыть Менеджер, скопировать список прав, создать новую роль, проставить чекбоксы заново. Часто пропускали мелкие права.
- Сделали
- Клонирование роли в один клик копирует все права и связанные группы прав. Создаётся точная копия с новым именем «Старший менеджер B2B». Потом коммерческий директор правит — добавляет / убирает несколько прав. Не настраивает 50+ галочек с нуля.
- Стало
- Новая роль создаётся за 2 минуты. Все ключевые права наследуются от исходной — ничего не пропустится. Правки только дельта — что отличает новую роль от старой. Все 4 новые роли за последние полгода созданы без багов прав.
Как модуль помогает розничной сети
Доступы в AIERP — три связанных слоя
Контур доступов AIERP построен на трёх слоях, работающих вместе. Базовый слой — промышленная система ролей и прав. У роли есть имя и стабильный уникальный идентификатор. У права — системное имя и человекочитаемое название для сводки. На пользователе доступен полный набор операций: проверка роли, проверка нескольких ролей сразу, проверка права, проверка возможности действия, выдача и отзыв прав, синхронизация ролей и прав, списки прямых и унаследованных прав. Список прав пользователя кэшируется на запрос — проверки идут по памяти без обращения к базе.
Второй слой — группы прав. Поля: системное имя, отображаемое название, описание, категория (для группировки на сводке), порядок (сортировка), активна ли. Связи многие-ко-многим с правами, ролями, пользователями. На сводке вместо плоского списка из 100+ прав — структура «Заказы → просмотр, создание, обновление, удаление», «Финансы → инкассация, согласование, распределение», «Отчёты → топ товаров, ABC-XYZ, маржинальность». Поддерживаются срезы «только активные», «по категории», «по порядку». Один и тот же набор операций над группами подключается и к пользователю, и к роли — таблица связей выбирается автоматически.
Группы прав — групповая выдача и отзыв
Выдача группы роли делает два действия в одной транзакции. Первое — создать связь группы с ролью, если её ещё нет. Второе — собрать имена всех прав группы и выдать роли пакетом. Идемпотентно: повторный вызов с той же группой и ролью ничего не меняет. Аналогично выдача группы напрямую пользователю — связь и выдача прав.
Отзыв группы у роли (или у пользователя) — безопасный. Шаги: 1) убрать связь с группой, 2) получить имена прав этой группы, 3) получить имена прав из ВСЕХ ДРУГИХ групп этой роли или пользователя, 4) вычислить разницу — права для отзыва (только те, которых нет в других группах), 5) отозвать пакетом. Это критично: если право входит в две группы (например, «заказы — просмотр» в группах «Управление заказами» и «Аналитика заказов»), отзыв одной группы не лишает права. Отдельная операция «прокатить» обновлённый состав прав по всем ролям и пользователям группы — после правки состава группы права автоматически разливаются.
10 операций над группами прав
Один и тот же набор операций над группами подключается и к пользователю, и к роли. Связи хранятся в соответствующих таблицах, выбор автоматический. Список связанных групп. Выдача одной группы. Выдача нескольких пакетом. Отзыв одной. Отзыв нескольких. Каждая операция принимает группу объектом, по идентификатору или по имени.
Синхронизация групп — аналог обычной синхронизации ролей. Принимает массив групп, разворачивает в идентификаторы, вычисляет разницу с текущими (какие убрать — есть сейчас и нет в новом списке; какие добавить — есть в новом и нет сейчас), применяет отзыв к одним и выдачу к другим. Идемпотентно. Проверки «есть ли группа», «есть ли хотя бы одна», «есть ли все» — три варианта. Получение плоского списка всех прав через все группы (без дублей) — полная картина прав модели.
Автоматическая фильтрация по магазинам
Собственный механизм подключается к моделям с настраиваемой колонкой магазина (по умолчанию «магазин»). Даёт две операции. Основная — автоматический фильтр по доступным пользователю магазинам. Шаги: берёт текущего пользователя; если не авторизован — пустой результат для гостя; если у пользователя не определены доступные магазины — пропускает фильтр (модель не предполагает фильтрацию по магазинам); если у пользователя есть право обхода — пропускает (для админов сети); иначе берёт список доступных магазинов, если пусто — пустой результат, иначе фильтр «магазин в списке».
Вторая — фильтр по запрошенным магазинам (например, фильтр на сводке «показать только эти 3 магазина»). Шаги: если есть право обхода — применить только переданный список без проверки; иначе пересечь запрошенные с доступными; если пересечение пусто — пустой результат; иначе фильтр по пересечению. Защищает от попытки увидеть «не свой» магазин через подмену параметра запроса — даже если попросил конкретный магазин, увидит только если у него есть доступ. Этот двухслойный подход критичен для безопасности: фильтр работает на уровне выборки, а не контроллера — никакой контроллер не может «случайно забыть» отсечь чужие данные.
Определение доступных магазинов
У пользователя берётся список идентификаторов магазинов. Начинается с основного магазина пользователя (например, у кассира). Если у пользователя есть карточка сотрудника, и привязанные к ней магазины уже подгружены — добавляются к списку. Если карточка есть, но магазины не подгружены — подгружаются отдельным запросом. Дубли убираются. Если результат не пустой — возвращается (это перечень доступных).
Если результат пустой и у пользователя есть право обхода — возвращается пустой список как специальный признак. Соглашение: пустой список + право обхода означает «доступ ко всему» (фильтрация не применяется); пустой список без права обхода — это «нет доступа никуда», фильтр вернёт пустой результат. Проверка доступа к конкретному магазину: сначала смотрит право обхода — если есть, доступ есть; иначе проверяет, входит ли магазин в список доступных. Признак «нужно ли вообще фильтровать» — это просто отсутствие у пользователя права обхода.
Многоколоночные модели и фильтр через «или»
Не все модели имеют одну колонку с магазином. Заказ имеет «магазин клиента» (где оформлен — например, опт-клиент позвонил в один офис) и «магазин получателя» (где фактически выдают товар — может быть другой магазин). Финансовая операция имеет три: «магазин учёта» (где операция учитывается в отчётах), «магазин кассы» (через какую кассу прошли деньги), «магазин согласования» (директор какого магазина согласовал). Для таких моделей одной колонки недостаточно.
Решение — переопределить фильтр в самой модели. Вместо одного условия по одной колонке — несколько по каждой релевантной колонке через «или». Запись видна, если хотя бы одна колонка попадает в доступные магазины пользователя. Это правильное поведение для финансовых операций: операция могла быть «приписана к ТТ-7», но проведена через кассу ТТ-1 и согласована из УК. Кассир ТТ-1 должен её видеть (через кассу), директор ТТ-7 — через магазин учёта, финдир УК — через магазин согласования или через право обхода.
Журнал действий и аудит изменений
Аудит реализован через промышленный пакет журнала действий. Каждая запись хранит: имя журнала (например, основной), описание события (создано / обновлено / удалено / восстановлено), объект (любая сущность системы — займ, документ, заказ, движение склада, финансовая операция и т.д.), автор (пользователь, который сделал), разбивку «было/стало» по изменённым полям, идентификатор пакета изменений (для группировки изменений в одной транзакции — позволяет показать «все правки, сделанные за один запрос»), момент времени. У каждого пользователя есть его лента действий.
Базовый наблюдатель аудита — общий компонент, который наследуется конкретными по каждой основной сущности. На события «создано / обновлено / удалено / восстановлено» автоматически пишется запись в журнал с автором (текущий пользователь), объектом (сама сущность), разбивкой по только изменённым полям. Полный аудит без необходимости явно писать код на каждой модели — подключил наблюдатель, добавил настройку логирования, забыл. На карточке любого объекта на сводке — кнопка «История», открывает таймлайн всех изменений с автором, временем и разбивкой.
Готовы автоматизировать?
Покажем модуль на ваших данных и подключим за 1–2 недели.
