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 получают эту роль миграцией. |
logist | Legacy-алиас роли логиста; получает те же складские 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(и legacyadmin/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/OPTIONS | admin, director |
system.global_admin | Полный глобальный административный обход | admin |
audit.view | GET /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/chain | admin, 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_rights | admin, 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.report | GET /api/v1/nda/report — отчёт о принятии соглашения | admin, OWNER, OPS |
nda.manage | POST /api/v1/nda/versions — публикация новой версии соглашения | admin, OWNER, OPS |
ai.manage | GET/PUT /api/v1/ai/settings, POST /api/v1/ai/settings/test — ключ провайдера, модели, функции и лимиты AI-помощника (миграция 0157) | admin, OWNER (через system.global_admin), OPS |
users.manage | POST /api/v1/users, GET/PUT /api/v1/users/:id, /api/v1/rbac | admin |
departments.manage | /api/v1/departments | admin, 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/companies | admin, head_of_department, manager |
contacts.manage | /api/v1/contacts | admin, 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_team | admin, head_of_department, manager |
time_entries.manage | /api/v1/time_entries | admin, 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/locations | admin, head_of_department, manager, logist, logistician |
equipment.manage | /api/v1/equipment | admin, head_of_department, manager, logist, logistician |
suppliers.manage | /api/v1/suppliers | admin, head_of_department, manager, logist, logistician |
logistics.manage | /api/v1/logistics | admin, head_of_department, manager, logist, logistician |
finance.manage | Разрешение на использование модуля /api/v1/finance; доступ к данным конкретного проекта определяется ролями в команде проекта | admin, head_of_department, manager |
trips.manage | /api/v1/trips | admin, head_of_department, manager |
accounting.view | GET /api/v1/accounts, /api/v1/payments, /api/v1/counterparties/* (касса, реестр платежей, взаиморасчёты). director проходит через system.global_read | admin, accountant, director |
accounting.manage | POST/PATCH /api/v1/accounts, /api/v1/payments (создание счетов, платежей, разнесений, смена статуса). Провести платёж (статус completed при создании или через PATCH) может только финансовая служба: глобальный администратор, запись затрат «все» или этот код; руководитель дивизиона и менеджер заводят только плановые платежи по проектам своих дивизионов и проектам, которыми руководят | admin, accountant, FIN_ASSIST |
legal.view | GET /api/v1/contracts/* (реестр договоров, сроки, юр. карточка). director проходит через system.global_read | admin, lawyer, director |
legal.manage | POST/PATCH /api/v1/contracts/* (договоры, связи, сроки) | admin, lawyer |
payroll.view | GET /api/v1/compensation-profiles, /api/v1/payroll/* | admin, accountant, director |
payroll.manage | POST/PATCH условий оплаты и ведомостей, утверждение и выплата | admin, accountant |
dashboard.view | /api/v1/dashboard (middleware + dept manager) | admin, head_of_department, manager, engineer |
clients.manage | Раздел "Клиенты" в RBAC/UI; восстановлен после миграции legacy clients в companies/contacts | admin, 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/participants | admin, head_of_department, manager, engineer |
chat.react | /api/v1/messages/:id/reactions | admin, head_of_department, manager, engineer |
chat.ping | /api/v1/users/:id/ping | admin, 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/denyoverride. Используйте их для исключений, а штатные сценарии моделируйте ролями и должностями.
Casbin (domain/object/action)
Casbin проверяет операции над объектами projects, tasks, files в домене отдела (department). Глобальный обход домена и фильтра участия зарезервирован за admin; наличие projects.manage или tasks.manage само по себе не делает пользователя суперпользователем. Политики хранятся в casbin_rule:
| Subject (role) | Domain | Object | Actions | Комментарий |
|---|---|---|---|---|
admin | * | * | read, write, upload, delete | Полный доступ. |
director | * | projects, tasks, files | read | Глобальный бизнес-просмотр без write-доступа. |
manager | department | projects | read, write | Управление проектами в своём отделе. |
manager | department | tasks | read, write | Управление задачами в своём отделе. |
manager | department | files | read, upload, delete | Файлы проектов своего отдела. |
head_of_department | via g | — | — | Наследует политику manager через g-связь. |
engineer | department | projects | read | Доступ на чтение проектов отдела. |
engineer | department | tasks | read, write | Работа с задачами в отделе. |
engineer | department | files | read, 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или permissionaudit.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
Возвращает все роли:
{
"items": [
{"id": 1, "name": "admin", "description": "Системный администратор"}
]
}Пример:
curl -H "Authorization: Bearer $TOKEN" \
https://crm.local/api/v1/rbac/rolesGET /api/v1/rbac/permissions
Список permission-кодов:
{
"items": [
{"id": 10, "code": "tasks.manage", "description": "Управление задачами"}
]
}PUT /api/v1/rbac/roles/:role/permissions
Полностью заменяет набор permissions у роли. В permission_codes нужно передавать только канонические коды из таблицы permissions.
Пример корректного payload:
{
"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"
]
}Проверка перед записью:
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.manage | clients.manage | clients.manage | clients.manage |
| Чаты | chat.read | chat.write | chat.write | chat.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.
curl -H "Authorization: Bearer $TOKEN" \
"https://crm.local/api/v1/rbac/policies?user_id=7&department_id=3&object=projects"Ответ:
{
"items": [
{"subject": "manager", "domain": "department", "object": "projects", "action": "write"}
]
}GET /api/v1/rbac/enforce
Симуляция Enforce: что может конкретный пользователь. Обязательные query: user_id, object, action; опционально department_id (если не передан, используется отдел пользователя).
curl -H "Authorization: Bearer $TOKEN" \
"https://crm.local/api/v1/rbac/enforce?user_id=7&object=tasks&action=write&department_id=3"Успешный ответ показывает собранный subject, использованный домен и matched политики:
{
"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"}
]
}