Роли

Источники требований

  • BR 1.4.3 — ввёл объектную модель ролей с permissions (Yuma-стиль)
  • BR 1.4.4удалил enum employees.role. Ролевая модель стала однослойной: объект-роль с permissions + scope по владению/магазинам.

Референс

Модуль управления правами сотрудников. Владелец франшизы создаёт роли с настраиваемыми правами на разделы бэк-офиса и операции POS, а затем назначает их сотрудникам с привязкой к торговым точкам.


Единая модель ролей

(Переработано в BR 1.4.4)

В системе один слой ролевой модели — объект-роль с настраиваемыми permissions. Enum (admin_franchise и т.п.) удалён.

У сотрудника:

  • Набор permissions-ролей (N штук, каждая со своим набором ТТ)
  • Полные права = объединение permissions всех назначенных ролей
  • Scope (какие данные видит) — определяется не ролью, а правилами из Ролевая модель:
    • Владелец главного ЮЛ франшизы → вся франшиза
    • Владелец ЮЛ партнёра → свои ЮЛ + их ТТ
    • Обычный сотрудник → ТТ из employee_role_stores

Сущность «Роль»

ПолеОбязательностьОписание
НазваниеОбязательноУникально в рамках франшизы
ОписаниеОпциональноКороткое пояснение для чего роль
Разрешения Бэк-офисаОбязательноНабор флажков Read/Edit по разделам (см. ниже)
Разрешения POSОбязательноНабор флажков на операции кассы
Формула зарплатыОпциональноОдна на роль. Применяется если у сотрудника нет индивидуальной
СистемнаяАвтофлагtrue — нельзя удалить/редактировать права
owner_legal_entity_idАвтофлагUUID ЮЛ-партнёра (если роль скрытая — персональная для владельца партнёра). См. раздел «Скрытые роли»
СтатусОбязательноАктивна / Удалена (soft delete)

Разрешения — вкладка «Разделы Бэк-офиса»

Для каждого раздела админки — два флажка: Чтение (Read) и Редактирование (Edit).

Правило Edit implies Read

Включение Edit автоматически включает Read. Выключение Read автоматически выключает Edit.

Каталог разделов

РазделЧто включает
МенюТовары, категории, модификаторы
Внешние менюКонструктор меню для рекламного монитора и JSON-экспорта; список товаров каталога с override-полями (имя, описание, цена, видимость), публикация в каналы. external_menus.read — просмотр списка и редактора (read-only); external_menus.edit — CRUD + публикация + удаление + восстановление. (Добавлено в BR 4.1)
ПрейскурантыНастройка прейскурантов, привязка к ТТ
ТехкартыРецептуры, per-size варианты
ИнгредиентыСправочник ингредиентов
Стоп-листыОтключение позиций по ТТ
СкладОперации приёма, списания, инвентаризации
Торговые точкиCRUD ТТ, публикация, расписание
Юридические лицаCRUD ЮЛ
СотрудникиCRUD сотрудников, назначение ролей
РолиCRUD ролей, настройка прав
Расписание сменПлановое расписание работы сотрудников
Кухонные станцииСправочник производственных зон + цветовые пороги для KDS-карточек (yellow_threshold_minutes, red_threshold_minutes per-станция). Управляется через catalog.edit (раздел «Меню» уже даёт это право). (Расширено в BR 5.1)
Настройки KDSPer-франшиза звуки KDS (мелодия нового заказа, интервал повтора, звук просрочки, громкость, авто-логаут), список зарегистрированных KDS-устройств с возможностью force-logout. kds.settings.edit — изменение настроек + удаление устройств. (Добавлено в BR 5.1)
Учёт рабочего времениФактически отработанные часы
ЗарплатаФормулы, ведомости
Дашборд активностиСводка по работе сотрудников
ОтчётыОтчёты по сменам, заказам, выручке
ЗаказыПросмотр и управление заказами. Помимо orders.read / orders.editотдельный orders.delivery (право двигать курьерские статусы handed_overin_deliverydelivered. Не даёт прав менять состав заказа или делать refund). Выдаётся обычно курьерам. (Добавлено в BR 2.5)
НастройкиНастройки франшизы
КлиентыCRM: база клиентов, адреса, привязка к заказам. Помимо customers.read / customers.editотдельный customers.delete (выдаётся ограниченно, только для Владельца франшизы). (Добавлено в BR 3.1)
Группы клиентовСегментация клиентов: статические и динамические группы (Добавлено в BR 3.1)
ИнтеграцииУправление подключениями к агрегаторам доставки и webhook-подписками для внешних POS. integrations.read — просмотр списка подключений и логов доставки; integrations.manage — CRUD подключений и подписок. (Добавлено в BR 2.5)
Маркетинговая информацияСлайды для standby-карусели на POS Desktop (per-store). marketing.read — просмотр списка и превью; marketing.write — загрузка, редактирование, удаление, изменение порядка. Edit implies Read. (Добавлено в BR 6.1)

