Security & RBAC
Авторизация
- Access JWT передается в
Authorization: Bearer <token>. - Refresh-token используется для обновления access.
- Middleware валидирует токен и формирует actor context.
- Access JWT содержит
typ=access; refresh JWT содержитtyp=refresh. Сервер отклоняет токены с неправильным типом даже при совпадающих ключах подписи. - Новые refresh-token записи хранятся в БД как
sha256(token). Старые plaintext-записи принимаются только для совместимого перехода и мигрируются/отзываются при ближайшем refresh/logout. POST /api/v1/auth/registerвозвращаетverification_tokenтолько в dev-окружении. В остальных окружениях подтверждение email должно идти через письмо.- Отказ во входе — по-русски, его показывает экран входа:
401 invalid_credentials«Неверная почта или пароль»,403 user_disabled«Учётная запись отключена — обратитесь к администратору»,429 too_many_attempts— после 5 неудачных попыток вход закрыт на 15 минут, текст говорит, через сколько минут повторить. Почта входа сравнивается без учёта регистра. - Новый пароль (регистрация, сброс, создание сотрудника) — от 8 символов (
min=8), не длиннее 72 байт. - Код новой роли — латиница, цифры,
_и-(400 rbac_role_code_invalid): он стоит в адресах/rbac/roles/:roleи/users/:id/roles/:role.
Доступ
- Permission-коды на уровне middleware (например,
projects.manage,files.upload). - Casbin-политики на уровне доменных объектов/департаментов.
- Типовые роли:
admin,director,head_of_department,manager,logist/logistician,engineer,employee. users.roleхранит primary role для actor/JWT/Casbin-контекста, аuser_rolesхранит роли для расчёта permission-кодов. Административные операции создания/обновления пользователя и назначения ролей синхронизируют эти два представления: primary role всегда присутствует вuser_roles, а при замене списка ролей primary role становится первой ролью из переданного списка.- Пользователь не может остаться без роли. Удаление последней роли или замена списка ролей на пустой список отклоняются.
user_permissionsхранит персональные override-исключенияallow/deny. Они нужны для редких случаев, когда создавать новую роль избыточно.denyперекрывает permission, полученный из роли.- Должности (
org_positions) не являются правами сами по себе. Таблицаorg_position_rolesхранит default RBAC-роли должности; при назначении должности роли добавляются пользователю, а для руководящих должностей primary role может быть поднята доdirectorилиhead_of_department.
admin является единственной штатной суперпользовательской ролью: она обходит доменные проверки и фильтр участия, видит все проекты/задачи, может открыть любой чат по ID и может переводить проекты или задачи между любыми валидными статусами. Удаление задач не входит в этот обход: удалить задачу может только её автор.
director и permission system.global_read дают глобальный бизнес-просмотр без технического администрирования. Middleware пропускает system.global_read только для read-запросов (GET, HEAD, OPTIONS). Для полного обхода проверок и write-операций нужен admin или system.global_admin.
Для обычных сотрудников видимость проектов и задач ограничена участием пользователя. Проект виден менеджеру проекта, активному участнику команды проекта, автору, основному исполнителю или соисполнителю задачи внутри проекта. Руководитель отдела продаж (departments.manager_id у отдела с названием Отдел продаж/Sales) видит все проекты как свою территорию. Общий список задач не раскрывает все задачи проекта только из-за участия в проектной команде: задача попадает в список для автора, основного исполнителя, соисполнителя или менеджера проекта. Также список автоматически включает задачи рекурсивных подчинённых из users.manager_id, если они назначены основными исполнителями или соисполнителями; это можно отключить query-параметром include_subordinates=false.
Внутри проекта менеджер проекта видит все задачи проекта. Участник проектной команды видит только свои задачи, задачи где он соисполнитель, и задачи своих рекурсивных подчинённых. Прямой руководитель автора, основного исполнителя или соисполнителя имеет доступ к задаче и её чату даже если задача находится в проекте без назначенного менеджера. Создать задачу в доступном проекте может любой участник проекта для любого пользователя. Удалить задачу может только её автор. Чат задачи содержит автора, основного исполнителя, соисполнителей и их руководителей из оргструктуры. Permission-коды projects.manage и tasks.manage дают доступ к операциям модуля, но не превращают пользователя в глобального администратора.
head_of_department видит проекты и задачи в отделах, которыми руководит, включая дочерние отделы из departments.parent_id. Это department scope: он расширяет область видимости, но не делает пользователя системным администратором.
Руководитель отдела продаж (departments.manager_id у отдела с названием sales, sales department или содержащим отдел продаж) имеет полный project-scope доступ ко всем проектам: карточка проекта, статусы, спецификации, задачи, проектные и task-чаты, команда, финансы, документы, файлы, бюджет, логистика и заявки. Это бизнес-доступ к проектному контуру, а не системный global bypass за пределами проекта.
manager, head_of_department, logist и logistician имеют доступ к складскому контуру: equipment.manage, locations.manage, suppliers.manage и logistics.manage. Это даёт создание и редактирование оборудования, локаций и поставщиков через соответствующие admin UI разделы, но не даёт глобальный административный обход. Персональные stale-deny override на эти permissions удаляются repair-миграцией для пользователей с такими ролями.
Списки компаний и контактов для не-глобальных пользователей ограничиваются оргструктурой: пользователь видит компании, где companies.manager_id равен ему или одному из его рекурсивных подчиненных из users.manager_id; контакты видны через такие компании по contacts.company_id или company_contacts. Охват считается отдельно для чтения и записи. admin и system.global_admin — полный просмотр и правка. Полный просмотр дают system.global_read и чтение справочника контрагентов «все» по матрице (counterparties_directory «П» или «Р», в том числе технический директор). Полную правку — запись «все» (counterparties_directory «П»: владелец, операционный и финансовый директор, ассистент, юристы, руководители дивизионов и менеджеры — клиентов ведут менеджеры). Технический директор («Р») правит по legacy-коду только свой клиентский контур. Счета, контакты и реквизиты компании или контакта проверяются так же, как их карточка.
Файлы, привязанные к проекту или задаче, доступны для чтения участникам соответствующего проекта/задачи: менеджеру проекта, активным участникам команды, автору задачи, основному исполнителю и соисполнителям. Для загрузки и удаления файлов продолжают применяться permission-коды files.upload, files.delete и доменные проверки.
Финансовые разделы проекта не раскрываются всем участникам команды. Доступ есть у admin, пользователей с глобальным finance.manage в рамках доступного им проекта, менеджера проекта и участников с проектными финансовыми ролями в project_team_members.role_codes/role_in_project: accountant, finance, financier, financial_manager, project_finance.
Оргструктура
departments.manager_id— руководитель отдела.departments.parent_id— родительский отдел для иерархии отделов.users.manager_id— прямой руководитель пользователя в оргиерархии.users.department_id— primary department для совместимости и actor context.user_departments— полный список отделов пользователя.
Правило разграничения:
- отдел отвечает за область данных;
- роль отвечает за действия;
- должность задаёт default-роли при назначении;
- персональные permissions используются как исключение, а не как основной способ моделирования штатных должностей.
Любой авторизованный сотрудник может получить собственный оргконтекст через GET /api/v1/org/me: свои отделы, primary department, руководителей отделов, цепочку прямых руководителей и своих подчинённых.
Полное дерево компании и просмотр чужих цепочек руководителей остаются за org.view; изменение руководителей и должностей — за org.manage.
Подробные endpoint-детали, схемы ошибок и примеры ответов см. в Scalar API Reference.