Skip to content

Управление командой и роли в проекте ​

Как в системе организуется команда проекта, какие роли существуют, как они влияют на ответственность и затраты.


Оргструктура сотрудника ​

Каждый авторизованный сотрудник может получить свой организационный контекст через GET /api/v1/org/me.

Ответ включает:

  • самого сотрудника с должностью, primary department и прямым руководителем;
  • все отделы сотрудника из user_departments;
  • руководителя каждого отдела (departments.manager_id);
  • цепочку руководителей вверх по users.manager_id;
  • список подчинённых текущего сотрудника.

Административные операции разделены:

  • отделы и руководители отделов управляются через /api/v1/departments и требуют departments.manage;
  • прямые руководители и должности управляются через /api/v1/org/users/:id/manager, /api/v1/org/users/:id/position и требуют org.manage;
  • полное дерево компании /api/v1/org/tree и просмотр чужих цепочек требуют org.view.

Функциональные роли отделов ​

Функциональная роль — то, что сотрудник умеет в своём отделе: «Звукорежиссёр», «Монтажник», «Видеоинженер». Это справочник для подбора людей на проект, а не права: права участника в проекте по-прежнему задают роли проекта (internal/projectroles — «Техник», «Инженер», «Менеджер проекта»…). У функциональной роли есть права в проекте по умолчанию (project_role_code), которые подставляются в заявку.

  • Справочник — functional_roles (отдел, название, описание, project_role_code, is_active), владеющие ролью — user_functional_roles; миграция 0161. Экран — «Администрирование → Функциональные роли».
  • API: GET /api/v1/functional-roles (читает любой сотрудник — нужен формам заявок), POST, PUT /:id, DELETE /:id, PUT /:id/members. Правят те, кто ведёт оргструктуру (users_and_rights или org.manage), и руководитель отдела (departments.manager_id) — роли своего отдела. Экран открыт по признаку functional_roles_view в /org/me: кто ведёт оргструктуру, кто читает справочник отделов, и руководитель отдела; править всё — functional_roles_manage. Владеть ролью могут только сотрудники её отдела, основного или дополнительного.
  • Заявка на людей: у позиции можно выбрать функциональную роль отдела (functional_role_id); права в проекте (role_code) тогда подставляются из неё и остаются редактируемыми. Роль должна быть активной и из того же отдела (team_requests_functional_role_not_found).
  • Назначение по позиции: руководитель отдела видит первыми тех, кто владеет ролью; если такой один и предпочтительного нет — он выбран сразу. Назначенный попадает в команду с функциональной ролью (project_team_members.functional_role_id).
  • Участник команды: функциональную роль можно задать и при ручном добавлении или правке (functional_role_id: 0 — снять, без поля — не менять). В списке команды она видна перед правами: «Звукорежиссёр · Техник».
  • Удалить роль, которая уже есть в заявках или командах, нельзя (functional_roles_in_use) — её отключают: она пропадает из форм, но остаётся в истории.

Концепция команды проекта ​

Команда проекта — это набор людей, которые работают вместе на достижение целей проекта. Каждый человек может иметь:

  • Роль в проекте (бизнес-роль, что он делает)
  • Ставку за время (сколько стоит его час)
  • Статус в проекте (активен/неактивен, временно включен/выключен)

Структура члена команды (Project Team Member) ​

Основные поля ​

Project Team Member:
  - ProjectID: 123 (в каком проекте)
  - UserID: 456 (какой пользователь)
  - RoleInProject: "frontend_developer" (основная бизнес-роль, legacy-поле)
  - RoleCodes: ["frontend_developer", "finance"] (набор ролей в проекте)
  - HourlyRate: 1500 (руб/ч)
  - IsLead: true (координатор проекта?)
  - IsActive: true (активен ли сейчас?)
  - CreatedAt: 2026-04-01 (когда добавлен)
  - UpdatedAt: 2026-04-20 (последнее изменение)

