Skip to content

RBAC Matrix ​

Матрица ролей и permission-кодов для ключевых модулей API. Используйте её при обновлении Casbin-политик, seed-данных или middleware.

Источник правил на уровне объектов (что видит и правит каждая из 11 ролей спецификации, охваты «все / свой дивизион / нет», вырезание денежных полей) — Матрица прав RMS и internal/permissions/matrix.go. Permission-коды ниже остаются техническим слоем middleware и fallback-ом для legacy-ролей; миграция 0137 выдаёт каждой роли спецификации набор кодов, эквивалентный её столбцу матрицы.

Роли ​

РольНазначение
adminПолный доступ ко всем модулям и доменам. Используется для системного администрирования.
directorГлобальный бизнес-просмотр без технического администрирования. Может получить admin отдельно при необходимости.
head_of_departmentРуководитель отдела с правами управления всеми объектами своего отдела и корпоративными справочниками.
managerОперационный менеджер, управляющий проектами и справочниками в рамках отдела.
logisticianЛогист: управление складским контуром, оборудованием, локациями, поставщиками и логистикой. Пользователи с global_function=logistician получают эту роль миграцией.
logistLegacy-алиас роли логиста; получает те же складские permissions, что logistician.
engineerИсполнитель: ведёт задачи, время и файлы в рамках проекта/отдела.
employeeБазовая роль обычного сотрудника.
accountantБухгалтер: касса, реестр платежей, разнесение оплат, взаиморасчёты с контрагентами (АРМ бухгалтера). Seeded в migrations/0110.
lawyerЮрист: реестр договоров, связи документов, сроки и напоминания (АРМ юриста). Seeded в migrations/0112.

Legacy-роли отображаются на роли спецификации при расчёте матрицы (admin/owner → OWNER, director → OPS, head_of_department → DIV_HEAD, manager/project_manager/pm → MANAGER, engineer → ENGINEER, employee/user → DIV_STAFF, accountant → FIN_ASSIST, legal/lawyer → LEGAL, warehouse/logist/logistician → WAREHOUSE).

Галочки разделов (миграция 0193) ​

Коды «просмотр» projects.view, companies.view, contacts.view, clients.view, equipment.view, departments.view, users.view — галочка «Просмотр» в редакторе роли без «Изменения». Раздел матрицы открывает только его галочка (permissions.ForUser, см. Матрица прав RMS); миграция проставила их ролям по строке матрицы, поэтому у ролей ниже сверх перечисленного есть: FIN_DIR, FIN_ASSIST, LEGAL — projects.view; ENGINEER, DIV_STAFF — projects.view, equipment.view; TECH_DIR — companies.view, contacts.view, clients.view; DIV_HEAD, MANAGER — companies.*, contacts.*, clients.*, equipment.view.

Роли спецификации RMS ​

Заведены миграцией 0130 (roles.name = код). Permission-коды выданы миграциями 0134 (obligations.*), 0135 (timesheets.*), 0136 (nda.*) и 0137 (всё остальное). Все 11 ролей получают общий набор: org.view, files.read, files.upload, chat.read, chat.write, chat.react, chat.ping. Ниже — только то, что сверх общего набора.

