Оргструктура, пользователи и доступы: инструкция для дизайна и фронтенда
Документ описывает административный интерфейс для создания пользователя, настройки отделов, руководителей, ролей и отображения оргструктуры.
Цель
Админ должен за один сценарий завести сотрудника в систему и связать его с организационной моделью:
- создать или обновить пользователя;
- назначить системную роль и RBAC-роли;
- назначить один или несколько отделов;
- выбрать primary department;
- назначить прямого руководителя;
- назначить должность;
- при необходимости назначить руководителя отдела;
- при необходимости настроить родительский отдел;
- при необходимости добавить персональные allow/deny permissions как исключение;
- проверить, какие права и видимость получит пользователь.
Обычный сотрудник должен видеть свой оргконтекст:
- к каким отделам относится;
- какой отдел primary;
- кто руководитель отдела;
- кто прямой руководитель;
- кто находится выше по цепочке;
- кто его подчинённые.
Аватары в списках
Ссылка на аватар (avatar_url) приходит в самих списках: GET /users, узлы GET /org/tree, user и руководители отделов в GET /org/me, GET /directory/users. Запрашивать профиль каждого сотрудника ради картинки не нужно; нет avatar_url — интерфейс рисует инициалы.
Роли Интерфейса
| Пользователь | Что видит | Что может менять |
|---|---|---|
admin | все пользователи, роли, отделы, оргдерево, должности, permissions | всё |
director | все бизнес-данные в read-режиме, оргструктуру и отчёты | ничего административного без отдельной роли admin |
пользователь с users.manage | список и карточки пользователей | пользователей, их primary role, отделы, активность |
пользователь с departments.manage | отделы | отделы и руководителей отделов |
пользователь с org.view | оргдерево, должности, чужие цепочки руководителей | только просмотр |
пользователь с org.manage | оргдерево, должности, руководители | прямых руководителей и должности |
| любой авторизованный сотрудник | только свой оргконтекст через /org/me | ничего в оргструктуре |
Для первого релиза административной страницы можно открывать весь раздел только admin. Позже можно разделить доступ по permissions выше.
Рекомендуемая Навигация
Раздел верхнего уровня: Организация.
Внутри:
Оргструктура
- дерево пользователей;
- поиск по сотруднику;
- фильтр по отделу;
- боковая панель выбранного сотрудника.
Пользователи
- таблица сотрудников;
- создание пользователя;
- редактирование пользователя;
- роли, отделы, руководитель, должность.
Отделы
- список отделов;
- создание/редактирование отдела;
- родительский отдел;
- назначение руководителя отдела.
Роли и права
- список ролей;
- permissions роли;
- роли пользователя.
Должности
- справочник должностей;
- уровень должности;
- default RBAC-роли должности;
- описание.
Модель Доступов
Правило для интерфейса:
- отдел определяет область данных;
- роль определяет действия;
- должность применяет default-роли;
- персональные permissions используются только для исключений.
Пример: должность Руководитель отдела должна иметь role_codes: ["head_of_department"]. При назначении такой должности пользователю backend добавит роль head_of_department и поднимет primary role, если пользователь не admin. Чтобы руководитель видел дочерние отделы, у отделов нужно настроить parent_id, а у руководимого отдела manager_id.
Должность Директор должна иметь role_codes: ["director"]. Это даёт глобальный read-доступ через system.global_read, но не даёт техническое администрирование. Если директор должен управлять пользователями и правами, ему отдельно назначается роль admin.
Экран: Оргструктура
Основной экран должен быть рабочим инструментом, а не landing page.
Layout
- Левая колонка: фильтры и список/дерево отделов.
- Центральная область: оргдерево сотрудников.
- Правая панель: карточка выбранного сотрудника.
Центральная область
Показывать дерево по users.manager_id.
Узел сотрудника:
- ФИО;
- должность;
- отдел primary;
- статус активности;
- количество прямых подчинённых;
- иконка/метка, если сотрудник руководит отделом.
Не перегружать узел permissions. Права показывать в карточке сотрудника или отдельной вкладке.
Правая Панель Сотрудника
Вкладки:
- Профиль: ФИО, email, телефон, активность.
- Оргструктура: отделы, primary department, прямой руководитель, цепочка руководителей, подчинённые.
- Роли: primary role, RBAC-роли, effective permissions.
- Проекты: проекты пользователя, проектные роли, активность в команде.
Для обычного сотрудника аналогичная информация берётся из GET /api/v1/org/me, но без доступа к чужим данным.
Экран: Пользователи
Таблица
Колонки:
- ФИО;
- email;
- primary role;
- RBAC-роли;
- primary department;
- все отделы;
- прямой руководитель;
- должность;
- активен/неактивен;
- дата создания/обновления.
Фильтры:
- отдел;
- роль;
- активность;
- руководитель;
- должность;
- поиск по ФИО/email.
Создание Пользователя
Форма должна быть разделена на шаги или секции.
1. Учётная запись
- email;
- пароль;
- ФИО или части ФИО;
- телефон;
- активность.
API: POST /api/v1/users.
Минимальное тело:
{
"email": "ivan.petrov@example.com",
"password": "strong-password-123",
"last_name": "Петров",
"first_name": "Иван",
"middle_name": "Сергеевич",
"role": "manager",
"department_ids": [1, 2],
"phone": "+79991234567"
}Важно:
roleобязателен и должен существовать в/rbac/roles;- первый ID в
department_idsстановится primary department; - пользователь не может остаться без роли;
- почта входа без учёта регистра: сохраняется строчными, вход, сброс пароля и проверка занятости ищут по
lower(email)(индекс0158); почта, отличающаяся от занятой только регистром, —409 users_email_already_in_use; - новый пароль (создание, регистрация, сброс) — от 8 символов и не длиннее 72 байт (предел bcrypt, ≈36 букв кириллицы); пароль сохраняется как введён, без обрезки пробелов — вход сравнивает его так же. Вход старые пароли не перепроверяет.
Правка (PUT /api/v1/users/:id, PUT /api/v1/users/:id/roles, DELETE /api/v1/users/:id/roles/:role):
- свою учётную запись отключить нельзя (
409 users_cannot_deactivate_yourself), свою роль владельца снять нельзя (409 users_cannot_remove_own_owner_role) — это делает другой администратор; интерфейс выключает переключатель и роль с причиной; phone: ""очищает телефон; должность снимаетсяPUT /api/v1/org/users/:id/position {"position_id": null}.
Список «Пользователи» читает GET /api/v1/users?include_inactive=true (пресет «Неактивные», включение обратно); справочник сотрудников сессии для выбора исполнителей — только активные. Подсчёт носителей роли и должности (кнопка «Удалить» выключена с причиной) тоже включает отключённых — сервер считает и их.
2. Роли
После создания пользователя:
- показать primary role из
user.role; - показать все RBAC-роли из
user.rolesв ответахGET /api/v1/usersиGET /api/v1/users/:id; - дать заменить список через
PUT /api/v1/users/:id/roles.
API:
{
"roles": ["manager", "engineer"]
}Правило:
- первая роль в массиве становится primary role (
users.role); - primary role всегда должна присутствовать в
user_roles; - нельзя отправлять пустой массив.
3. Отделы
Назначение отделов выполняется через PUT /api/v1/users/:id.
{
"department_ids": [1, 2]
}Правило:
- первый отдел в массиве является primary department;
- порядок отделов в UI должен быть управляемым;
- если нужно сменить primary department, фронт переставляет отдел первым.
- добавление отдела расширяет scope данных, но не выдаёт действия без соответствующей роли.
4. Руководитель и должность
Прямой руководитель:
PUT /api/v1/org/users/:id/manager{
"manager_id": 10
}Снять руководителя:
{
"manager_id": null
}Должность:
PUT /api/v1/org/users/:id/position{
"position_id": 3
}При назначении должности backend добавляет пользователю default-роли из org_position_roles. Снятие должности не удаляет роли автоматически, чтобы не отозвать доступы неожиданно; роли редактируются явно на вкладке Роли.
Backend запрещает циклы в иерархии: сотрудник не может стать руководителем самого себя или своего руководителя по нижней цепочке.
Экран: Отделы
Таблица
Колонки:
- название;
- родительский отдел;
- руководитель отдела;
- количество сотрудников;
- количество проектов;
- дата создания/обновления.
GET /api/v1/departments и GET /api/v1/departments/:id отдают users_count, projects_count и краткий объект manager.
users_count — число разных сотрудников отдела: и привязанных через user_departments, и тех, у кого отдел указан основным (users.department_id). Один человек в обоих источниках считается один раз.
Создание/Редактирование
API:
POST /api/v1/departments;PUT /api/v1/departments/:id;DELETE /api/v1/departments/:id.
Тело:
{
"name": "Проектный офис",
"parent_id": null,
"manager_id": 10
}Правила:
- название обязательно и уникально;
parent_idдолжен быть существующим отделом илиnull;- backend запрещает циклы в дереве отделов;
manager_idдолжен быть существующим пользователем;- удаление отдела запрещено, если есть связанные пользователи или проекты, а также задачи, командировки или позиции заявок в команду этого отдела —
409с перечнем и числом (departments_department_in_use), а не ошибка внешнего ключа; снимки KPI заполнения табеля отдела удаляются вместе с ним (расчётные данные); - несуществующий отдел в
GET /api/v1/departments/:id—404 departments_department_not_found; - руководитель отдела (
departments.manager_id) не равен автоматически прямому руководителю (users.manager_id).
UI должен явно различать:
- руководитель отдела — управляет отделом как структурной единицей;
- прямой руководитель сотрудника — используется в оргдереве и цепочке подчинения.
Экран: Роли и Права
Роли
API:
GET /api/v1/rbac/roles;POST /api/v1/rbac/roles;GET /api/v1/rbac/roles/:role;PUT /api/v1/rbac/roles/:role;DELETE /api/v1/rbac/roles/:role.
Создание:
{
"name": "project_manager",
"description": "Менеджер проекта",
"permission_codes": ["projects.manage", "tasks.manage"]
}Permissions Роли
API:
GET /api/v1/rbac/roles/:role/permissions;PUT /api/v1/rbac/roles/:role/permissions;GET /api/v1/rbac/permissions.
Тело замены permissions:
{
"permission_codes": ["users.manage", "org.view"]
}Роли Пользователя
API:
GET /api/v1/users/:id/roles;PUT /api/v1/users/:id/roles;POST /api/v1/users/:id/roles/:role;DELETE /api/v1/users/:id/roles/:role.
Для UX предпочтителен PUT /users/:id/roles, потому что он явно показывает итоговый набор ролей и порядок primary role.
Персональные Permissions
API:
GET /api/v1/users/:id/permissions;PUT /api/v1/users/:id/permissions.
Тело полной замены override:
{
"permissions": [
{"permission_code": "finance.manage", "effect": "allow"},
{"permission_code": "files.delete", "effect": "deny"}
]
}Используйте этот механизм только для исключений. Если одинаковое исключение нужно многим сотрудникам, создавайте роль или настройте default-роли должности.
Экран: Должности
API:
GET /api/v1/org/positions;POST /api/v1/org/positions;GET /api/v1/org/positions/:id;PUT /api/v1/org/positions/:id;DELETE /api/v1/org/positions/:id.
Поля:
name;description;level.role_codes.
level определяет уровень в иерархии: чем меньше число, тем выше должность.
Пример:
{
"name": "Руководитель отдела",
"description": "Руководитель структурного подразделения",
"level": 3,
"role_codes": ["head_of_department"]
}API Для Сотрудника
GET /api/v1/org/me доступен любому авторизованному пользователю.
Использовать для виджета “Моя оргструктура” в профиле или на dashboard.
Ответ содержит:
user;departments;primary_department;manager_chain;subordinates.
UI-состояния:
- нет отдела: показать пустое состояние “Отдел не назначен”;
- нет руководителя: “Прямой руководитель не назначен”;
- нет подчинённых: “Подчинённых нет”;
- несколько отделов: primary department показывать первым и отмечать бейджем.
Порядок Вызовов Для Формы Создания
Загрузить справочники:
GET /api/v1/rbac/roles;GET /api/v1/departments;GET /api/v1/users;GET /api/v1/org/positions.
Создать пользователя:
POST /api/v1/users.
Если выбрано несколько RBAC-ролей:
PUT /api/v1/users/:id/roles.
Если выбран прямой руководитель:
PUT /api/v1/org/users/:id/manager.
Если выбрана должность:
PUT /api/v1/org/users/:id/position.
Перезагрузить карточку:
GET /api/v1/users/:id;GET /api/v1/org/users/:id/chain;GET /api/v1/org/users/:id/subordinates.
Ошибки и Состояния
Обязательные состояния UI:
- loading;
- empty state;
- validation errors;
- forbidden;
- conflict;
- stale data после обновления.
Типовые ошибки:
| Сценарий | Код | Поведение UI |
|---|---|---|
| роль не существует | 400 | подсветить поле роли |
| пустой список ролей | 400 | запретить сохранение |
| последний admin удаляется | 409 | показать блокирующее сообщение |
| отдел уже существует | 409 | подсветить название |
| отдел используется | 409 | запретить удаление |
| циклический руководитель | 400 | показать ошибку в поле руководителя |
| нет permission | 403 | скрыть действие или показать read-only |
Видимость Проектных Сущностей
Ограничения видимости не должны быть только на отделе или только на роли. Нужна комбинированная модель:
Роль/permission отвечает за capability
- что пользователь в принципе может делать;
- примеры:
projects.manage,tasks.manage,finance.manage,org.view.
Отдел отвечает за организационный scope
- к какой части компании пользователь относится;
- подходит для dashboard, KPI, отчетности, дефолтных фильтров и управления ресурсами отдела.
Участие в проекте отвечает за фактическую видимость конкретного проекта
- менеджер проекта;
- активный участник команды проекта;
- автор/исполнитель/соисполнитель задач проекта.
Проектная роль отвечает за разделы внутри проекта
- финансы видят не все участники, а менеджер проекта и участники с финансовыми проектными ролями;
- документы и логистика могут иметь отдельные section grants.
Итоговое правило для фронтенда:
- не показывать пользователю проект только потому, что он в том же отделе;
- не показывать финансовые разделы только потому, что у пользователя роль
manager; - сначала проверять список/детали, которые вернул backend;
- действия включать по permissions и по данным доступа в сущности;
- для фильтров отдел использовать как scope, но не как единственный access-control механизм.
Рекомендуемая модель для продукта:
| Сущность | Видимость |
|---|---|
| проект | admin/global, руководитель отдела продаж или участник проекта/задач |
| задача | admin/global, менеджер проекта или участник задачи; в списках также задачи подчинённых, прямой руководитель участника задачи имеет прямой доступ |
| финансы проекта | admin/global finance, менеджер проекта, финансовая проектная роль |
| документы проекта | участник проекта с доступом к documents или explicit grant |
| логистика проекта | участник проекта с доступом к logistics или explicit grant |
| KPI отдела | admin/global или руководитель/сотрудник своего отдела |
| оргструктура целиком | org.view |
| свой оргконтекст | любой авторизованный пользователь |
Для дизайна это означает: права и видимость нужно объяснять пользователю через бейджи и disabled states, но финальное решение о доступе всегда остаётся за backend.