Что значит каждое поле ​

ProjectID и UserID ​

  • Обязательны — определяют, кто именно в каком проекте
  • Один пользователь может быть в разных проектах с разными ролями и ставками

RoleInProject и RoleCodes ​

  • role_in_project сохраняется как основная/первая роль для обратной совместимости.
  • role_codes — основной механизм, когда у участника несколько функций в одном проекте.
  • Это проектные бизнес-роли, отдельные от системной должности/роли пользователя.
  • Канонические роли проекта:
    • manager, lead, engineer, technician, designer, qa, logistician, accountant, finance, lawyer, executor, observer
  • Legacy-алиасы (dev, financier, project_finance, co_executor и др.) автоматически нормализуются к каноническим кодам.

Практическое значение: один пользователь может быть одновременно, например, accountant и lead в конкретном проекте, оставаясь инженером или менеджером по основной системной роли. Глобальная роль пользователя в системе не подменяет его проектную роль при проверке проектного финансового доступа.

HourlyRate ​

  • Опционально
  • Если указана, это проектная ставка участника и основной источник для расчета трудовых cost items.
  • Если не указана, backend не подставляет универсальную "базовую ставку" из пользователя: финансовый расчет должен брать ставку из отдельного правила оплаты или создавать cost item вручную.
  • Позволяет иметь разные ставки в разных проектах, но сама по себе не создает запись в бюджете.

Пример:

Проект A:
  HourlyRate: 1500 (стандартная ставка)

Проект B:
  HourlyRate: 2000 (проект более сложный, ставка выше)
  Или вообще не указана → в команде проекта ставки нет, финансовый расчет должен взять другое правило

Проект C (почасовой найм контрактора):
  HourlyRate: 3000 (дорогой специалист)

IsLead ​

  • true/false
  • Помечает, кто является лидом/координатором проекта
  • Может быть несколько лидов в одном проекте
  • Лидов может быть один или несколько (в зависимости от структуры)

Практическое значение:

  • Лид явно виден в составе команды.
  • Лида можно использовать как координатора в UI, фильтрах и уведомлениях.
  • Финансовые и документные секции могут учитывать lead как проектную роль доступа.
  • Операционные права все равно проверяются через backend RBAC и проектный доступ, а не только через флаг is_lead.

IsActive ​

  • true/false
  • true: человек активно работает в проекте
  • false: человек больше не работает в проекте (ушел, закончился контракт)

Практическое значение:

  • Неактивных людей не показываем в "Текущей команде"
  • Но их можно увидеть в истории проекта
  • Их Time Entries остаются в системе (для финансов)
  • Новые Time Entries не могут быть добавлены неактивному члену команды

Жизненный цикл члена команды ​

Фаза 1: Добавление в команду ​

Кто может добавить:

  • Создатель проекта
  • Менеджер проекта
  • Project Lead
  • Администратор

Как добавляется:

  1. Открыть проект
  2. Перейти в раздел "Team"
  3. Нажать "Add Member"
  4. Выбрать пользователя из каталога
  5. Указать роль (опционально)
  6. Указать ставку (опционально, иначе используется базовая)
  7. Отметить, является ли лидом
  8. Сохранить
Result:
Project Team Member created
  ProjectID: Event Setup
  UserID: Иван (123)
  RoleInProject: "Project Lead"
  HourlyRate: 1500
  IsLead: true
  IsActive: true
  CreatedAt: 2026-04-01

Фаза 2: Активная работа ​

Человек работает в проекте:

  • Видит проект в своем списке
  • Может видеть свои задачи
  • Может создавать задачи (если это лид)
  • Заполняет Time Entries
  • Участвует в чатах проекта

Система отслеживает:

  • Все Time Entries этого человека в проекте
  • Все задачи, назначенные этому человеку
  • Все комментарии и обсуждения
  • Назначения задач и упоминания в чатах создают in-app уведомления и, если включено в профиле, email delivery.