РольНазначениеДополнительные permission-коды
OWNERВладелец, полный доступsystem.global_admin; projects.manage, tasks.manage, project_team.manage, trips.manage, files.delete, chat.manage_participants; finance.manage, accounting.manage, accounting.view; legal.manage, legal.view, documents.manage; payroll.manage, payroll.view; departments.manage, org.manage, users.manage, audit.view; companies.manage, contacts.manage, clients.manage; equipment.manage, locations.manage, suppliers.manage, logistics.manage; dashboard.view; time_entries.manage; obligations.read, obligations.manage; timesheets.read_all, timesheets.approve; nda.report, nda.manage; ai.manage
OPSОперационный директорsystem.global_read; projects.manage, tasks.manage, project_team.manage, trips.manage, files.delete, chat.manage_participants; finance.manage, accounting.manage, accounting.view; legal.view; payroll.manage, payroll.view; departments.manage, org.manage, users.manage, audit.view; companies.manage, contacts.manage, clients.manage; equipment.manage, locations.manage, suppliers.manage, logistics.manage; dashboard.view; time_entries.manage; obligations.read; timesheets.read_all, timesheets.approve; nda.report, nda.manage; ai.manage
FIN_DIRФинансовый директорfinance.manage, accounting.manage, accounting.view; legal.manage, legal.view, documents.manage; payroll.manage, payroll.view; companies.manage, contacts.manage, clients.manage; dashboard.view; obligations.read, obligations.manage; timesheets.read_all
FIN_ASSISTАссистент финдиректораaccounting.manage (миграция 0148), accounting.view; legal.manage, legal.view, documents.manage; companies.manage, contacts.manage, clients.manage; dashboard.view; obligations.read, obligations.manage; timesheets.read_all
LEGALЮридический отделaccounting.view; legal.manage, legal.view, documents.manage; companies.manage, contacts.manage, clients.manage; obligations.read
TECH_DIRТехнический директорprojects.manage, tasks.manage, project_team.manage, trips.manage, files.delete, chat.manage_participants; legal.view; dashboard.view; time_entries.manage; timesheets.read_all, timesheets.approve
DIV_HEADРуководитель дивизионаprojects.manage, tasks.manage, project_team.manage, trips.manage, files.delete, chat.manage_participants; dashboard.view; time_entries.manage
MANAGERМенеджер проектовprojects.manage, tasks.manage, project_team.manage, trips.manage, files.delete, chat.manage_participants; legal.view; dashboard.view
ENGINEERИнженертолько общий набор
DIV_STAFFСотрудник дивизионатолько общий набор
WAREHOUSEСкладequipment.manage, locations.manage, suppliers.manage, logistics.manage

Охват «свой дивизион» (DIV_HEAD, MANAGER по проектам; DIV_HEAD по чужим табелям) кодами не выражается — его задаёт матрица и сужают сервисы. Объекты obligations/recurring_payments и others_timesheets проверяются прямо в handler-ах по матрице, а коды obligations.*/timesheets.* заведены для совместимости с админкой прав. Табели сверх матрицы открыты администратору (включая свой) и начальнику по оргструктуре — по его подчинённым (см. docs/concepts/timesheets.md, «Права»). Функциональные роли отделов правят те, кто ведёт оргструктуру (users_and_rights или org.manage), и руководитель отдела — роли своего отдела; журнал действий виден по audit.view.

Выдача прав ​

Правила выдачи ролей и кодов (internal/modules/rbac/grant.go, подробно — Матрица прав):

  • system.global_admin, роль OWNER (и legacy admin/owner) выдаёт и снимает только глобальный администратор;
  • другим пользователям тот, у кого есть кадровые права (users_and_rights, users.manage, для /org — org.manage), выдаёт любые роли и коды, кроме владельческих;
  • себе — ничего сверх своего: ни роли, ни кода, расширяющих собственные права (rbac_grant_self_escalation); снимать права у себя можно;
  • проверяются /users/:id/roles, /users/:id/permissions, /rbac/roles*, роль при POST/PUT /users, роли должности и её назначение (/org/positions, /org/users/:id/position).

Матрица по решениям заказчика: counterparties_directory у MANAGER и DIV_HEAD — «П», client_budget у них же — «С» (сумма сделки и вероятность своих проектов). Permission-коды ролей эти решения не меняли.

Permission codes (middleware) ​

Текущая модель смешанная:

  • *.manage означает полный доступ к модулю или к набору операций, если backend пока не разделяет CRUD на отдельные permissions.
  • Отдельные action-permissions (*.read, *.upload, *.delete, chat.read, chat.write) используются только там, где middleware и handlers уже реально проверяют разные операции.
  • Нельзя просто добавить module.create, module.update, module.delete в таблицу permissions: такие коды не будут работать, пока соответствующие маршруты не начнут проверять их через RequirePermissions.