Разрешения — вкладка «Функции POS-терминала»

Флажки на операции, доступные сотруднику на кассе.

Источник — YumaPOS, без позиций, нерелевантных нашему скоупу

Убраны настройки для вендинговых автоматов, торговых устройств, кухонных терминалов — они вне MVP.

Каталог операций

ОперацияPermissionОписание
Доступ к POSpos.accessБазовая возможность входить в приложение (используется PIN-логином)
Открытие сменыНачало смены кассира
Закрытие сменыЗавершение смены + Z-отчёт
Приём заказовСоздание и редактирование заказа
Применение скидокРучная скидка на позицию или заказ
Внесение наличныхПополнение денежного ящика
Изъятие наличныхИзъятие из денежного ящика
ИнкассацияПередача наличных в сейф магазина
Возврат средствВозврат клиенту по закрытому заказу
Аннулирование заказаОтмена незакрытого заказа
Аннулирование позицииУдаление позиции из заказа
Изменение ценыВвод цены для товаров с открытой ценой
Настройки кассыДоступ к настройкам POS-терминала
Быстрое создание клиентаcustomers.create_quickПоиск клиента по телефону, quick-create на POS, прикрепление клиента к заказу. (Добавлено в BR 3.1)

Deferred: лимиты Min/Max

YumaPOS поддерживает у отдельных операций минимум/максимум (например, «Изъятие наличных — не более 5000 ₽»). В этой итерации не реализуется — только флажки on/off. См. раздел Deferred.


Разрешения — вкладка «Функции KDS-терминала»

(Добавлено в BR 5.1)

Флажки на операции, доступные сотруднику в KDS-приложении (Android-планшет на кухне).

ОперацияPermissionОписание
Доступ к KDSkds.accessБазовая возможность входить в KDS-приложение по PIN и менять kitchen_status позиций. Выдаётся поварам, барменам, менеджерам. Без этого права — 403 KDS_ACCESS_DENIED при попытке логина
Управление настройками устройстваkds.settings.editМенять локальные настройки на устройстве (звуки, локальные пороги, layout), регистрировать новое устройство (выбор ТТ при первом запуске). Также используется в админке для редактирования kds_franchise_settings и удаления устройств

Сотрудник может иметь и pos.access, и kds.access одновременно — типично для менеджера, который и за кассой работает, и кухню контролирует.


Разрешения — вкладка «Зарплата»

На вкладке роли указывается формула начисления зарплаты для сотрудников с этой ролью.

Типы формул, поля и иерархия применения описаны в спеке Зарплатабез изменений по сравнению с BR 1.4.1.

Изменение по сравнению с 1.4.1: формула привязана к конкретной роли (объекту), а не к enum-значению. Одна роль → одна формула на всю франшизу.

Deferred: формулы по ТТ

BR 1.4.1 предусматривал различие ставок по ТТ (роль × ТТ → формула). В этой итерации — одна формула на роль для всей франшизы. Per-ТТ ставки — отдельной BR когда возникнет реальная потребность. См. раздел Deferred.


Системная роль «Администратор»

СвойствоЗначение
СозданиеАвтоматически при bootstrap франшизы
Флаг Системнаяtrue
НазваниеФиксированное: «Администратор»
ПраваВсе флажки Read/Edit по разделам, все операции POS, pos.access
Редактирование правЗапрещено
УдалениеЗапрещено
Кому выдаётсяВладельцу франшизы при bootstrap; владельцу партнёра — если выбран режим «Полный доступ» (см. ниже)

Переименование, изменение описания — допустимо. Права и статус системной — нет.

Сотрудники с одной и той же системной ролью «Администратор» различаются scope (см. Ролевая модель), а не правами.


Скрытые роли владельцев партнёров

(Введено в BR 1.4.4 §5.2)

Когда главный админ создаёт ЮЛ партнёра и выбирает режим «Настроенные права» (вместо «Полный доступ»), для владельца партнёра создаётся скрытая персональная роль.

Зачем скрытые роли

  • У каждого партнёра свой набор прав (админ может дать Петрову всё кроме «изменение цен», а Сидорову — всё кроме «публикации ТТ»)
  • Эти роли не переиспользуются и не должны мешать в списке ролей /admin/roles
  • Управление правами партнёра происходит в карточке ЮЛ партнёра, а не в общем списке ролей