Фаза 3: Изменение ролей и ставок ​

В ходе проекта может измениться:

  • Ставка (перезаключили контракт, изменилась система оплаты)
  • Роль (был "Developer", стал "Tech Lead")
  • Статус (ушел в отпуск → IsActive = false)

Как изменить:

  1. Открыть проект
  2. Перейти в Team
  3. Найти члена команды
  4. Отредактировать его данные
  5. Сохранить

Важно: История изменений сохраняется. Система запомнит, что ставка была 1500, потом стала 1800.

Отключённые сотрудники. Сотрудника с отключённой учётной записью в команду не добавить — ни вручную, ни назначением по заявке (409 projectteam_user_is_inactive / teamrequests_assignee_is_inactive). Правка роли или ставки уже состоящего участника остаётся доступной.

Фаза 4: Удаление из команды ​

Кто может удалить:

  • Менеджер проекта
  • Project Lead
  • Администратор

Когда нельзя: сотрудник отвечает за незавершённые задачи проекта (статус не done и не cancelled) — 409 projectteam_user_has_assigned_tasks_in_project, сначала задачи передают другому. Завершённые и отменённые задачи исключению не мешают. Флаг has_assigned_tasks в списке команды считается по тому же правилу, интерфейс выключает действие заранее.

Что происходит при удалении:

  • IsActive = false (человека помечают как неактивного)
  • Человек больше не может добавлять новые Time Entries в этот проект
  • Существующие Time Entries остаются (для финансового учета)
  • Все его задачи остаются (могут быть переназначены другому)
  • При включенной настройке APP_REMOVE_FROM_CHAT_ON_TEAM_REMOVAL пользователь также удаляется из проектного чата и перестает получать realtime-события этого чата.

Вариант "полного удаления" (редко используется):

  • Удаляются все связи (если это было ошибка при добавлении)
  • Обычно не используется, чтобы не потерять историю

Роли в проекте: примеры и ответственность ​

Роли в IT-проекте ​

РольЧто делаетСтавкаLead?
Project ManagerУправляет бюджетом, сроками, коммуникациями2000-3000Обычно да
Tech LeadКоординирует разработку, делает архитектурные решения2000-2500Часто
Frontend DeveloperРазрабатывает интерфейс1500-2000Нет
Backend DeveloperРазрабатывает API и логику1500-2000Нет
QA EngineerТестирует1200-1500Нет
DevOpsУправляет инфраструктурой2000-2500Нет
ContractorВнешний разработчик2500-5000+Нет

Роли в event/logistics проекте ​

РольЧто делаетСтавкаLead?
Project ManagerКоординирует, взаимодействует с клиентом2000-3000Да
Logistics SpecialistПодбирает и доставляет оборудование1200-1500Часто
InstallerФизически расставляет оборудование800-1200Нет
DesignerПроектирует локацию, дизайн1500-2000Нет
QA/InspectorПроверяет качество1000-1200Нет

Как роли влияют на работу ​

Проектные роли дополняют общий RBAC:

  1. Передать контекст — новый сотрудник видит, кто за что отвечает.
  2. Организовать коммуникацию — можно фильтровать команду по функциям.
  3. Рассчитать затраты — ставка применяется в рамках конкретного проекта.
  4. Ограничить финансы — финансовые данные проекта доступны admin, менеджеру проекта и участникам с финансовыми проектными ролями (manager, lead, accountant, finance; legacy-алиасы поддерживаются).

Как команда влияет на финансы ​

Пример: Event Setup проект ​

Команда:

Project: Event Setup
Created: 2026-04-01
Manager: Александр (1500 руб/ч)
Lead: Иван (1500 руб/ч)
Team:
  - Дизайнер Анна (1200 руб/ч)
  - Установщик Виктор (800 руб/ч)
  - QA Мария (900 руб/ч)
  - Logistics Петр (1200 руб/ч)

Расчет трудовых затрат за 4 дня проекта:

