О платформе Войти
← К списку версий
v0.80.0 27.09.2026 MINOR
Состав проекта: откуда взялся каждый участник и журнал изменений
ТЗ 251 «Куча пользователей в проекте». Найдена причина, по которой в проекты попадали люди, которых никто не добавлял: синхронизация с платформой задач молча прикрепляла каждого участника из project_ids и при этом ещё раз прикрепляла владельца проекта как обычного участника. Теперь привязка владельца пропускается, а каждая новая связь получает дату, источник и автора. Управление составом вынесено на отдельную страницу /admin/projects/{id}/members: видно, кто привязан, когда, откуда (вручную в my.ipd или синхронизацией с платформой задач), кем добавлен и было ли это массовым заходом; там же — история изменений состава. На странице проекта широкая таблица пользователей заменена компактной карточкой со сводкой и переходом на новую страницу, добавление участника получило свой адрес /members/create, а сломанная вёрстка шапки страницы (незакрытый div, из-за которого вся страница попадала в flex-блок) исправлена.
Что сделано
  • Найдена причина массовых привязок - SyncManager::linkClientsToProjects() и привязка владельца при импорте проектов прикрепляли каждого человека из project_ids платформы задач без проверки: владелец проекта оставался ещё и в списке участников, источник и дата не сохранялись, в журнал ничего не писалось. На тестовом стенде это дало 41 дубль «владелец = участник» из 53 связей и клиента №6 с 30 проектами.
  • Источник каждой связи - Новая колонка provenance в client_project: attached_at (дата привязки), attached_by (кто привязал) и attached_source (manual — вручную в my.ipd, sync — синхронизация с платформой задач, unknown — источник неизвестен). Существующие связи не переписываются выдуманными данными: attached_at перенесён из created_at, источник помечен unknown, потому что по старым данным восстановить его нельзя.
  • Журнал изменений состава - В журнал действий добавлены actor_name (снимок имени автора) и source (web / sync / system / api). Каждая привязка, снятие, назначение и снятие владельца пишется отдельной записью с автором и источником; массовая синхронизация добавляет сводную запись о числе добавленных и пропущенных связей. Слова «удалён» в журнале заменены на «снят с проекта»: данные не удаляются, а отключаются.
  • Отдельная страница участников - Новая страница /admin/projects/{id}/members (admin.projects.members) со сводкой (всего людей, владелец, участники, вручную, синхронизацией, источник неизвестен, дублей владельца, массовых заходов), блоком «Откуда взялись участники» человеческим языком, таблицей с ролью, датой, автором, источником и пометками «Дубль владельца» и «Массовый заход», историей изменений состава и действиями в кебаб-меню: сделать владельцем, снять владельца, снять с проекта. Добавление участника вынесено на /admin/projects/{id}/members/create со своим адресом; повторное добавление владельца или текущего участника блокируется понятным сообщением.
  • Разбор состава - Новая функция ProjectMembershipService::explain() отвечает по каждой строке на четыре вопроса: кто человек (владелец или участник), когда появилась связь, откуда и кто её создал. Массовый заход определяется по одинаковой секунде привязки. Владелец показывается всегда, даже если отдельной связи-участника у него нет, — иначе им нельзя управлять.
  • Страница проекта - Вместо широкой таблицы пользователей — компактная карточка: сводка по источникам, владелец, первые участники с датой и источником, переходы «Все участники и журнал» и «+ Добавить». Инлайн-форма добавления убрана. Исправлена сломанная вёрстка: блок page-head не закрывался, из-за чего вся страница находилась внутри flex-шапки. Убраны оставшиеся жёстко заданные цвета (фиолетовая подсветка строки владельца, синие иконки писем) и синие бейджи статусов — используются переменные темы и нейтральные бейджи.
  • Проверка - Новые тесты tests/Feature/ProjectMembersPageTest.php (9 проверок: рендер страницы и объяснение источников, форма добавления, запись provenance и журнала, запрет дубля владельца, назначение владельца со связью-участником, снятие с проекта без слова «удалён», ссылка со страницы проекта, разбор дубля и массового захода, неизвестный источник старых связей) и tests/Feature/SyncProjectMembershipFeatureTest.php (3 проверки: синхронизация не прикрепляет владельца повторно, новая связь помечена источником sync и попадает в журнал, существующая связь не переписывается). Обновлены ProjectOwnerRolesFeatureTest, AdminPeopleExportWizardFeatureTest и ClientPortfolioFeatureTest под исправленное поведение синхронизации. Полный прогон: 280 тестов (1624 проверки), php artisan view:cache — без ошибок.
  • Версия - Текущая версия платформы: v0.80.0 (.env, .env.example, config/app.php, VersionSeeder, README.md, DESIGN_SYSTEM.md).
Результат
  • В проекте видно, кто привязан, когда, откуда и кем: массовые привязки помечены как сделанные синхронизацией, а не «вручную», синхронизация больше не превращает владельца в дубликата участника, каждое изменение состава попадает в журнал с автором и источником, а управление участниками живёт на отдельной странице.