Техническая характеристика

  • В таблице roles поле owner_legal_entity_id (UUID NULL, FK → legal_entities.id)
  • Если задано → роль скрыта из всех списков /admin/roles, фильтров, выпадающих списков при создании сотрудника
  • Редактируется только через карточку ЮЛ партнёра → вкладка «Права»
  • Название в БД техническое (владелец не видит)

Управление через карточку ЮЛ партнёра

В карточке ЮЛ партнёра /admin/legal-entities/{id} есть вкладка «Права»:

ИП Петров
[Реквизиты] [Владелец] [Права] [ТТ]

─ Права владельца ──────────
  ○ Полный доступ (системная роль «Администратор»)
  ● Настроенные права

  Разделы Бэк-офиса:
    Меню             ☑ чтение ☑ редакт.
    Прейскуранты     ☑ чтение ☐ редакт.
    Публикация ТТ    ☐
    ...
  Функции POS:
    ☑ pos.access  (нельзя снять)
    ☑ Открытие смены
    ...

Режимы

РежимЧто происходит
Полный доступВладельцу партнёра назначается системная роль «Администратор». Scope ограничен его ЮЛ (через правила scope). Scope не смешивается с правами.
Настроенные праваСоздаётся скрытая роль с owner_legal_entity_id = {id ЮЛ}, назначается владельцу. Админ вручную выбирает permissions.

Минимум permissions владельца партнёра

Всегда выдаётся автоматически (нельзя снять через UI):

  • pos.access — чтобы владелец мог логиниться на POS по PIN
  • stores.read — видеть свои ТТ
  • employees.read — видеть свой персонал

Это форсится как на UI (галки заблокированы), так и серверной валидацией.

Переключение режима

  • «Настроенные» → «Полный доступ»: скрытая роль отсоединяется от владельца; назначается системная «Администратор»
  • «Полный доступ» → «Настроенные»: создаётся новая скрытая роль (галки по умолчанию — все включены или копия системной минус настройки на усмотрение UX)

Видимость

  • В /admin/roles скрытые роли не отображаются никогда
  • В списке сотрудников permissions-роли сотрудника показываются, но скрытая роль отображается как «Собственные права» или подобный лейбл (без её тех. названия)

CRUD обычных (не скрытых) ролей

Создание

  • Кнопка «Добавить» на странице списка ролей
  • Форма с четырьмя вкладками: Общее (название, описание), Разделы Бэк-офиса, Функции POS, Зарплата
  • Минимально достаточно заполнить название; права по умолчанию — все выключены
  • Сохранение: ошибка при дублировании названия в рамках франшизы

Редактирование

  • Клик по строке роли → открывается та же форма
  • Системную роль «Администратор» можно переименовать/изменить описание, но не права и не флаг системной
  • Изменения применяются немедленно — все сотрудники с этой ролью получают новые права со следующего запроса

Удаление (soft delete)

  • Кнопка «Удалить» в списке ролей или в форме редактирования
  • Запрещено, если роль назначена хоть одному активному сотруднику — UI показывает: «Снимите эту роль со всех сотрудников перед удалением» + список сотрудников
  • Системную роль удалить нельзя — кнопка недоступна
  • Скрытые роли удалить через /admin/roles нельзя (их там нет). Они удаляются автоматически при удалении ЮЛ партнёра или при переключении режима на «Полный доступ»
  • Удалённая роль попадает в архив (статус «Удалена»)

Восстановление

  • Страница «Удалённые роли» (открывается с основного списка)
  • Кнопка «Восстановить» возвращает роль в статус «Активна» со всеми правами и формулой зарплаты
  • Срок хранения в архиве — без ограничения (не удаляется физически)

Список ролей

Колонки

  • Название
  • Количество работников (число сотрудников, у кого эта роль назначена) — клик ведёт на отфильтрованный список сотрудников
  • Системная (иконка/флаг для системных)
  • Дата создания

Фильтры

  • Системные / Пользовательские
  • Активные / Удалённые

Поиск

  • По названию

Действия на панели

  • Добавить
  • Удалить (mass delete выбранных, с учётом правил)
  • Удалённые роли (переход в архив)

Скрытые роли не отображаются

Все роли с owner_legal_entity_id != NULL исключаются из списка, фильтров, поиска и счётчика.


Ролевая матрица доступа к модулю «Роли»

(Обновлено в BR 1.4.4 — колонки scope вместо enum-ролей; permission roles.read / roles.edit для обычных сотрудников)

ДействиеВладелец франшизыВладелец партнёраОбычный сотрудник
Просмотр списка ролейВсе роли франшизыРоли, назначенные его сотрудникамroles.read permission
Создание ролиДаНет (scope)roles.edit permission (обычно не выдаётся)
Редактирование ролиДаНет (scope)roles.edit permission
Удаление ролиДаНет (scope)roles.edit permission
Восстановление ролиДаНет (scope)roles.edit permission
Назначение роли сотрудникуЛюбому сотруднику франшизыТолько своим сотрудникамЕсли есть employees.edit
Настройка скрытой роли своего партнёраНе напрямую (управляется главным админом через карточку ЮЛ)Нет