Фаза подготовки (2 дня):
  Александр: 16 ч × 1500 = 24 000 (встречи, планирование)
  Иван:      16 ч × 1500 = 24 000 (дизайн, координация)
  Анна:      16 ч × 1200 = 19 200 (дизайн локации)
  → Subtotal: 67 200

Фаза логистики и доставки (1 день):
  Петр: 8 ч × 1200 = 9 600 (подготовка и координация)
  → Subtotal: 9 600

Фаза выполнения (день события):
  Иван: 10 ч × 1500 = 15 000 (координация на объекте)
  Виктор: 8 ч × 800 = 6 400 (установка)
  Мария: 4 ч × 900 = 3 600 (инспекция качества)
  → Subtotal: 25 000

ИТОГО LABOR: 101 800 руб

Смета проекта:

Labor: 101 800
Tech (оборудование): 55 000
Logistics (доставка): 2 000
─────────────
ИТОГО: 158 800

Это бизнес-расчет для планирования. Чтобы сумма Labor появилась в GET /api/v1/projects/:id/budget, в finance.cost_items должна быть создана строка категории labor. Текущие time_entries и auto time entries задач сохраняют часы, но не создают денежный cost item сами по себе.

Изменение команды во время проекта ​

Сценарий: Иван (Project Lead, 1500 руб/ч) заболел. Его заменила Людмила (1800 руб/ч).

Что происходит:

  1. Иван помечается как IsActive = false
  2. Людмила добавляется в команду с ставкой 1800
  3. Все Time Entries Ивана остаются в истории
  4. Новые Time Entries Людмилы создаются уже на ее пользователя
  5. Финансовая смета изменится только после обновления соответствующих labor cost items

Заявки в команду (Team Requests) ​

Когда используется ​

Если нужный ресурс находится в другом отделе, менеджер может создать Team Request. Заявка запрашивает не конкретное поле requested_user, а одну или несколько строк: отдел, роль и предпочтительные сотрудники.

Team Request:
  ProjectID: Event Setup
  Status: "draft"
  Items:
    - DepartmentID: 12
      RoleCode: "engineer"
      PreferredEmployees: [44, 45]

Жизненный цикл заявки ​

  1. draft — менеджер создал черновик через POST /api/v1/projects/:id/team-requests.
  2. pending — менеджер отправил заявку через POST /api/v1/team-requests/:id/submit; руководители отделов из позиций заявки (departments.manager_id) получают уведомление, ведущее в карточку проекта («Команда»). Раньше Submit передавал в уведомление заявку без позиций, и оно никому не уходило.
  3. approved — заявка согласована через POST /api/v1/team-requests/:id/approve.
  4. rejected — заявка отклонена (только из pending).
  5. cancelled — заявка отменена: из draft, pending или approved (status: "cancelled" в том же approve). Сотрудники, уже назначенные по согласованной заявке, остаются в команде; неназначенные строки больше не назначить. Отклонённую или отменённую заявку отменить нельзя (409 teamrequests_request_cannot_be_cancelled).

Роль строки (role_code) проверяется при создании по справочнику ролей проекта (internal/projectroles, алиасы приводятся к каноническому коду): неизвестная роль — 400 teamrequests_unknown_project_role, а не ошибка позже при назначении.

После approved руководитель отдела или менеджер проекта назначает строки:

  • assigned — выбран assignee_id, backend добавляет сотрудника в project_team_members. Сотрудник должен быть активен и работать в отделе строки — основном или дополнительном (user_departments). Строка помечается назначенной условно (только из pending), затем сотрудник добавляется в команду; если добавить не удалось, строка возвращается в pending без исполнителя — назначение и участие в команде не расходятся;
  • declined — строку закрыли без назначения.

Отдельного статуса accepted в текущем коде нет.

API ​