Permission codeГде применяетсяРоли (по умолчанию)
system.global_readГлобальный read-доступ; middleware пропускает только GET/HEAD/OPTIONSadmin, director
system.global_adminПолный глобальный административный обходadmin
audit.viewGET /api/v1/audit/events; просмотр общей audit timeline по всем сущностямadmin, OWNER, OPS
org.viewЧтение оргструктуры: GET /api/v1/org/tree, /org/positions, /org/users/:id/subordinates, /org/users/:id/chainadmin, manager, все 11 ролей спецификации; с 0147 — engineer, head_of_department, employee, accountant, lawyer, warehouse, logist, logistician, director, user
org.manageИзменение иерархии и должностей: PUT /api/v1/org/users/:id/manager, CRUD /org/positions, назначение должностей; fallback объекта users_and_rightsadmin, OWNER, OPS
obligations.read / obligations.manageРеестр обязательств /api/v1/obligations — фактический доступ решает матрица (объекты obligations, recurring_payments), коды заведены для совместимостиOWNER, FIN_DIR, FIN_ASSIST, admin (manage); OPS, LEGAL (read)
timesheets.read_all / timesheets.approveСводный табель /api/v1/timesheets — фактический доступ решает матрица (объект others_timesheets)OWNER, OPS, TECH_DIR, admin (approve); FIN_DIR, FIN_ASSIST (read_all)
nda.reportGET /api/v1/nda/report — отчёт о принятии соглашенияadmin, OWNER, OPS
nda.managePOST /api/v1/nda/versions — публикация новой версии соглашенияadmin, OWNER, OPS
ai.manageGET/PUT /api/v1/ai/settings, POST /api/v1/ai/settings/test — ключ провайдера, модели, функции и лимиты AI-помощника (миграция 0157)admin, OWNER (через system.global_admin), OPS
users.managePOST /api/v1/users, GET/PUT /api/v1/users/:id, /api/v1/rbacadmin
departments.manage/api/v1/departmentsadmin, OWNER, OPS (у head_of_department снят миграцией 0147: у DIV_HEAD справочник отделов «-»)
documents.manageДокументы проекта: все типы и статусы (/api/v1/projects/:id/documents/*, /documents/:id/status)admin, OWNER, FIN_DIR, FIN_ASSIST, LEGAL (у manager и head_of_department снят миграцией 0150: смету своего проекта менеджер формирует по записи бюджета клиента, счета и акты — финансы, договоры — юристы)
companies.manage/api/v1/companiesadmin, head_of_department, manager
contacts.manage/api/v1/contactsadmin, head_of_department, manager
projects.manageДоступ к операциям управления проектами; не снимает фильтр участияadmin, head_of_department, manager
tasks.manageДоступ к операциям управления задачами; не снимает фильтр участияadmin, head_of_department, manager, engineer
project_team.manage/api/v1/project_teamadmin, head_of_department, manager
time_entries.manage/api/v1/time_entriesadmin, head_of_department, manager, engineer
files.manage/api/v1/files (полн. доступ)admin, head_of_department
files.read/api/v1/files (GET)admin, head_of_department, manager, engineer
files.upload/api/v1/files (POST)admin, head_of_department, manager, engineer
files.delete/api/v1/files (DELETE)admin, head_of_department
locations.manage/api/v1/locationsadmin, head_of_department, manager, logist, logistician
equipment.manage/api/v1/equipmentadmin, head_of_department, manager, logist, logistician
suppliers.manage/api/v1/suppliersadmin, head_of_department, manager, logist, logistician
logistics.manage/api/v1/logisticsadmin, head_of_department, manager, logist, logistician
finance.manageРазрешение на использование модуля /api/v1/finance; доступ к данным конкретного проекта определяется ролями в команде проектаadmin, head_of_department, manager
trips.manage/api/v1/tripsadmin, head_of_department, manager
accounting.viewGET /api/v1/accounts, /api/v1/payments, /api/v1/counterparties/* (касса, реестр платежей, взаиморасчёты). director проходит через system.global_readadmin, accountant, director
accounting.managePOST/PATCH /api/v1/accounts, /api/v1/payments (создание счетов, платежей, разнесений, смена статуса). Провести платёж (статус completed при создании или через PATCH) может только финансовая служба: глобальный администратор, запись затрат «все» или этот код; руководитель дивизиона и менеджер заводят только плановые платежи по проектам своих дивизионов и проектам, которыми руководятadmin, accountant, FIN_ASSIST
legal.viewGET /api/v1/contracts/* (реестр договоров, сроки, юр. карточка). director проходит через system.global_readadmin, lawyer, director
legal.managePOST/PATCH /api/v1/contracts/* (договоры, связи, сроки)admin, lawyer
payroll.viewGET /api/v1/compensation-profiles, /api/v1/payroll/*admin, accountant, director
payroll.managePOST/PATCH условий оплаты и ведомостей, утверждение и выплатаadmin, accountant
dashboard.view/api/v1/dashboard (middleware + dept manager)admin, head_of_department, manager, engineer
clients.manageРаздел "Клиенты" в RBAC/UI; восстановлен после миграции legacy clients в companies/contactsadmin, head_of_department, manager
chat.read/api/v1/chats (GET), /api/v1/chats/reaction-options, /api/v1/tasks/:id/chat, /api/v1/messages/:id (GET)admin, head_of_department, manager, engineer
chat.write/api/v1/chats (POST/PUT/DELETE), /api/v1/chats/:id/files, /api/v1/tasks/:id/chat/messages, /api/v1/tasks/:id/chat/files, /api/v1/messages (POST/PUT/DELETE)admin, head_of_department, manager, engineer
chat.manage_participants/api/v1/chats/:id/participantsadmin, head_of_department, manager, engineer
chat.react/api/v1/messages/:id/reactionsadmin, head_of_department, manager, engineer
chat.ping/api/v1/users/:id/pingadmin, head_of_department, manager, engineer

Department, Position and User Overrides ​

Модель разграничения:

  • departments.parent_id строит дерево отделов; руководитель отдела получает scope своего отдела и дочерних отделов.
  • Руководитель отдела продаж (departments.manager_id у отдела sales, sales department или с названием, содержащим отдел продаж) получает полный project-scope доступ ко всем проектам и вложенным сущностям проекта без системного global bypass.
  • user_departments назначает пользователю отделы. Это расширяет область данных, но не выдаёт действия само по себе.
  • org_position_roles связывает должность с default RBAC-ролями. При назначении должности роли добавляются пользователю; admin не снимается автоматически.
  • user_permissions хранит персональные allow/deny override. Используйте их для исключений, а штатные сценарии моделируйте ролями и должностями.

Casbin (domain/object/action) ​

Casbin проверяет операции над объектами projects, tasks, files в домене отдела (department). Глобальный обход домена и фильтра участия зарезервирован за admin; наличие projects.manage или tasks.manage само по себе не делает пользователя суперпользователем. Политики хранятся в casbin_rule:

Subject (role)DomainObjectActionsКомментарий
admin**read, write, upload, deleteПолный доступ.
director*projects, tasks, filesreadГлобальный бизнес-просмотр без write-доступа.
managerdepartmentprojectsread, writeУправление проектами в своём отделе.
managerdepartmenttasksread, writeУправление задачами в своём отделе.
managerdepartmentfilesread, upload, deleteФайлы проектов своего отдела.
head_of_departmentvia g——Наследует политику manager через g-связь.
engineerdepartmentprojectsreadДоступ на чтение проектов отдела.
engineerdepartmenttasksread, writeРабота с задачами в отделе.
engineerdepartmentfilesread, uploadРабочие файлы проекта, без удаления.

Комментарии из этой матрицы продублированы в миграции 0033_rbac_matrix.sql для удобства сопровождения.

Messenger: модели и ограничения ​

  • Чаты и сообщения: объекты chats и messages используют permission-коды chat.read и chat.write. Общие чаты создаются как direct или group; чаты задач создаются через /tasks/:id/chat и привязаны к задаче. Удалённые чаты недоступны для чтения; операции требуют участия пользователя в чате (кроме admin).
  • Сотрудники: GET /api/v1/users доступен всем авторизованным пользователям для общего списка сотрудников. Создание, административная карточка GET /api/v1/users/:id и изменение пользователей остаются под users.manage.
  • Реакции: добавление и удаление реакций (/messages/:id/reactions) контролируются chat.react; реакция записывается в chat_message_reactions и связана по message_id + type + user_id. Стандартный набор emoji доступен через GET /api/v1/chats/reaction-options.
  • Пинги: POST /users/:id/ping создаёт прямой чат при отсутствии и отправляет системное сообщение типа ping. Требует chat.ping и наличие пользователя-отправителя в создаваемом/найденном чате.
  • Прикрепления: файлы загружаются в entity type chat, затем идентификаторы передаются в file_ids; ссылка на вложение доступна только участникам чата. Исполняемые файлы запрещены, максимальный размер — 1 GB.
  • Админ-доступ: роли с глобальным доступом (admin) обходят проверку участия в чате, но логика проверки существования проектов/файлов остаётся обязательной.

Project and Task Visibility ​

Актуальные правила видимости по 11 ролям (охваты «все / свой дивизион / участие», project_departments, вырезание денежных полей) — в Матрице прав RMS. Ниже — правила для legacy-ролей и участия, которые продолжают действовать как нижний слой.

  • admin видит все проекты и задачи, может открыть любой чат по ID, создавать/удалять проекты и переводить проекты/задачи между любыми валидными статусами, включая возврат done -> in_progress. Удаление задач остаётся доступным только автору задачи.
  • director и пользователи с system.global_read видят все проекты и задачи в read-режиме.
  • head_of_department видит задачи, где он автор, основной исполнитель, соисполнитель или руководитель основного исполнителя/соисполнителя.
  • Руководитель отдела продаж (departments.manager_id у отдела Отдел продаж/Sales) видит все проекты.
  • Для остальных пользователей списки проектов фильтруются по участию: менеджер проекта, активный участник команды проекта, автор, основной исполнитель или соисполнитель задачи в проекте.
  • Глобальный список задач фильтруется по участию в задаче: автор задачи, основной исполнитель, соисполнитель, а также задачи подчинённых по оргструктуре.
  • Внутри проекта менеджер проекта видит все задачи проекта. Участник команды проекта может создавать задачи для любого пользователя, но видит только задачи, где он автор, основной исполнитель, соисполнитель или руководитель основного исполнителя/соисполнителя. Прямой руководитель участника задачи сохраняет доступ к задаче и чату даже без projects.manager_id.
  • Прямой запрос проекта/задачи по ID также требует участия пользователя. Permission-коды остаются проверкой возможности работать с модулем, но не раскрывают чужие проекты и задачи.
  • Файлы проекта/задачи на чтение доступны тем же участникам, включая соисполнителей задачи.
  • Финансы проекта доступны admin, менеджеру проекта (projects.manager_id) и участникам команды с проектными ролями manager, lead, accountant, finance (с учетом legacy-алиасов financier, financial_manager, project_finance).

Audit Timeline ​

  • GET /api/v1/entities/:type/:id/timeline доступен авторизованным пользователям с обычной проверкой видимости конкретной сущности. Для проектных сущностей применяется project-scope доступ.
  • GET /api/v1/audit/events является security/admin endpoint и требует admin, system.global_admin или permission audit.view.
  • system.global_read не открывает общий audit endpoint, чтобы директорский read-only доступ не раскрывал security/auth timeline.

RBAC API (admin-only) ​

Маршруты /api/v1/rbac/* доступны только администраторам (middleware RequireRoles("admin")) и пишут аудит в таблицу rbac_audit_logs с методой, путём, actor_id и параметрами запроса.

GET /api/v1/rbac/roles ​

Возвращает все роли:

json
{
  "items": [
    {"id": 1, "name": "admin", "description": "Системный администратор"}
  ]
}

Пример:

bash
curl -H "Authorization: Bearer $TOKEN" \
  https://crm.local/api/v1/rbac/roles

GET /api/v1/rbac/permissions ​

Список permission-кодов:

json
{
  "items": [
    {"id": 10, "code": "tasks.manage", "description": "Управление задачами"}
  ]
}

PUT /api/v1/rbac/roles/:role/permissions ​

Полностью заменяет набор permissions у роли. В permission_codes нужно передавать только канонические коды из таблицы permissions.

Пример корректного payload:

json
{
  "permission_codes": [
    "documents.manage",
    "audit.view",
    "users.manage",
    "departments.manage",
    "companies.manage",
    "contacts.manage",
    "projects.manage",
    "tasks.manage",
    "project_team.manage",
    "time_entries.manage",
    "files.manage",
    "files.read",
    "files.upload",
    "files.delete",
    "locations.manage",
    "equipment.manage",
    "suppliers.manage",
    "logistics.manage",
    "finance.manage",
    "trips.manage",
    "dashboard.view",
    "clients.manage",
    "chat.read",
    "chat.write",
    "chat.manage_participants",
    "chat.react",
    "chat.ping"
  ]
}

Проверка перед записью:

bash
curl -H "Authorization: Bearer $TOKEN" \
  https://crm.local/api/v1/rbac/permissions

Если один из кодов отсутствует в БД, API вернёт invalid_request с указанием конкретного отсутствующего permission code.

Если в БД уже применена старая версия 0062, но отсутствуют chat.*, примените следующую миграцию 0063_restore_chat_permissions.sql. Goose не переисполняет уже отмеченные версии миграций.

UI matrix mapping ​

Админская таблица прав показывает строки модулей и колонки Просмотр, Создание, Изменение, Удаление. Не каждый модуль имеет все четыре backend permission.

UI moduleПросмотрСозданиеИзменениеУдаление
Дашбордdashboard.view———
Клиентыclients.manageclients.manageclients.manageclients.manage
Чатыchat.readchat.writechat.writechat.write

Для дашборда backend поддерживает только просмотр. Колонки создания, изменения и удаления для этой строки должны быть скрыты или отключены на frontend, иначе сохранять там нечего.

Если frontend должен показывать одинаковые CRUD-колонки для всех модулей, используйте эти правила:

  • Для модулей с единственным *.manage отмеченная любая CRUD-операция должна сохранять один и тот же *.manage.
  • Для files используйте отдельные files.read, files.upload, files.delete; files.manage означает полный доступ.
  • Для chats используйте chat.read на просмотр и chat.write на создание/изменение/удаление; chat.manage_participants, chat.react, chat.ping лучше показывать отдельными дополнительными опциями, потому что это не CRUD над самим чатом.
  • Для dashboard доступен только dashboard.view.

GET /api/v1/rbac/policies ​

Позволяет смотреть текущие Casbin-политики. Поддерживаемые query-параметры: user_id (роль подтягивается автоматически), department_id (домен), object, action.

bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://crm.local/api/v1/rbac/policies?user_id=7&department_id=3&object=projects"

Ответ:

json
{
  "items": [
    {"subject": "manager", "domain": "department", "object": "projects", "action": "write"}
  ]
}

GET /api/v1/rbac/enforce ​

Симуляция Enforce: что может конкретный пользователь. Обязательные query: user_id, object, action; опционально department_id (если не передан, используется отдел пользователя).

bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://crm.local/api/v1/rbac/enforce?user_id=7&object=tasks&action=write&department_id=3"

Успешный ответ показывает собранный subject, использованный домен и matched политики:

json
{
  "user_id": 7,
  "role": "manager",
  "department_id": 3,
  "has_global_access": false,
  "domain": "3",
  "object": "tasks",
  "action": "write",
  "allowed": true,
  "permissions": ["tasks.manage", "projects.manage"],
  "policies": [
    {"subject": "manager", "domain": "department", "object": "tasks", "action": "write"}
  ]
}

Загружаем документацию…