Бизнес-правила

  • Уникальность названия роли — в рамках франшизы (case-insensitive). Скрытые роли не участвуют в проверке
  • Один сотрудник → N ролей одновременно (см. Сотрудники)
  • Каждая связка сотрудник × роль имеет собственный набор магазинов, где роль действует
  • Permissions не кладутся в JWT — только role_ids; полный список прав отдаётся через отдельный эндпоинт
  • Мгновенное применение изменений — при изменении прав роли все активные JWT продолжают работать, но следующий запрос к сервису получает обновлённые permissions
  • Edit implies Read — нельзя разрешить редактирование раздела, не разрешив его чтение
  • Системная роль — права и флаг фиксированы, редактируются только название и описание
  • Скрытые роли — не отображаются в /admin/roles, редактируются только через карточку ЮЛ партнёра, имеют принудительный минимум pos.access + stores.read + employees.read

Миграция

BR 1.4.3 (разовая акция при выкатке permissions-модели)

  1. Создаётся системная роль «Администратор» для текущей франшизы
  2. Сотрудник admin@erp.local (бывший enum admin_franchise) привязывается к этой системной роли
  3. Удаляются все остальные сотрудники (бывшие admin_franchisee, manager, cashier)
  4. Для удаляемых владельцев: legal_entities.owner_user_id → NULL — ЮЛ остаются, ТТ остаются, можно позже привязать новых владельцев

BR 1.4.4 (удаление enum)

(Введено в BR 1.4.4 §9)

  • ALTER TABLE employees DROP COLUMN role — колонка enum удаляется
  • ALTER TABLE franchises ADD COLUMN type VARCHAR(20) DEFAULT 'corporate' NOT NULL
  • Сервисы пересобираются и деплоятся синхронно (зависимости от enum убираются одновременно)
  • admin@erp.local остаётся с привязанной системной ролью и как owner_user_id главного ЮЛ → его scope после миграции = вся франшиза, permissions — полный набор

Тестовая среда

Production-миграции не предусмотрено — платформа ещё не в проде.


UI-гейтинг по permissions

(Введено в BR 1.5)

Фронтенд скрывает UI-элементы на основании массива permissions[], полученного из /auth/me.

Принцип

  • Нет section.read → пункт меню скрыт, маршрут недоступен
  • Есть section.read без section.edit → страница открывается в read-only режиме (кнопки создания/редактирования/удаления скрыты, формы заблокированы)
  • Есть section.edit → полный доступ (edit implies read)

Группы разделов

Каталог и Склад — группы с подпунктами. Группа видна если хотя бы один подпункт доступен. Например: нет menu.read, но есть price_list.read → группа «Каталог» отображается, внутри только «Прейскуранты».

Franchise owner bypass

Владелец франшизы (scope.type = all_franchise) видит все разделы и кнопки — проверки permissions пропускаются. Реализовано в usePermission hook.

POS-only сотрудники

Если у сотрудника нет ни одного backoffice *.read permission (только pos.* ключи) — вход в бэк-офис запрещён. При попытке логина отображается сообщение: «У вашей роли нет доступа к бэк-офису. Используйте POS-приложение.»

Дашборд

Дашборд доступен всегда (если сотрудник вошёл в бэк-офис). Является fallback-страницей.

Подробная спецификация

Полная таблица sidebar-гейтинга, кнопок на страницах, route guard и 403-обработки — в фронтенд-спеке UI-гейтинга.


Deferred

Отложено до отдельных BR

Зафиксировано сознательно, чтобы не раздувать скоуп текущей задачи.

ФункцияОбоснование отсрочкиВозврат
Per-ТТ формулы зарплаты (роль × ТТ → formula)Нужна инфраструктура настроек per-ТТ ставок. Пока одна формула на роль покрывает 90% сценариевОтдельная BR когда появится запрос от нескольких партнёров с разными ставками по городам
Min/Max лимиты на POS-операцияхUX лимитов требует отдельной проработки. Пока достаточно on/off флажковОтдельная BR когда появится жалоба/риск
Шаблоны ролей владельцев партнёровСейчас скрытая роль создаётся с нуля для каждого партнёра. В будущем — библиотека шаблонов «Партнёр (базовый)», «Партнёр без цен» и т.п., из которых можно создавать скрытую роль по пресетуОтдельная BR когда появится реальный запрос на переиспользование

Связи с другими модулями


Ссылки