СценарийEndpoint
Заявки проектаGET /api/v1/projects/:id/team-requests?status= — конверт {items, meta}, новые первыми, строки заявки в items[].items
Создать черновикPOST /api/v1/projects/:id/team-requests
Получить заявкуGET /api/v1/team-requests/:id
ОтправитьPOST /api/v1/team-requests/:id/submit
Согласовать/отклонить/отменитьPOST /api/v1/team-requests/:id/approve
Назначить или отклонить строкуPOST /api/v1/team-request-items/:id/assign

Кто видит и ведёт заявки ​

  • Все заявки проекта видят и ведут: администратор, роли с записью карточки проекта «все» (OWNER, OPS, TECH_DIR), роли с охватом «свой дивизион» (DIV_HEAD, MANAGER) для проектов своих дивизионов, менеджер проекта и руководитель основного отдела проекта.
  • Руководитель отдела, в который запрошен человек (departments.manager_id — любого отдела, не только основного для него), видит только заявки со строками своего отдела и назначает по ним сотрудников. Карточку проекта чужого дивизиона он открывает, пока заявка на согласовании или согласована.
  • Код projects.manage сам по себе больше не даёт доступа к заявкам чужих проектов: у менеджеров он есть, а охват по матрице — свой дивизион.

Практическое применение ​

Заявки помогают:

  • Формально запросить ресурс из другого отдела
  • Учитывать нагрузку на сотрудников
  • Получить согласие руководства до того, как начать работу
  • Документировать причину привлечения человека

Best Practices для управления командой ​

1. Добавлять людей в команду ДО начала работы ​

Не добавлять членов команды в процессе. Лучше спланировать состав сразу.

2. Указывать правильные ставки ​

  • Если ставка человека в проекте отличается от базовой, указать именно эту ставку.
  • Это важно для расчета затрат.

3. Отмечать лидов ​

  • Проект должен иметь как минимум одного явного лида.
  • Лид получает уведомления и может управлять командой.

4. Менять IsActive при необходимости ​

  • Человек ушел/заболел? Сразу IsActive = false.
  • Это предотвратит добавление новых Time Entries от неправильного человека.

5. Документировать изменения ​

  • Если меняется ставка, ставить комментарий (почему, с какой даты).
  • Если меняется роль, тоже документировать.

6. Просматривать команду регулярно ​

  • Менеджер должен время от времени проверять состав команды.
  • Убедиться, что все люди остаются активными, нет дублей.

Интеграция с другими частями системы ​

Команда → Задачи ​

  • При создании задачи указывается основной исполнитель из пользователей-сотрудников
  • Соисполнители передаются отдельным списком co_assignee_ids
  • Отдел задачи не вводится вручную: backend определяет его по проекту или основному исполнителю

Команда → Time Entries ​

  • Time Entry может быть заполнена только членом команды проекта
  • Проектная ставка хранится в Project Team Member и может использоваться финансовым расчетом
  • Если человека удалили из команды, новые Time Entries добавить нельзя

Команда → Budget ​

  • Budget агрегирует finance.cost_items; команда и ставки сами по себе не создают строки бюджета
  • Если меняется состав команды или ставка, нужно обновить трудовые cost items, если проект ведет денежный учет труда

Команда → Уведомления ​

  • Уведомления о статусах задач, о незаполненном времени отправляются членам команды
  • Если человек неактивен, уведомления ему не приходят

Резюме ​

Команда проекта — это ключевой элемент системы:

  • Определяет, кто работает
  • Определяет стоимость работ (через ставки)
  • Определяет ответственность (через роли и IsLead)
  • Определяет, кто видит что в системе (через RBAC)

Менеджер должен:

  1. Сформировать команду ДО начала работ
  2. Указать роли и ставки
  3. Отметить лидов
  4. Следить за активностью (менять IsActive)
  5. Документировать все изменения

Система автоматически:

  • Проверяет участие в проекте при создании Time Entries
  • Синхронизирует проектный чат при добавлении/удалении участника
  • Отправляет уведомления
  • Ограничивает доступ на основе ролей

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