О платформе Войти
Система управления проектами v0.98.0

Экосистема

Управление проектами, задачами и документами в одном окне

Платформа для координации работы между командами и клиентами: направления, проекты, задачи, документы и безопасные гостевые ссылки под контролем

Что это за платформа

Экосистема — система управления проектами, под которой работает команда ООО «Студия ИПД»: от постановки задачи до сдачи результата клиенту.

Направления и проекты
Управление проектами с привязкой клиентов, владельцев и направлений — всё в одном окне.
Задачи с шагами
Создание и отслеживание задач с поэтапными шагами выполнения и перепиской.
Безопасные гостевые ссылки
Токены для безопасного доступа гостей к проектам и документам без регистрации.
Документы и файлы
Хранение и версионирование документов, вложения с контролем видимости.
Синхронизация данных
Обмен данными с внешними системами через API и планировщик синхронизации.
Панель администратора
Аналитика, журнал действий, управление пользователями и настройками.
Информация о системе

Технологическая база, на которой работает платформа.

ПлатформаЭкосистема · v0.98.0
Версия PHP8.4.27
СтекPHP 8.4.27 + Laravel 13.19.0 + Vite (Tailwind 4)
База данныхMySQL
АвторизацияLaravel Auth + Remember Me
СерверHerd · my.ipd.test
СредаProduction
Платформу развивает ООО «Студия ИПД»

Это не «самоделка на коленке», а официально работающая система под управлением юридического лица. Рядом с администрированием — подтверждённая экспертиза в партнёрских программах.

Официальное юридическое лицо
Платформа развивается в рамках ООО «Студия ИПД». Направление — разработка, администрирование и автоматизация цифровых сервисов.
Алексей Гапеев — сертифицированный партнёр amoCRM
Алексей Гапеев — сертифицированный партнёр amoCRM
Открыть ↗
ООО «Студия ИПД» — сертифицированный партнёр amoCRM
ООО «Студия ИПД» — сертифицированный партнёр amoCRM
Открыть ↗
Свежий сертификат партнёра amoCRM: Алексей Гапеев и ООО «Студия ИПД» подтвердили официальную экспертизу в программе amoSTART — сертификат получен 31 июля 2026. Управление платформой и администрирование amoCRM — соседние направления одной команды: можно заказать и то, и другое.
Связаться с нами

Пишите в Telegram, звоните или отправляйте email — отвечаем быстро.

Алексей Гапеев
Алексей Гапеев
Руководитель и ведущий разработчик платформы
История версий

Как развивается платформа: что сделано, для чего и какую ценность это даёт.

v0.98.0 19.10.2026 MINOR Текущая
Предупреждения о запланированной рассылке в Telegram
ТЗ 289 «Контроль рассылки». 19 октября 2026 года с продакшена my.ipd.by ушла массовая рассылка, о которой администратор узнал постфактум: письма формируются по расписанию и уходят сами (буфер PreparedEmail и кампании Campaign), а отдельного предупреждения о запуске не было. Теперь платформа заранее сообщает администратору в Telegram: за 24 часа, 4 часа, 1 час и 15 минут до отправки ближайших писем приходит одно сводное сообщение со числом писем и списком получателей и тем. Каждое пороговое окно отправляется один раз (дедупликация в таблице mailing_alerts), повторные запуски не дублируют предупреждения. Версия v0.98.0.
Что сделано
  • Предупреждение до отправки - Администратору в Telegram (admin-бот) приходит сообщение за 24 часа, 4 часа, 1 час и 15 минут до отправки ближайших писем: сколько писем уйдёт, когда и кому — получатели и темы. Окно выбирается по остатку времени до самого раннего письма, поэтому «за час» не придёт раньше, чем письмо окажется в часе от отправки.
  • Триггеры — буфер и кампании - Мониторятся оба источника плановой рассылки: готовые письма в буфере (PreparedEmail со статусом queued и scheduled_at) и запланированные кампании (Campaign со статусом scheduled).
  • Одно сообщение на окно, без повторов - Один запуск команды собирает все письма, попадающие в пороговое окно, и отправляет одно сводное сообщение; факт отправки фиксируется в mailing_alerts (тип + id + порог), поэтому повторные запуски каждые 5 минут не дублируют предупреждения.
  • Только оповещение - Фича ничего не отменяет и не задерживает: рассылка идёт как шла, предупреждение лишь информирует. Управляется флагом MAILING_ALERTS_ENABLED; команда mail:preflight-alerts поддерживает --dry-run — показать, что было бы отправлено, не отправляя.
Проверено
  • Тесты - tests/Feature/MailingPreflightAlertsTest.php — 7 тестов: порог выбирается по остатку времени, письма вне окна не попадают, одно сообщение на окно, повторный запуск не дублирует, отключённый флаг молчит, --dry-run ничего не отправляет и не помечает, сообщение содержит получателя и тему. Полный прогон платформы: 478 тестов, 477 пройдено, 1 условно пропущен (2501 утверждение).
  • Схема versions - Восстановлены пропущенные колонки таблицы versions (released_at, notes): при релизе 0.97.1 их завели только в сидер, из-за чего сид падал на чистой базе и часть тестов не запускалась. Теперь сид и весь набор тестов зелёные.
  • Регрессия ссылок - Название расписания на странице расписаний оформлено как ссылка по правилу ТЗ 280 (color: var(--link) + text-decoration: underline) — TextLinkVisibilityTest проходит.
  • Версия платформы - Поднята до v0.98.0: config/app.php, APP_VERSION в .env и .env.example; VersionSeeder — v0.98.0 актуальная. VersionFeatureTest и SeederKeepsWorkingDataCleanTest проходят.
Открыть версию →
v0.96.2 06.10.2026 PATCH
Категории проектов: постоянные адреса разделов и статусов
ТЗ 284 «Категории проектов». Раздел проектов жил на одном адресе /admin/projects с параметром ?scope=all|clients|mine — состояние страницы нельзя было запомнить, отправить в ссылке или открыть в новой вкладке. Теперь у каждой категории свой постоянный адрес: /admin/projects (вход — клиентские активные, как раньше), /admin/projects/clients|all|mine и /admin/projects/clients|all|mine/active|completed|all (например /admin/projects/clients/completed — завершённые клиентские). Сверху два ряда вкладок: разделы и статусы, каждый со своим счётчиком; счётчики считаются в рамках выбранного раздела до применения статуса, поэтому «Клиентские · завершённые · 7» честно показывает, сколько станет после клика. Старые ссылки ?scope=X ведут на постоянный адрес того же раздела, поиск/сортировка/пагинация остаются параметрами и не меняют адрес. Версия v0.96.2.
Что сделано
  • Постоянные адреса - /admin/projects — вход (клиентские активные), /admin/projects/clients|all|mine — раздел, /admin/projects/<раздел>/<статус> — раздел со статусом: active (все, кроме закрытых — completed+archived), completed (завершённые и архив), all (все статусы). Адрес полностью описывает страницу — его можно запомнить, отправить и открыть в новой вкладке.
  • Два ряда вкладок - Первый ряд — разделы (Клиентские / Все проекты / Мои), второй — статусы (Активные / Завершённые / Все) с числом проектов рядом с подписью. Счётчики статусов считаются в рамках выбранного раздела, счётчики разделов — в рамках выбранного статуса; каждая ссылка собирается из текущих фильтров, поэтому ни один выбор не сбрасывает другой.
  • Заголовок и пустой список - Заголовок страницы называет выбранное состояние («Проекты клиентов · завершённые»), а пустой список объясняет, чего именно нет («В этом разделе нет завершённых проектов») вместо безликого «Ничего не найдено».
  • Старые ссылки не ломаются - ?scope=all и другие прежние адреса редиректом уходят на постоянный адрес того же раздела, остальные параметры (поиск, сортировка, размер страницы) сохраняются; неизвестный раздел или статус — 404.
Проверено
  • Тесты - tests/Feature/AdminProjectAddressesTest.php — 8 тестов: корень открывает клиентские активные, адреса разделов и статусов работают, вкладки — ссылки без «?», фильтры едут параметрами, счётчики соответствуют разделу, неизвестные адреса — 404, ?scope ведёт на постоянный адрес. Обновлён AdminProjectsScopeTest. Полный прогон платформы: 471 тест, 470 пройдено, 1 условно пропущен.
  • Версия платформы - Поднята до v0.96.2: config/app.php, APP_VERSION в .env и .env.example; VersionSeeder — v0.96.2 актуальная. VersionFeatureTest и SeederKeepsWorkingDataCleanTest проходят.
Открыть версию →
v0.96.1 06.10.2026 PATCH
Задачи клиентов по умолчанию и переключатель «Клиентские / Все / Мои»
ТЗ 283 «Задачи клиентов». Страница /admin/tasks-platform по умолчанию открывалась списком «моих» направлений (config('sync.my_directions')) — админ видел работу разработчика, а не то, что ждёт клиентов. Теперь по умолчанию показываются клиентские задачи: всё, кроме зоны ответственности — направлений «Производство», «Поддержка, сервис» и задач, где исполнитель (meta.assignee) — он сам. Сверху появился переключатель-чипсы «Клиентские (дефолт) / Все / Мои» (?who=clients|all|mine) с живыми счётчиками: «мои» = всё, что связано со мной — мои направления, мои проекты (клиент проекта — я сам, clients.personal_client_id) и задачи, где исполнитель — «Администратор» либо «Алексей Гапеев», «клиентские» — всё остальное, «все» — весь список. Счётчики чипсов направлений и статусов считаются в рамках выбранного режима (в «Клиентских» направления зоны ответственности показывают 0 — это честно, клик ведёт в пустой список). Старые ссылки ?direction=my|all|<id> сохраняют прежний смысл: направление по-прежнему открывает полный список задач направления, а ?direction=my работает как «Мои». Версия v0.96.1.
Что сделано
  • Клиентские задачи — по умолчанию - Открывая «Задачи с платформы задач», админ сразу видит, что ждёт клиентов: по умолчанию показываются все задачи, которые не связаны с ним — кроме направлений config('sync.my_directions'), его собственных проектов (клиент проекта — он сам, clients.personal_client_id) и задач, где исполнитель (meta.assignee) — он («Администратор» либо «Алексей Гапеев»). Подзаголовок объясняет правило, а внизу списка — расшифровка: «„Мои“ — ваши направления, ваши проекты (клиент — вы) и задачи, где вы исполнитель; „Клиентские“ — всё остальное».
  • Переключатель «Клиентские / Все / Мои» - Три чипса вверху списка: «Клиентские» (активен по умолчанию), «Все», «Мои» — параметр ?who=clients|all|mine со счётчиками задач в каждом режиме. Чипсы направлений и статусов, поиск, сортировка и пагинация сохраняют выбранный режим; в поисковую строку режим тоже подставляется скрытым полем.
  • Честные счётчики - Счётчики чипсов считаются в контексте остальных фильтров: числа отражают, что реально появится после клика. В режиме «Клиентские» направления зоны ответственности показывают 0 (там только свои задачи), направления клиентов — свои количества.
  • Старые ссылки не ломаются - ?direction=my по-прежнему открывает «мои» задачи, ?direction=<id> и ?direction=none — полный список соответствующего направления (как раньше, без отбора «клиентские»).
Проверено
  • Тесты - tests/Feature/AdminPlatformTaskWhoFilterTest.php — 9 тестов: дефолтная страница показывает только клиентские задачи и скрытое поле who, ?who=mine включает задачи моего направления и с моим исполнителем, ?who=all показывает всё, клиентский режим с фильтром направления исключает мою задачу, проекты, где клиент — сам админ, и задачи с исполнителем «Алексей Гапеев» не попадают в клиентские, старые ссылки ?direction=my и ?direction=<id> работают как прежде, счётчики чипсов соответствуют выбранному режиму. Полный прогон платформы: 463 теста, 462 пройдено, 1 условно пропущен.
  • Версия платформы - Поднята до v0.96.1: config/app.php, APP_VERSION в .env и .env.example; VersionSeeder — v0.96.1 актуальная. VersionFeatureTest и SeederKeepsWorkingDataCleanTest проходят.
Открыть версию →
v0.96.0 06.10.2026 MINOR
Обращение к получателю на карточке пользователя и уведомление о пустых полях
ТЗ 282 «Обращение к получателю». Поле «Обращение к получателю» было видно только в редактировании, о пустоте админ узнавал по письмам: когда поле пустое, письмо начинается строкой «Здравствуйте, <первое слово ФИО>!» (для «Авраменко Виолетта Владимировна» — «Здравствуйте, Авраменко!», то есть с фамилией). Теперь на карточке пользователя в списке и на его странице сразу видно, как система обратится к человеку: заполненное обращение — зелёный бейдж, пустое — красное предупреждение с тем, что уйдёт в письмо по умолчанию. В колокольчик администратору приходит уведомление «Не заполнено обращение» с числом таких клиентов (считаются рабочие клиенты: статус «В работе», активный вход, роль «Клиент») и ссылкой на список. Изменения полей пользователя логируются понятными подписями («Обращение к получателю: «…» → «…»») с автором действия. Версия v0.96.0.
Что сделано
  • Обращение видно на карточке пользователя - В списке пользователей у каждого человека появилась строка «Обращение»: заполненное поле — зелёный бейдж с текстом обращения (подпись «так система обратится к пользователю в письмах»), пустое — красное «Обращение: не задано — „Здравствуйте, <первое слово>!“» с пояснением в подсказке. Пустых полей больше не нужно искать по письмам.
  • Та же подсказка на странице пользователя - Карточка «Обращение к получателю» показывала просто «—». Теперь заполненное обращение — зелёный бейдж с пояснением, пустое — красное «Не заполнено» и строка о том, что письма начнутся именем по умолчанию и поле стоит заполнить.
  • Уведомление в колокольчик - Если у активных клиентов «Обращение» пустое, в колокольчике администратора появляется пункт «Не заполнено обращение»: сколько таких клиентов, ссылка на список пользователей. Считаются только рабочие клиенты (статус «В работе», активный вход, роль «Клиент»); админы, «На проверке», «В корзине» и «Удалённые» не учитываются. Уведомление живёт, пока есть пустые поля, и само исчезает после заполнения.
  • Понятный лог изменений - Изменения полей пользователя пишутся человеческими подписями вместо английских ключей: «Имя», «Обращение к получателю», «Email», «Компания», «Телефон», «Telegram» — в формате «было: … → стало: …». На странице пользователя в «Логи активности» добавлена колонка «Автор».
Проверено
  • Тесты - tests/Feature/UsersSalutationFeatureTest.php — 6 тестов: заполненное и пустое обращение на карточке в списке, подсказка на странице пользователя, человеческие подписи полей в логе изменения, уведомление в колокольчик появляется при пустых полях и исчезает после заполнения, «не в работе» и админы не считаются. Полный прогон платформы: 454 тестов, 453 пройдено.
  • Версия платформы - Поднята до v0.96.0: config/app.php, APP_VERSION в .env и .env.example; VersionSeeder — v0.96.0 актуальная. VersionFeatureTest и SeederKeepsWorkingDataCleanTest проходят.
Открыть версию →
v0.95.0 06.10.2026 MINOR
Дедлайн проекта и задачи со сроками на странице проекта
Дедлайн проекта был завязан только на активную подписку: у проектов без подписки карточка «Дедлайн» показывала «—», хотя срок завершения у проекта есть. У проекта появилось собственное поле deadline (планируемая дата завершения) с отдельным полем в редактировании; на странице проекта показывается оно, а если пусто — дедлайн из подписки с пометкой «по договору». Заодно задачи на странице проекта превращены из списка с процентами в карточки: поставлена дата и время, крайний срок, дата выполнения, описание, прогресс (с платформы задач, иначе доля выполненных шагов) и шаги с отметками «сделано / не сделано». Выполненная задача никогда не считается просроченной и всегда показывается на 100% со всеми шагами отмеченными; шаги идут вертикальным списком с номерами. Версия v0.95.0.
Что сделано
  • Свой дедлайн проекта - В редактировании проекта появилось поле «Дедлайн проекта» (планируемая дата завершения), отдельное от подписки. На странице проекта карточка «Дедлайн» показывает его, а если поле пусто — дедлайн из активной подписки с пометкой «по договору».
  • Задачи — карточки со сроками - У каждой задачи на странице проекта видно: когда поставлена («Поставлена: дд.мм.гггг чч:мм» — дата начала с платформы задач, иначе дата появления в MY IPD), крайний срок (просроченные подсвечены и подписаны «просрочена»), дату выполнения, полное описание, прогресс (процент с платформы задач через meta.remote_progress, иначе доля выполненных шагов) и шаги с отметками «сделано / не сделано».
  • Ссылка на полную карточку - Название задачи в карточке ведёт на страницу задачи (admin.projects.tasks.show) и оформлено как ссылка по правилу ТЗ 280: color: var(--link) + text-decoration: underline.
  • Выполненная задача не бывает просроченной - Если задача выполнена (статус или completed_at), даже при сроке в прошлом «Крайний срок» выводится спокойным цветом как справочная дата, пометка «просрочена» остаётся только у незавершённых. Прогресс выполненной задачи всегда 100%, все шаги отмечены — даже если на платформе шаги не проставлены (задача пришла уже выполненной).
  • Шаги — вертикальный список - Список шагов в карточке переведён из нескольких колонок в один столбец с нумерацией: декомпозицию легче читать. Выполненные шаги — зелёная галочка и зачёркнутый текст.
  • Дата «Выполнена» - Берётся из completed_at; если его нет (задача импортирована уже выполненной) — из истории переходов статусов (TaskStatusChange) по to_status = completed, когда она есть.
Проверено
  • Тесты - tests/Feature/TasksReadOnlyTest.php: добавлены 3 теста — богатая карточка задачи (даты поставлена/срок/выполнена, описание; выполненная задача — 100%, все шаги отмечены и не считается просроченной: «просрочена» на странице ровно одна; активная — «80% — 1 из 2 шагов»), дедлайн проекта и запасной из подписки с пометкой «по договору», сохранение дедлайна из формы редактирования. Полный прогон платформы: 448 тестов, 447 пройдено, 1 условно пропущенный.
  • Версия платформы - Поднята до v0.95.0: config/app.php, APP_VERSION в .env и .env.example; VersionSeeder — v0.95.0 актуальная. VersionFeatureTest и SeederKeepsWorkingDataCleanTest проходят.
  • Регрессия ссылок - TextLinkVisibilityTest (ТЗ 280) проходит: новая ссылка-заголовок задачи в карточке не нарушает правило «ссылка в тексте синяя и подчёркнутая».
Открыть версию →
v0.94.2 06.10.2026 PATCH
Ссылки в тексте: синие и подчёркнутые
ТЗ 280 «Ссылки в тексте». Ссылка выглядела как обычный текст, и человек не знал, что на неё можно нажать. Причина оказалась не в вёрстке, а в токенах: общее правило a { color: var(--link); text-decoration: underline } в resources/css/app.css было и раньше, но локальные правила экранов его перебивали — красили ссылки в --accent (в тёмной теме #e2e8f0, в светлой #0f172a, то есть в цвет текста) и убирали подчёркивание. Исправлено 26 файлов blade и сам app.css. Кнопки, вкладки, карточки, кебаб, пагинация, сортировка, хлебные крошки и навигация сайта остались без подчёркивания — это элементы управления, у них свой вид. Версия v0.94.2.
Что сделано
  • Ссылка в тексте — токен, а в письме — прямой цвет - На страницах платформы ссылки переведены на color: var(--link) + text-decoration: underline, чтобы не тащить цвет из одной темы в другую. В письмах (resources/views/emails/*) и в предпросмотрах писем внутри платформы цвет остался прямым: почтовый клиент не понимает CSS-переменных и оставил бы ссылку вообще без цвета. Там исправлено главное — убрано text-decoration: none.
  • Пройдены все экраны платформы - Панель письма и его предпросмотр, списки писем и пользователей, карточки проектов и задач, рабочий стол админа и клиента, еженедельные отчёты, кампании и рассылки, заявки в поддержку, расписание, мастер выгрузки людей, кабинет клиента по проекту, подпись писем — 26 файлов blade плюс resources/css/app.css.
  • Подчёркивание не пропадает при наведении - Раньше наведение местами убирало подчёркивание, и ссылка «терялась» ровно в момент, когда человек решал нажать. Теперь меняется только цвет (--link-hover), линия остаётся.
  • Кнопки и навигация выглядят как раньше - Элементы управления намеренно остались без подчёркивания: у них рамка, заливка или подсветка фоном, и подчёркивание им мешает. Различать их помогает оформление (рамка, заливка, иконка рядом) — это правило зафиксировано в тесте, чтобы «ослабление» не расползлось по платформе.
Проверено
  • Тесты - tests/Feature/TextLinkVisibilityTest.php: 5 тестов, 17 проверок — общий стиль ссылки, различие токена --link в тёмной и светлой темах, отсутствие «ссылок как текста» в CSS-правилах и инлайновых стилях, сохранение подчёркивания при наведении и пример из жалобы (панель данных письма). Полный прогон платформы: 445 тестов, 444 пройдено, 1 условно пропущенный.
  • Сам тест проверен на регрессию - Первый вариант разбирал тег регуляркой <a[^>]*> и потому обрывался на стрелке «->» внутри $email->client->id: атрибут style выпадал из проверки, и сломанная ссылка проходила молча. Тег теперь разбирается посимвольно с учётом кавычек, а тест проверен мутацией — со старым видом ссылки он падает и называет проблемное место.
Открыть версию →
v0.94.1 06.10.2026 PATCH
Буфер писем: управление письмами прямо со страницы
ТЗ 279 «Буфер писем, управление». В буфере было видно, что письмо зависло, но нельзя было ничего с ним сделать: ни удалить, ни отредактировать — приходилось искать письмо в общем списке и терять его там. Теперь у каждого письма в буфере есть галочка и меню действий, а над списком — панель массовых действий: отметили пять ненужных писем и удалили их одним действием, не покидая страницу. Попутно исправлена ошибка, из-за которой после успешного массового удаления показывалось ложное сообщение об ошибке, и счётчики групп буфера перестали расходиться с тем, что на экране. Версия v0.94.1.
Что сделано
  • Галочка у каждого письма в буфере - Строка буфера перестала быть ссылкой целиком: теперь это контейнер из трёх частей — галочка слева, сама письмо в середине и меню действий справа. Так галочка не оказалась вложена внутрь ссылки, а по строке по-прежнему можно открыть письмо одним кликом.
  • Массовое удаление прямо из буфера - Отметили нужные письма галочками (или одной галочкой «выбрать все») — над списком появилась панель «Выбрано: N» с действием «Удалить выбранные». Оно спрятано в меню опасных действий и спрашивает подтверждение с числом писем. Отправляется тем же маршрутом `/admin/emails/bulk-action`, который уже обслуживал список и корзину, — новое действие на сервере не заводилось.
  • Меню действий у письма - В кебабе строки: «Смотреть», «Редактировать», «Копия» и «Удалить» с подтверждением. Удаление и одиночное, и массовое уводит письмо в корзину, откуда его можно восстановить.
  • Починен баг с ложной ошибкой - Функция обновления панели выбора была объявлена внутри изолированной функции и потому была недоступна обработчику массового действия. После успешного удаления код падал с ReferenceError, и человек вил «Не удалось выполнить операцию» — притом, что письма были удалены. Заодно панель теперь пересчитывается после того, как строки действительно исчезли, а не заранее.
  • Счётчики перестали расходиться с экраном - Счётчик группы показывает все письма группы, включая спрятанные за «Ещё N», поэтому пересчитать его по оставшимся строкам нельзя. Скрипт уменьшает его на число реально исчезнувших строк, а ответ сервера теперь содержит и счётчики групп буфера — плитки «Просрочено», «Сегодня», «Завтра» показывают новое число сразу, без перезагрузки. Когда группа опустела, показывается честная пустая строка.
  • Меню действий не обрезается - Блок группы перестал обрезать содержимое по своему краю: выпадающее меню в последней строке раньше могло уйти за границу блока.
Проверено
  • Тесты - tests/Feature/AdminPreparedEmailBufferViewTest.php: 17 тестов, 84 проверки — добавлены 6 тестов на управление из буфера: галочка и кебаб в строке, панель массовых действий, выбор не предлагает черновики и отправленные, пустой буфер не показывает панель, массовое удаление уводит письма в корзину и возвращает свежие счётчики групп, у групп есть данные для пересчёта на месте. Полный прогон платформы: 440 тестов, 439 пройдено, 1 условно пропущенный.
  • Существующие виды - «Список» и «Корзина» не сломаны: тот же обработчик массового действия используется всеми тремя видами, исправление ошибки проверило и их.
Открыть версию →
v0.94.0 06.10.2026 MINOR
Буфер писем: что уйдёт сегодня, завтра и на неделе
ТЗ 278 «Буфер писем». Ссылка «Буфер писем» в меню вела в общий список всех писем, где нужное письмо найти невозможно, а плитка «Сегодня/завтра» считала ближайшие 24 часа от текущей минуты и показывала 0, хотя письма на сегодня были. По умолчанию теперь открывается буфер: просроченные письма отдельным блоком, дальше сегодня, завтра и каждый следующий день до конца недели. Периоды считаются по календарным дням. Версия v0.94.0.
Что сделано
  • Буфер открывается по умолчанию - `/admin/emails` без параметров открывает новый вид «Буфер» — только письма в статусе «в очереди», разложенные по дням отправки. Вкладки «Список», «Календарь» и «Корзина» остались на месте и открываются явно.
  • Почему старая плитка показывала 0 - Граница «Сегодня/завтра» считалась как «сейчас + 24 часа». В 21:30 это окно заканчивается завтра в 21:30, и письма, запланированные на сегодня в 08:30, в него не попадали — ни в плитку, ни в фильтр. Теперь «сегодня» значит до 23:59 сегодняшних суток, «завтра» — целые следующие сутки. Проверено на живых данных: при 21:30 в плитке было 0 при 184 письмах на сегодня.
  • Просроченные видно сразу - Письма, у которых время отправки уже прошло, а статус всё ещё «в очереди», вынесены в отдельный блок «Просрочено». На тесте таких оказалось 184 — они молчали в общем списке. Блок обычный, внимание привлекает формулировкой, а не красным цветом. Отдельный блок «Дальше» честно показывает число писем за пределами недели, а не прячет их.
  • Горизонты 3 дня и неделя - Добавлены плитки «На 3 дня» и «На неделю» с календарными границами. Плитки просроченного и ближайших дней показывают число нейтральным цветом.
  • В списке не больше 50 строк на блок - В каждом блоке показываются первые 50 писем, дальше честная строка «Ещё N — открыть все в списке». Ничего не обрезается молча.
  • Убрана вводящая в заблуждение подпись - Плитка плана по расписанию была подписана «завтра (пт)» — день недели был зашит в текст. Сегодня понедельник, и подпись врала. Теперь дата и день недели считаются, а в подсказке разделено: план по расписанию — это не фактический буфер.
Проверено
  • Тесты - Новый tests/Feature/AdminPreparedEmailBufferViewTest.php: 11 тестов, 47 проверок — границы по календарным дням, просроченное письмо попадает в свой блок, горизонт 3 дня обрезается по 00:00 четвёртого дня, письма за пределами недели не вываливаются в страницу, одно письмо не дублируется между блоками, черновики/отправленные/ошибки в буфер не попадают, виды list/calendar/trash не сломаны. Полный прогон платформы: 434 теста, 433 пройдено, 1 условно пропущенный.
  • Ширины экрана - /admin/emails проверен в браузере на ширинах от 1920 до 360: горизонтальной прокрутки нет ни на одной, ни один заголовок блока и ни одна тема письма не обрезаются. Плитки: 13 в ряду при 1920, 7 при 1024, 2 при 360, ни одна без числа.
  • Шрифт и вкладки - Все новые размеры шрифта — 14px и выше, правило «не меньше 14px» не смягчалось. Вкладка «Буфер» сделала перенос строки вкладок обязательным: на 360px четыре вкладки в одну строку не помещались.
Открыть версию →
v0.93.3 05.10.2026 MINOR
Список пользователей: карточки вместо таблицы
ФИО в списке пользователей переносилось по две буквы. Причина найдена замером, а не на глаз: в таблице из 11 колонок колонка «Имя» сжималась до 63px при ширине окна 1440px — «Тариф» с длинным названием занимал 287px, а «Роль», «Статус» и «Вход» по 90–144px каждая; сверху `overflow-wrap:anywhere` разрешал рвать слово в любом месте. Список переведён с таблицы на карточки: у каждого поля своя ширина, имя занимает свободное место целой строкой и переносится только по словам. Замер после изменения: ширина имени 419px при 1366px, одна строка на всех ширинах до 360px. Сортировка вынесена в отдельную строку над списком, все поля и меню действий сохранены. Версия v0.93.3.
Что сделано
  • Замер вместо догадок - Ширина каждой колонки измерена в браузере на 10 ширинах экрана. Картина: при 1440px «Имя» — 63px, «Тариф» — 287px, «Роль» — 144px. Таблица из 11 колонок физически не помещается в рабочую область ноутбука, и это не лечится брейкпоинтами — приходилось выбирать, кому станет плохо.
  • Список стал карточками - Вместо таблицы — решётка карточек шириной 380px: при 1920 в ряд встают 4, при 1366 — 2, при 1024 — 1. В карточке у каждого поля своя ширина, поэтому имя больше не соревнуется за место с тарифом.
  • Имя не рвётся по буквам - `overflow-wrap:anywhere` на ячейках таблицы был второй причиной переноса: он разрешал разрыв слова в любом месте. В карточке имя переносится только по словам (`break-word`). Замер: ширина имени 63px → 419px при 1366px, одна строка на всех ширинах до 360px.
  • Сортировка вынесена отдельно - У карточек нет заголовков колонок, поэтому сортировка стала отдельной строкой над списком: «Сортировать: Имя, Email, Роль, Статус, Вход, Создан». Ссылки те же (`sort`/`dir`), активные фильтры сохраняются, направление переключается по клику.
  • Ничего не скрыто - Раньше часть колонок приходилось прятать по ширине экрана. В карточке осталось всё: роль, тариф, статус, вход, почта со ссылкой «написать», счётчик проектов с подписью «проект / проекта, владелец», дата последнего входа, дата создания и меню действий.
  • Убрана битая кнопка «На странице» - Внизу списка стоял select с одной неактивной опцией и знаком «—» — он ничего не делал. Настоящий выбор размера страницы остался в форме фильтров.
Проверено
  • Тесты - tests/Feature/AdminUsersListPortfolioCountTest.php переписан под карточную вёрстку: 7 тестов, 38 проверок — есть карточки, сортировка, `break-word`, и при этом таблицы со списком в разметке нет. Полный прогон платформы: 422 теста, 421 пройдено, 1 условно пропущенный на отсутствии прод-клиента.
  • Ширины экрана - /admin/users проверен в браузере на ширинах 1920, 1440, 1366, 1280, 1152, 1024, 900, 768, 640, 420 и 360 пикселей: горизонтальной прокрутки страницы нет ни на одной, ни одно имя не переносится по частям слов.
  • Шрифт - Правило «шрифт не меньше 14px» не смягчалось: имя 15px, остальной текст 14px, на узких экранах уменьшаются рамки и отступы.
Открыть версию →
v0.93.2 05.10.2026 MINOR
Счётчик проектов в списке пользователей и адаптивность admin-разделов
ТЗ 277 «У Дмитрия ноль проектов и горизонтальная прокрутка». В списке пользователей счётчик проектов считал только участие человека в проекте (client_project). Владелец проекта в эту связь не попадает намеренно, поэтому у клиента с собственным проектом стоял ноль. Теперь счётчик берёт объединение «владелец + участник» без двойного учёта, а роль в счётчике подписана явно. Тот же подсчёт перенесён в фильтр «С проектами» и в блок статистики — раньше список и счётчик показывали разные числа. Вторая часть задачи — адаптивность: таблица пользователей из 11 колонок скрывает второстепенные колонки по ширине экрана, широкие таблицы прокручиваются внутри себя вместо растягивания всей страницы, шапка переносится на узких экранах. Версия v0.93.2.
Что сделано
  • Счётчик проектов учитывает владельца - В списке пользователей (/admin/users) счётчик брал только проекты, где человек участник (client_project). Владелец в эту связь не пишется намеренно (иначе он дублировался бы участником), из-за чего у клиента с собственным проектом стоял «0». Теперь счётчик — объединение проектов, где человек владелец, и проектов, где участник, без двойного учёта; роль подписана явно («владелец» / «участник» / «владелец и участник»), а в подсказке видно, из чего сложился итог.
  • Один подсчёт для списка, фильтра и статистики - Фильтр «С проектами» и блок статистики считали только участие, поэтому список и счётчик показывали разные числа. Все три места переведены на один и тот же подсчёт владельцев и участников.
  • Таблица пользователей подстраивается под экран - В таблице 11 колонок, на ноутбуках они не помещались. Второстепенные колонки скрываются по ширине экрана: до 1400px — Email и Тариф, до 1024px — Роль и Вход, до 860px — даты. Всегда остаются аватар, имя, статус, проекты и действия. Email дублировал ссылку в имени, поэтому скрывается первым.
  • Горизонтальная прокрутка убрана со страницы - Рабочей области добавлен min-width: 0. Широкая таблица раньше растягивала flex-контейнер вместе с отступом бокового меню и уводила за границу экрана всю страницу целиком. Теперь лишняя ширина уходит в прокрутку самой таблицы, страница остаётся на месте.
  • Шапка переносится на узких экранах - На ширине 420px и меньше заголовок, метка окружения и блок пользователя не помещались в одну строку и выталкивали страницу за границу. Шапка переносится на вторую строку, длинный заголовок сокращается многоточием.
  • Подпись клиента в блоке «Расписание» - На главной админки длинное название клиента выносило подпись за границу экрана на 420px. Подпись теперь переносится по словам и не выходит за контейнер. На ширине до 480px строка расписания переносится целиком: статус с датой и кнопка действий уходят на вторую строку, а не выталкивают меню за край окна на 360px.
  • Длинные куски в описаниях версий - В описаниях версий встречаются неразрывные куски — пути к тестам, имена файлов, идентификаторы. На публичной странице /versions они растягивали страницу шире окна: при ширине 360 документ уходил до 645. Текст описаний теперь переносится по любому символу, страница остаётся на месте.
Проверено
  • Тесты - tests/Feature/AdminUsersListPortfolioCountTest.php (6 тестов, 25 проверок) плюс AdminUserAddressesTest, AdminUserStatusTest, AdminDashboardHintsFeatureTest, ClientProjectsPageTest, AdminPeopleExportWizardFeatureTest, DesignSystemRenderTest, AdminProjectsScopeTest и ClientPortfolioFeatureTest: 87 тестов, 832 проверки, падений нет. Полный прогон платформы: 421 тест, 420 пройдено, 1 условно пропущенный на отсутствии прод-клиента.
  • Ширины экрана - /admin/users, /admin, /admin/projects, /versions и /about проверены в браузере на ширинах 1920, 1440, 1366, 1280, 1024, 900, 768, 640, 420 и 360 пикселей: горизонтальной прокрутки страницы нет ни на одной, широкая таблица проектов прокручивается внутри своего контейнера.
  • Шрифт - Правило «шрифт не меньше 14px» не смягчалось ради того, чтобы таблица поместилась: на узких экранах уменьшаются рамки и отступы, а не размер текста.
Открыть версию →
v0.93.0 02.10.2026 MINOR
Письма на неделю/месяц: генерация и пересборка upcoming
Восстановлен функционал управления письмами на неделю/месяц: добавлены кнопки «Сформировать на неделю/месяц», «Пересобрать на неделю/месяц» (с отменой будущих в выбранном периоде и повторной генерацией), роуты и методы контроллера. После генерации автоматически очищаются просроченные queued (scheduled_at <= now). Статистика «На неделю/месяц» в админке стала корректной.
UI (Буфер писем)
  • Кнопки генерации - Добавлены кнопки «Сформировать на неделю», «Сформировать на месяц».
  • Кнопки пересборки - Добавлены «Пересобрать на неделю», «Пересобрать на месяц» (отменяют queued-письма в ближайшие 7/30 дней и формируют новые).
Backend
  • Контроллер - В AdminPreparedEmailController добавлены методы generateUpcoming/generateWeek/generateMonth/rebuildUpcoming.
  • Роуты - Добавлены POST-роуты admin.prepared-emails.generate-upcoming/week/month и rebuild-upcoming.
  • Очистка после генерации - Просроченные queued (scheduled_at <= now) автоматически отменяются, чтобы очередь оставалась только будущей.
Открыть версию →
v0.92.1 02.10.2026 PATCH
Очередь подготовленных писем: просроченные в очереди не отправляются
Исправлена проблема, когда письма в статусе «В очереди» с запланированной датой в прошлом оставались в очереди и могли быть отправлены позже. Теперь команда email:send-prepared автоматически отменяет сильно просроченные queued (>48ч) и берёт в отправку только актуальные по расписанию.
Что сделано
  • Защита от просроченных queued-писем - В `app/Console/Commands/SendPreparedEmails.php` добавлена автоотмена queued с `scheduled_at < now()-48h` (cancelled с комментарием в `admin_notes`). В отправку берутся только queued в окне (now-48h .. now).
Открыть версию →
v0.92.0 02.10.2026 MINOR
Одна кнопка на всех: люди, проекты, связи и задачи за один проход
ТЗ 273 «Люди загрузились, а проектов у них нет». Загрузка людей и загрузка проектов были разными кнопками в двух мастерах, и порядок зависел от того, какую нажали: люди успевали появиться раньше проектов — и проект оставался без владельца, а у клиента не появлялось ни одного проекта. Причина в сопоставлении: у человека без почты на площадке person_external_id пустой, а почта в карточке проекта и в списке людей расходится, поэтому владелец не находился вообще. Теперь одна кнопка «Синхронизировать всё» делает всё в правильном порядке (направления → люди → проекты → связи «человек → проект» → задачи) и одной транзакцией, а владелец проекта ищется через общий список людей по person_id — это работает и без почты. Версия v0.92.0.
Что сделано
  • Одна кнопка вместо трёх - На странице «Синхронизация данных» (/admin/sync) — кнопка «Синхронизировать всё с платформы задач». За один проход и в одной транзакции: направления → люди → проекты (с владельцем) → связи «человек → проект» → задачи и шаги. Письма по задачам не отправляются: массовый импорт не должен слать клиентам письма, их готовят мастера писем отдельно. После запуска — страница итога с цифрами: сколько людей, проектов, связей и задач создано и обновлено.
  • Владелец проекта находится и без почты - Порядок поиска: person_external_id → person_id через общий список людей выгрузки (PersonMatcher: внешний id, почта, затем имя + организация) → person_email из карточки проекта → person_name. Раньше использовались только person_external_id и person_email, поэтому у человека без почты владелец не находился никогда. Связь по person_id однозначна: 41 проект из 41 сопоставляется с человеком из списка людей.
  • Связи внутри того же прохода - Привязка людей к проектам перенесена в тот же запуск и ту же транзакцию, что и импорт проектов (linkClientsToProjectsFromPayload), и работает по уже полученной выгрузке — без второго обращения к платформе. Владелец участником не дублируется.
  • Повторный запуск чинит накопленное - Кнопка безопасна для повторов: связи только добавляются, владелец проставляется, если его нет, люди и проекты не создаются заново. Поэтому один запуск закрывает и уже накопившийся долг, без ручной доводки по спискам.
Найдено в данных
  • 2 проекта были без владельца - «Медтехника Гродно» (проект 9 на площадке) и «АльденаГрупп — сопровождение и развитие (2026)» (4509).
  • 5 клиентов были без единого проекта - Воронов Вадим, Калита Алексей, Михнюк Дмитрий, Покалюк Денис (ООО «АльденаГрупп») и Кипеть Александр (РУП «Медтехника» Могилёв) — ровно участники этих двух проектов. Все без почты, поэтому и не находились.
  • 20 задач без проекта — это другое - Их проектов уже нет на платформе (личные и архивные проекты IPD). Не трогались: это случай осиротевших задач, а не синхронизации.
Проверено
  • 5 тестов на полную синхронизацию - tests/Feature/FullPlatformSyncTest.php: владелец без почты находится по person_id и появляется владельцем проекта; все участники получают проект в том же запуске; владелец не дублируется участником; второй запуск ничего не создаёт и не ломает; проект, оставшийся без владельца, получает его при следующем запуске; кнопка и страница итога работают через HTTP.
  • Полный набор тестов зелёный - 403 теста, падений нет.
Открыть версию →
v0.91.0 02.10.2026 MINOR
Одна синхронизация людей, проектов и задач: без почты создаём, смену статуса показываем в письме
ТЗ 272 «Одна кнопка и правдивые письма». Люди без email молча пропускались, а смена статуса задачи нигде не сохранялась — платформа отдаёт только текущий статус, поэтому письмо об изменении просто не могло появиться. Теперь: клиент без email создаётся с пустой почтой (появится в проектах и списках, писем не получит); каждый переход статуса «было → стало» пишется при синхронизации в новую таблицу task_status_changes и выводится в отчётных письмах плейсхолдером {{status_changes_list}}; сопоставление человека с клиентом вынесено в один сервис PersonMatcher для превью и импорта сразу. Попутно исправлена ошибка сопоставления по кириллице: сравнение шло через SQL LOWER(), который в SQLite не понижает регистр кириллицы, из-за чего людей без почты создавали заново при каждом импорте. Версия v0.91.0.
Что сделано
  • Человек без email создаётся - Раньше он просто исчезал: шаг 1 показывал его в блоке «не будет добавлен», шаг 2 пропускал. Теперь клиент создаётся с пустым email (поле стало nullable), попадает в проекты и списки; писем он не получает, потому что отбор идёт по наличию адреса. Оба мастера — «Синхронизация всех людей» и «Синхронизация людей с платформы задач» — показывают его отдельным блоком «добавятся, но писем не получат».
  • История смены статуса задачи - Новая таблица task_status_changes (task_id, project_id, from_status, to_status, source, origin, changed_at). Заполняется в момент синхронизации — это единственное место, где известны оба значения. Переход из закрытой задачи в историю пишется, но письмо не отправляет: это факт, а не повод слать «задача открыта заново».
  • Письма показывают смену статусов - ReportDispatcher собирает блок «Изменился статус задач» за отчётный период (не больше 20 переходов) и подставляет его через новый плейсхолдер {{status_changes_list}} в шаблоны report-wednesday и report-friday. Пустой период даёт пустую строку — лишний заголовок в письме не появляется. Переходы по внутренним (невидимым клиенту) задачам в письмо не попадают.
  • Одно сопоставление вместо двух - Новый сервис App\Services\Sync\PersonMatcher используют и предпросмотр (DiffEngine), и импорт (SyncManager), и оба контроллера: порядок поиска один — внешний id человека (= id клиента в MY IPD), затем email, затем имя вместе с организацией. Одного имени без организации недостаточно: однофамильцев с разными компаниями склеивать нельзя.
  • Исправлена ошибка сопоставления по кириллице - Сравнение имени и email шло через SQL LOWER()/TRIM(), а SQLite не понижает регистр кириллических букв: «Человек Без Почты» никогда не совпадал с «человек без почты», и при каждом импорте создавался новый клиент. Сравнение перенесено в PHP с нормализацией пробелов и регистра.
  • Организация и адреса больше не теряются - Организация человека с платформы пишется в clients.company — по ней он и находится в следующих импортах. Обновление email и списка emails происходит только когда платформа реально прислала адреса: иначе у человека без почты на площадке стирались бы адреса, добавленные в MY IPD.
Проверено
  • Полный набор тестов зелёный - 398 тестов, падений нет. Обновлены тесты двух мастеров под новое правило (люди без email больше не пропускаются), добавлены TaskStatusChangeSyncFeatureTest (3 теста: переход записан со старым и новым статусом, при неизменившемся статусе история пуста, переоткрытая задача не шлёт письмо) и три теста на блок смены статусов в WeeklyReportCompositionTest (внутренняя задача скрыта, переход вне периода не показывается).
  • Миграции применены на TEST - clients.email стал nullable, создана task_status_changes, в существующие шаблоны report добавлен плейсхолдер.
Открыть версию →
v0.90.1 01.10.2026 PATCH
Задачи только с платформы: убран мусор, снято 196 ложных пометок
ТЗ 271 «Задачи велись в двух местах». Задачи приходят с платформы task.ipd, но в MY IPD у синхро-задач были свои формы правки: маршруты create/store/edit/update/destroy и отдельный AdminStepController для шагов. Правка жила до следующей синхронизации и затиралась, удалённая задача возвращалась из выгрузки снова. Для синхро-задач маршруты правки удалены, карточка задачи только читается, кнопка «+ Задача» на странице проекта убрана; удаление осталось только в сверке мусора. Причина заваленности базы: 1112 синхро-задач, из них 327 на платформе нет вообще (тестовые D-04…D-111 и прочие), а 196 задач были ошибочно помечены «нет на платформе» — синхронизация сверялась по ответам на отдельные запросы вместо полного списка задач платформы. Предпросмотр и SyncManager теперь считают известные идентификаторы по объединению всех источников. Добавлена команда tasks:reconcile-platform с режимами --dry-run, --restore, --purge. На TEST удалено 327 задач и 20 шагов, 196 задач восстановлено. Версия v0.90.1.
Что сделано
  • Задачи только читаются - У синхро-задач убраны маршруты create/store/edit/update/destroy и AdminStepController, удалены шаблоны tasks/create.blade.php и tasks/edit.blade.php. Карточка задачи показывает шаги, пришедшие с платформы («Шаги приходят с платформы задач»), ничего не редактируя на месте. Клиентские ТЗ (client_tasks) не затронуты.
  • Ложные пометки «нет на платформе» - 196 задач были помечены как отсутствующие на платформе, потому что синхронизация сверялась с ответами на отдельные запросы, а не с полным списком задач платформы. Такие задачи скрывались у клиента и попадали в отчёт об удалённых. Сверка теперь идёт по объединению известных идентификаторов (knownIds ∪ remoteTaskIds) в предпросмотре и в SyncManager при загрузке ответа задачи.
  • Команда tasks:reconcile-platform - Сверяет локальные синхро-задачи с платформой и показывает четыре группы: есть на платформе, нет на платформе, ошибочно помеченные, скрытый мусор без пометки. Режимы: --dry-run (только отчёт, по умолчанию), --restore (снять ложные пометки, вернуть видимость клиенту), --purge (удалить отсутствующие на платформе), --yes (без подтверждения), --project (один проект). Всё в одной транзакции с откатом при ошибке.
  • Удаление задачи чистит всё - Task::purgeWithRelations() удаляет задачу вместе со шагами, сообщениями и вложениями, включая файлы на приватном диске. Раньше удаление из контроллера трогало только запись в tasks, а файлы вложений оставались на диске. Этим же методом пользуются одиночное и массовое удаление мусора.
Почищено на TEST
  • Удалено 327 задач, которых нет на платформе - Тестовые задачи D-04…D-111, «Тестовая задача», «Тестовая задача E2E» и прочие; вместе с ними удалено 20 шагов. Скрытого мусора (нет на платформе, но без пометки) не оказалось — синхронизация пометила всё, что не нашла.
  • Возвращено 196 задач - Снята пометка «нет на платформе», включена видимость клиенту. Итог сверки: локальных синхро-задач 785, есть на платформе 785, нет на платформе 0, ошибочно помеченных 0.
  • Пересчитаны счётчики проектов - tasks_total/tasks_completed в 41 проекте совпадают с фактическим числом задач, расхождений 0.
  • Проверка целостности ссылок - Сирот нет в tasks.project_id, steps.task_id, task_messages.task_id, task_attachments.task_id, support_requests.task_id.
  • Бэкап - storage/app/private/my_ipd_local_before_task_purge_2026-10-01_142538.sql (24,5 МБ, проверен импортом в чистую базу my_ipd_restore_check).
Открыть версию →
v0.90.0 01.10.2026 MINOR
Настоящие даты закрытия задач и запрет пустых месячных писем
ТЗ 270 «Месячные письма приходят пустыми». Найдено две причины. Первая: экспорт платформы задач /api/export/full вообще не отдаёт дату закрытия задачи — синхронизация её никогда не заполняла, поэтому 667 закрытых задач оставались без даты, а отчётный период — это диапазон дат, и задача без даты не попадала ни в один месяц. Добавлена команда tasks:import-completion-dates, которая берёт completed_date из БД платформы напрямую (подключение task_platform) и сверяет задачи по внешнему идентификатору; на TEST проставлено 460 настоящих дат (162 за июль, 95 за август, 123 за сентябрь), снесено 60 выдуманных дат, поправлено 3. Вторая: пустое письмо всё равно уходило клиенту. Добавлен гейт наполнения — письмо, в котором нет ни задач, закрытых внутри отчётного месяца, ни задач в работе, не отправляется, а остаётся в черновиках с причиной; тело письма пересобирается по свежим данным проекта прямо перед постановкой в очередь, потому что буфер готовится за месяцы вперёд. Версия v0.90.0.
Почему письма были пустыми
  • Экспорт не отдаёт дату закрытия - В блоке «задачи» ответа /api/export/full (task.ipd 2.52.5) ключа даты закрытия нет, тогда как у проектов он есть. Синхронизация completed_at в my.ipd не заполнялась никогда: 667 закрытых задач оставались без даты, а месячный отчёт отбирает задачи по диапазону дат — задача без даты не попадает ни в один месяц.
  • Даты, выдуманные моделью - App\Models\Task при переходе в статус completed сам проставляет completed_at = now(). У задач, закрытых в MY IPD без даты с платформы, completed_at совпадал с updated_at — это отметка синхронизации, а не момент выполнения. Такие даты команда сносит, а даты, проставленные вручную (completed_at != updated_at), не трогает.
  • Пустое письмо уходило клиенту - Даже когда задач в периоде не было, месячное письмо всё равно попадало в очередь на отправку. На проде 01.10.2026 ушло 5 месячных писем, из них 4 содержали нули.
Что сделано
  • Команда tasks:import-completion-dates - Берёт настоящие completed_date из БД платформы напрямую (подключение task_platform в config/database.php, параметры TASK_PLATFORM_DB_* в .env). Сверяет задачи по tasks.external_id = платформа tasks.task_id. Опции: --project (один проект), --dry-run. Платформа — источник истины: есть дата — проставляем/исправляем, нет даты — сносим выдуманную (равную updated_at).
  • Даты ставятся поштучно по своим значениям - Задачи группируются по дате и обновляются отдельным UPDATE на каждую дату. Одним общим UPDATE всем ушла бы дата первой задачи — из-за такой ошибки первый прогон дал всем 397 задач 27.07.2026 и был откачен по бэкапу.
  • Гейт наполнения месячного письма - Новый сервис App\Services\Reports\ReportContentCheck считает наполнение по живым данным проекта: задачи, закрытые внутри периода, и задачи в работе, видимые клиенту. Если обе цифры нулевые — письмо не отправляется: mail:send-monthly кладёт его в черновик с причиной, email:send-prepared отменяет отправку, email:rebuild-monthly показывает «Пустых отчётов: N». Счётчики проекта (tasks_total, progress_pct) в проверке не участвуют — они устаревают и показывали нули при полном отчёте.
  • Письмо пересобирается перед отправкой - Буфер писем готовится на месяцы вперёд, и задачи клиента закрываются уже после сборки. Перед постановкой в очередь тело, тема и metadata письма пересобираются по свежим данным проекта (MonthlyDigestService::refresh), в metadata пишется content с числами закрытых и идущих в работу задач.
Что важно знать
  • Пустой отчёт — это нормальное состояние - Для будущих месяцев (ноябрь 2026 и далее) отчёт закономерно пуст: данных за отчётный месяц ещё нет. Письмо остаётся в буфере и наполнится, когда клиенту закроют задачи; отправка заблокирована только если к дате отправки наполнения так и не появится.
  • Задание платформы не менялось - Правки только в my.ipd. task.ipd не трогался: даты читаются из его локальной копии БД в режиме чтения.
  • Что сделано на TEST - Проставлено 460 дат закрытия: июль 2026 — 162, август — 95, сентябрь — 123; снесено 60 отметок синхронизации, исправлено 3. Месячные письма с 01.10.2026 по 01.03.2027 пересобраны (60 писем), в пересборке видно «закрыто N, в работе M» по каждому клиенту.
  • Бэкапы - Перед заливкой дат: storage/app/private/tasks_before_completion_dates_2026-10-01_101513.sql. Перед пересборкой месячных: storage/app/private/prepared_emails_monthly_before_rebuild_2026-10-01_082408.sql.
Открыть версию →
v0.89.0 01.10.2026 MINOR
Месячный отчёт — за предыдущий месяц, по одному письму на клиента
ТЗ 269 «Месячные письма называют не тот месяц». Генератор будущих писем email:generate-upcoming готовил месячный дайджест с датой отправки как отчётной: письмо, намеченное на 1 октября, называлось «Ваш проект — итоги за Октябрь 2026» ещё до начала октября, и список выполненных задач отбирался за неверный месяц. Сборка месячного письма вынесена в единый сервис MonthlyDigestService, где отчётный период всегда равен месяцу отправки минус один. Месячный отчёт — один на клиента и собирается по его текущему проекту (вместо письма на каждый активный проект), а требование активной подписки снято: получателем является любой клиент со статусом «В работе». Добавлена команда email:rebuild-monthly для пересборки буфера. На тестовом стенде пересобраны месячные письма с октября 2026 по март 2027 — 60 писем для 10 клиентов «в работе», каждое с подписью предыдущего месяца. Версия v0.89.0.
Что сделано
  • Правильный отчётный месяц - Отчётный период месячного письма считается как месяц отправки минус один: письмо на 1 октября подписывается «итоги за Сентябрь 2026» и собирает задачи, завершённые в сентябре. Раньше и генератор будущих писем, и список задач смотрели в месяц отправки.
  • Одно письмо на клиента - Месячный дайджест собирается по текущему проекту клиента (Client::resolveCurrentProject) и отправляется один раз в месяц. Раньше письмо создавалось на каждый активный проект — у клиента с 29 проектами это означало бы 29 писем в месяц.
  • Без требования подписки - Получателем месячного отчёта является любой клиент со статусом «В работе», у которого заполнен адрес и который не отписался от рассылки. Требование активной подписки (client_subscriptions) снято: письмо не должно зависеть от того, как заведён тариф.
  • Отчётный период в данных письма - В письмо пишутся metadata.report_period (тип, границы, подпись, ключ периода) и task_ids — буфер и предпросмотр показывают, за какой месяц и за какие задачи собрано письмо. Раньше это заполняла только команда mail:send-monthly.
  • Пересборка буфера - Добавлена команда email:rebuild-monthly (--from, --months, --dry-run): обновляет уже подготовленные месячные письма, создаёт недостающие, отменяет дубли и письма клиентам вне рассылки. Уже отправленные письма не трогаются.
Что важно знать
  • Пересобрано на TEST - Месячные письма с 01.10.2026 по 01.03.2027 (6 месяцев) пересобраны для 10 клиентов «в работе» (№ 5, 6, 18, 19, 23, 24, 27, 29, 32, 36) — по одному письму на клиента, все с подписью предыдущего месяца. Клиенты в корзине, на проверке и без активного проекта письма не получают.
  • Письма 1 сентября остаются историей - Шесть писем, отправленных 01.09.2026, оставлены без изменений: они уже ушли клиентам, переписывать историю нельзя.
  • Список выполненных зависит от дат задач - В отчёт попадают только задачи с заполненной датой завершения, попадающей в отчётный месяц. Задачи без даты завершения в отчёт не берутся — если у проекта не проставлены даты закрытия, месячный список выполненных будет пустым, и письмо об этом честно сообщает.
Открыть версию →
v0.88.0 01.10.2026 MINOR
Гейт получателя: буфер писем больше не пишет тем, кому писать нельзя
ТЗ 268 «На production уходят письма не тем клиентам». Найдена и устранена первопричина: команда email:send-prepared отправляла всё, что лежит в буфере со статусом queued, не проверяя текущий статус клиента — адрес в письме был снимком на момент подготовки, а не текущими данными клиента. Теперь перед отправкой проверяется, что клиент активен, имеет статус «В работе», не отписался от email-рассылки и что адрес письма всё ещё входит в список его адресов; иначе письмо снимается в статус «Отменено» с причиной в admin_notes и не отправляется. Генераторы месячных писем mail:send-monthly и email:generate-upcoming тоже переведены на Client::emailActive, поэтому клиентам в корзине и на проверке письма больше не создаются вовсе.
Что сделано
  • Проверка получателя при отправке - В email:send-prepared добавлена проверка получателя: письмо без клиента, со статусом клиента не «В работе», с is_active=false, с отказом от email-рассылки или с адресом to_email, которого больше нет среди адресов клиента (clients.email и clients.emails), снимается со статусом «Отменено». Причина отмены записывается в служебное поле письма и видна в админке.
  • Меньше лишних писем - mail:send-monthly и email:generate-upcoming выбирают клиентов через Client::emailActive — то есть «В работе», активные, не отписавшиеся и с заполненным адресом. Раньше месячные письма готовились в том числе клиентам в корзине и на проверке.
  • Покрытие - Добавлены 14 тестов: 9 на гейт отправки (включая отмену при удалённом клиенте и при адресе, вышедшем из списка) и 5 на генераторы (активный клиент получает письмо, корзина, проверка и отказ — не получают).
Что важно знать
  • Косается только получателя - Содержимое писем, отбор задач, отчёты за период и календарь отчётов не менялись: правка касается только того, кому письмо имеет право уйти.
  • Снятые письма не удаляются - Отменённое письмо остаётся в буфере со статусом «Отменено» и причиной — его видно в админке, при необходимости его можно вернуть в очередь вручную.
  • Пустые адреса - У клиента без единого адреса любое подготовленное письмо снимается: отправлять письмо, адрес которого не подтверждён ни одним адресом клиента, нельзя.
Открыть версию →
v0.87.0 30.09.2026 MINOR
Отчёты за период: только задачи, закрытые внутри него
ТЗ «Отчёты перестали повторять старые задачи». Список выполненных в отчётах больше не строится как «все completed, limit(5)»: добавлена дата закрытия задачи tasks.completed_at, которая проставляется в момент реального перехода в статус «выполнена». В письмо попадает только то, что закрыто внутри выбранного периода — недели, месяца, календарного сезона или года. Каждое отсеяние объясняется причиной, администратор видит состав отчёта в предпросмотре и может снять задачу вручную, а повторная отправка за тот же период больше не дублирует уже отправленные задачи. Версия v0.87.0.
Что сделано
  • Дата закрытия - В таблицу задач добавлено поле completed_at. Оно заполняется только в момент фактического перехода задачи в статус «выполнена», а не при каждом сохранении: иначе любая пересинхронизация старой задачи проставила бы ей сегодняшнее число и отчёт за тот период втянул бы чужую работу.
  • Отчётный период - Появился сервис периодов: неделя (пн–вс), месяц, календарный сезон (зима — декабрь–февраль через два года, весна — март–май, лето — июнь–август, осень — сентябрь–ноябрь) и год. Период письма хранится в его метаданных, поэтому пересборка и предпросмотр старого письма не «уезжают» на текущий период.
  • Прозрачный отбор - Новый отборщик возвращает и включённые задачи, и отсеянные с причиной: завершена вне периода, скрыта от клиента, нет задач на платформе, нет даты завершения, уже была в отправленном отчёте, снята вручную. Причина показывается и в CLI, и в предпросмотре в админке.
  • Ручное исключение - В предпросмотре «Итоги недели» появилась панель «Состав отчёта»: задачи с галочками уходят клиенту, снятая галочка сохраняется в письме и учитывается как при предпросмотре, так и при реальной отправке.
  • Защита от повторов - Уже отправленные за этот же период задачи не попадают в новое письмо повторно. Учитываются только реально отправленные письма, поэтому пересборка письма не исключает задачи по собственным же данным этого письма.
  • Команды - mail:send-reports получил параметры --period (week|month|season|year) и --at, а --dry-run теперь показывает состав отчёта с причинами отсечения. Месячное письмо 1-го числа подписывается итогами прошлого месяца: 1 октября — это итоги сентября.
Что важно знать
  • Старые закрытые задачи - Даты закрытия у них достоверно восстановить нельзя: в базе нет ни одного источника точной даты, а updated_at перезаписывается синхронизацией (все 605 закрытых задач лежат на 5 датах запусков синка). Автоматически проставлять им дату нельзя — весь бэклог попал бы в отчёт за сентябрь. Поэтому у них completed_at остаётся пустым: в отчёт они не попадают и видны в предпросмотре с причиной «Нет даты завершения».
  • Осознанное решение оператора - Новая команда tasks:assign-completed-at проставляет дату вручную: по конкретной дате или по концу периода, с ограничением по проекту и лимиту, с --dry-run.
Что не сломалось
  • Письма обновлений - Рассылка обновлений проекта (task_update) не менялась: она по-прежнему строится по событиям синхронизации.
  • Текущие в работе - Списки задач «в работе» и планы не фильтруются по периоду — период относится только к выполненным.
  • Календарь отчётов - Поиск писем в календаре «Итоги недели» теперь учитывает оба типа служебных писем (report и reports), поэтому плановые и фактические письма больше не теряются из списка.
Открыть версию →
v0.86.0 30.09.2026 MINOR
Изолированный просмотр письма в админке
ТЗ «Дизайн стилей при просмотре письма». Просмотр письма в /admin/emails/{id} переведён на изолированный рендер: содержимое письма отдаётся отдельным HTML-документом (iframe srcdoc на странице и полноценный standalone-документ по маршруту /admin/emails/{id}/preview), поэтому стили письма больше не протекают в админку (чёрный текст на чёмном фоне, белые кнопки с белым текстом), а стили админки не ломают письмо. Добавлена кнопка «Открыть письмо» — открывает письмо отдельным документом в новой вкладке. Версия v0.86.0.
Что сделано
  • Изоляция превью - В show.blade.php email больше не встраивается «сырым» HTML в админ-лейаут: он рендерится в iframe srcdoc как отдельный автономный документ. Стили письма и админки больше не пересекаются ни в одну сторону.
  • Отдельный просмотр - Добавлена кнопка «Открыть письмо»: письмо открывается полноценным standalone-документом по существовавшему, но не закрытому маршруту /admin/emails/{id}/preview (view admin.prepared-emails.preview теперь возвращает email напрямую, а не отсутствующий шаблон).
  • Общая логика рендера - Логика сборки email вынесена в приватный renderEmailHtml() и переиспользуется и на странице, и в маршруте preview; частичное тело (task_status без DOCTYPE) оборачивается в минимальный автономный документ.
Что не сломалось
  • Сами письма - Публичный preview (preview-public) и отправляемые тела не изменены; изолировано только отображение в админке.
  • Админка - Тема, кнопки и панели админ-интерфейса остаются в своих стилях при просмотре любого письма.
Открыть версию →
v0.85.3 30.09.2026 PATCH
Дозированная отправка писем на один ящик
ТЗ 263 «Дозированная отправка». Письма на один и тот же почтовый ящик (получатель ИЛИ BCC-копия администратору) теперь уходят с паузой по умолчанию 5 секунд (настраивается MAIL_SAME_RECIPIENT_INTERVAL), чтобы адресат не получил залп из десятков писем разом — типичный триггер спам-фильтров. Разным получателям письма отправляются сразу. Очередное письмо дожидается паузы только если в тот же ящик реально ушло предыдущее; пропущенные дубли и dry-run паузу не сбивают. Версия v0.85.3.
Что сделано
  • Интервал для одного ящика - В email:send-prepared добавлена дозировка: письма на один ящик (to_email или BCC админиистрации) отправляются с паузой по умолчанию 5 секунд (ключа MAIL_SAME_RECIPIENT_INTERVAL в .env). Ранее ящик с 30–70 письмами (например, 43 обновления для info@ipd.by + копии администратору) получал всё одним залпом.
Что не сломалось
  • Разные получатели - Письма разным клиентам отправляются без задержки; пауза считается только для совпадающих ящиков.
  • Дубли и dry-run - Пропущенные дубли и режим --dry-run не влияют на дозировку.
Открыть версию →
v0.85.2 30.09.2026 PATCH
Обновления проекта — полные карточки задач и обращение «Отец Николай»
ТЗ 262 «Обновления проекта как 5468». Все queued/draft письма «Обновление проекта» (62 письма, № 5552–5613) пересобраны по архитектуре эталона 5468: изменения сгруппированы по задачам, каждая задача показана полной карточкой (чип статуса, прогресс-бар, даты «Задача поставлена / Планируем завершить», этапы с галочками, описание), события — бейджами с датами. Обращение к духовным лицам («Отец Николай», «Отец Досифей») больше не усекается до «Отец» — greeting в письмах «Здравствуйте, отец Николай!». Месячные письма отца Николая (6 писем, № 5409–5414 на октябрь 2026 – март 2027) пересобраны с новым обращением. Версия v0.85.2.
Что сделано
  • Карточки задач в обновлениях - 62 queued/draft письма «Обновление проекта» пересобраны: события восстановлены из уведомлений клиента (группировка по минуте создания), изменения сгруппированы по задачам, каждая задача рендерится полной карточкой EmailTaskCards (статус, прогресс, даты, этапы, описание) с бейджами событий («Новая задача», «Выполнен шаг», «Статус задачи изменён»).
  • Обращение к духовным лицам - Client::first_name больше не усекает «Отец Николай» до «Отец»: для имён с титулом «Отец»/«Батюшка» возвращается полное имя, greeting — «Здравствуйте, отец Николай!».
  • Месячные письма отца Николая - 6 месячных дайджестов клиента 23 (№ 5409–5414) пересобраны с новым обращением на все запланированные месяцы.
Что не сломалось
  • Обычные клиенты - Для имён без титула по-прежнему используется первое слово («Егор Савинский» → «Егор»).
  • Отправленные письма - Уже отправленные письма не изменялись.
Открыть версию →
v0.85.1 30.09.2026 PATCH
Месячные дайджесты пересобраны в цветных карточках с обращением по имени
ТЗ 261 «Месячные письма как 5468». Queued месячные дайджесты (24 письма на 01.10.2026–01.03.2027) пересобраны по архитектуре эталона 5468: вместо плоских зелёных блоков задачи рендерятся карточками со чипом статуса, прогресс-баром, датами «Задача поставлена / Планируем завершить» и описанием. Обращение в письме теперь по имени («Здравствуйте, Егор!»), а не по ФИО. Синхронизирован БД-шаблон monthly-digest с богатым телом; отправленные сентябрьские письма не тронуты. Удалены 6 дублей-копий старого шаблона и 3 устаревших черновика. Письма Марины Лакатун (клиент 24) перенаправлены с удалённого проекта «Ришелье стиль» (355) на актуальный проект 371; месячные письма клиентов Татьяны (25) и Любови (26), исключённых из рассылки, удалены. Версия v0.85.1.
Что сделано
  • Карточки задач в месячных письмах - 24 queued месячных дайджеста на 01.10.2026–01.03.2027 пересобраны через MonthlyEmailRenderer: задачи рендерятся цветными карточками со чипом статуса («Выполнена», «В работе»), прогресс-баром, датами постановки и завершения и описанием. Шаблон monthly-digest в БД синхронизирован с богатым телом.
  • Обращение по имени - Письма начинаются с «Здравствуйте, Егор!» вместо «Здравствуйте, Егор Савинский!»: получатель подставляется из Client::address_name (первое слово имени).
  • Уборка очереди - Удалены 6 дублей месячных писем Егора (5455–5458, 5460–5461, старый короткий формат) и 3 устаревших черновика (5369, 5371, 5372).
  • Клиенты «Ришелье стиль» - Письма Марины Лакатун (клиент 24) перепривязаны с удалённого проекта 355 на актуальный проект 371 и пересобраны; месячные письма Татьяны (25) и Любови (26), больше не включённых в рассылку, удалены.
Что не сломалось
  • Отправленные письма - Сентябрьские месячные дайджесты со статусом sent (5373, 5380, 5387, 5394, 5408, 5415) не изменены.
  • Другие типы писем - Шаблоны недельных и изменений проекта не затронуты.
Открыть версию →
v0.85.0 30.09.2026 MINOR
Несколько email у человека: основной и дополнительные
ТЗ 260 «Несколько email». У человека на платформе задач может быть несколько email — один основной. Кнопка «Синхронизировать с платформы задач» привела email клиента и список всех его адресов к данным платформы: основной email (по нему уходят письма и идёт вход в кабинет) обновляется у той же записи, а полный список хранится в новой колонке clients.emails и виден в карточке пользователя (основной — с бейджем «основной»). История писем при смене ящика не теряется: она хранится по client_id и фактическому адресу в prepared_emails.to_email / mail_logs, поэтому старые отправленные письма остаются у старого ящика, а новые уходят на новый. Письма Егора Савинского (16 писем в очереди и черновиках) переадресованы на новый основной ящик esav2@yandex.ru. Версия v0.85.0.
Что сделано
  • Полный список адресов - Новая колонка clients.emails (JSON): основной email живет в clients.email (вход, верификация, адресация писем), остальные адреса подтягиваются с платформы задач и хранятся списком. Дубликаты по регистру отбрасываются, основной адрес всегда первый.
  • Синхронизация контактов кнопкой - Кнопка на карточке пользователя обновляет email и список адресов до импорта проектов: у проектов платформы задач есть только «человек_почта» (внешнего id человека на проекте нет), поэтому проект человека связывается с клиентом по актуальному email. В сообщении об успехе появилась строка «Email обновлён: … → …». Телефон и Telegram больше не затираются пустыми значениями, когда платформа их не прислала.
  • Карточка пользователя - В /admin/users/{id} основной email показан с бейджем «основной», дополнительные адреса — списком; текст кнопки «Синхронизировать с платформы задач» и подтверждение теперь упоминают контакты.
  • Переадресация писем Егора - 16 писем в очереди и черновиках (клиент 5, Егор Савинский) переписаны на новый основной ящик esav2@yandex.ru; отправленные письма остались в истории у старого ящика (egor@jetpeel.club).
Что не сломалось
  • Вход в кабинет - Пароль и email_verified_at при синхронизации не трогаются, вход не зависит от смены ящика.
  • История писем - Старые письма остались видны в карточке клиента: фильтр идёт по client_id, а фактический адрес хранится в prepared_emails.to_email / mail_logs.
Открыть версию →
v0.84.0 29.09.2026 MINOR
Письма снова в зелёных плашках: статусы вернулись к эталону 5468
ТЗ 259 «Письма как 5468». В обновлении 0.77.2 (ТЗ 247) письма-уведомления о задачах посерели: зелёные плашки «выполнено», цвета статусов и синий призыв заменили на нейтральный серый, и письмо слилось в один безликий блок. Вернули цветную архитектуру эталона 5468 и распространили её на письма, которые готовились к отправке. Статусы задач, галочка «выполнено», блок «Обслуживание и поддержка», регламент и кнопка личного кабинета снова цветные. Вступительный текст письма стал зависеть от проекта: у проекта «Медтехника Гродно» — прежний текст, у остальных — общий. Писем, лежащих в очереди отправки, это касается напрямую: их тела пересобраны по новой архитектуре. Автотест проверяет, что в шаблонах писем статусы не серые, а цветные (эталон 15/15).
Что сделано
  • Цветные статусы и галочки - В письме «Статус задач» и в «Изменениях проекта» восстановлены зелёные плашки выполненных задач и шагов (#16a34a), синий призыв к действию (#1d4ed8), плашки статусов (в работе — синяя, выполнено — зелёная, ожидает — янтарная, запланировано — серая-тёплая). Серый фолбэк #334155 из шаблонов убран.
  • Блоки поддержки и регламента - Блок «Обслуживание и поддержка» — на том же зелёном фоне (#f0fdf4), что и на странице SLA; регламент поддержки — в синем блоке (#eff6ff) со ссылкой calc.ipd.by/sla. Кнопка «Открыть личный кабинет» снова синяя (#1d4ed8).
  • Письма в очереди пересобраны - 62 письма «Изменения проекта» (task_update), готовящиеся к отправке, переотрисованы новой архитектурой: события реконструированы из уведомлений клиента, число изменений в каждом письме совпадает с темой. Письма-эталон «Статус задач» (5268) не тронуты.
  • Вступление зависит от проекта - defaultIntro() теперь получает проект: для «Медтехника Гродно» сохранён прежний текст, для остальных проектов — общий вступительный текст с именем проекта.
Что не сломалось
  • Контраст кнопок в админке - Исправление 0.83.1 (ТЗ 258) не затронуто: письма — это отдельные вёрстка и токены, кнопки в административном интерфейсе остались читаемыми.
  • Предпросмотр и правки текста - Поле «Вступительный текст» (ТЗ 178) продолжает работать: свой вступление остаётся как введено.
Открыть версию →
v0.83.1 29.09.2026 PATCH
Кнопки и плашки, которые перестали «светиться белым по белому»
ТЗ 258 «Контраст кнопок». Кнопки «Новое письмо», «Найти», «Сохранить», «У нас / У клиента» и им подобные на светлой теме выглядели как серые прямоугольники, а надпись на них не читалась: белая надпись лежала на светлой заливке. Причина была одна и системная — заливка кнопки бралась из токена темы, который в тёмной теме тёмный, а в светлой — светлый, и надпись на нём всегда оставалась белой. Вместо «цвет под текущую тему» появились отдельные токены заливки: --btn-solid, --btn-solid-hover и --on-btn-solid. Они одинаковы в тёмной и светлой темах, поэтому надпись читается в обеих (контраст от 6:1). Попутно та же правка убрала такие же белые надписи на зелёных и красных ховер-состояниях Telegram-виджета и формы «Оставить заявку», на аватарах, на бейдже непрочитанных уведомлений, на тостах, на кнопке закрытия в просмотре версий и на кнопке в письме-напоминании. Кнопки действий в разметке переведены с inline-стилей на классы btn btn-primary / btn-sm. Эталон тестов 321 passed, эталон сборки vite build.
Что сделано
  • Отдельные токены заливки кнопок - --btn-solid / --btn-solid-hover / --on-btn-solid заданы в тёмной теме, в светлой теме и в фолбэке по системной теме. Кнопка, плашка, аватар и тост больше не берут заливку из --accent, который меняет полярность вместе с темой, и больше не зависят от «цветного» токена как от фона под белым текстом.
  • Кнопки действий на классах - «Новое письмо» и «Найти» в /admin/emails, «Сохранить» в письмах, настройках, профиле, безопасности, шаблонах писем, KPI и расписании, «Настроить» у получателей уведомлений, «Все письма» в напоминаниях, «Изменить пароль», переход в тарифы — переведены с inline-стилей на btn btn-primary / btn-sm.
  • Убраны белые надписи на цветном - Ховеры Telegram-виджета и формы «Оставить заявку» (включая зелёный WhatsApp), аватары в шапке и у получателей, бейдж непрочитанных, тосты (успех/ошибка/информация), кнопка закрытия в просмотре версий, переключатель «Мяч у нас / У клиента» — теперь используют токены заливки. Заодно добавлены в фолбэк темы недостающие --accent-solid, --danger-solid и --success-solid, из-за чего кнопки теряли заливку, если тему выбирала система, а не человек.
  • Письмо и превью - Кнопка в письме-напоминании о статусе мяча и дата в превью письма в админке переведены на нейтральный тёмный фон с читаемой надписью.
Что не сломалось
  • Цвета статусов - Красный, жёлтый и синий не тронуты: сигнал остался сигналом, а «статус» нигде не стал зелёным.
  • Вид кнопок - Заливка и рамка в обеих темах те же, что были (тёмно-серый #475569, наведение #334155), меняется только источник цвета.
Открыть версию →
v0.83.0 29.09.2026 MINOR
Пользователи: постоянные адреса разделов и «В работе» по умолчанию
ТЗ 257 «Пользователи, ссылки». Слева в меню было одно слово «Пользователи», и по нему открывался общий список всех людей: сначала нужно было догадаться, где сейчас тот, с кем мы работаем, а потом ещё переключиться на нужную вкладку. Теперь у каждого состояния свой постоянный адрес: /admin/users — люди, с кем работаем сейчас, /admin/users/review — на проверке, /admin/users/trash — в корзине, /admin/users/deleted — удалённые, /admin/users/all — все вместе (нужен редко, для сплошной проверки, поэтому стоит последним и тихим). Вкладки «?bucket=…» заменены адресами, поэтому внутрь любого раздела можно добавлять под-страницы, а ссылку можно отправить другому человеку — она всегда откроет то же самое. Старые ссылки с вопросиком не сломаны: такой адрес один раз переводит на постоянный и дальше живёт по нему. Версия v0.83.0.
Что сделано
  • «Пользователи» открывает тех, с кем работаем - Вход в раздел по умолчанию — вкладка «В работе» (/admin/users). Порядок вкладок повторяет жизнь человека: В работе → На проверке → В корзине → Удалённые, а «Все» — последняя, через разделитель и приглушённая: это сплошной список, в который заглядывают раз в месяц.
  • Постоянные адреса вместо вопросика - /admin/users/review, /admin/users/trash, /admin/users/deleted, /admin/users/all. Внутрь адреса можно дописывать под-страницы (например /admin/users/active/import), поэтому развивать раздел дальше можно, не переделывая ссылки. Неизвестное состояние в адресе — честная 404, а не молчаливый показ «В работе».
  • Старые ссылки не теряются - Адрес вида /admin/users?bucket=review один раз переводит на постоянный /admin/users/review и дальше человек живёт по нему; фильтры и поиск при этом сохраняются.
  • Раздел отвечает на вопрос, а не на настроение - Заголовок страницы называет раздел словами («Пользователи», «Пользователи · на проверке», «Все пользователи»), счётчики вкладок остались, у каждой вкладки подписьtitle объясняет, что это за состояние, а у пункта меню — подсказка с адресами разделов.
Открыть версию →
v0.82.0 29.09.2026 MINOR
Корзина пользователей: «На проверке», «В корзине», «Удалённые»
ТЗ 256 «Корзина пользователей». У человека был один переключатель «Активен/Неактивен»: выключенный пользователь просто исчезал из рассылок, но оставался в общем списке без следа, почему его больше нет, и без возможности вернуть его в работу. Теперь у пользователя отдельный статус-корзина из четырёх состояний: «В работе» → «На проверке» → «В корзине» → «Удалённые», и каждое состояние возвращается в работу одним действием. Статус не пересекается с переключателем «Вход» (is_active): статус решает, отправляем ли мы человеку письма и отчёты, а «Вход» — пускаем ли мы его в личный кабинет. На странице пользователей появились вкладки с постоянными счётчиками («Все · N / В работе · N / На проверке · N / В корзине · N / Удалённые · N»), отдельная колонка «Статус» с бейджем и новые пункты кебаб-меню: «На проверку», «В корзину», «Вернуть в работу», «Восстановить», «Удалить навсегда». «Удалить» стало мягким: запись уходит в «Удалённые» вместе со своими проектами и письмами, её можно восстановить; «Удалить навсегда» доступно только оттуда и вычищает связанные данные. Письма и отчёты не отправляются всем, кто вне «В работе»: гейт стоит в scopeEmailActive, в подборке получателей кампаний, массовых уведомлений, недельных отчётов и статусов задач, а вход закрыт в логине, смене аккаунта, автовходе и восстановлении пароля. Версия v0.82.0, эталон тестов 312 passed.
Что сделано
  • Статус у пользователя - Новая колонка clients.status (active / review / trash / deleted, по умолчанию active) и константы Client::STATUS_*. Хелперы: isOperational() — «в работе», статус-подпись «В работе / На проверке / В корзине / Удалён». Статус независим от is_active: один закрывает письма, другой — вход.
  • Вкладки на странице пользователей - /admin/users: вкладки с живыми счётчиками («Все», «В работе», «На проверке», «В корзине», «Удалённые»), вкладка «Все» скрывает удалённых, фильтры и сортировка работают внутри вкладки, сортировка добавлена по статусу. Бывший фильтр «Статус» переименован в «Вход» (Открыт/Закрыт) — чтобы «статус» значил одно.
  • Кебаб-меню по статусу - «На проверку» и «В корзину» — у человека в работе; «Вернуть в работу» и «На проверку» — в корзине; «Восстановить» и «Удалить навсегда» — в удалённых. «Войти как» показывается только для людей в работе.
  • Мягкое удаление - «Удалить» переводит запись в «Удалённые» (данные, проекты и письма сохраняются), оттуда — «Восстановить» или «Удалить навсегда» с вычисткой связанных записей. Обе операции пишутся в журнал действий.
  • Письма и вход - Гейт статуса добавлен туда, где выбираются клиенты: scopeEmailActive, получатели кампаний (всех типов) и массовые уведомления, недельные отчёты и статусы задач. Вход закрыт в логине, восстановлении пароля, смене аккаунта и автовходе по устройству; NextStepService подсказывает администратору, что человек вне работы, и ведёт на нужную вкладку.
Открыть версию →
v0.81.0 28.09.2026 MINOR
Вкладки в форме пользователя: редактирование без простыни
ТЗ 255 «Вкладки». Форма редактирования пользователя собирала все поля в одну простыню: постоянные данные (имя, обращение, email, компания, телефон, Telegram, подтверждения контактов) и то, что правится постоянно (роль, проекты, доступ к платформам), были на одном экране — человек прокручивал десятки полей, чтобы добраться до нужного. Форма разбита на вкладки одного экрана по образцу платформы задач (task.ipd project-edit / person-edit) и встроенной страницы проекта: «Основная информация», «Настройки», «Проекты», «Платформы». Один экран, одна форма и одна кнопка «Сохранить»: вкладки только группируют поля, маршрут обновления не изменился, внизу панель «Сохранить/Отмена/Безопасность» с подсказкой «Все вкладки — одна форма: данные сохраняются одной кнопкой». Кебаб-меню платформы научилось открываться от края окна: кнопка внизу (низ карточки пользователя) раскрывает меню вверх, а не за край экрана, у левого края — вправо, у правого — влево; авто-направление — `positionKebabMenu()` в `toggleKebab()` (`layouts/app.blade.php`). Правило зафиксировано в методологии: «03 Стиль интерфейса» раздел 7.1 (длинные формы — вкладки) и 5.1 (открытие кебаб-меню), «02 Правила разработки» — блоки проверки. Эталон тестов 305 passed.
Что сделано
  • Вкладки в редактировании пользователя - /admin/users/{id}/edit стал одним экраном с четырьмя вкладками на штатных классах .tabs/.tab-btn/.tab-panel (те же, что у проекта): Основная информация / Настройки / Проекты / Платформы. Переключение — JS по data-tab, активная по умолчанию — «Основная информация».
  • Группировка по смыслу работы - Постоянные данные, которые записывают один раз и редко трогают (имя, обращение, email, компания, телефон, Telegram, подтверждения контактов), — первая вкладка; служебное (роль, пароль, связь личного кабинета, активность) — «Настройки»; «над чем работают постоянно» (проекты-владелец, проекты-доступ, платформы-доступ) — отдельные вкладки.
  • Методология - В «03 Стиль интерфейса» добавлен раздел 7.1 «Много полей — вкладки одного экрана»: полей больше 4–5 — не простыня, а вкладки; один экран, одна форма, одна кнопка сохранения; вкладки не создают новых URL; группировка по смыслу. В «02 Правила разработки» — блок «Длинные формы — вкладки одного экрана» с проверкой DesignSystemRenderTest (data-tab на странице пользователя) и view:cache.
Открыть версию →
v0.80.1 28.09.2026 PATCH
Мусорные проекты убраны: откуда они взялись и почему не вернутся
ТЗ 254 «Локальные проекты». Найдена причина, по которой в списке проектов появлялись пустые строки с бейджем «Локальный»: их создавал сам DatabaseSeeder — при каждом запуске `php artisan db:seed`, то есть при каждой смене версии платформы, он вставлял пять проектов-шаблонов каждому клиенту без проверок. Один запуск 25.09.2026 в 20:40:16 дал 93 проекта с нулём задач, нулём участников и нулём писем, а заодно привязал четыре демо-токена к пустым проектам. Демо-данные вынесены в отдельный DemoSeeder, который запускается только на пустой базе и больше не вызывается при смене версии; учётная запись администратора больше не переписывается (пароль не сбрасывается, дата создания не затирается). Из базы удалены 93 мусорных проекта и 4 демо-клиента вместе с их токенами.
Что было
  • Источник мусора - DatabaseSeeder::seedProjects() вставлял пять проектов-шаблонов («Разработка сайта», «SEO-продвижение», «Мобильное приложение», «Техподдержка», «Дизайн-проект») каждому клиенту, кроме администратора, без проверки на повтор. Штатная процедура смены версии платформы требует `php artisan db:seed`, поэтому мусор появлялся сам, без участия человека. Доказательство: у всех 93 проектов одна и та же дата created_at 2026-09-25 20:40:16, и в ту же секунду в versions появилась запись 0.77.1.
  • Что было на самом деле - Из 135 проектов 41 имел external_id (настоящие, с платформы задач), 1 был локальным, но настоящим («Ришелье стиль», 22.08.2026, 3 участника, 123 письма, папка Total Commander), и 93 были пустыми заготовками.
  • Откуда взялись «непонятные люди» - Иван Петров (client@ipd.by), Тестовый Пользователь (test@ipd.by) и Демо Клиент (demo@ipd.by) создавались ClientSeeder, а Тестовый Клиент (client@project.ipd.test, 29.07.2026) был заведён вручную. Тестовый Пользователь — единственный с ролью test.
Что изменено в коде
  • DemoSeeder - Новый сидер database/seeders/DemoSeeder.php: три демо-клиента, пять проектов-шаблонов на каждого и токены. DatabaseSeeder его не вызывает. Запуск только на пустой базе: если в projects есть хоть одна строка или в clients есть хоть один не-администратор, сидер бросает RuntimeException с объяснением.
  • DatabaseSeeder - Вызывает только идемпотентные сидеры: TariffSeeder, ClientSeeder, ClientTaskTemplateSeeder, VersionSeeder. Методы seedProjects() и seedProjectTokens() удалены.
  • ClientSeeder - Осталась только учётная запись администратора и её токен. Создаёт их, только если их нет: повторный запуск больше не переписывает created_at и не сбрасывает пароль на admin123 (раньше updateOrInsert делал именно это при каждой смене версии).
  • Версия - v0.80.1 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
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).
Открыть версию →
v0.79.0 27.09.2026 MINOR
Проекты клиента: отдельная страница с источником каждого проекта и отключением лишних
ТЗ 250 «Проекты клиента». Список проектов человека вынесен с карточки пользователя на отдельную страницу /admin/users/{id}/projects и отвечает на вопрос «почему их восемь, если проект один». Для каждого проекта видно, откуда он: пришёл с платформы задач (с её ID и датой синхронизации) или создан вручную в my.ipd, роль человека (владелец или участник), статус, дата добавления и реальное число задач. Отдельный блок «Откуда взялись проекты» объясняет состав портфеля цифрами, а проекты без задач и без связи с платформой помечаются как «Без задач», а созданные в одну секунду одинаковыми заходами у разных клиентов — как «Массовое добавление». Лишний проект можно отключить одним действием из меню «⋮»: он уходит в архив, перестаёт быть активным и попадать в отчёты и письма, но задачи и история остаются на месте, а действие обратимо.
Что сделано
  • Отдельная страница - Новая страница /admin/users/{id}/projects (маршрут admin.users.projects, Admin\AdminUserController@projects, вьюха resources/views/admin/users/projects.blade.php) со своим адресом: сводка, объяснение состава, фильтр по разделам «Все / Активные / Отключённые и закрытые», таблица проектов и действия в кебаб-меню. Карточка «Проекты (всего)» на странице пользователя стала ссылкой на неё, в разделе «Проекты» вместо таблицы — кнопки «Все проекты клиента» и «Проверить проекты на платформе задач».
  • Откуда взялся каждый проект - Новая функция ClientPortfolioService::explainPortfolio() разбирает портфель человека: источник (external_id платформы задач с датой синхронизации или ручное создание с датой добавления), роль (владелец/участник), статус, прогресс, дата завершения, реальное число задач одним сгруппированным запросом и число «пустых» проектов. Массовое добавление определяется по одинаковой секунде created_at: если в эту секунду появились такие же проекты (в том числе у других клиентов) — проект помечается как массовый, с указанием, сколько их было.
  • Почему список длиннее, чем кажется - На странице сводка (всего, активных, отключённых и закрытых, с платформы задач, создано вручную, без задач) и блок «Откуда взялись проекты» с пояснением по каждой группе. На тестовом стенде это объяснило клиента №5: 3 проекта с платформы задач (Бобер Боб, Mysteria, Алексей Гапеев) и 5 созданных вручную 25.09.2026 в 20:40 одним заходом вместе с такими же проектами 19 других клиентов (всего 95 штук) — пустые, без задач.
  • Управление проектом - Отключение и возврат в работу одним действием из кебаб-меню строки (POST /admin/users/{id}/projects/{projectId}/status, admin.users.projects.status): отключение ставит статус archived, возврат — active. Проект не удаляется: задачи, история и карточка остаются. Действие пишется в журнал (user_project_disabled / user_project_enabled). Защиты: нельзя отключить текущий проект и нельзя отключить последний активный проект человека — сначала нужно выбрать другой текущий проект; нельзя отключить проект, который человеку не принадлежит.
  • Проверка - Новый тест tests/Feature/ClientProjectsPageTest.php — 13 проверок: свой адрес и состав списка, источники и ID платформы, пометки «Без задач» и «Массовое добавление», фильтр разделов, отключение и возврат с журналом, защита текущего проекта (выбранного и выбранного автоматически), защита последнего активного, чужой проект, ссылка со страницы пользователя, рендер без проектов и завершённого проекта. Существующий тест ClientPortfolioFeatureTest переведён на новую страницу. Полный прогон: 267 тестов (1559 проверок), сборка CSS и php artisan view:cache — без ошибок.
  • Версия - Текущая версия платформы: v0.79.0 (.env, .env.example, config/app.php, VersionSeeder, README.md, DESIGN_SYSTEM.md).
Открыть версию →
v0.78.0 26.09.2026 MINOR
ИИ-агент под управлением: переключатель, шестерёнка и статистика
ТЗ 249 «Спросить у ИИ — настройка показа». ИИ-агент стал управляемым: администратор может одним переключателем показать или скрыть его для всей платформы и отдельно — для любого пользователя, а сам пользователь решает, видеть ли агента в своём кабинете. В заголовке окна агента появилась шестерёнка, которая ведёт прямо в настройки. Каждое открытие агента теперь записывается, и администратор видит статистику: сколько раз открывали окно, за 7 и 30 дней, сколько человек пользуются агентом, сколько у них просмотров страниц, а также самые популярные страницы, с которых открывали агента.
Что сделано
  • Общая логика - Создан сервис app/Services/AiAgentService.php — единая точка правды о видимости агента: глобальный флаг в platform_settings (ai_agent_enabled, по умолчанию включён), персональный флаг в clients (ai_agent_enabled), запись каждого изменения в settings_history и адрес страницы настроек для администратора и пользователя. Виджет в resources/views/layouts/app.blade.php подключается только если агент разрешён глобально и лично.
  • Переключатели - В админке появилась вкладка «ИИ-агент» (/admin/settings/ai-agent) с общим переключателем «Показывать ИИ-агента на платформе» и таблицей пользователей, где у каждого есть свой переключатель. В кабинете человека появилась страница /settings/ai-agent с переключателем «Показывать мне ИИ-агента» и личной статистикой.
  • Шестерёнка в окне агента - В заголовке всплывающего окна ИИ-агента добавлена кнопка-шестерёнка (id=chatSettingsBtn) рядом с крестиком: администратору она ведёт в /admin/settings/ai-agent, пользователю — в /settings/ai-agent. Если агент скрыт, окна нет, а значит нет и кнопки.
  • Логирование - Каждое открытие окна агента записывается как действие пользователя с типом ai_agent_open — вместе со страницей, с которой открыли, и её названием; заодно обновляются число открытий и время последнего открытия сессии агента. Само событие открытия больше не засчитывается как просмотр страницы: посещаемость остаётся в существующих счётчиках page_view.
  • Статистика - Администратор на вкладке «ИИ-агент» видит: число открытий (всего, за 7 и 30 дней), сколько человек пользуются агентом, просмотры страниц пользователей (всего и за 7 дней), число сессий агента, сообщений и заявок, а также самые популярные страницы, с которых открывали агента. В карточке пользователя в админке — статус агента, число открытий, просмотров и последнее открытие со ссылкой на настройки. Пользователь на своей странице видит свои открытия, просмотры и последнее открытие.
  • Миграция и проверка - Миграция 2026_09_26_100000_add_ai_agent_settings_to_clients_table.php добавляет clients.ai_agent_enabled, ai_agent_sessions.client_id, open_count и last_open_at. Новый тест tests/Feature/AiAgentVisibilityTest.php — 9 проверок (видимость по глобальному и личному флагам, переключатели пользователя и администратора, логирование открытия, статистика, порядок истории настроек). Полный прогон тестов, сборка CSS и php artisan view:cache — без ошибок.
  • Версия - Текущая версия платформы: v0.78.0 (.env, .env.example, config/app.php, VersionSeeder, README.md, DESIGN_SYSTEM.md).
Открыть версию →
v0.77.3 26.09.2026 MINOR
Удаление — в меню действий: явных красных кнопок больше нет
ТЗ 248 «Меню, а не красная кнопка». Все разрушительные и редкие опасные действия на платформе — удаление, безвозвратное удаление, снятие и открепление, отзыв токена, ключа и ссылки, отмена отправки, отклонение заявки, завершение сессий, массовое удаление — перенесены в вертикальное кебаб-меню «⋮». Явных красных кнопок удаления в ленте не осталось: красный цвет остался только у пункта скрытого меню, где действие подтверждается дополнительным вопросом. Частые и безопасные действия (сохранить, редактировать, подробнее, одобрить, восстановить, отправить сейчас) остались обычными кнопками. Попутно устранены самодельные меню и вложенная форма тестовой отправки кампании.
Что сделано
  • Общее меню действий - Создан общий blade-компонент resources/views/components/kebab-menu.blade.php (вертикальная иконка «⋮», props title/align/class/style, слот пунктов). Все меню на платформе переведены на него: кнопка, форма и разделитель внутри пункта, красный — только у пункта danger.
  • Перенесено в кебаб - Удаление и отзыв: карточка проекта, карточка человека, карточка письма, письма и рассылки, кампании, задачи и платформенные задачи, тарифы, заявки на тарифы, платформы, пользователи, настройки (API-ключи), расписание писем, ссылка проекта в кабинете человека. Отмена отправки кампании и письма, завершение сессий и очистка устройств пользователя, отклонение заявки на тариф, массовое удаление писем и осиротевших задач.
  • Что осталось видимым - Сохранить, редактировать, подробнее, одобрить, восстановить, отправить сейчас, отправить тест, показать/скрыть, копировать, пересобрать, включить/выключить, активировать ключ. Форма строк инструкций и поддержки в карточке проекта — нейтральная кнопка без красной заливки.
  • Попутные правки - Перестал работать псевдокебаб в списке писем — заменён общим компонентом. Самодельное меню расписаний (sc-kebab) заменено общим компонентом, его CSS удалён. Убрана вложенная форма тестовой отправки кампании: форма вынесена из основной, кнопка и поле связаны атрибутом form. Удалён неиспользуемый стиль .kebab-menu__note с 13px. Кнопка выхода из всех аккаунтов на странице входа стала нейтральной, как на втором её варианте.
  • Методология - В «03 Стиль интерфейса» раздел 5.1: разрушительные действия — только в кебаб-меню, красный только у пункта меню, безопасные действия не прячутся, опасная зона не используется, вложенные формы запрещены. В «02 Правила разработки» и «04 Темы и дизайн» — проверки, таблица красного и запрет самодельных меню. Версия методологии 1.6.0.
  • Проверка - Новый регрессионный тест tests/Feature/DestructiveActionsInKebabTest.php: 4 проверки (нет вложенных форм, разрушительное действие оформлено пунктом кебаб-меню, нет явных красных кнопок удаления, наличие компонента и его стилей). Полный прогон: 245 тестов, сборка CSS и php artisan view:cache — без ошибок.
  • Версия - Текущая версия платформы: v0.77.3 (.env, .env.example, config/app.php, VersionSeeder, README.md, DESIGN_SYSTEM.md).
Открыть версию →
v0.77.2 25.09.2026 MINOR
Серый вместо зелёного: статусы и сообщения об успехе
ТЗ 247 «Цвет, span». Информационные статусы и сообщения об успехе переведены из зелёного в нейтральный серый: зелёные токены дизайн-системы (--green, --green-soft, --success, --success-bg, --success-solid) заменены на серые, бейджи «зелёный/жёлтый» заменены на серые, состояния «в работе», «готово», «отправлено», «в очереди», «сохранено», «проверено» во всех разделах админки, кабинета человека, гостя, мастеров синхронизации и во всех письмах стали серыми. Красный сохранён для проблем, просрочек, запретов и потерь; жёлтый — только для реального внимания и срочности; синий — для ссылок, бренда и информационных категорий. Категорийные и фирменные цвета (стадии проекта, типы событий, типы писем, источники данных, диаграммы) сохранены. Светофор в блоке «Следующий шаг» не изменялся.
Что сделано
  • Токены дизайн-системы - В resources/css/app.css токены --green/--green-soft/--success/--success-bg/--success-solid переведены на нейтральные значения (тёмная тема #cbd5e1 / rgba(203,213,225,.14) / #334155, светлая #475569 / rgba(71,85,105,.12)). Обе темы и все токены статусов на страницах обесцвечены одной правкой; --red, --warning, --link, --accent не тронуты.
  • Бейджи и статусы - Классы badge-green и badge-yellow заменены на badge-gray; variant="green|yellow" заменён на variant="gray"; динамические карты статусных цветов (Project, ClientSubscription, ClientTariffRequest, ProjectEvent, TaskStatusDispatcher) переведены на серый. Убраны оставшиеся «зелёные» подписи: «сохранено», «отправлено», «в очереди», «доставлено», «открыто», «кликнуто», «проверено», «создано», «обновлено», «готово».
  • Разделы - Админка: сводка, проекты (список/карточка/статусы/источники), пользователи (карточка, безопасность, email, платформенные проекты), письма (список, карточка, шаблоны, превью, отчёты, календарь, подготовленные письма), кампании, задачи, синхронизация (сводка и 4 мастера), расписание, платформы, тарифы, токены, настройки, журналы, уведомления. Кабинет человека: письма, тариф, настройки. Гость: страница проекта. Общие компоненты: переключатели, флеш-сообщения, тосты.
  • Письма - Все 10 шаблонов resources/views/emails: статусные плашки, «выполнено», чек-боксы шагов, плашки прогресса и кнопки-переходы переведены в серый (#334155 / #1f2937). Красные и жёлтые предупреждения сохранены.
  • Что сохранено - Красный (просрочка, ошибка, запрет, нет доступа, потерянный доступ клиента), жёлтый (требует внимания, высокий приоритет, тестовое окружение), синий (ссылки, бренд, вордмарка писем, служебные панели), категорийные цвета (стадии проекта, типы событий и писем, источники данных, тарифы, диаграммы), градиенты аватаров и оформление «О платформе». Светофор в блоке «Следующий шаг» (resources/views/components/next-step.blade.php, App\Services\NextStepService) не изменялся.
  • Проверка - В tests/Feature/DesignSystemRenderTest добавлены 5 регрессионных тестов: нейтральность success-токенов, отсутствие зелёных статусных классов в blade-шаблонах, отсутствие зелёных цветов в письмах, сохранение светофора «Следующего шага», отсутствие зелёных цветов в отрендеренных страницах админки, кабинета и гостя.
  • Версия - Текущая версия платформы: v0.77.2 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.77.1 25.09.2026 MINOR
Чёрно-бело-серый интерфейс: цвет только для статусов, путь клиента на ключевых страницах
Платформа переведена с цветного оформления на спокойное чёрно-бело-серое: синий больше не красит кнопки и бейджи, акцент — тёмно-серый. Цвет остался только там, где несёт смысл: красный — опасность, жёлтый — в работе, зелёный — готово, серый — нет данных. Ссылки стали синими с подчёркиванием, как в Яндексе, чтобы их невозможно было спутать с кнопкой. Исправлены статусы, которые врали цветом: завершённый проект больше не красный, активный больше не зелёный. На рабочем столе, карточке человека и карточке проекта появился блок «Следующий шаг» с одним главным сигналом и кнопкой, которая его закрывает; когда сигналов нет — прямо написано, что всё в порядке.
Что сделано
  • Синий убран из интерфейса — кнопки (главные, акцентные, зелёные, фиолетовые), бейджи и служебные отметки стали серыми; главное действие — серая кнопка с тёмной рамкой. Локальные переопределения цветов в blade-страницах переписаны, класс btn-green больше не используется (заменён на btn-accent).
  • Ссылки — синие и подчёркнутые — отдельные токены --link/--link-hover/--link-soft для светлой и тёмной темы; навигация, меню и таблицы сохранили своё оформление.
  • Светофор статусов починен — «завершён» теперь зелёный (готово), «активен» и «в процессе» жёлтые (в работе), «приостановлен»/«ждёт» жёлтые, закрытые и неизвестные серые. Раньше завершённый проект светился красным, а активный — зелёным.
  • Блок «Следующий шаг» — компонент x-next-step и App\Services\NextStepService: один главный сигнал страницы с уровнем светофора, объяснением и кнопкой решения. Человек: нет доступа, не подтверждён email, письма с ошибкой, пароль не установлен, нет проектов. Проект: просроченные задачи, задачи ждут подтверждения, не оплачена подписка, в активном проекте нет задач. Если сигналов нет — блок «всё в порядке».
  • Рабочий стол — подсказки отсортированы по важности (красное → жёлтое → серое), зелёная подсказка о последней синхронизации стала серой, действия в подсказках — нейтральные кнопки с тёмной рамкой, добавлена ветка «Сигналов нет — всё в порядке».
  • Регрессии — в DesignSystemRenderTest проверяется блок следующего шага на карточках человека и проекта, якорь секции задач, отсутствие цветных кнопок/бейджей в app.css и правильные цвета статусов.
  • Версия платформы — тестовая версия поднята до v0.77.1 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.77.0 25.09.2026 MINOR
Несколько проектов у человека: статусы, даты завершения, текущий проект
Человек может вести несколько проектов, и my.ipd теперь показывает их все, а не один. Страница пользователя (/admin/users/{id}) выводит все проекты человека, включая завершённые и архивные: роль, статус, этап платформы задач, дату завершения, прогресс, задачи, синхронизацию. Появился «текущий проект» — тот, по которому идут отчёты и письма: он определяется автоматически (самый свежий по дате синхронизации среди активных проектов), но администратор может выбрать проект вручную или вернуть автоматику. Закрытые проекты текущими не становятся и в отчёты и письма не попадают. Синхронизация клиента теперь забирает с платформы задач и завершённые проекты, из выгрузки читаются дата завершения и признак завершения, статус платформы «архив» больше не превращается в «активен» — это отдельный статус «В архиве». Кнопка «Проверить проекты на платформе задач» показывает, что есть на платформе у этого человека, чего нет в my.ipd, и импортирует выбранные проекты, не перезаписывая локальные названия.
Что сделано
  • Все проекты человека на странице пользователя — блок «Проекты (N)» на /admin/users/{id}: роль (владелец/участник), статус, этап, дата завершения, прогресс, задачи, синхронизация, действия; карточки «Проекты (всего)» и «Текущий проект». Завершённые и архивные проекты видны в конце списка, для закрытых показывается причина («статус платформы: завершено»).
  • Текущий проект — `Client::resolveCurrentProject()`: ручной выбор (clients.current_project_id) или автоматика — самый свежий активный проект по last_synced_at, затем updated_at, затем id; форма выбора на странице пользователя с вариантом «Автоматически», маршрут admin.users.current-project, закрытый проект текущим стать не может.
  • Отчёты и письма только по активным проектам — `Client::reportProjects()` (текущий первым) используется в mail:send-reports, mail:send-monthly, upcoming-письмах и превью писем; уведомления по событиям закрытые проекты не создают (`Project::isClosed()`).
  • Проверка проектов на платформе задач — страница /admin/users/{id}/projects/platform (admin.users.platform-projects) показывает проекты человека на task.ipd.test: статус, дату завершения, этап, прогресс, задачи, ссылку на проект и отметку «есть в my.ipd»; выбранные проекты импортируются кнопкой (admin.users.import-platform-projects), локальные названия не перезаписываются.
  • Синхронизация забирает завершённые проекты — во все выгрузки добавлен include_completed=1; `TaskExportNormalizer` понимает ключи «завершён» и «дата_завершения»; при импорте сохраняются platform_status, completed_at, stage и признак личного проекта из блока «люди → проекты».
  • Статусы — у платформы появился статус «архив» (проект закрыт и убран в архив), в my.ipd это статус archived «В архиве» в фильтрах, списках и на странице проекта; константы Project::STATUS_* и CLOSED_STATUSES вместо строковых литералов; в редакторе проекта поле «Дата завершения».
  • Новые поля базы — projects.completed_at, projects.platform_status, projects.stage, projects.is_personal, clients.current_project_id (миграция add_portfolio_fields_to_projects_and_clients).
  • Ссылка на проект ведёт на тестовую платформу — на странице проекта ссылка на проект на платформе задач теперь ведёт на task.ipd.test, а не на продакшн task.ipd.by.
  • Сервис портфеля — app/Services/Sync/ClientPortfolioService.php: локальные проекты человека (текущий → активные → закрытые), проекты на платформе, принадлежность проекта/человека клиенту, подписи этапов и дат; используется и SyncManager, и контроллером пользователей.
  • Версия платформы — тестовая версия поднята до v0.77.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.76.0 25.09.2026 MINOR
Мастер «Получить данные по проекту»: 4 шага вместо одной кнопки
Кнопка «Получить данные по проекту» на странице проекта заменена на мастер из 4 шагов (проверка данных → синхронизация → результат → готово), как мастер «Синхронизация всех людей». Направление данных показано явно на каждом шаге: импорт с платформы задач (task.ipd.test) в my.ipd в одну сторону, обратно ничего не отправляется и ничего не удаляется. Шаг 1 только читает данные (`SyncManager::previewProject`): показывает, что есть на платформе и что изменится, ничего не записывая. Шаг 2 импортирует задачи и шаги только этого проекта (`executeProject`), шаг 3 показывает счётчики и списки созданного/обновлённого, шаг 4 завершает мастер. Дополнительно исправлен подсчёт шагов в предпросмотре: шаги приходят вложенными в задачах, поэтому счётчики «шагов» на шаге 1 были всегда нулевыми.
Что сделано
  • Мастер вместо одной кнопки — на странице проекта (/admin/projects/{id}) кнопка «Получить данные по проекту» ведёт в мастер из 4 шагов (/admin/projects/{id}/sync-wizard, маршруты admin.projects.sync-wizard.*): 1 «Проверка данных», 2 «Синхронизация», 3 «Результат», 4 «Готово». Логика вынесена в трейт app/Http/Controllers/Admin/Concerns/AdminProjectSyncWizard.php, вьюха — resources/views/admin/projects/sync-wizard.blade.php (стили wz-* как у мастера людей).
  • Шаг 1 только чтение — предпросмотр (`SyncManager::previewProject`) забирает данные с платформы задач и считает их, но ничего не пишет: показаны площадка-источник, что сейчас на платформе (задачи, шаги, выполнено) и что изменится в my.ipd (новые задачи, новые шаги).
  • Шаг 2 импорт одного проекта — `SyncManager::executeProject` импортирует задачи и шаги только текущего проекта (по external_id проекта и названию проекта в выгрузке), актуализирует счётчики и last_synced_at; задачи других проектов не затрагиваются.
  • Направление данных — на шагах 1, 3 и 4 показан блок «Направление данных»: task.ipd.test → my.ipd, в одну сторону; обратно ничего не отправляется, существующие данные не удаляются.
  • Шаги 3–4 — результат показывает бейджи «Задач создано/обновлено», «Шагов создано/обновлено» и итог «Всего»; шаг 4 «Готово» завершает мастер, очищает сессию мастера и ведёт к проекту.
  • Исправление подсчёта шагов — выгрузка платформы отдаёт шаги вложенными в задачах («шаги»), верхнеуровневого ключа steps в ответе API нет, поэтому счётчики шагов в предпросмотре были всегда 0; теперь шаги собираются из задач, а «новые шаги» считаются по названию (шаги синхронизируются по названию, без external_id).
  • Версия платформы — тестовая версия поднята до v0.76.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.75.2 25.09.2026 PATCH
Мастер синхронизации: шаг 2 «Синхронизация» показывает направление данных и детальные списки созданного/обновлённого
Шаг 2 «Синхронизация» мастера «Синхронизация всех людей» стал информативнее: добавлен явный блок «Направление данных» — данные идут с платформы задач (задание: откуда сюда, куда сюда; блока нет, списки сгруппированы по типам), в верхней заметке уточнено, что именно импортировано в my.ipd в одну сторону и что обратно ничего не отправляется. Счётчик «Всего» теперь выводит сумму по объединённой статистике (включая шаги задач и людей, созданных на шаге 2), поэтому совпадает с бейджами. Таблицы «Создано» и «Обновлено» сгруппированы по типам (направления, проекты, задачи, шаги, люди) с полным числом записей, в списках показаны первые 20, у шагов — задача, у людей — email, у проектов — прогресс.
Что сделано
  • Направление данных — в шаге 2 добавлен блок «Направление данных»: слева площадка-источник task.ipd.test (направления, проекты, задачи, шаги, люди), стрелка в одну сторону, справа my.ipd; пояснение «Данные идут с платформы задач в my.ipd (импорт). Ничего из my.ipd на платформу задач в этом мастере не отправляется».
  • Что именно сделано — в шаге 2 таблицы «Создано» и «Обновлено» сгруппированы по типам: направления, проекты, задачи, шаги задач, люди. У каждой группы заголовок с полным числом записей («Направления · создано 1», «Задачи · обновлено 210»); в таблице показаны первые 20 записей; у шага указана задача, у задачи — проект, у человека — email, у проекта — процент прогресса.
  • Итог «Всего» — счётчик итога пересчитывается по объединённой статистике (шаги задач и люди, созданные на шаге 2, входят в сумму как и в бейджи) — «Всего: создано N, обновлено M» теперь сходится с бейджами по типам.
  • Версия платформы — тестовая версия поднята до v0.75.2 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.75.1 24.09.2026 PATCH
Мастер синхронизации: понятные изменения в шаге 1 — «было → станет» по каждому полю и пояснения статусов
Шаг 1 «Проверка данных» мастера «Синхронизация всех людей» стал понятнее: по каждому изменённому проекту, задаче и человеку в таблице показана колонка «Что изменится» — по полям «было → станет» (станет — значение с платформы задач, оно же будет в my.ipd после шага 2); смена email подсвечена красным. Добавлены пояснения статусов («Новый» — объект ещё не в my.ipd и будет создан; «Изменён» — значение отличается, ничего не изменяется до кнопки «Следующий шаг»), таблица различий по задачам (раньше были только счётчики), в заголовках таблиц — счётчики «новых N · изменённых M» и «Показаны первые 30 из N».
Что сделано
  • «Было → станет» по полям — в таблицах шага 1 («Проекты», «Задачи», «Люди») у каждого изменения колонка «Что изменится»: список полей, старое значение зачёркнуто и «→ станет» новое (значение платформы задач). Смена email у человека подсвечена красным (критично для писем).
  • Пояснения статусов — над таблицами блок «Как читать таблицы»: «Новый» — объекта нет в my.ipd, будет создан на шаге 2; «Изменён» — значение отличается от платформы, до кнопки «Следующий шаг» ничего не изменяется. В блоке «Люди» те же пояснения для клиентов (сопоставление по ID и по email).
  • Таблица задач — раньше в шаге 1 были только счётчики «Задачи новые/изменённые», таблицы не было: добавлена таблица различий задач (задача, проект, статус, что изменится — включая шаги, например 6/10 → 5/10).
  • Счётчики и лимит — в заголовках таблиц показано «новых N · изменённых M», при более чем 30 различиях — «Показаны первые 30 из N».
  • Версия платформы — тестовая версия поднята до v0.75.1 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.75.0 24.09.2026 MINOR
Синхронизация всех людей: мастер из 4 шагов вместо однокнопочного импорта
Кнопка «Синхронизировать всех людей» на странице синхронизации (POST /admin/sync/all-people, «нажал — и всё пропало») заменена мастером из 4 шагов с явной площадкой-источником (task.ipd.test): шаг 1 «Проверка данных» показывает подключение к платформе, что сейчас на ней (проекты, задачи, люди, направления) и что изменится в my.ipd (новые/изменённые счётчики) — до нажатия кнопки ничего не изменяется; шаг 2 «Синхронизация» импортирует проекты, задачи и людей всех направлений (письма в мастер не входят); шаг 3 «Привязка к клиентам» — дополнительная привязка людей к их проектам (без дублей, повтор безопасен); шаг 4 «Готово» — ссылки на проекты и пользователей. В каждом шаге проактивное сообщение: что происходит сейчас, что будет дальше и что НЕ изменится до нажатия кнопки. В методологию добавлен раздел «05 Синхронизация» с правилами мастеров.
Что сделано
  • Мастер из 4 шагов — страница /admin/sync/people (маршруты admin.sync.people.*): шаг 1 «Проверка данных» (площадка-источник: версия, доступность, последняя синхронизация; что сейчас на платформе — проекты, задачи, люди, направления; что изменится — новые/изменённые), шаг 2 «Синхронизация» (импорт проектов, задач и людей всех направлений), шаг 3 «Привязка к клиентам» (люди привязываются к своим проектам, pivot client_project), шаг 4 «Готово» (переход к проектам и пользователям).
  • Вместо однокнопочного импорта — старый POST /admin/sync/all-people и форма с окном подтверждения убраны; главная страница /admin/sync ведёт в мастер заметным блоком «Синхронизация всех людей» с адресом площадки.
  • Проактивные сообщения — каждый шаг объясняет, что сейчас происходит, что будет дальше и что НЕ изменится до нажатия кнопки («Сейчас — только проверка данных. Ничего не изменяется…», «Письма в рамках мастера не отправляются»).
  • Письма в мастер не входят — импорт идёт с отложенными уведомлениями (deferNotifications): письма и уведомления по событиям задач не создаются, в мастере шага писем нет.
  • Методология — добавлен раздел «05 Синхронизация» (правила работы с площадками, мастера синхронизации, структуры данных сервисов).
  • Версия платформы — тестовая версия поднята до v0.75.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.74.1 24.09.2026 PATCH
Мастер синхронизации людей: без некритичного телефона в интерфейсе, со ссылкой на платформу задач и проактивными пояснениями в шагах
Шаг «Кого мы не добавим» мастера «Синхронизация людей» переработан: заголовок стал «Кто не будет добавлен», по каждой категории появилась ссылка на платформу задач (куда добавлять проекты и email, чтобы человек попал в экосистему), а в каждом шаге мастера появилось проактивное сообщение — что происходит сейчас, что будет дальше и что НЕ изменится до нажатия кнопки. Некритичное поле «Телефон» убрано из интерфейса: колонка не выводится в таблицах мастера, смена телефона больше не показывается и не считается изменением, хотя в базе телефон по-прежнему обновляется при импорте.
Что сделано
  • Без «мы» и без телефона — шаг «Кого мы не добавим» переименован в «Кто не будет добавлен», колонка «Телефон» убрана из таблиц мастера (телефон в интерфейсе не используется, смена телефона не считается изменением), в тексте интерфейса нет слова «мы».
  • Ссылка на платформу задач — в блоке «Кто не будет добавлен» по каждой категории («Без активных бизнес-проектов» и «Без email») появилась ссылка на платформу задач: добавьте проекты или email — и человек придёт следующей синхронизацией. Ссылка ведёт на публичный адрес платформы (task.ipd.by), а в тестовой среде — на внутренний (task.ipd.test).
  • Проактивные сообщения в шагах — каждый шаг мастера показывает, что происходит сейчас, что будет дальше и что НЕ изменится до нажатия кнопки: синхронизация людей, привязка к проектам, завершение и переход к пользователям.
  • Версия платформы — тестовая версия поднята до v0.74.1 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.74.0 24.09.2026 MINOR
Люди с проектами: мастер добавляет только тех, кто в активных бизнес-проектах и с email
Мастер «Синхронизация людей с платформы задач» больше не тянет всех подряд: в экосистему попадают только люди с активными бизнес-проектами и электронной почтой. Люди без проектов (личные контакты/друзья) и без email на платформе задач не добавляются и не изменяются — в шаге 1 видно отдельные блоки «Кого мы не добавим» с причинами. В таблицах появилась колонка «Проекты»: видно, какие активные проекты (и стадии) у каждого человека. Экспорт платформы задач дополнен проектами людей (ид_проектов и проекты с названием, направлением, статусом, флагом «личный» и этапом), по которым мастер решает и привязывает людей к проектам.
Что сделано
  • Только люди с проектами — критерий добавления: у человека есть хотя бы один активный бизнес-проект (не личный, не завершённый). Личные проекты и завершённые экосистему не интересуют.
  • Только с email — платформа работает с электронными ящиками: люди без email не добавляются. В мастере подсказка «добавьте email на платформе задач и вернитесь».
  • Блок «Кого мы не добавим» — в шаге 1 две категории: «Без активных бизнес-проектов» и «Без email на платформе задач», каждая со списком людей и причиной. Без email люди с проектами видны с их проектами.
  • Колонка «Проекты» — в таблицах «Новые» и «Обновления» показаны активные проекты человека (название и стадия: продажи/производство/поддержка).
  • Экспорт платформы задач — в блок «люди» выгрузки добавлены ид_проектов и проекты (название, направление, статус, личный, этап). Мастер привязывает людей к проектам по реальным project_ids экспорта.
  • Версия платформы — тестовая версия поднята до v0.74.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.73.0 24.09.2026 MINOR
Синхронизация людей с платформы задач: цветная сверка по ID и датам
Мастер «Экспорт людей с платформы» переименован в «Синхронизацию людей с платформы задач» — это синхронизация, а не односторонний экспорт. Шаг 1 «Проверка данных» теперь раскрашивает разницу: зелёные строки — люди будут добавлены, жёлтые — изменены (переименование/контакты), красные — смена email (критично, письма переедут на новый ящик). Каждая строка показывает ID человека на платформе задач и ID пользователя в my.ipd (сопоставление идёт по ID — имя и email могут меняться, ID стабилен), дату актуальности выгрузки платформы и дату последнего обновления записи в my.ipd.
Что сделано
  • Переименование — мастер и кнопка в /admin/users называются «Синхронизация людей с платформы задач»: данных может быть и импортировано, и экспортировано, это двусторонний обмен (синхронизация).
  • Цветная сверка по ID — шаг 1 сравнивает людей платформы задач с пользователями my.ipd по ID (id человека на платформе ↔ id пользователя в my.ipd через внешний ID). Зелёный — будет добавлено, жёлтый — изменено (имя/телефон/Telegram/роль), красный — смена email, что критично для истории писем.
  • Даты актуальности — в шаге 1 видна дата формирования выгрузки платформы («данные платформы задач актуальны на …») и для каждой изменяемой записи — дата последнего обновления в my.ipd.
  • Старые и новые значения — в таблице обновлений каждое поле показано в виде «старое → новое»: сразу видно, что именно переименуется или переехало на другой ящик.
  • Версия платформы — тестовая версия поднята до v0.73.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.72.0 23.09.2026 MINOR
Экспорт людей с платформы задач в админку пользователей
В админке появился мастер «Экспорт людей»: люди с платформы задач (task.ipd.test) переносятся в пользователей my.ipd (/admin/users) за 4 шага — проверка данных (кто новый, у кого изменятся контакты), импорт/актуализация (создание недостающих, обновление имени, телефона, Telegram, роли и почты), привязка к проектам (pivot client_project) и итог. Смена email выполняется у той же записи клиента, поэтому история писем на старые ящики сохраняется, а новые письма уходят на актуальные адреса.
Что сделано
  • Мастер из 4 шагов — страница /admin/people-export/wizard (кнопка «Экспорт людей с платформы» в /admin/users): шаг 1 «Проверка данных» (подключение к платформе, счётчики новых/изменённых/без изменений), шаг 2 «Импорт людей» (создано/обновлено, смена email у той же записи), шаг 3 «Привязка к проектам» (добавление в client_project), шаг 4 «Готово» (ссылка на /admin/users).
  • Актуализация без потери истории — новый email (например, у Егора) обновляется у той же записи клиента по external_id человека (id клиента my.ipd): client_id не меняется, вся история писем и писем старых ящиков сохраняется, новые письма отправляются на актуальный адрес.
  • Создание новых пользователей — людей с платформы, у которых нет клиента в экосистеме, мастер создаёт с ролью «Клиент», активным статусом и пустым (случайным) паролем.
  • Привязка к проектам — люди связываются со своими проектами платформы по external_id проектов: добавляется строка client_project, если такой связи ещё нет (конфликтов/дублей нет).
  • Письма в мастере не готовятся — шага писем нет: письма экосистемы и дальше идут на актуальные адреса, решений по рассылке мастер не принимает.
  • Версия платформы — тестовая версия поднята до v0.72.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.71.5 23.09.2026 PATCH
Массовое удаление осиротевших задач + уточнение бейджа «Нет на платформе задач»
В список «Задачи с платформы задач» (/admin/tasks-platform) добавлена кнопка «Удалить все осиротевшие (N)» — разом удаляет все задачи с is_orphaned=true, которых больше нет на платформе задач. Бейдж «Нет на платформе» уточнён до «Нет на платформе задач» — теперь явно видно, что речь именно о платформе задач (task.ipd.test), а не о другой платформе.
Что сделано
  • Бейдж «Нет на платформе задач» — формулировка уточнена: теперь видно, что речь именно о платформе задач (task.ipd.test), а не о другой платформе.
Открыть версию →
v0.71.4 23.09.2026 MINOR
Мастер синхронизации: живой прогресс подготовки писем
На шаге 3 мастера после нажатия «Подготовить письма» страница раньше «зависала» на всё время подготовки (до ~10 минут) без обратной связи. Теперь при подготовке виден живой прогресс: шкала 0–100 % с обновлением по ходу работы, строка «что именно готовится» (письмо N из M: клиент — проект), счётчики обработанных и ошибок и список ошибок в реальном времени. Прогресс отдаётся потоком (text/event-stream) в том же запросе, по завершении страница сама открывает шаг 4 «Письма подготовлены».
Что сделано
  • Прогресс 0–100 — на шаге 3 появился оверлей с прогресс-баром и процентом; обновляется по каждому сформированному письму (поток SSE), итоговый результат читается из кэша по run-id.
  • Что готовится — под шкалой подпись «Письмо N из M: клиент — проект» и статус (готово / ошибка), плюс счётчик обработанных и ошибок.
  • Ошибки сразу — ошибки подготовки видны по мере появления и дублируются на финальном шаге 4.
  • Автопереход — по завершении страница сама открывает шаг 4; при отключённом JS сохраняется прежний блокирующий запрос с перенаправлением.
  • Версия платформы — тестовая версия поднята до v0.71.4 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.71.3 23.09.2026 PATCH
Платформа задач: задачи, скрытые от клиента (осиротевшие)
Синхронизация с платформы задач перестала показывать клиентам служебные и устаревшие задачи: задачи, у которых нет соответствия на стороне платформы или которые исключены, помечаются «осиротевшими» (is_orphaned) и скрываются из кабинета клиента, отчётов и писем. В админке напротив такой задачи виден баннер «Нет на платформе» и действия «Вернуть»/«Удалить». Счётчики прогресса проекта пересчитываются только по видимым клиенту задачам.
Что сделано
  • Баннер и действия — на карточке осиротевшей задачи баннер «Нет на платформе» и кнопки «Вернуть» (restore) / «Удалить» (destroy).
  • Скрыты от клиента — осиротевшие задачи исключены из кабинета клиента, отчётов прогресса и писем (is_visible_to_client=0).
  • Осиротевшие при синхронизации — SyncManager помечает отсутствующие на платформе или непривязанные задачи is_orphaned=1; счётчики проекта (всего/выполнено) пересчитываются по видимым.
  • Версия платформы — тестовая версия поднята до v0.71.3 (.env, .env.example, config/app.php).
Открыть версию →
v0.71.2 22.09.2026 MINOR
Задачи с платформы: мастер синхронизации из 4 шагов
Кнопка «Синхронизировать с платформы задач» на вкладке «Задачи» ведёт в мастер из 4 шагов: 1 — подключение и актуальные данные (что изменится), 2 — импорт (что заменено/изменено), 3 — выбор получателей писем об изменённых статусах задач, 4 — подготовка писем в буфер. Синхронизация выполняется только по направлениям за зону ответственности разработчика (Производство, Поддержка, сервис). Письма больше не отправляются автоматически при импорте: администратор сам решает, кому готовить, на шаге 3.
Что сделано
  • Мастер из 4 шагов — страница /admin/tasks-platform/wizard: шаг 1 «Проверка данных» (подключение к платформе, что сейчас на платформе и в экосистеме, изменения: новые/изменённые задачи и проекты), шаг 2 «Импорт» (что создано/обновлено), шаг 3 «Письма клиентам» (чекбоксы кому готовить письма об изменённых статусах), шаг 4 «Готово» (письма положены в буфер).
  • Только свои направления — мастер синхронизирует только направления config sync.my_directions (11 «Производство» и 19 «Поддержка, сервис»), вместо всех направлений платформы.
  • Письма — отдельным шагом — при импорте из мастера письма клиентам больше не создаются автоматически: события изменений (статус задачи, задача выполнена, новая задача, выполнен шаг) сохраняются, и администратор сам отмечает получателей на шаге 3; на шаге 4 письма кладутся в буфер PreparedEmail (отправка — командой email:send-prepared).
  • Быстрый импорт остался — мгновенная синхронизация всех направлений одним действием сохранена как подчинённый пункт «…» рядом с кнопкой мастера.
  • Версия платформы — тестовая версия поднята до v0.71.2 (.env, .env.example, config/app.php).
Открыть версию →
v0.71.0 22.09.2026 MINOR
Задачи с платформы: мастер синхронизации из 4 шагов
Кнопка «Синхронизировать с платформы задач» на вкладке «Задачи» ведёт в мастер из 4 шагов: 1 — подключение и актуальные данные (что изменится), 2 — импорт (что заменено/изменено), 3 — выбор получателей писем об изменённых статусах задач, 4 — подготовка писем в буфер. Синхронизация выполняется только по направлениям за зону ответственности разработчика (Производство, Поддержка, сервис). Письма больше не отправляются автоматически при импорте: администратор сам решает, кому готовить, на шаге 3.
Что сделано
  • Мастер из 4 шагов — страница /admin/tasks-platform/wizard: шаг 1 «Проверка данных» (подключение к платформе, что сейчас на платформе и в экосистеме, изменения: новые/изменённые задачи и проекты), шаг 2 «Импорт» (что создано/обновлено), шаг 3 «Письма клиентам» (чекбоксы кому готовить письма об изменённых статусах), шаг 4 «Готово» (письма положены в буфер).
  • Только свои направления — мастер синхронизирует только направления config sync.my_directions (11 «Производство» и 19 «Поддержка, сервис»), вместо всех направлений платформы.
  • Письма — отдельным шагом — при импорте из мастера письма клиентам больше не создаются автоматически: события изменений (статус задачи, задача выполнена, новая задача, выполнен шаг) сохраняются, и администратор сам отмечает получателей на шаге 3; на шаге 4 письма кладутся в буфер PreparedEmail (отправка — командой email:send-prepared).
  • Быстрый импорт остался — мгновенная синхронизация всех направлений одним действием сохранена как подчинённый пункт «…» рядом с кнопкой мастера.
  • Версия платформы — тестовая версия поднята до v0.71.0 (.env, .env.example, config/app.php).
Открыть версию →
v0.70.1 22.09.2026 PATCH
Месячный дайджест: месяц и год в теме письма
Письма «Итоги месяца» у одного клиента выглядели одинаково (тема «Итоги месяца — имя» без указания месяца). В тему месячного письма добавлены месяц и год: «Ваш проект — итоги за Октябрь 2026». Обновлён шаблон monthly-digest в БД (ранее рассинхронизирован с сидом) и пересчитаны темы уже подготовленных в буфере месячных писем.
Что сделано
  • Тема месячного письма — в теме письма monthly-digest теперь указываются месяц и год: «Ваш проект — итоги за {{month_name}} {{month_year}}» (например «Ваш проект — итоги за Октябрь 2026»).
  • Синхронизация с сидом — субъект шаблона monthly-digest в БД приведён к формату CampaignTemplateSeeder, который уже содержал месяц и год.
  • Готовые письма в буфере — темы уже подготовленных месячных писем (queued/draft) пересчитаны по их дате отправки; письма одного клиента теперь различаются месяцем и годом.
  • Версия платформы — тестовая версия поднята до v0.70.1 (.env, .env.example, config/app.php).
Открыть версию →
v0.70.0 21.09.2026 MINOR
Состав писем: управление на рабочем столе, корзина с восстановлением и групповые действия
Подготовленные письма теперь полностью управляются прямо с рабочего стола администратора (/admin): у каждой строки «Подготовленных писем» появилось кебаб-меню (⋯) — смотреть, редактировать, копия, удалить. Удаление стало «корзиной»: письмо перемещается в корзину и его можно восстановить, а через 30 дней оно удаляется безвозвратно автоматически. В центре буфера появились вкладка «Корзина» (с счётчиком), восстановление письма, кнопка «Удалить навсегда», групповое удаление/восстановление нескольких писем сразу (чекбоксы, как в почте).
Что сделано
  • Кебаб-меню на рабочем столе — в блоке «Подготовленные письма» страницы /admin у каждой строки появилось кебаб-меню: «Смотреть», «Редактировать» (кроме отправленных/отправляемых), «Копия» и «Удалить».
  • Корзина писем — в центре писем (/admin/emails) добавлена вкладка «Корзина» с счётчиком мягко удалённых писем; каждое можно «Восстановить» в буфер или «Удалить навсегда».
  • Автоочистка корзины через 30 дней — команда email:purge-trashed раз в сутки безвозвратно удаляет письма, пролежавшие в корзине более 30 дней (расписание в routes/console.php).
  • Групповые действия — в списке и в корзине появились чекбоксы и панель выбора: «Удалить выбранные» (в корзину), а в корзине — «Восстановить» и «Удалить навсегда» сразу для нескольких писем.
  • Версия платформы — тестовая версия поднята до v0.70.0 (.env, .env.example, config/app.php).
Открыть версию →
v0.69.0 21.09.2026 MINOR
Буфер писем: кебаб-меню «Удалить» с мягким удалением (deleted_at)
В списке «Буфер писем» (/admin/emails) у каждой карточки появилось кебаб-меню (⋯) с действиями «Смотреть», «Редактировать», «Копия» и «Удалить». Удаление теперь мягкое (SoftDeletes, deleted_at), а не жёсткий DELETE: письмо исчезает из буфера и не попадёт в рассылку, но запись остаётся в истории. Копии статистики по prepared_emails в кампаниях учитывают только неудалённые письма.
Что сделано
  • Кебаб-меню в списке буфера — каждая карточка /admin/emails получила кебаб-меню справа: «Смотреть», «Редактировать» (кроме отправленных/отправляемых), «Копия», разделитель и «Удалить» (с подтверждением).
  • Мягкое удаление писем — PreparedEmail переведён на SoftDeletes (миграция добавляет deleted_at). destroy() больше не выполняет жёсткий DELETE: письмо помечается удалённым, скрывается из буфера и исключается из очереди отправки (email:send-prepared), но остаётся в таблице для истории.
  • Защита от удаления отправляемых — удаление блокируется, пока письмо в статусе «Отправляется» (sending).
  • Кампании: статистика без удалённых — агрегаты по prepared_emails в /admin/campaigns теперь фильтруют deleted_at IS NULL.
  • Версия платформы — тестовая версия поднята до v0.69.0 (.env, .env.example, config/app.php).
Открыть версию →
v0.65.0 15.09.2026 MINOR
Письма: блок переписки на странице пользователя и сводка писем в колокольчике админа
Письма — главный показатель «заботы» о клиенте. На странице пользователя в админке теперь есть явный блок «Письма и переписка»: счётчики (всего, отправлено, прочитано, в очереди/ошибки) и последние письма клиента со статусами (отправлено/ошибка/в очереди) и фактом получения (прочитано/кликнул/доставлено) — чтобы видеть переписку в 1–2 клика. В колокольчике уведомлений администратора добавлена сводка исходящих писем за сутки.
Что сделано
  • Блок «Письма и переписка» — на странице пользователя (/admin/users/{id}): карточки-счётчики (всего писем, отправлено, прочитано, в очереди/ошибки) и таблица последних 15 писем с типом, темой, статусом и фактом получения (прочитано/кликнул/доставлено).
  • Переписка без служебных писем — в показателях учитываются только «человеческие» письма (персональные, кампании, дайджесты статуса проектов); служебные (подтверждение email, восстановление доступа) не смешиваются с перепиской.
  • Ссылки-действия — из блока одним кликом: «Вся переписка →» (журнал писем с фильтром по клиенту) и «Написать письмо».
  • Сводка писем в колокольчике админа — в шапке рядом с уведомлениями администратор видит «Письма за 24 часа»: всего, отправлено, прочитано, в очереди, ошибки, со ссылкой в журнал писем.
  • Версия платформы — тестовая версия поднята до v0.65.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.64.0 15.09.2026 MINOR
Резервная копия v0.64.0 — полный снимок платформы с накопленными изменениями v0.61.0–v0.63.0
Создана полная резервная копия (code + db) по стандарту (Задание 208): архив кода, дамп БД my_ipd_local, README.md и changelog.md в папке v0.64.0. Версия 0.64.0 объединяет все изменения с момента последнего бекапа v0.60.2: задачи с платформы задач (v0.61.0), раздел «Актуальная информация» и производственная платформа (v0.62.0), дизайн письма «Актуальная информация» (v0.62.1), фикс автовхода, Total Commander (v0.63.0). Корневые README.md и changelog.md бэкапов обновлены.
Что сделано
  • Архив кода — my-ipd_test_code_2026-09-15_v0_64_0.zip (PHP ZipArchive, исключены vendor/node_modules/storage/.git/.idea/.herd/bootstrap/cache/.env).
  • Дамп БД — my-ipd_test_db_2026-09-15_v0_64_0.sql (mysqldump, my_ipd_local, --no-tablespaces --routines --triggers).
  • Документация бекапа — README.md (состав, размеры, инструкция по восстановлению) и changelog.md (детальный список изменений v0.61.0–v0.64.0) в папке v0.64.0.
  • Корневые файлы — обновлены корневые README.md и changelog.md (таблица версий, полная история).
  • Версия платформы — поднята до v0.64.0 (.env, .env.example, config/app.php, VersionSeeder, README.md).
Открыть версию →
v0.63.0 14.09.2026 MINOR
Total Commander — единый источник правды: данные платформы (письма) в папках клиентов
Платформа выгружает переписку с клиентами в Total Commander: у каждого проекта есть свой путь в системе (tc_path), как у проектов платформы задач. В папку каждого проекта в служебную подпапку platform записывается файл «Письма.md» — все отправленные письма (журнал) и буфер подготовленных писем с датами, темой, получателем и полным видом письма. В настройках появилась вкладка «Total Commander»: видно, какие проекты имеют папку, есть ли папка на диске, сколько писем и когда была последняя выгрузка; кнопка «Выгрузить данные в Total Commander» обновляет данные во всех папках. Если платформа сломается — переписка восстанавливается из папок Total Commander.
Что сделано
  • Выгрузка писем в Total Commander — сервис TotalCommanderService пишет в папку каждого проекта (tc_path) markdown-файл «Письма.md»: клиент, отправленные письма (дата, тип, кому, тема, статус, источник, полный вид) и буфер подготовленных писем (плановая дата, тип, кому, тема, статус).
  • Вкладка «Total Commander» в настройках — в /admin/settings появилась вкладка: таблица проектов с путём в Total Commander, статусом папки на диске, количеством писем и буфера, датой последней выгрузки.
  • Кнопка «Выгрузить данные в Total Commander» — выгружает переписку во все папки проектов одним действием; опционально точечная выгрузка по проекту (totalcmd:export {id}).
  • Журнал выгрузок — даты последних выгрузок хранятся в настройках платформы и показываются на вкладке (день, месяц, год, часы, минуты).
  • Артефакты — команда totalcmd:export, конфиг totalcmd.php (корень системы, служебный каталог, имя файла).
  • Версия платформы — тестовая версия поднята до v0.63.0 (.env, config/app.php).
Открыть версию →
v0.62.1 14.09.2026 PATCH
Письмо «Актуальная информация»: единый дизайн экосистемы
Понедельничное письмо «Актуальная информация» переведено на общий дизайн-шаблон платформы: та же шапка «Экосистема», приветствие, карточки проектов и полноценный футер (Алексей Гапеев, реквизиты ООО «Студия ИПД», управление уведомлениями, отписка). Раньше письмо собиралось отдельным HTML (другой фон, шрифт, упрощённый футер) — теперь все письма платформы в одной экосистеме дизайна.
Что сделано
  • Общий шаблон письма — создан emails/actual-info.blade.php на основе дизайна task-update (шапка «Экосистема», фон #f4f5f7, системный шрифт, карточки #f8fafc).
  • Единый футер — подключён общий partial emails/partials/footer: «С уважением, Алексей Гапеев», телефоны, info@ipd.by, реквизиты ООО «Студия ИПД», ссылка на управление уведомлениями и отписка.
  • Версия платформы — тестовая версия поднята до v0.62.1 (.env, config/app.php).
Открыть версию →
v0.62.0 14.09.2026 MINOR
Актуальная информация: экосистема производства и поддержки (production.ipd.test)
В платформе появился раздел «Актуальная информация» — единый взгляд на клиентов,две зоны ответственности Разработчика 2: где находится каждый проект (в производстве или на поддержке), на каком этапе конвейера, какие задачи выполняются и что планируется. Данные приходят из трёх источников экосистемы: платформа задач (task.ipd.test), производственная платформа (production.ipd.test — заказы, этапы, задачи) и локальные проекты платформы. Понедельничная рассылка «Актуальная информация» готовит письма в буфер с текущим статусом каждого проекта и планами на неделю.
Что сделано
  • Раздел «Актуальная информация» — новая страница в админке: каждый заказ производства сопоставлен с проектом, показан этап конвейера, статус (производство/поддержка/готово), приоритет, срок и задачи.
  • Производственная платформа подключена — третий источник экосистемы: заказы, этапы и задачи с production.ipd.test синхронизируются в платформу; сопоставление проектов авто-по имени, остальное — вручную со страницы.
  • Кнопка синхронизации — «Обновить данные» выгружает актуальный срез заказов, этапов и задач; видна дата последней синхронизации.
  • Понедельничная рассылка — команда подготовки писем «Актуальная информация» собирает по каждому клиенту текущий статус его проектов и планы на неделю и кладёт письма в буфер PreparedEmail.
  • Версия платформы — тестовая версия поднята до v0.62.0 (.env, config/app.php).
Открыть версию →
v0.61.0 13.09.2026 MINOR
Задачи с платформы задач: отдельная вкладка с зоной ответственности разработчика
В платформе появилась отдельная вкладка «Задачи» — задачи, выгруженные с платформы задач (task.ipd.test). По умолчанию показываются задачи направлений «Производство» и «Поддержка, сервис» — тех, за которые отвечает Разработчик 2; есть переключатель на все направления. На странице видна дата и время последней синхронизации, а кнопка «Синхронизировать с платформы задач» обновляет данные. По каждой задаче доступны проект, направление, статус, приоритет, срок, исполнитель и список шагов.
Что сделано
  • Вкладка «Задачи» — слева в админке появился раздел «Задачи» с задачами, синхронизированными с платформы задач task.ipd.test.
  • Зона ответственности — по умолчанию показываются задачи направлений «Производство» и «Поддержка, сервис» (за них отвечает Разработчик 2); переключатель расширяет список на все направления платформы.
  • Синхронизация — кнопка «Синхронизировать с платформы задач» выгружает актуальные данные; на странице отображается дата и время последней синхронизации.
  • Детали задачи — по каждой задаче видно проект, направление, статус, приоритет, срок, исполнителя и шаги с прогрессом.
  • Версия платформы — тестовая версия поднята до v0.61.0 (.env, config/app.php).
Открыть версию →
v0.60.2 10.09.2026 MINOR
Письма: обращение по salutation или имени, индикатор среды, журнал отправки с источником
Приветствие во всех письмах приведено к единому правилу: если у клиента задано обращение (salutation) — используется оно, иначе имя (первое слово), но не фамилия и не полное имя. В шапке появился индикатор, на каком сайте вы работаете (тестовый/продуктовый), а подготовленные письма и журнал отправки снабжены источником и понятным временем.
Что сделано
  • Единое обращение — во всех письмах (task-update, task-status, client-task, project-status, support-notification) приветствие идёт через общий партиал: salutation, если задан, иначе «Здравствуйте, Имя!» (ранее часть писем использовала фамилию или полное имя).
  • Обращение по умолчанию — имя — метод Client::address_name при пустом salutation возвращает имя (первое слово), а не полное имя; подстановка {{client_name}} в ежемесячных и прочих письмах больше не пишет полное ФИО.
  • Индикатор среды — в шапке платформы появился бейдж «Тестовый сайт» / «Продуктовый сайт» (и «Staging»), чтобы нельзя было перепутать среду.
  • Источник и время в журнале — журнал отправки (mail_logs) отмечает источник (тест/staging/продакшн) и корректное время (Europe/Minsk).
  • Версия платформы — тестовая версия поднята до v0.60.2 (.env, config/app.php).
Открыть версию →
v0.49.3 01.09.2026 PATCH
Предпросмотр письма в админке показывает настоящее оформление с единым футером
Исправлен предпросмотр подготовленного письма в админке (/admin/emails/{id}): раньше панель «Предпросмотр» показывала только голое тело (body) из БД и строку-футер «Отправлено из Экосистема IPD» — без карточки Алексея Гапеева, юрданных и кнопки отписки, поэтому письмо выглядело «по-старому». Теперь страница отрендеривает настоящее письмо через ReportMail (тот же макет, что уходит клиенту, с единым футером-партиалом), и предпросмотр 1:1 соответствует реальному письму.
Что сделано
  • Настоящий рендер в предпросмотре — метод show() контроллера AdminPreparedEmailController теперь строит ReportMail из данных письма и вызывает ->render(); готовый HTML передаётся в представление и показывается в панели «Предпросмотр».
  • Единый футер виден в админке — в предпросмотре теперь видны карточка Алексея Гапеева, юридические данные «ООО «Студия ИПД»», «Управление уведомлениями» и рабочая кнопка «Отписаться от рассылки» (при наличии клиента).
  • Fallback — если рендер по какой-то причине не удался, показывается прежний упрощённый вид (без падения страницы).
  • Версия платформы — поднята до v0.49.3 (.env, config/app.php).
Открыть версию →
v0.49.2 01.09.2026 PATCH
Единый футер во всех письмах и починка рассылочных писем кампаний
Футер писем приведён к единому виду во всех письмах по эталону письма 81: карточка контакта Алексея Гапеева, юридические данные и «Управление уведомлениями». Вместо трёх разных инлайн-футеров и общего партиала теперь все письма используют один общий партиал emails/partials/footer, в который добавлена рабочая кнопка отписки. Дополнительно исправлен критический баг: рассылочное письмо кампании (CampaignMail) не отправлялось вовсе из-за несовместимой сигнатуры метода with() и отсутствующей переменной $subject.
Что сделано
  • Единый футер — в письмах report, project-status, campaign инлайн-футеры заменены на общий партиал emails/partials/footer; теперь все письма (report, project-status, client-task, task-update, campaign, monthly-digest) имеют одинаковый футер: карточка Алексея Гапеева с телефонами и email, юридические данные ООО «Студия ИПД», «Управление уведомлениями» и рабочая кнопка «Отписаться от рассылки».
  • Отписка в кампаниях — ссылка отписки (unsubscribeUrl) передаётся и в рассылочные письма кампаний: кнопка отписки показывается, когда письмо отправляется конкретному клиенту (sendTest / SendCampaignEmailJob), и скрывается для проверочных писем администратора.
  • Починка CampaignMail — исправлен фатальный баг: метод with() в CampaignMail имел несовместимую сигнатуру with(): array вместо with($key, $value) — из-за этого класс падал при загрузке и рассылочные письма кампаний не отправлялись вовсе; метод переименован во withData() с передачей данных через Content::with().
  • Версия платформы — поднята до v0.49.2 (.env, config/app.php).
Какие письма затронуты
  • Проверено рендером — все 6 клиентских писем (report, project-status, client-task, task-update, campaign, verification-code) отрендерены: во всех присутствует карточка контакта, юридические данные и кнопка отписки (кроме verification-code — там отписка намеренно отсутствует).
Открыть версию →
v0.49.1 01.09.2026 PATCH
Вид письма: полноэкранный предпросмотр в редакторе, кнопка отписки и ценное вступление
Доработан интерфейс работы с письмами. В редакторе письма появился полноэкранный предпросмотр на весь экран с переключением «Просмотр / HTML», чтобы удобно смотреть и редактировать письмо. В футер писем добавлена рабочая кнопка «Отписаться от рассылки»: по ссылке клиент отключается от рассылок без входа в систему. Вступление месячного письма переписано без «мы присылаем» — теперь оно сразу несёт ценность для получателя.
Что сделано
  • Полноэкранный предпросмотр — в редакторе письма (/admin/emails/{id}/edit) кнопка «Показать на весь экран» открывает письмо на весь экран с переключением «Просмотр» и «HTML», предпросмотр обновляется по мере ввода.
  • Кнопка отписки — в футер письма добавлена рабочая кнопка «Отписаться от рассылки»: по публичной ссылке клиент отключается от рассылок (email_campaign_opt_out) без входа в систему.
  • Ценное вступление — вступление месячного письма rewritten без «мы присылаем»: теперь сразу о ценности итога для клиента.
  • Версия платформы — поднята до v0.49.1 (.env, config/app.php).
Открыть версию →
v0.49.0 31.08.2026 MINOR
Ежемесячная рассылка: единый поток, идемпотентность и письмо с ценностью
Устранено дублирование месячной рассылки: команда mail:send-monthly переведена на единый идемпотентный поток через подготовленные письма (PreparedEmail) с защитой от повторной отправки в текущем месяце. Ежемесячное письмо полностью переработано: добавлено вступление с месяцем, блок общего прогресса, списки выполненных задач и задач в работе, заметки проекта, блок о ценности и пояснение, почему клиент получил письмо.
Что сделано
  • Единый поток рассылки — mail:send-monthly больше не отправляет письма напрямую в обход очереди; теперь месячная рассылка идёт через подготовленные письма PreparedEmail, как и остальные автоотправки.
  • Идемпотентность — месячное письмо для клиента и проекта создаётся и отправляется ровно один раз за месяц; повторный запуск команды не создаёт дубль и не отправляет повторно.
  • Защита от дублей — проверка: если письмо по проекту за текущий месяц уже отправлено или стоит в очереди, оно не отправляется повторно ни одним из путей рассылки.
  • Ценность письма — месячный шаблон monthly-digest переписан: приветствие, месяц в теме письма, блок прогресса, списки «что сделано» и «над чем работаем», заметки, блок о ценности и дружелюбное закрытие.
  • Общий макет письма — в письмо добавлены дата, заголовок-тема, строка статистики (прогресс, задачи, имя) и пояснение для получателя.
  • Версия платформы — поднята до v0.49.0 (.env, config/app.php).
Открыть версию →
v0.48.2 31.08.2026 PATCH
Описания версий приведены в соответствие с безопасностью: без внутренних данных доступа
Проведён аудит текстов истории версий: из публичных описаний убраны и обобщены места, раскрывавшие внутренние данные доступа — логины и пароли, служебные адреса, имена внутренних токенов и ключей, точные параметры токенов и конфигураций. Методы и алгоритмы описаны профессионально, без раскрытия уязвимостей.
Что сделано
  • Аудит описаний — пройдены все исторические версии (v0.1.0 … v0.48.1) на предмет раскрытия внутренних данных доступа и нюансов безопасности.
  • Логины и пароли — удалены явные комбинации учётных записей и их значения из текстов публичных версий.
  • Служебные адреса — внутренние почтовые адреса системы заменены на обезличенные формулировки; значения хранятся только в окружении.
  • Токены и ключи — из текстов убраны имена внутренних ключей доступа, точные параметры генерации и имена секретных конфигурационных полей.
  • Профессиональная подача — методы и алгоритмы (хеширование, ролевой доступ, защита API) описаны корректно и полно, но без раскрытия уязвимостей.
  • Версия платформы — поднята до v0.48.2 (.env, config/app.php).
Открыть версию →
v0.48.1 31.08.2026 PATCH
История версий приведена к единому виду: чистые заголовки и кликабельные ссылки на каждую версию
Доработаны описания исторических версий: из заголовков убраны внутренние пометки «(Задание NNN)», а сам заголовок каждой версии на странице списка стал кликабельной ссылкой на её отдельную карточку. Теперь история версий читается как единый аккуратный список «что и зачем сделано».
Что сделано
  • Чистые заголовки — из ~47 исторических заголовков убраны внутренние служебные пометки «(Задание NNN)», чтобы список читался как готовый changelog продукта.
  • Кликабельные заголовки — на странице /versions заголовок каждой версии стал явной кликабельной ссылкой на её карточку /versions/{version}.
  • Единый формат — заголовки версий приведены к единому стилю с образцом текущей публикации (без служебных слов).
  • Версия платформы — поднята до v0.48.1 (.env, config/app.php).
Открыть версию →
v0.48.0 31.08.2026 MINOR
Версионность из файла перенесена в базу данных: у каждой версии своя ссылка
История версий больше не хранится в единственном markdown-файле changelog.md. Каждая версия теперь — отдельная запись в базе данных со своей собственной ссылкой, что исключает потерю истории изменений.
Что сделано
  • Новая таблица versions — в базе данных добавлена таблица versions: версия, заголовок, дата, тип, аннотация, секции изменений, результат и признак текущей версии.
  • Модель и сервис — добавлены модель Version и сервис VersionService, через которые все страницы читают версии из БД, а не из файла.
  • Отдельная ссылка у каждой версии — у каждой версии теперь есть собственный URL вида /versions/0.48.0, по которому она открывается отдельно.
  • Общие публичные страницы — список версий /versions и карточка отдельной версии /versions/{version}.
  • Единый формат — страница «О платформе», админ-настройки и новые публичные страницы приведены к единому формату секций.
  • Полная история — в базу засеяна вся история версий с v0.1.0 по v0.48.0 (получена с публичной страницы my.ipd.by/about).
  • Версия платформы — поднята до v0.48.0 (.env, config/app.php).
Открыть версию →
v0.47.1 29.08.2026 PATCH
Вид письма: единый богатый футер для всех писем
Исправления после релиза 0.47.0.
Исправления
  • Письма из буфера и автописем (ClientTaskMail, TaskUpdateMail, VerificationCodeMail) содержали короткий generic-футер «Экосистема — Пространство заботы о вашем бизнесе» вместо богатого оформления старого письма (фото, контактные данные, юрданные, ссылка «Управление уведомлениями»).
  • Добавлен общий partial emails/partials/footer.blade.php с богатым футером по образцу старого письма: авто-уведомление, карточка Алексея Гапеева (фото, должность, телефоны, email, сайт), ООО «Студия ИПД», УНП 291457456, адрес и ссылка «Управление уведомлениями».
  • Богатый футер подключён в emails/client-task.blade.php, emails/task-update.blade.php, emails/verification-code.blade.php и admin/prepared-emails/preview-public.blade.php — единый футер во всех письмах.
  • Версия платформы поднята до v0.47.1 (.env, config/app.php).
Открыть версию →
v0.41.4 26.08.2026 PATCH
Расписание писем по дням недели
Что сделано
  • Миграция `2026_08_26_025032` — `day_of_week` (0=ежемесячно, 1=Пн..7=Вс), `email_type`, `template_slug`, `time`, `recipient_filter` (JSON), `is_active`, `sort_order`
  • Константы `DAY_NAMES`, `EMAIL_TYPES`
  • Accessor: `day_name`, `type_label`, `recipient_label`
  • Scopes: `active()`, `forDay()`
  • Пн = Планы на неделю (report-monday)
  • Ср = Текущий прогресс (report-wednesday)
  • Пт = Итоги недели (report-friday)
  • Ежемесячно = Ежемесячный дайджест (monthly-digest)
  • Дайджест статуса (авто), Напоминание просроченных, Напоминание по мячу
  • `index()` — недельный вид с группировкой по дням
  • `store()`, `update()`, `destroy()` — CRUD
  • `toggle()` — AJAX toggle active
  • `reorder()` — AJAX reorder
  • `GET /admin/schedule-config` → index
  • `POST /admin/schedule-config` → store
  • `PUT /admin/schedule-config/{id}` → update
  • `DELETE /admin/schedule-config/{id}` → destroy
  • `POST /admin/schedule-config/{id}/toggle` → toggle
  • `POST /admin/schedule-config/reorder` → reorder
  • Недельный вид: 7 карточек (Пн..Вс), в каждой — список рассылок
  • Toggle включения/выключения, удаление
  • Форма добавления: название, день, тип, время, шаблон, получатели
  • Навигация: «Расписание» в sidebar и mobile drawer
  • `APP_VERSION` изменён: `0.41.3` → `0.41.4`
Открыть версию →
v0.41.3 26.08.2026 PATCH
Персонализация писем: коррективы per-client
Что сделано
  • Миграция `2026_08_26_021721` — таблица `email_overrides`: `client_id`, `email_type`, `project_id`, `subject_override`, `body_override`, `is_sent`
  • `EmailOverride` модель — `findPending()`, `markSent()`, связи `client()`, `project()`
  • `EmailOverrideService` — статические методы: `consume()`, `applySubject()`, `wrapBody()`, `markSent()`
  • Каждый отправщик проверяет overrides перед отправкой и помечает как отправленные после:
  • `GET /admin/schedule/override/{command}/{clientId}` → `scheduleOverride()` — загрузка коррективы
  • `POST /admin/schedule/override/{command}/{clientId}` → `scheduleSaveOverride()` — сохранение/сброс
  • Третья вкладка «Персонализация» во всех раскрытых строках расписания
  • Выпадающий список получателей (с id, именем, email)
  • Поля: тема письма (персональная), текст сообщения (перед стандартным контентом)
  • Кнопки «Сохранить коррективу» и «Сбросить»
  • Статус-индикация: загружено / сохранено / ошибка
  • CSS: `.override-form`, `.override-select-row`, `.override-fields`, `.override-field`, `.override-actions`, `.override-status`
  • `client_tasks` больше не содержит `client_id` — запросы переписаны через `project.client_id` и `whereHas('project', ...)`
  • `APP_VERSION` изменён: `0.41.2` → `0.41.3` (`.env`, `config/app.php`)
Открыть версию →
v0.41.2 26.08.2026 PATCH
Интерактивный виджет «Предстоящие письма»
Что сделано
  • `AdminController@index` — `buildScheduleItems()` теперь включает реальных получателей (до 20), команды для предпросмотра и тестовой отправки
  • `AdminController::schedulePreview($command)` — возвращает HTML предпросмотра письма (GET JSON)
  • `AdminController::scheduleRecipients($command)` — возвращает список получателей (GET JSON)
  • `AdminController::scheduleTestSend(Request $request, $command)` — отправляет тестовое письмо на указанный email
  • Приватные методы: `getActiveClientRecipients()`, `getOverdueClientRecipients()`, `getBallReminderRecipients()`, `previewProjectStatusDigest()`, `previewOverdueReminder()`, `previewReportEmail()`, `previewBallReminder()`, `wrapPreview()`, `sendTestProjectStatus()`, `sendTestOverdueReminder()`, `sendTestReport()`, `sendTestBallReminder()`
  • Исправлены китайские символы "取决于「мяч」статусов" → корректный русский текст
  • Кликабельные строки расписания с раскрытием деталей (onclick toggle)
  • Вкладки «Получатели» и «Предпросмотр письма» в раскрытой секции
  • Список получателей с аватарами, именами, email, метаданными проекта
  • Если ≥20 получателей — показ «... и ещё N получателей»
  • Предпросмотр письма в iframe через fetch JSON
  • Кнопка «Отправить тест» с prompt для email
  • `GET /admin/schedule/preview/{command}` → `AdminController::schedulePreview`
  • `GET /admin/schedule/recipients/{command}` → `AdminController::scheduleRecipients`
  • `POST /admin/schedule/test-send/{command}` → `AdminController::scheduleTestSend`
  • `.schedule-expandable`, `.schedule-open`, `.schedule-right`, `.schedule-chevron` — раскрывающиеся строки
  • `.schedule-detail`, `.schedule-detail-inner`, `.schedule-detail-tabs`, `.sdtab`, `.sdtab-panel` — вкладки деталей
  • `.recipients-list`, `.recipient-row`, `.recipient-avatar`, `.recipient-info`, `.recipient-name`, `.recipient-email`, `.recipient-meta`, `.recipients-more`, `.recipients-empty` — список получателей
  • `.preview-loading`, `.preview-content`, `.preview-content iframe` — предпросмотр
  • `.schedule-detail-actions`, `.btn`, `.btn-sm`, `.btn-primary`, `.btn-outline` — кнопки действий
  • `.spin` — анимация загрузки
  • Убита мёртвая ссылка «Рассылки» в клиентском дашборде (была видна non-admin пользователям)
  • Типографика: шрифт мин. 14px в элементах расписания
  • `APP_VERSION` изменён: `0.41.1` → `0.41.2` (`.env`, `config/app.php`)
Открыть версию →
v0.41.1 25.08.2026 PATCH
Система email-рассылок: шаблоны, трекинг, дашборд
Что сделано
  • `AdminController@index` — передаёт `$upcomingCampaigns`, `$scheduledForTomorrow`, `$scheduledForWeek` во view
  • `admin/index.blade.php` — новый блок «Предстоящие письма» между подсказками и «Требуют внимания»: список запланированных кампаний с датой/временем, типом аудитории, числом получателей
  • Подсветка: сегодня — красный, завтра — жёлтый, позже — серый
  • Hint-блок: «Завтра запланировано рассылок: N»
  • `CampaignService::buildUtmParams()` — генерирует `utm_source=ipd_platform`, `utm_medium=email`, `utm_campaign={slug}`
  • `CampaignMail` — принимает `$utmSource`, `$utmMedium`, `$utmCampaign`, `$mailLog`; передаёт `$utmParams` и `$trackingPixelUrl` в Blade
  • Кнопка «Открыть на платформе» теперь содержит UTM-параметры
  • Миграция `2026_08_25_230000` — `tracking_token` (char 32, unique, nullable) в `mail_logs`
  • `MailLog` — автогенерация `tracking_token` при создании (Str::random(32)), методы `trackingPixelUrl()` и `clickUrl()`
  • `emails/campaign.blade.php` — `<img>` tracking pixel внизу письма (1x1 transparent GIF)
  • `SendCampaignEmailJob` — передаёт `$mailLog` в CampaignMail для инъекции пикселя
  • `emails/campaign.blade.php` — обновлён: карточка Алексея Гапеева (фото, должность, телефоны, email, сайт), footer с ООО «Студия ИПД» и УНП, ссылка «Управление уведомлениями»
  • `CampaignService::buildRecipients()` — `$seenEmails` массив: один email = одно письмо, дубликаты пропускаются
  • Version bump → 0.41.1
Открыть версию →
v0.41.0 25.08.2026 PATCH
Персональный ИИ-помощник для клиентов
Что сделано
  • `ChatController` — расширен: принимает `user_name`, `user_email`, `user_role` из виджета, строит персональный system_prompt с контекстом пользователя (имя, роль, компания, проекты, задачи)
  • `buildUserContext()` — загружает из БД проекты клиента (статус, прогресс, «мяч») и задачи, требующие внимания (с приоритетами, дедлайнами, блокирующими)
  • `getSystemPrompt()` — контекстная: если пользователь авторизован — «Заботливый помощник» с инструкцией знать проекты/задачи, направлять, помогать навигацией. Если нет — общие ответы + предложение войти
  • `generateFollowUpSuggestions()` — клиентоориентированные: care-сигналы (помоги, не понимаю), статус-сигналы, задачи, навигация. Для авторизованных — «Покажи проекты», «Какие задачи требуют внимания»
  • Персонализированные ошибки: обращение по имени
  • Layout: `@auth('client')` блок инжектит `window.__ipdChatUser` (name, email, role) в JS
  • Виджет: читает `chatUser`, персонализирует приветствие («Здравствуйте, {name}!»), меняет заголовок и статус
  • Запрос к API: передаёт `user_name`, `user_email`, `user_role` в payload
  • Rate-limit: персонализированное сообщение для авторизованных
  • Version bump → 0.41.0
Открыть версию →
v0.40.1 25.08.2026 MINOR
AI Agent для Экосистемы
Что сделано
  • `ChatController` — POST `/api/chat/send` → n8n webhook → JSON response → store in chat_messages. Rate limit 8 messages/session, getConversationHistory(), generateFollowUpSuggestions(), operatorReply(), history()
  • `AiAgentController` — track (digital trail), suggestions (context-aware), lead-form, lead-capture, increment-msg
  • `ChatMessage` model + migration: session_id, role (user/assistant/operator), operator_name, message, page_url, page_title, ip_address, utm_*, msg_number, response_time_ms
  • `ai_agent_sessions` table — digital trail, msg_count, lead_captured
  • `ai_agent_leads` table — captured leads from AI chat
  • `NotificationService` — Telegram + email notifications for chat messages and leads
  • `config/telegram.php` — параметры подключения к Telegram-боту и приёмному чату (значения подставляются из окружения)
  • `config/ai.php` — webhook_url, max_messages, enabled
  • Floating chat widget (`.tg-fab`, `.tg-popup`) — dark theme, design tokens, rate limit, typing indicators
  • Lead capture form (`.ai-lead-form`) — Telegram/phone/email selection, submit to `/api/ai-agent/lead`
  • Follow-up suggestions — context-aware, auto-suggested after each AI reply
  • Operator mode — polls `/api/chat/history` every 15s for operator messages
  • Digital trail tracking — sends page visits to `/api/ai-agent/track`
  • Session persistence via sessionStorage
  • `POST /api/chat/send` → ChatController@send
  • `GET /api/chat/history` → ChatController@history
  • `POST /api/chat/operator-reply` → ChatController@operatorReply
  • `POST /api/ai-agent/track` → AiAgentController@track
  • `POST /api/ai-agent/suggestions` → AiAgentController@suggestions
  • `POST /api/ai-agent/lead-form` → AiAgentController@leadForm
  • `POST /api/ai-agent/lead` → AiAgentController@leadCapture
  • `POST /api/ai-agent/increment-msg` → AiAgentController@incrementMsg
  • `app/Http/Controllers/ChatController.php`
  • `app/Http/Controllers/AiAgentController.php`
  • `app/Models/ChatMessage.php`
  • `app/Services/NotificationService.php`
  • `config/telegram.php`
  • `config/ai.php`
  • `database/migrations/2026_08_26_000001_create_chat_messages_table.php`
  • `database/migrations/2026_08_26_000002_create_ai_agent_tables.php`
  • `resources/views/components/ai-chat-widget.blade.php`
  • `resources/views/components/ai-lead-form.blade.php`
  • `resources/css/app.css` — AI Chat Widget section (`.tg-*`, `.ai-lead-*`)
  • `routes/api.php` — chat + ai-agent routes
  • `.env` — TELEGRAM_*, AI_* variables
  • `config/app.php` — APP_VERSION = 0.40.1
  • Виджет: «Спросить у ИИ», «AI-ассистент», «онлайн», приветствие, подсказки, лимит
  • Lead form: «Оставьте контакт», «Ваше имя», «Отправить», «Или напишите напрямую»
  • Typing: «Думаю», «Анализирую», «Подбираю ответ», «Формулирую»
  • Ошибки: «Извините, AI-ассистент временно недоступен...»
  • System prompt на русском для AI-ассистента
  • Подсказки на русском (hot/warm/price/case/social сигналы)
  • Уведомления: «Новое сообщение в AI-чате», «Новая заявка из AI-чата»
  • Создать n8n workflow для my.ipd (подключение к единому webhook-узлу для обработки чата)
  • Подключить KB-файлы к workflow
Открыть версию →
v0.39.14 25.08.2026 MINOR
Внешний вид письма: предпросмотр, расписание, следующая рассылка
Что сделано
  • Кнопка-глаз в каждой строке журнала почты — открывает модальное окно с предпросмотром HTML-содержимого письма
  • Модальное окно: полноэкранный overlay с iframe, заголовок, ссылка «Открыть полностью», закрытие по Escape/клик вне
  • Загрузка тела письма через AJAX-эндпоинт `/admin/mail/{id}/body`
  • Заменён `srcdoc="{{ }}"` (проблемы с экранированием) на JS-based загрузку через fetch → srcdoc
  • Заглушка для писем без сохранённого тела (старые записи до включения body storage)
  • Блок «Расписание рассылок» — 4 карточки: дайджест (пн/ср/пт 8:30), просроченные (ежедневно 9:00), отчёты (пн/ср/пт 8:30), мяч (ежедневно 10:00)
  • Каждая карточка: название, расписание, описание, команда
  • Блок «Кому будут отправлены письма» — таблица активных клиентов с подписками: клиент, email, проект
  • Показывает количество писем, которые уйдут при следующей рассылке
  • `resources/views/admin/mail/index.blade.php` — модальный предпросмотр, расписание, таблица следующей рассылки
  • `resources/views/admin/mail/show.blade.php` — исправлен iframe, заглушка для null body
  • `app/Http/Controllers/Admin/AdminMailController.php` — метод `body()`, данные расписания/предпросмотра
  • `routes/web.php` — маршрут `admin.mail.body`
Открыть версию →
v0.39.13 25.08.2026 PATCH
Email-столбец в журнале почты
Что сделано
  • Добавлен столбец «Email» в таблицу журнала почты (`admin/mail/index.blade.php`)
  • Столбец показывает `to_email` — конкретный email-адрес получателя каждого письма
  • Решает проблему: при наличии у клиента нескольких ящиков теперь видно, на какой именно адрес было отправлено письмо
  • Обновлён colspan пустого состояния (8 → 9)
  • `resources/views/admin/mail/index.blade.php` — новый столбец Email в таблице journal
Открыть версию →
v0.39.12 25.08.2026 PATCH
Внутренняя перелинковка
Что сделано
  • Добавлены связи `mailLogs()` в модели `Project` (HasMany) и `Client` (HasMany)
  • В journal.project (проекты → индекс): ссылка на клиента в колонке «Клиент», кликабельные бейджи платформ, новая колонка «Почта» с датой последнего письма и ссылкой на журнал
  • В journal.project (проекты → просмотр): ссылка на владельца в карточке деталей, кнопка «Письма» в хедере, карточка «Почта» в деталях
  • В journal.platforms (платформы → просмотр): ссылки на владельцев в таблице проектов
  • В journal.users (пользователи → просмотр): кнопка «Письма клиента» в хедере, ссылки на владельцев в таблице проектов
  • В journal.index (дашборд админа): ссылки на клиентов в карточках проектов, title-атрибуты
  • Title-атрибуты на всех перелинкованных ссылках (навигация, хедеры, детали)
  • `app/Models/Project.php` — `mailLogs()` HasMany
  • `app/Models/Client.php` — `mailLogs()` HasMany
  • `app/Http/Controllers/Admin/AdminProjectController.php` — eager loading `mailLogs` в index/show
  • `admin/projects/index.blade.php` — client link, platform links, mail column
  • `admin/projects/show.blade.php` — owner link, mail button, mail detail card
  • `admin/platforms/show.blade.php` — owner links
  • `admin/users/show.blade.php` — mail button, owner links
  • `admin/index.blade.php` — client links in project cards
Открыть версию →
v0.39.11 25.08.2026 PATCH
Цвета статусов (светофор) и видимость ссылок
Что сделано
  • Завершен = **красный** (был зелёный на странице проектов,ixinв务)
  • Активен = **зелёный** (работаем, всё хорошо)
  • Пауза/ожидание = **жёлтый** (есть нюансы)
  • Архив/неактивен = **серый** (нейтральный)
  • Исправлены ВСЕ blade-файлы (15+ файлов) по всей экосистеме: admin/projects, admin/index, admin/platforms, admin/users, admin/tasks, dashboard/projects, guest, campaign views, global app.css
  • Подчёркивание при наведении (underline) с плавным переходом
  • Изменение цвета при hover: `#3b82f6` → `#60a5fa` (светлее)
  • `cursor: pointer` на всех ссылках
  • `focus-visible` outline для клавиатурной навигации (accessibility)
  • Убраны inline `text-decoration:none` из 47 blade-файлов (кроме email-шаблонов)
  • `.btn` ссылки не подчёркиваются (text-decoration: none !important)
  • `resources/css/app.css` — стили `a`, `.btn`, `.status-completed`, `.status-active`
  • `admin/projects/index.blade.php` — completed=badge-red, waiting_admin=badge-yellow
  • `admin/projects/show.blade.php` — completed=badge-red, task completed=badge-red
  • `admin/index.blade.php` — completed=badge-red
  • `admin/platforms/show.blade.php` — completed=badge-red
  • `admin/users/show.blade.php` — completed=badge-red (2 таблицы)
  • `admin/users/edit.blade.php` — completed='red' в match()
  • `admin/users/create.blade.php` — completed='red' в match()
  • `admin/tasks/show.blade.php` — task completed=badge-red
  • `dashboard/projects/index.blade.php` — completed=red
  • `dashboard/projects/show.blade.php` — project+task completed=red
  • `guest/project.blade.php` — completed=red
  • 47 blade-файлов — удалён inline text-decoration:none
Открыть версию →
v0.39.10 25.08.2026 PATCH
Kebab-меню, ссылки на сущности, alt-тексты
Что сделано
  • Кнопка «Удалить» скрыта в kebab-меню (⋯) — предотвращает случайное удаление
  • Kebab-меню содержит: «Подробнее» и «Удалить» (красным)
  • Меню закрывается при клике вне его
  • Клик на клиента → переход на страницу клиента (`/admin/users/{id}`)
  • Клик на проект → переход на страницу проекта (`/admin/projects/{id}`)
  • Alt-текст (title): «Перейти к клиенту: Егор Савинский», «Перейти к проекту: Шелье»
  • Тип письма: title «Фильтр: Дайджест статуса проекта»
  • Тема письма: title «Открыть письмо»
Открыть версию →
v0.39.9 25.08.2026 PATCH
Ссылки на сущности + содержимое письма
Что сделано
  • Клик на клиента → переход на страницу клиента (`/admin/users/{id}`)
  • Клик на ID клиента → переход на страницу клиента
  • Клик на проект → переход на страницу проекта (`/admin/projects/{id}`)
  • Клик на ID проекта → переход на страницу проекта
  • Клик на владельца → переход на страницу владельца
  • Отображение содержимого письма (HTML) в iframe
  • Переключатель «Показать HTML» / «Показать превью»
  • Кнопки «Профиль клиента» и «Страница проекта» в быстрых ссылках
  • Новая колонка `body` (longText, nullable) в таблице `mail_logs`
  • Все сервисы отправки теперь сохраняют HTML тела письма при отправке:
Открыть версию →
v0.39.8 24.08.2026 PATCH
Улучшение навигации в журнале почты
Что сделано
  • Клиенты, проекты, темы и типы писем стали кликабельными ссылками
  • Клик на клиента → фильтр всех писем этому клиенту
  • Клик на проект → фильтр всех писем проекта
  • Клик на тип → фильтр всех писем этого типа
  • Клик на тему → страница детализации письма
  • Добавлена кнопка «Подробнее» в каждую строку журнала
  • Добавлен фильтр по ID проекта в форме фильтрации
  • Полная информация о письме: получатель, клиент, проект
  • Визуальная воронка доставки (отправлено → доставлено → открыто → клик)
  • Мета: тип, статус, Message ID, время всех событий
  • Ошибка (если есть)
  • Быстрые ссылки: все письма типа, клиенту, проекту
  • Клиенты и проекты стали кликабельными → фильтрация в журнале
Открыть версию →
v0.39.6 24.08.2026 PATCH
Деплой на staging: Экосистема + статистика email
Что сделано
  • Название «Среда» заменено на «Экосистема» во всех интерфейсных элементах
  • Слоган «Цифровая среда для бизнеса» заменён на «Пространство заботы о вашем бизнесе»
  • Обновлены: заголовки страниц, логотипы в сайдбаре, email-шаблоны, авторизация, гостевые страницы, настройки админки
  • УНП в футере email: `193547744` → `291457456`
  • Добавлен юридический адрес: Республика Беларусь, 224011, г. Брест, ул. Луцкая, 82
  • `resources/views/layouts/app.blade.php` — сайдбар и мобильный drawer
  • `resources/views/about.blade.php` — страница «О платформе»
  • `resources/views/auth/login.blade.php` — страница входа
  • `resources/views/auth/set-password.blade.php` — установка пароля
  • `resources/views/auth/forgot-password.blade.php` — восстановление доступа
  • `resources/views/auth/forgot-password-code.blade.php` — ввод кода
  • `resources/views/guest/show.blade.php` — гостевая страница клиента
  • `resources/views/guest/project.blade.php` — гостевая страница проекта
  • `resources/views/emails/verification-code.blade.php` — email верификации
  • `resources/views/emails/task-update.blade.php` — email обновления задачи
  • `resources/views/emails/client-task.blade.php` — email задачи клиенту
  • `resources/views/emails/campaign.blade.php` — email кампании
  • `resources/views/emails/project-status.blade.php` — email статуса проекта
  • `resources/views/emails/report.blade.php` — email отчёта
  • `resources/views/admin/index.blade.php` — админ-панель
  • `resources/views/admin/settings.blade.php` — настройки
  • `resources/views/admin/campaigns/create.blade.php` — создание кампании
  • `resources/views/admin/users/email.blade.php` — отправка email пользователю
  • `app/Http/Controllers/AboutController.php` — данные «О платформе»
  • `app/Services/MailSettingsService.php` — дефолты почтовых настроек
  • `app/Services/ReportDispatcher.php` — дефолт футера отчёта
  • `app/Services/CampaignService.php` — дефолт футера кампании
  • `app/Jobs/SendCampaignEmailJob.php` — дефолт футера кампании
  • `app/Http/Controllers/Admin/AdminUserController.php` — дефолт футера
  • `database/seeders/EmailTemplateSeeder.php` — сидеры email-шаблонов
  • `database/seeders/CampaignTemplateSeeder.php` — сидеры шаблонов кампаний
Открыть версию →
v0.39.3 24.08.2026 PATCH
Исправление email-рассылок, футер с контактами, admin email
Что сделано
  • Получатель системных уведомлений переведён на актуальный служебный адрес платформы (значение хранится в настройках окружения).
  • Резервный адрес напоминаний приведён к актуальному служебному адресу платформы (значение хранится в настройках окружения).
  • Admin-копии дайджестов теперь приходят на реальный почтовый ящик
  • Добавлен блок «Почему вы получили это письмо» — объяснение для клиента
  • Добавлена карточка контактного лица: фото Алексея Гапеева, роль, телефоны, email, сайт
  • Добавлены юридические данные: ООО «Студия ИПД», УНП 193547744
  • Добавлена ссылка «Управление уведомлениями» → `/settings/notifications`
  • Футер обновлён в обоих шаблонах: `project-status.blade.php` и `report.blade.php`
  • Ссылка «Открыть проект» в `project-status.blade.php` теперь ведёт на `my.ipd.by` (prod) через route
  • Версия обновлена до 0.39.3
Открыть версию →
v0.39.1 21.08.2026 PATCH
Клиентская панель инструкций, Материалы поддержки, Напоминания по мячу
Что сделано
  • Инструкции проекта теперь видны клиенту на странице проекта (только с флагом `is_visible_to_client`)
  • 3 типа инструкций: онлайн-встреча (ссылка), видео-запись, текст с скриншотами
  • Секция «Инструкции» на клиентской странице проекта с иконками по типу
  • Таймлайн событий проекта теперь виден клиенту (без CRUD — только просмотр)
  • Цветные точки по датам с типами событий и описаниями
  • Статус мяча виден клиенту на странице проекта (только при `ball_status !== 'none'`)
  • Цветной индикатор + дата + заметка
  • предупреждение для клиента когда мяч у него
  • Новый JSON-блок `support_materials` в проекте — обучающие видео, презентации, PDF, документы
  • CRUD для админа: вкладка «Материалы поддержки» в редактировании + секция на странице проекта
  • Видно клиенту на странице проекта (с флагом `is_visible_to_client`)
  • 4 типа материалов: ссылка, видео, PDF, текст
  • Новая команда `project:ball-reminder` — проверяет проекты где мяч не двигается 7/14/30 дней
  • Отправляет email-напоминания админу + in-app уведомления владельцу проекта
  • Запускается ежедневно в 10:00 (Europe/Minsk) через планировщик
  • Дублирование не допускается (трекинг порогов в памяти)
  • Миграция `add_support_materials_to_projects_table` — JSON-поле `support_materials`
  • Модель `Project`: +`support_materials` в fillable/casts
  • `AdminProjectController`: +`cleanSupportMaterials()`, +`updateSupportMaterials()`, валидация
  • `AdminProjectEventController`: события проекта — CRUD без изменений
  • `MailLog`: добавлен тип `TYPE_BALL_REMINDER`
  • `BallStatusReminderMail` — HTML-письмо напоминания
  • Планировщик: +`project:ball-reminder` ежедневно в 10:00
  • Версия: 0.39.1
Открыть версию →
v0.39.0 21.08.2026 PATCH
Инструкции, Follow-up, Календарь/События по проектам
Что сделано
  • Новый JSON-блок `instructions` в проекте — список инструкций (текст, ссылки, видео)
  • Каждая инструкция: заголовок, тип (текст/ссылка/видео), URL, описание, флаг «видно клиенту»
  • Секция «Инструкции для клиента» на странице проекта — просмотр, добавление, редактирование
  • Отдельная вкладка «Инструкции» в редактировании проекта с динамическим добавлением записей
  • Валидация и очистка при сохранении (метод `cleanInstructions`)
  • Новые поля проекта: `ball_status` (admin/client/none), `ball_since`, `ball_note`
  • Виджет на странице проекта — индикатор текущего статуса (цветной badge + дата + заметка)
  • Кнопки быстрого переключения: «У нас» / «У клиента» / «Нет»
  • Отдельный метод `updateBall` в контроллере с логированием
  • Новая таблица `project_events` — события проекта (старт, оплата, коммуникация, задача, встреча, пауза и др.)
  • Модель `ProjectEvent` с 10 типами событий (цвет + иконка)
  • CRUD для событий через `AdminProjectEventController` (store/update/destroy)
  • Вертикальный таймлайн на странице проекта — цветные точки по датам
  • Форма добавления события с выбором типа и описанием
  • Добавлены статусы `waiting_client` (Ожидаем клиента) и `waiting_admin` (Ожидаем админа)
  • Выбор новых статусов в редактировании проекта
  • Цветовые бейджи в списке проектов и на странице проекта (жёлтый / красный)
  • Миграции: `add_instructions_and_ball_to_projects_table`, `create_project_events_table`
  • Модель `ProjectEvent` с типами, accessors, relationships
  • Обновлена модель `Project`: fillable, casts, relationships, accessors
  • Новые маршруты: `admin.projects.events.*`, `admin.projects.ball.update`, `admin.projects.instructions.update`
  • Eager loading events в `AdminProjectController::show`
  • JavaScript-функции `addInstruction()` / `addEditInstruction()` для динамических форм
Открыть версию →
v0.38.0 21.08.2026 MINOR
Персональные письма пользователям
Что сделано
  • Новая страница `/admin/users/{id}/email` — форма отправки персонального письма конкретному клиенту
  • Кнопка «✉ Отправить письмо» на странице пользователя (`/admin/users/{id}`)
  • Выбор шаблона из `EmailTemplate` (загрузка темы, вступления, тела, футера)
  • Привязка к проекту (для подстановки {{project_name}}, {{progress}} и т.д.)
  • Ручное редактирование всех полей перед отправкой
  • Предпросмотр письма в реальном времени (дизайн «Среда»)
  • Кнопки-плейсхолдеры для быстрой вставки `{{client_name}}`, `{{project_name}}`, `{{progress}}` и т.д.
  • Тип `personal` добавлен в `MailLog` — каждое отправленное письмо сохраняется в БД
  • История писем клиента на странице email (вкладка «История писем»)
  • Лог активности: запись `user_personal_email` при каждой отправке
  • Mailable: переиспользуется `CampaignMail` (тот же HTML-шаблон «Среда»)
  • Placeholder'ы подставляются на стороне сервера перед отправкой
  • Предпросмотр на стороне клиента с `decodeEntities()` (исправление из v0.37.1)
  • 2 маршрута: `GET /admin/users/{id}/email` + `POST /admin/users/{id}/email`
Открыть версию →
v0.37.1 20.08.2026 MINOR
Кликабельные табы wizard + предпросмотр
Что сделано
  • Табы шагов (Аудитория, Шаблон, Редактор, ...) теперь кликабельны и обновляют URL hash (`#step1`..`#step7`)
  • При загрузке страницы — автоматический переход на шаг из URL hash (например, `admin/campaigns/create#step5` открывает шаг «Тест»)
  • Обработка `hashchange` — кнопка «Назад» браузера корректно переключает шаги
  • `history.pushState` — URL обновляется без перезагрузки страницы
  • Предпросмотр теперь показывает полный дизайн письма «Среда»: шапка с логотипом, тема, вступление, тело с подставленными плейсхолдерами, кнопка «Открыть на платформе», футер
  • Плейсхолдеры подставляются с тестовыми данными: Иван Петров, ivan@test.by, ООО Тест, Тестовый проект, 65%, 12/8 задач
  • Вынесено в общую функцию `replacePlaceholders()` для переиспользования
  • XSS-безопасность: `{{chr(123)}}` в Blade заменено на `@{{` синтаксис (строки 159, 179, 215)
  • JS-regex с `{{ }}` экранированы через `\{\{` (строки 386-393) для предотвращения ошибок компиляции Blade
  • `sumThrottle2` — добавлена проверка на null перед присвоением
Открыть версию →
v0.37.0 19.08.2026 PATCH
Email-маркетинг платформа
Что сделано
  • Модель `Campaign` — статусы (draft/scheduled/sending/completed/cancelled/failed), типы аудитории (all/active/project/custom), статистика
  • Модель `CampaignRecipient` — отслеживание каждого получателя (pending/sent/delivered/failed/unsubscribed/bounced)
  • Миграции: `campaigns`, `campaign_recipients`, `clients.email_campaign_opt_out`
  • `SendCampaignEmailJob` — ShouldQueue job, tries=3, backoff=60
  • Каждое письмо = отдельный job с delay(throttle_seconds)
  • Автоматический переход к следующему после отправки
  • Очередь на database driver
  • `buildRecipients()` — формирование списка по фильтру
  • `getAudienceStats()` — подсчёт аудитории
  • `renderBody()` / `renderSubject()` — подстановка переменных
  • `sendTest()` — тестовая отправка
  • `startCampaign()` — запуск (создание recipients + dispatch jobs)
  • `cancelCampaign()` — отмена (остановка + пометка pending как failed)
  • `updateStats()` — пересчёт счётчиков
  • `scheduledCampaigns()` — обработка запланированных кампаний
  • `CampaignMail` — универсальный Mailable для кампаний
  • View: `emails/campaign.blade.php` — дизайн «Среда»
  • Список кампаний с фильтрацией и статистикой
  • Детальная страница: прогресс-бар, статистика, список получателей
  • Предпросмотр письма в отдельном окне
  • Кнопки: Запустить / Отменить / Удалить
  • Ссылка «Кампании» в почте и в сайдбаре
  • `welcome-client` — Приветствие клиента (system)
  • `monthly-digest` — Ежемесячный дайджест (report)
  • `GET /admin/campaigns` — список
  • `GET /admin/campaigns/create` — wizard
  • `POST /admin/campaigns` — создание
  • `GET /admin/campaigns/{id}` — детали
  • `PUT /admin/campaigns/{id}` — редактирование
  • `DELETE /admin/campaigns/{id}` — удаление
  • `GET /admin/campaigns/{id}/preview` — предпросмотр
  • `POST /admin/campaigns/{id}/send` — запуск
  • `POST /admin/campaigns/{id}/cancel` — отмена
  • `POST /admin/campaigns/{id}/test` — тест
  • `POST /admin/campaigns/audience` — AJAX аудитория
Открыть версию →
v0.36.0 19.08.2026 MINOR
Шаблоны email-отчётов
Что сделано
  • Таблица `email_templates` (slug, name, subject, intro, body, footer, type, is_active)
  • Модель `EmailTemplate` с типами: report, system, promo
  • `report-monday` — Понедельник: планы на неделю (прогресс, запланированные задачи)
  • `report-wednesday` — Среда: текущий прогресс (выполненные и в работе задачи)
  • `report-friday` — Пятница: итоги недели (общий прогресс, выполненные задачи, заметки)
  • Профессиональный HTML-дизайн с логотипом «Среда»
  • Кнопка «Открыть на платформе»
  • Прогресс-бар с процентами
  • Цветовая кодировка задач: синий (активные), жёлтые (в работе), зелёные (выполненные)
  • Footer с названием компании
  • `ReportMail` — универсальный Mailable для отчётов
  • Поддержка переменных: {{client_name}}, {{project_name}}, {{progress}}, {{tasks_list}}, {{completed_list}}, {{in_progress_list}}, {{notes_list}}
  • `ReportDispatcher` — сервис отправки отчётов
  • `sendReport()` — отправка клиенту по шаблону
  • `sendTest()` — отправка тестового письма на любой email
  • Данные берутся из модели Project (задачи, прогресс, заметки)
  • Три вкладки: Журнал | Шаблоны | Отправить
  • Журнал: статистика, фильтрация, логи писем
  • Шаблоны: список шаблонов, предпросмотр, редактирование темы и тела
  • Отправить: тестовое письмо (на любой email) + ручная отправка клиенту (выбор клиента → проекта → шаблона)
  • Динамическая загрузка проектов клиента через JSON
  • GET `/admin/mail` — журнал + шаблоны + отправка (с `?tab=`)
  • POST `/admin/mail/test` — тестовое письмо
  • POST `/admin/mail/manual` — ручная отправка клиенту
  • GET `/admin/mail/template/{id}/preview` — предпросмотр шаблона
  • PUT `/admin/mail/template/{id}` — обновление шаблона
  • GET `/admin/users/{id}/json` — JSON с проектами клиента
Открыть версию →
v0.35.5 19.08.2026 MINOR
Название «Среда»
Что сделано
  • Название платформы: «Среда»
  • Подзаголовок: «Цифровая среда для бизнеса»
  • Верхний левый угол сайдбара: заголовок + подзаголовок вместо «IPD v0.35.4»
  • Мобильный drawer: «Среда» вместо «IPD»
  • Сайдбар (десктоп): «Среда / Цифровая среда для бизнеса»
  • Мобильный drawer: «Среда»
  • Страницы авторизации: вход, восстановление доступа, установка пароля, ввод кода
  • Страница «О платформе»: заголовок, описание, footer
  • Гостевые страницы: client/show, client/project
  • Email-шаблоны: verification-code, task-update, project-status, client-task
  • Админ-панель: заголовок дашборда, настройки (site_name, mail_from_name, subjects, footer)
  • MailSettingsService: все дефолты обновлены
  • AboutController: название в данных
Открыть версию →
v0.35.4 19.08.2026 PATCH
Тариф «Цифровой операционный партнёр»
Что сделано
  • Стоимость: 36 000 BYN/год (3 000 BYN/мес), договор на 12 месяцев
  • 6 направлений: маркетинг, CRM, платформа, AI, аналитика, поддержка
  • Время реакции: до 2 часов
  • Поддержка: персональное сопровождение
  • Цвет: #f97316 (оранжевый), иконка: handshake
  • Доступен после прохождения «Экосистема роста»
  • Цифровая архитектура — стал «Хит» (is_popular=true), бейдж «Хит» на карточке
  • Базовый запуск — скрыт с сайта (is_gated=true, is_public=false)
  • Стратегическое партнёрство — теперь доступно после «Цифровой операционный партнёр»
  • Level 0 (Free) → Цифровая архитектура (вместо Базового запуска)
  • Level 1 → Экосистема роста
  • Level 2 → Цифровой операционный партнёр
  • Level 3 → Стратегическое партнёрство
  • Level 4 → топ
  • SVG-иконка handshake для нового тарифа
  • Бейдж «Хит» на карточке популярного тарифа (accent цвет)
Открыть версию →
v0.35.3 19.08.2026 PATCH
Исправление видимости в тёмной теме
Что сделано
  • В базе данных: `#6b7280` → `#9ca3af` (светлый серый, читаем на тёмном фоне)
  • TariffSeeder: дефолтный цвет Free обновлён до `#9ca3af`
  • Все использования `{{ $tariff->color }}` как `color:` CSS автоматически исправлены (KPI, админ-дашборд, проекты, подписки)
  • `.sub-status.free` цвет текста: `#6b7280` → `#9ca3af`
  • Непрозрачность фона бейджа: `0.15` → `0.2`
  • `.badge-gray` цвет текста: `#6b7280` → `#9ca3af`
  • Непрозрачность фона: `0.15` → `0.2`
Открыть версию →
v0.35.2 19.08.2026 PATCH
Заявки на тарифы и предоплата
Что сделано
  • Создана таблица `client_tariff_requests` (client_id, tariff_id, status, client_message, admin_note)
  • Статусы: pending, approved, rejected
  • Связи: client(), tariff()
  • Атрибуты: status_label, status_color
  • Кнопка «Отправить заявку» вместо «Подключить»
  • Форма с сообщением для администратора (необязательное)
  • Заявка создаёт статус pending
  • Баннер «Заявка ожидает решения администратора»
  • Запрет на дублирование заявок на один тариф
  • Предыдущиеpending-заявки отклоняются при новой
  • Контроллер `AdminTariffRequestController` (index, approve, reject)
  • Виджет `admin/tariff-requests/index.blade.php`
  • Кнопки «Одобрить» / «Отклонить» с подтверждением
  • Одобрение = создание подписки + обновление finance
  • Отклонение = смена статуса
  • Маршруты: admin/tariff-requests, .../approve, .../reject
  • Ссылка в сайдбаре (десктоп + мобильное меню)
  • Обновлены описания: «Договор на N месяцев» вместо «рассрочка»
  • Предоплата 50% от стоимости
  • Базовый запуск: 3000 BYN, предоплата 1500 BYN, 3 мес
  • Цифровая архитектура: 6000 BYN, предоплата 3000 BYN, 6 мес
  • Экосистема роста: 12000 BYN, предоплата 6000 BYN, 12 мес
  • Итеративная поставка: 6000 BYN, этапная поставка
  • Заменены все эмодзи на SVG-иконки (rocket, layers, trending, star, repeat, shield)
  • Чеклисты, бейджи, баннеры — всё на SVG
  • Предоплата отображается под ценой
  • Форма заявки прямо на карточке тарифа
  • Убраны ссылки на «Подключить» (режим subscribe)
Открыть версию →
v0.35.1 19.08.2026 PATCH
Тариф Free
Что сделано
  • Добавлено поле `is_free` (boolean, default false) в таблицу `tariffs`
  • Создан тариф «IPD Free» (id=0, slug=ipd-free, level=0)
  • Тариф не публичный (is_public=false) — нельзя подключить вручную
  • Бесплатный: base_price=0, hourly_rate=0
  • Описание: «Вы находитесь в системе IPD. Поддержка доступна по мере освобождения ресурсов.»
  • Особенности: доступ к платформе, хранение проекта, базовая поддержка, возможность升级
  • Добавлен `is_free` в fillable/casts
  • Добавлен метод `isFree()` — возвращает true для тарифа Free
  • Добавлен метод `isOnFreeTariff()` — проверяет, находится ли клиент на Free
  • Добавлен метод `getEffectiveTariff()` — возвращает текущий тариф (платный или Free)
  • `subscriptions:expire` — переводит клиентов с истёкшими подписками на Free
  • `clients:ensure-tariffs` — устанавливает Free для всех клиентов без тарифа
  • Обновлён `index()` — передаёт freeTariff и isOnFree в виджет
  • Тарифы для подписки: исключён Free (только публичные, не-free)
  • Новый блок «IPD Free» — показывает текущий бесплатный тариф с описанием и особенностями
  • Бейдж «Текущий тариф: IPD Free» для клиентов без платной подписки
  • Подсказки для升级 к платным тарифам
  • Добавлена колонка «Тариф» в список пользователей
  • Показывает название платного тарифа или «Free» для бесплатных
  • Все существующие клиенты переведены на тариф Free (7 клиентов)
  • Единственный платный клиент (Егор Савинский) остался на «Итеративная инкрементная поставка»
Открыть версию →
v0.35.0 19.08.2026 PATCH
Система тарифов и задач по уровням
Что сделано
  • Добавлено поле `level` (unsigned tiny integer, default 0) в таблицу `tariffs`
  • Добавлено поле `tariff_level` (unsigned tiny integer, default 0) в таблицу `client_task_templates`
  • Базовый запуск: level 0, 3000 BYN, 3 мес (1000/мес)
  • Цифровая архитектура: level 1, 6000 BYN, 6 мес (1000/мес)
  • Экосистема роста: level 2, 12000 BYN, 12 мес (1000/мес)
  • Стратегическое партнёрство: level 3, 15000 BYN, VIP (гейтинг)
  • Итеративная инкрементная поставка: level 1, 6000 BYN, 5 этапов
  • `ClientTariffController::subscribe()` — создаёт подписку, деактивирует предыдущую, обновляет finance
  • POST-роут `tariff/{tariff}/subscribe`
  • Валидация: проверка публичности, доступности, дубликатов
  • ActivityLogger логирует подключение
  • Шаблоны задач (`ClientTaskTemplate`) имеют поле `tariff_level` (0–3)
  • Level 0: базовые задачи (ТЗ, договор, оплата, материалы, проверка) — доступны всем
  • Level 1: аналитика, контент-план, SEO-отчёт
  • Level 2: стратегия продвижения, стратегическая сессия
  • Level 3: персональная дорожная карта
  • Клиент видит только задачи с `tariff_level <= его уровень`
  • `DashboardController::index()` — фильтрует clientTasks по tariff_level клиента
  • `ProjectController::show()` — фильтрует clientTasks по tariff_level
  • `ProjectTokenController::show()` — фильтрует clientTasks по tariff_level (гостевой доступ)
  • Задачи без шаблона (`template_id = null`) доступны всегда
  • Добавлен `level` в fillable/casts
  • Добавлен `Tariff::levelLabel(int $level)` — возвращает название уровня
  • Добавлен `Tariff::getClientLevel(Client $client)` — определяет уровень клиента по активной подписке
  • Добавлен `tariff_level` в fillable/casts
  • Показывает все публичные тарифы (не только апгрейды)
  • Текущий тариф выделен зелёным с бейджем «Ваш тариф»
  • Кнопка «Подключить» — POST-форма с CSRF
  • Текущий тариф — кнопка «Текущий тариф» (disabled)
  • Недоступные — замок с причиной
Техническое
  • `app.css`: добавлен блок «Kebab menu (универсальный)» (~80 строк)
  • `app.blade.php`: глобальный `toggleKebab` + click-outside + Escape handler
  • `APP_VERSION` изменён: `0.34.2` → `0.34.3`
  • 142 тестов, 580 ассертов — все пройдены.
Что исправлено
  • Добавлены унифицированные CSS-классы: `.kebab-wrap`, `.kebab-btn`, `.kebab-menu`, `.kebab-item`, `.kebab-sep`
  • Ранее стили были размазаны по инлайн-блокам `<style>` в каждом blade-файле
  • Теперь kebab-меню работает везде: карточки проектов, админка, страница проекта
  • `toggleKebab(btn)` — глобальная, определена в layout (ранее дублировалась в каждом файле)
  • Закрытие по клику вне меню — глобальный обработчик
  • Закрытие по Escape — глобальный обработчик
  • `dashboard/index.blade.php` — удалены инлайн kebab-стили и JS
  • `admin/index.blade.php` — удалены инлайн kebab-стили и JS
  • `admin/projects/index.blade.php` — удалены инлайн kebab-стили и JS
  • `admin/projects/show.blade.php` — удалены инлайн kebab-стили и JS, `.kebab` → `.kebab-wrap`
Открыть версию →
v0.34.2 19.08.2026 MINOR
Мобильное меню
Что изменено
  • Нижняя панель навигации (bottom nav) — 5 элементов: Главная, Проекты, Финансы, Уведомления, Ещё
  • Боковое выдвижное меню (drawer) — открывается по кнопке «Ещё»
  • Drawer содержит все пункты сайдбара + раздел «Аккаунт» (Профиль, Уведомления настр., Безопасность, Инструкция, Поддержка, Выйти)
  • Тёмный оверлей при открытом drawer, закрытие по свайпу/клику
  • Адаптивный topbar на мобильном: скрыто имя, уменьшены отступы
  • User dropdown на мобильном: позиционирование внизу экрана
  • Уведомления dropdown: адаптивная ширина
  • Новые компоненты: `.mobile-bottomnav`, `.mbn-item`, `.mobile-overlay`, `.mobile-drawer`, `.mdrawer-*`
  • Padding-bottom на контенте для пространства над bottom nav
  • `openMobileDrawer()` / `closeMobileDrawer()` — toggle drawer с анимацией
  • Закрытие по клику на оверлей или кнопку ✕
  • `document.body.style.overflow` блокируется при открытом drawer
Техническое
  • `app.blade.php`: добавлен HTML для bottom nav и drawer (скрыты на desktop через CSS)
  • `app.css`: стили для мобильных компонентов
  • `APP_VERSION` изменён: `0.34.1` → `0.34.2`
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.34.1 19.08.2026 PATCH
Исправления KPI и тарифов
Что исправлено
  • Бобер Боб (Егор Савинский): `tariff_id` исправлен на 1 (Базовый запуск)
  • Подписка: `tariff_id=1`, `total_amount=1200`, `payments_made=600`
  • Подсвечивается тариф клиента (зелёная рамка), а не «Популярный»
  • Блок «Детали подписки»: стоимость тарифа, оплачено, остаток
  • Блок «Что входит в ваш тариф»: список фич текущего тарифа
  • Блок «Повысить тариф»: только тарифы ВЫШЕ текущего
  • Убрана подсветка «Популярный» — теперь это «Ваш тариф»
  • Показывает реальные данные: тариф, оплачено, остаток
  • Привязана к `client_finances` и `client_subscriptions`
  • Показывает дату начала подписки
Техническое
  • `ClientTariffController`: передаёт `finance`, отмечает `is_current`
  • `KpiController`: передаёт `finance`, `subscription`
  • Вью тарифов: фильтрация только повышающих тарифов
  • `APP_VERSION` изменён: `0.34.0` → `0.34.1`
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.34.0 19.08.2026 PATCH
Показатели KPI
Что изменено
  • 22 показателя эффективности, сгруппированных по 8 категориям
  • Каждый KPI привязан к уровню тарифа (0-4)
  • Визуальные чекбоксы: доступные — зелёные, недоступные — серые с пометкой
  • Трафик: мониторинг посещаемости
  • SEO: позиции в поисковиках
  • Финансы: управление продажами, ROI
  • Коммуникация: отчёты, созвоны, менеджер
  • Аналитика: конверсия, A/B тесты, прогнозы
  • ROI: окупаемость вложений
  • SLA: время реагирования
  • Проекты: задачи, совместные проекты
  • Уровень 0 (без тарифа): ежемесячный отчёт, базовая коммуникация
  • Уровень 1 (Базовый запуск): трафик, SEO, еженедельные отчёты
  • Уровень 2 (Цифровая архитектура): аналитика, A/B тесты, стратегия
  • Уровень 3 (Экосистема роста): ROI, прогнозирование, персональный менеджер
  • Уровень 4 (Партнёрство): совместные проекты, выход на рынки
  • Блок «Хотите больше возможностей?» с ссылкой на следующий тариф
  • Недоступные KPI показаны с пометкой «Требуется тариф ≥ N»
Техническое
  • Миграции `kpi_indicators`, `client_kpis`
  • Модели `KpiIndicator`, `ClientKpi`
  • Контроллер `KpiController`
  • View `dashboard/kpi/index.blade.php`
  • Seeder `KpiIndicatorSeeder` — 22 индикатора
  • Route `GET /kpi`
  • Sidebar раздел «Системное»: KPI → Тариф
  • `APP_VERSION` изменён: `0.33.0` → `0.34.0`
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.33.0 18.08.2026 MINOR
Админ-панель уведомлений
Что изменено
  • 7 типов уведомлений с глобальными переключателями
  • Включение/отключение по каналам: Email, Telegram, В приложении
  • Настройки действуют как «по умолчанию» — пользователь может отключить
  • Список всех активных клиентов с их персональными настройками
  • Редактирование настроек для каждого пользователя
  • Видно, какие типы отключены системой, а какие — пользователем
  • Форма для отправки тестового уведомления конкретному пользователю
  • Выбор типа, канала, темы и текста
  • Автоматическая проверка: система → пользователь → отправка
  • Логирование в `notification_sends` с причиной пропуска
  • Статистика: всего, отправлено, доставлено, ошибок, пропущено
  • Таблица с фильтрацией по дате, пользователю, типу, каналу, статусу
  • Причины пропусков: `user_disabled`, `invalid_email`, etc.
  • Публичная страница — отключает ВСЕ уведомления для пользователя
  • Ссылка внизу писем для соответствия GDPR/CAN-SPAM
Техническое
  • Миграции `system_notification_settings`, `notification_sends`
  • Модели `SystemNotificationSetting`, `NotificationSend`
  • Контроллер `AdminNotificationController` (8 методов)
  • Views `admin/notifications/{index,clients,client-settings,report,unsubscribe}.blade.php`
  • Seeder `SystemNotificationSettingSeeder` — 7 типов по умолчанию
  • Routes 8 маршрутов + `/unsubscribe/{token}`
  • `APP_VERSION` изменён: `0.32.0` → `0.33.0`
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.32.0 18.08.2026 MINOR
Настройки профиля и уведомлений
Что изменено
  • Редактирование имени, телефона, компании
  • Смена пароля (с проверкой текущего)
  • Просмотр информации об аккаунте (роль, верификация каналов)
  • Три канала: В приложении, Email, Telegram
  • 7 типов уведомлений: статус проекта, назначение задачи, выполнение задачи, новое сообщение, финансы, системные объявления, еженедельный отчёт
  • Каждый тип включается/выключается отдельно для каждого канала
  • Автоматическое создание записей при первом входе
  • В меню пользователя ( top-right ) добавлены: «Профиль», «Уведомления», «Безопасность»
  • Кнопка «Настройки» (админ) удалена из меню клиента
  • Все изменения профиля записываются в `settings_history`
  • Смена пароля логируется
Техническое
  • Миграция `create_client_notification_preferences_table` — таблица настроек уведомлений
  • Модель `ClientNotificationPreference` — настройки по каналам
  • Контроллер `ProfileController` — профиль, уведомления, пароль
  • Views `settings/profile.blade.php`, `settings/notifications.blade.php`
  • Routes `GET/PUT /settings/profile`, `GET/PUT /settings/notifications`, `PUT /settings/profile/password`
  • `APP_VERSION` изменён: `0.31.1` → `0.32.0` (`.env`, `.env.example`, `config/app.php`).
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.31.1 18.08.2026 MINOR
Финансовые данные из Total Commander
Что изменено
  • Данные извлечены из README проектов в Total Commander (`L:\Система\02 Клиенты\...`)
  • Заполнены `client_finances` для 4 клиентов:
  • Исправлен `client_id=18` для проекта «Медтехника Гродно» (был `null`)
Техническое
  • Seeder `ClientFinanceSeeder` — заполнение данными из README
  • Миграция данных через `updateOrInsert` (без дублей)
  • `APP_VERSION` изменён: `0.31.0` → `0.31.1` (`.env`, `.env.example`, `config/app.php`).
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.31.0 18.08.2026 PATCH
Сайдбар клиента, Финансы
Что изменено
  • «Панель управления» переименована в «Рабочий стол» (без группы)
  • Раздел **Основное**: Проекты, Финансы, Платформы, Сообщения
  • Раздел **Системное**: Тариф
  • Статистика: баланс, внесено всего, предоплата, следующий платёж
  • Блок «Договор»: дата первого контакта, заключение, начало/окончание действия, текущий этап
  • Блок «Оплаты»: предоплата, дата предоплаты, внесено всего, баланс, следующий платёж
  • Автоматическое создание записи `ClientFinance` при первом входе
Техническое
  • Модель `ClientFinance` + миграция `client_finances`
  • Контроллер `Dashboard\FinanceController@index`
  • Маршрут `GET /finance` → `client.finance.index`
  • Связь `Client::finance()` → `HasOne(ClientFinance)`
  • `APP_VERSION` изменён: `0.30.0` → `0.31.0` (`.env`, `.env.example`, `config/app.php`).
  • 142 тестов, 580 ассертов — все пройдены.
Открыть версию →
v0.30.0 18.08.2026 MINOR
Рабочий стол клиента: светофор, задачи, активность
Что добавлено
  • Зелёный (`light-green`) — все задачи клиента выполнены
  • Жёлтый (`light-yellow`) — есть ожидающие задачи
  • Красный (`light-red`) — есть просроченные или блокирующие задачи
  • Серый (`light-grey`) — нет задач клиента
  • Каждая карточка проекта показывает два прогресс-бара: прогресс разработчика (синий) и прогресс клиента (зелёный)
  • Отдельный счётчик задач для каждой стороны
  • До 5 невыполненных задач с бейджами статуса (Ожидает / На подтверждении / Просрочено)
  • Блокирующие задачи выделены красным + пометка «блокирует»
  • Предупреждения о блокирующих и просроченных задачах сверху
  • Всего задач / Выполнено / Ожидают / Прогресс в процентах
  • Отдельный progress-bar для клиента
  • Последние 10 действий (входы, просмотры страниц, выполнение задач)
  • Цветовые точки: зелёный = вход, синий = просмотр, фиолетовый = выполнение
  • Автоматически логирует все GET-запросы клиентов (просмотры страниц)
  • Пропускает маршрут `client.dashboard` (отслеживается отдельно в контроллере)
  • Типы: `login`, `page_view`, `task_view`, `task_complete`, `task_start`
  • Привязка к клиенту и проекту
  • Хранит IP, user_agent, метаданные
Изменения
  • Заголовок: «Панель управления» → «Рабочий стол»
  • Секция «Проекты (Производство)» → «Проекты»
  • Секция «Статистика» → «Другие проекты»
  • Тарифная секция перенесена в конец
Файлы
  • `app/Models/ClientActivity.php` — модель активности клиента
  • `app/Http/Middleware/TrackClientActivity.php` — middleware логирования просмотров
  • `database/migrations/2026_08_18_111219_create_client_activities_table.php` — миграция
  • `app/Http/Controllers/Dashboard/DashboardController.php` — переработан: задачи, светофор, активность
  • `app/Http/Controllers/Auth/ClientAuthController.php` — добавлено логирование входа в `ClientActivity`
  • `app/Http/Controllers/Dashboard/ClientTaskController.php` — добавлено логирование выполнения задач
  • `bootstrap/app.php` — `TrackClientActivity` добавлен в web middleware
  • `resources/views/dashboard/index.blade.php` — полностью переработан в «Рабочий стол»
  • `tests/Feature/ClientDesktopTest.php` — 10 тестов (25 assertions)
  • `tests/Feature/DashboardProjectsSplitFeatureTest.php` — обновлены под новые заголовки
Открыть версию →
v0.29.1 18.08.2026 MINOR
Исправление dashboard/projects: видимость проектов при impersonate
Баг: dashboard показывал все проекты при входе под пользователем
  • Зачем: при impersonate (вход под пользователем) `/dashboard` показывал **все** проекты из внешнего API (13 штук), хотя у пользователя есть только 1 проект. Страница `/dashboard/projects` показывала «Нет проектов».
  • Корень: `DashboardController` и `ProjectController` использовали `$client->projects()` (BelongsToMany через pivot `client_project`), не учитывая владение проектами (`client_id`). Если у клиента нет записей в pivot — список пуст. А `$apiProjects` загружал **все** проекты из API без фильтрации по пользователю.
  • Исправление:
  • `APP_VERSION` изменён: `0.29.0` → `0.29.1` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.29.0 18.08.2026 PATCH
Вход под пользователем: Impersonate
Новое
  • Кнопка «Войти как» на страницах `/admin/users` (список) и `/admin/users/{id}` (детали) — рядом с «Просмотр» и «Редактировать». Показывается только для не-admin и активных пользователей.
  • Реализована функция «Войти как»: администратор временно просматривает платформу от имени клиента с явной пометкой в интерфейсе и полным журналом таких входов; использование функции для других администраторов заблокировано.
  • Жёлтый баннер в кабинете клиента при impersonate: «Вы вошли как {имя} — видите платформу глазами пользователя. ← Вернуться к админу».
  • Кнопка «Вернуться к админу» POST `/stop-impersonate`, восстанавливает сессию админа и перенаправляет на список пользователей.
  • Логирование: все входы через impersonate записываются в `activity_log` (`user_impersonate`).
Файлы
  • `app/Http/Controllers/Admin/AdminUserController.php` — `impersonate()`, `stopImpersonate()`
  • `routes/web.php` — `POST /admin/users/{id}/impersonate`, `POST /stop-impersonate`
  • `resources/views/admin/users/index.blade.php` — кнопка «Войти как»
  • `resources/views/admin/users/show.blade.php` — кнопка «Войти как»
  • `resources/views/layouts/app.blade.php` — жёлтый баннер impersonate
Автотесты
  • `tests/Feature/AdminImpersonateTest.php` (10 тестов, 23 assertions): вход под клиентом; запрет входа под другим админом; запрет входа под неактивным; возврат к админу; сохранение admin_id в сессии; stopImpersonate без admin_id; кнопка видна для клиентов; кнопка скрыта для админов; баннер при impersonate; баннер не показывается при обычном входе.
  • `APP_VERSION` изменён: `0.28.6` → `0.29.0` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.28.6 18.08.2026 MINOR
Дайджест статуса проектов и уведомления клиентам
Автоматическая рассылка дайджестов клиентам
  • Зачем: клиенты не в курсе текущего статуса проекта — что сделано разработчиком, что ожидается от клиента (документы, подписи, ответы). Нужна автоматическая система, которая показывает прогресс «как диаграмма Ганта» и напоминает о просроченных задачах.
  • Новая модель email: `ProjectStatusMail` (`app/Mail/ProjectStatusMail.php`) — дайджест статуса проекта с прогресс-баром, списками задач (выполнено / в работе / ожидаем от клиента / просрочено), этапами проекта.
  • Email-шаблон: `resources/views/emails/project-status.blade.php` — HTML-письмо с цветовыми секциями: зелёный (выполнено), синий (в работе), жёлтый (ожидаем от клиента), красный (просрочено).
  • Сервис: `ProjectStatusNotificationService` (`app/Services/ProjectStatusNotificationService.php`) — вычисляет статус проекта (группировка задач), отправляет дайджест клиенту + копию служебному адресу администратора (адрес из окружения), создаёт in-app уведомление.
  • Artisan-команда: `project:status-notify` — отправляет дайджесты по всем активным проектам.
  • Расписание: пн/ср/пт в 8:30 (Europe/Minsk) — полный дайджест; ежедневно в 9:00 — напоминания по просроченным задачам клиента.
  • Напоминания по просроченным задачам: `ClientTaskNotificationService::remind()` — ранее реализованный метод, который нигде не вызывался. Теперь подключён в расписании (ежедневно 9:00).
  • Лог почты: `TYPE_PROJECT_STATUS = 'project_status'` в `MailLog` (дайджест статуса проекта).
  • Тип уведомления: `project_status` в `ClientNotification` — in-app уведомления с иконкой `clipboard`.
Синхронизация и актуализация проекта 40 (Бобер Боб)
  • Запущена синхронизация с `task.ipd.test/project/15` — данные обновлены (прогресс 50% → 84%, новая задача «Ответ от Егора по поводу теста»).
  • Заполнены milestones: старт 17.07.2026, подготовка 17.07–05.08, производство с 05.08 (в работе).
  • Добавлено описание проекта.
  • `APP_VERSION` изменён: `0.28.5` → `0.28.6` (`.env`).
Автотесты
  • `tests/Feature/ProjectStatusNotifyTest.php` (9 тестов, 31 assertion): группировка задач по статусам; отправка дайджеста с MailLog記錄; in-app уведомление с правильным заголовком; обработка только активных проектов; dry-run; overdue-only; тип лога; исключение done/awaiting_confirmation задач из pending; проверка milestones.
Открыть версию →
v0.28.5 12.08.2026 PATCH
Этапы и даты проекта
Даты старта и этапов вместо «даты создания записи»
  • Зачем: на гостевой странице проекта «Каменецкое благочиние» показывалось «Проект ведётся с **24.07.2026**» — это `created_at` (когда запись завели в системе), а не реальная дата старта работ (январь). Клиент не понимал, откуда эта дата. Теперь по проекту можно задать реальные даты: старт, три этапа и срок службы — они показываются клиенту как наглядный график.
  • Новое поле `projects.milestones` (миграция `2026_08_12_150000_add_milestones_to_projects_table.php`): JSON `{start_date, stages{preparation|production|support}, lifespan_years, note}`.
  • Три этапа (названия и пояснения заданы в модели, `Project::MILESTONE_STAGES`):
  • Админка (`/admin/projects/{id}/edit`): вкладка **«Этапы проекта»** — дата старта проекта, у каждого этапа даты «с» и «по» + пояснение для клиента, срок службы платформы в годах (по умолчанию 10) и общее примечание по срокам.
  • График этапов (общий партиал `resources/views/partials/project-milestones.blade.php`): горизонтальная диаграмма-линия с сегментами этапов (пропорционально длительности, от старта до конца сопровождения), подпись «Завершение сопровождения: дата», легенда этапов с датами и пояснениями, примечание о сроке службы (~10 лет).
  • Показ клиенту: гостовая страница по токену (секция «Этапы проекта») и личный кабинет. Вместо «Проект ведётся с {created_at}» при заполненных датах показывается «Проект стартовал {дата}»; для проектов без дат — прежняя логика (ничего не ломается).
  • Страница проекта в админке: блок «Этапы проекта (даты)» с графиком и ссылкой на редактирование.
  • Экспорт/импорт JSON: `milestones` включены в выгрузку и загрузку проекта (для ИИ и переноса данных).
  • Данные проекта «Каменецкое благочиние» (id 37): проставлены реальные даты — старт 15.01.2026, этапы аналитика/производство/поддержка, срок службы 10 лет.
  • `APP_VERSION` изменён: `0.28.4` → `0.28.5` (`.env`, `.env.example`).
Автотесты
  • `tests/Feature/ProjectMilestonesFeatureTest.php` (8 тестов): сохранение этапов из формы редактирования; пустые этапы отбрасываются и срок службы по умолчанию 10 лет; блок этапов на странице проекта в админке; кабинет клиента показывает «Старт проекта» и график; гостовая страница показывает «Проект стартовал» вместо «Проект ведётся с»; fallback на `created_at` для проектов без дат; экспорт включает `milestones`; вкладка «Этапы проекта» в форме редактирования.
Открыть версию →
v0.28.4 12.08.2026 PATCH
Токен и email: подтверждение уходит владельцу проекта
Почему в гостевой ссылке показывался email администратора
  • Зачем: на гостевой странице проекта «Каменецкое благочиние» для подтверждения email показывался адрес администратора, который создал гостевую ссылку, а не владельца проекта. Владелец проекта — Отец Николай (`cerkv_kamen@mail.ru`).
  • Корень: гостевая ссылка привязывалась к аккаунту того, кто её создал, а не к владельцу проекта. Поэтому подтверждение email уходило администратору, а не настоящему владельцу.
  • Исправление (код):
  • Данные: существующий токен проекта «Каменецкое благочиние» (id 76) перепривязан с админа (client 1) на владельца Отец Николай (client 23).
  • Понятность админки: подсказка у списка «Пользователи (доступ)» теперь объясняет, что это список **всех клиентов платформы** (из всех проектов), а доступ — только у отмеченных галочкой (по умолчанию только у владельца). Так понятно, почему «несколько доступов» и что это не ошибка.
  • `APP_VERSION` изменён: `0.28.3` → `0.28.4` (`.env`, `.env.example`).
Автотесты
  • `tests/Feature/GuestTokenEmailFeatureTest.php` (5 тестов): гостевая страница токена, привязанного к админу, показывает email владельца; код подтверждения уходит на email владельца; подтверждение по коду помечает владельца; генерация токена админом из кабинета привязывает токен к владельцу; генерация клиентом привязывает к клиенту.
Открыть версию →
v0.28.3 12.08.2026 PATCH
Favicon и установка как приложения
Иконки сайта и веб-приложение
  • Зачем: платформа была «без иконки, без приложения» — в браузере сложно определить, что это за сайт, а `public/favicon.ico` был пустым файлом (0 байт). Теперь сайт узнаваем: есть маленькая и большая иконки во вкладке, и его можно установить как приложение (Android/iOS/desktop) с подписью.
  • Набор иконок в `public/` (бренд IPD: синий квадрат `#3b82f6` со скруглением и белыми вертикальными полосами — как логотип в шапке):
  • Веб-манифест `public/site.webmanifest` установка как PWA: название приложения **«IPD»** (short_name, подпись на рабочем столе/в списке приложений), `name` «IPD Platform — управление проектами», `display: standalone` (полноэкранное окно без браузера), `theme_color: #3b82f6`, `background_color: #0f172a`, `start_url/scope: /`.
  • Meta-теги в `<head>` всех страниц (общий partial `resources/views/partials/favicons.blade.php`, подключён в `layouts/app.blade.php`, `layouts/guest.blade.php`, `welcome.blade.php`):
  • `APP_VERSION` изменён: `0.28.2` → `0.28.3` (`.env`, `.env.example`).
Автотесты
  • `tests/Feature/FaviconFeatureTest.php`: мета-теги favicon/manifest присутствуют на страницах кабинета и гостевой странице; файлы иконок и манифеста существуют в `public/` и не пустые; манифест корректно валиден как JSON с нужными ключами (name, short_name, display, icons 192/512).
Открыть версию →
v0.28.2 11.08.2026 PATCH
«Поля проекта»: ссылки и информация вместо копирования версий
Поля проекта со ссылками вместо копирования текста версий
  • Зачем: Алексей ведёт версии проектов у себя (например, открытая история версий `/platform-version/` и `/about` на bober-bob.ipd.by). Копировать готовый текст в поле changelog — «бесполезная работа». Теперь по каждому проекту можно завести **поля = подпись + ссылка/текст**, и клиенту/ИИ отдаётся ссылка на исходник, а не копия.
  • Новое поле `projects.fields` (миграция `2026_08_11_140000_add_fields_to_projects_table.php`): JSON-массив `{label, value, type: link|text, is_visible_to_client}` — разные поля под разные сайты, проекты, площадки.
  • Админка (`/admin/projects/{id}/edit`): вкладка **«Поля проекта»** (заменила «Версии проекта»). Кнопки-пресеты в один клик добавляют готовое поле: «История версий», «Сайт проекта», «Платформа», «Ссылка», «Заметка (текст)» — остаётся вписать только ссылку. Строки добавляются/удаляются, у каждой — подпись, значение, тип и чекбокс «видно клиенту».
  • Автопоказ клиенту без копирования: заполненные поля автоматически видны клиенту **без логина** — на гостевой странице (секция «Ссылки и информация», ссылки-чипы) и в личном кабинете (страница проекта). Скрытые от клиента поля не показываются.
  • Для ИИ: поля попадают в экспорт JSON проекта (`fields`) и в импорт — ИИ получает ссылку на исходник (например, на историю версий) и сам её читает, копировать ничего не нужно.
  • Страница проекта в админке: блок «Поля проекта (ссылки и информация)» со всеми полями (скрытые помечены) и ссылкой на редактирование.
  • Текстовое поле `changelog` (Задание 94) сохранено в БД, но вводить его больше не нужно — вместо него поля со ссылками.
  • `APP_VERSION` изменён: `0.28.1` → `0.28.2` (`.env`, `.env.example`).
Автотесты
  • `tests/Feature/ProjectFieldsFeatureTest.php`: сохранение полей из формы редактирования (пресеты/произвольные), отображение на странице проекта в админке, в личном кабинете клиента и на гостевой странице (без логина), скрытие полей, помеченных «скрыто», пустой список → секции нет, экспорт включает `fields`, наличие пресетов в форме.
Открыть версию →
v0.28.1 11.08.2026 PATCH
«История версий проекта»: Changelog по каждому проекту
История версий (Changelog) у каждого проекта
  • Новое поле `projects.changelog` (миграция `2026_08_11_130000_add_changelog_to_projects_table.php`): история версий конкретного проекта в формате markdown (версия, дата, «что сделано» и «зачем» — как в `changelog.md` платформы).
  • Админка (`/admin/projects/{id}/edit`): новая вкладка **«Версии проекта»** — текстовое поле с подсказкой формата и примером. Сохраняется кнопкой «Сохранить» вместе с остальными полями.
  • Страница проекта (`/admin/projects/{id}`): блок «История версий (Changelog)» с отрисованным markdown и ссылкой на редактирование.
  • Личный кабинет клиента: секция **«История версий»** на странице проекта — что сделано и зачем.
  • Гостевая страница (по ссылке, без логина): секция **«История версий — что сделано»** — главная ценность доступна клиенту без входа в кабинет (аналогично `https://xn----7sbbdliaae3aaodrirjkg5m4a.xn--90ais/platform-version/` и `https://bober-bob.ipd.by/about`).
  • Экспорт/импорт JSON проекта теперь включает поле `changelog`.
  • Описание ведётся Алексеем по мере работы и может использоваться для ИИ-отчётов по клиентам (задачи/план/диаграмма Ганта + история версий).
  • `APP_VERSION` изменён: `0.28.0` → `0.28.1` (`.env`, `.env.example`).
Автотесты
  • `tests/Feature/ProjectChangelogFeatureTest.php`: сохранение changelog из формы редактирования проекта, отображение на странице проекта в админке, в личном кабинете клиента и на гостевой странице (без логина), рендер markdown и скрытие при пустом поле.
Открыть версию →
v0.28.0 11.08.2026 PATCH
«Актуальные данные по проекту»: синхронизация с платформой задач по кнопке
Точечная синхронизация проекта с платформы задач
  • Страница проекта (`/admin/projects/{id}`): новый блок «Синхронизация с платформой задач» — ссылка на проект task-платформы (`task.ipd.test/project/{external_id}`), бейдж «Данные обновлены: дата/время» и кнопка **«Получить данные по проекту»**. Нажатие тянет с платформы задач актуальные данные конкретного проекта: описание, статус, прогресс, задачи (включая завершённые — полная история), шаги.
  • Список проектов (`/admin/projects`): кнопка **«Получить данные по всем проектам»** — точечно синхронизирует каждый проект, привязанный к платформе задач (заполнен `external_id`), не создавая лишних проектов. В kebab-меню проекта добавлен пункт «Синхронизировать».
  • Новый метод `SyncManager::executeProject()` фильтрует данные экспорта по `external_id` проекта, запрашивает `include_completed=1` (чтобы клиент видел историю — что сделано и когда), импортирует направление/проект/задачи/шаги и обновляет `last_synced_at`, `tasks_total`, `tasks_completed` проекта. `SyncManager::execute()` вынесен в общий `runImport()`.
  • `importTasks`: задачи, уже привязанные к локальному проекту по `external_id`, обновляются даже когда в экспорте нет `project_name` (завершённые/архивные задачи) — их статус и шаги приводятся к актуальным. Новые задачи без проекта по-прежнему пропускаются.
  • `PlatformRegistry::fetchData(..., ['include_completed' => true])` добавляет к экспорту `?include_completed=1`.
  • Логи: синхронизация проекта пишется в историю проекта (`ActivityLog` с `project_id`).
  • `APP_VERSION` изменён: `0.27.0` → `0.28.0` (`.env`, `.env.example`).
Автотесты
  • `tests/Feature/ProjectTaskPlatformSyncFeatureTest.php`: точечная синхронизация проекта по кнопке (Http::fake — платформа задач), обновление прогресса и `last_synced_at`, импорт активных и завершённых задач, история для клиента (завершённые задачи не теряются), массовая синхронизация «по всем проектам».
Открыть версию →
v0.27.0 10.08.2026 MINOR
«Что нужно от клиента»: голосовые/заметки проекта и контрольные точки
«Мои данные по проекту» — голосовые и заметки Алексея (админка + клиент)
  • Новая сущность `project_notes` (миграция `2026_08_10_100000_create_project_notes_table.php`): запись с типом (`voice` — голосовое, `text` — заметка, `report` — итоговый отчёт), заголовком, текстом/расшифровкой (markdown), прикреплённым аудио-файлом (название, размер, MIME) и флагом видимости клиенту.
  • Админка (страница проекта): секция «Мои данные по проекту» — добавить голосовое (загрузка файла MP3/M4A/WebM до 20 МБ, диск `private`), заметку или отчёт, редактирование, переключение видимости «видно клиенту/скрыто», скачивание аудио, удаление. Дата записи фиксируется автоматически.
  • Итоговый markdown-отчёт: кнопка «Сформировать итоговый отчёт» собирает все видимые записи проекта в один markdown-отчёт (название проекта, статус, прогресс, ссылка на ИИ-проект `ai_url`, все записи с датами и текстом/аудио) и сохраняет его как запись-отчёт, видимую клиенту.
  • Клиентский кабинет и гостевая страница: секция «Мои данные по проекту» — список видимых записей с датами, отрисованным markdown (`Str::markdown`) и ссылкой на прослушивание/скачивание голосового (маршруты `client.projects.notes.audio`, `guest.project.notes.audio`). Скрытые записи клиенту не показываются.
  • Уведомления: при добавлении записи с чекбоксом «Уведомить клиентов» создаётся уведомление в личном кабинете (тип `project_note`, сервис `ProjectNoteNotificationService`).
  • Модель `ProjectNote` , контроллеры `Admin\AdminProjectNoteController` (store/update/toggleVisibility/destroy/downloadAudio/generateReport) и `Dashboard\ProjectNoteController` (скачивание аудио с проверкой доступа).
«Задачи для клиента» — контрольные точки с ожиданиями от заказчика
  • Доп. поля `client_tasks`: `category` (категория ожидания: документ, оплата, материалы, проверка, возврат, доступ, другое), `template_id` (из какого шаблона создана), `is_blocking` (блокирует проект — «проект остановлен в ожидании клиента») и `client_response` (комментарий клиента при отметке «выполнено»).
  • Новая сущность `client_task_templates` (миграция `2026_08_10_100001_create_client_task_templates_table.php`) — шаблоны-заготовки контрольных точек: название, категория, описание «что нужно от клиента», срок по умолчанию в днях, порядок, активность.
  • Сид `ClientTaskTemplateSeeder` 7 типовых контрольных точек разработки: согласовать ТЗ, подписать договор, внести предоплату, предоставить материалы, проверить работу и согласовать, возврат исходников и доступов, проверить доступ к кабинету.
  • Админка: на странице проекта — блок «Применить шаблон» (выбор шаблона + свой срок + уведомление), в форме создания задачи — категория, шаблон, чекбокс «Блокирует проект»; управление шаблонами (CRUD) на `/admin/client-task-templates`. В таблице задач бейджи: категория, «Блокирует», «Просрочено», ответ клиента.
  • Клиентский кабинет: бейдж «Блокирует проект» и «Просрочено», комментарий при отметке «Отметить выполненной». Гостевая страница: секция «Что нужно от вас» с категорией, сроками и блокирующими задачами.
  • Уведомления и напоминания: в `ClientTaskNotificationService` добавлен метод `remind()` для напоминаний (просрочено / приближается срок / блокирует) — уведомление в кабинет + письмо; исправлена передача `$action` в `createNotification()`.
  • Новое поле `projects.ai_url` ссылка на ИИ-проект (форма редактирования проекта, включается в итоговый отчёт).
Автотесты (14 новых, всего 75/75)
  • `tests/Feature/ProjectNoteFeatureTest.php` (8 тестов): добавление заметки, скрытие от клиента, рендер видимых/скрытых, уведомление клиенту, генерация отчёта, удаление, запрет скачивания аудио клиенту без доступа.
  • `tests/Feature/ClientTaskTemplateFeatureTest.php` (6 тестов): наличие сида шаблонов, создание шаблона, применение шаблона (со сроком из шаблона и со своим сроком), создание блокирующей задачи с категорией, бейдж «Блокирует проект» у клиента, отметка задачи с комментарием.
  • `APP_VERSION` изменён: `0.26.1` → `0.27.0` (`.env`, `.env.example`).
Открыть версию →
v0.26.1 10.08.2026 MINOR
Очистка проектов после синхронизации
Исправление: на `/admin/projects` отображались «не те» проекты
  • Причина: полная синхронизация 07.08.2026 с task-платформы была выполнена без фильтра «Только производство» (флаг `production_only` не был активен на момент запуска). В БД my.ipd попали все 22 проекта экспорта, включая не производственные: AmoCRM, «Встреча Агроусадьба "Угляны"», «Ремонт в квартире», «CRM + сайт + AI-консультант + техническая поддержка», VipLabel, PWA, «Медтехника Гродно — IID», «Поездка в Могилев», сайты *.ipd.by и дубль «Mysteria — Монтаж видео». При сортировке по умолчанию `updated_at desc` они попадали в начало списка и путали Алексея.
  • Исправление: удалены 17 лишних (не производственных) проектов вместе со связанными задачами/шагами/токенами (каскад, как в `AdminProjectController::destroy()`). В системе остались только 6 производственных проектов: Mysteria, Каменецкое благочиние, Медтехника Гродно, Алексей Гапеев, Бобер Боб, Mysteria — Монтаж видео (направление «Производство», external_id=11).
  • Профилактика: фильтр «Только производство» в коде (`SyncManager::filterProduction()`, `config/sync.php`, чекбокс на `/admin/sync`) включён по умолчанию — при следующих синхронизациях лишние проекты импортироваться не будут.
  • Бэкап перед очисткой: `my_ipd_backup_20260810_1112.sql` (дамп полной БД до удаления).
  • `APP_VERSION` изменён: `0.26.0` → `0.26.1` (`.env`, `.env.example`).
Открыть версию →
v0.26.0 09.08.2026 PATCH
Производство и статистика на панели управления; Системные подсказки на панели управления
Исправление: стабильный запуск полного набора тестов (`php artisan test` — 62/62)
  • Причина массовых падений: `phpunit.xml` использует `sqlite :memory:`. Часть тестов использовала трейт `DatabaseTransactions`, который получает пустую базу (схема создаётся только `RefreshDatabase`-тестами) — отсюда «no such table» при изолированном или переупорядоченном запуске (в т.ч. `ApiProjectApiTest`: 2 теста «no such table: api_keys»).
  • Исправление: тесты переведены на `RefreshDatabase` (со `$this->seed()` там, где нужны сидированные данные): `ApiProjectApiTest`, `ApiKeyTest`, `DesignSystemRenderTest`, `ManualTasksFeatureTest`, `ProjectOwnerRolesFeatureTest`, `ProjectSyncTest`, `TempAuthDiagTest`.
  • Исправлены устаревшие/ошибочные тесты:
  • Результат: `php artisan test` — 62 passed, 0 failed, 0 errors (273 assertions).
Разделение проектов на панели управления: «Производство» и «Статистика»
  • Главный раздел «Проекты (Производство)»: на панели управления (`/dashboard`) теперь основными показываются только активные проекты направления «Производство» (направление id=16, внешний id=11). Локально это Mysteria, Каменецкое благочиние, Алексей Гапеев.
  • Раздел «Статистика»: все остальные проекты (другие направления и паузы) вынесены в отдельный раздел ниже — они не засоряют главную ленту, но остаются полностью доступными.
  • Кнопка «Показать завершённые проекты (N)»: в разделе «Статистика» кнопка раскрывает архив завершённых проектов (статус `completed`) со значком «Завершён». Ничего не удаляется — все проекты остаются в системе и доступны через карточки.
  • Контроллер `Dashboard\DashboardController`: метод `splitProjects()` разделяет проекты на три группы — производственные активные, остальные и завершённые (определение направления «Производство» по `external_id = 11` или названию). Для админа список проектов больше не ограничен 20 — показываются все, чтобы раздел «Статистика» был полным.
  • Автотест `tests/Feature/DashboardProjectsSplitFeatureTest.php` (2 теста): разделение для админа (все проекты) и для клиента (собственные проекты), наличие секций и кнопки архива.
  • `APP_VERSION` изменён: `0.25.2` → `0.26.0` (`.env`, `.env.example`).
Исправление: русские названия проектов отображались «кракозябрами»
  • Причина: при создании дампа локальной БД использовался PowerShell-канал (`| Out-File` / `>`), который перекодировал вывод mysqldump через CP866 — UTF-8 байты ломались (двойная кодировка). Русские строки (проекты, задачи, клиенты) на staging (`my_ipd_dev_app`) и prod (`my_ipd_app`) оказались искажены.
  • Исправление: дамп создан через `cmd /c` (как в инструкции `03_Резервное_копирование_тестового_сайта.md`): `mysqldump --default-character-set=utf8mb4 --single-transaction --routines --triggers`. Обе БД пересозданы из корректного дампа локальной `my_ipd_local` — данные на staging и prod снова в правильном UTF-8.
  • `APP_VERSION` изменён: `0.26.0` → `0.25.2` (`.env`, `.env.example`).
Подсказки на панели управления
  • Новая секция «Системные подсказки» на панели управления (`/admin`): система сама подсказывает, что требует внимания и куда перейти.
  • Почта не настроена: если SMTP-сервер не подключён (пустой хост или отправитель) — подсказка «Почта не настроена» с переходом на вкладку «Почта» в настройках. После заполнения настроек SMTP подсказка исчезает.
  • Синхронизация: если синхронизация ещё ни разу не выполнялась — подсказка «Синхронизация ещё не выполнялась» с переходом на страницу синхронизации; если последняя синхронизация была более 7 дней назад — предупреждение «Данные могли устареть».
  • Что добавилось на последней синхронизации: из журнала активности разбирается статистика последнего импорта и показывается подсказка «Что добавилось на последней синхронизации» (сколько проектов/задач/шагов/клиентов добавлено и изменено).
  • Задачи ждут подтверждения: если у клиентов есть задачи в статусе «Ожидает подтверждения» — подсказка с их количеством и переходом к проектам.
  • Клиенты не подтвердили email: если есть клиенты без подтверждённого email — подсказка с переходом к списку клиентов.
  • Сервис `AdminDashboardHintsService` формирует подсказки (уровень: danger/warning/success/info, текст, ссылка-действие).
  • Автотест `tests/Feature/AdminDashboardHintsFeatureTest.php` (9 тестов): каждая подсказка, скрытие при решённой проблеме и рендер секции на дашборде.
  • `APP_VERSION` изменён: `0.25.1` → `0.26.0` (`.env`, `.env.example`).
Открыть версию →
v0.25.1 07.08.2026 MINOR
Статус «ожидает подтверждения» для задач клиента
Подтверждение выполненной клиентом задачи администратором
  • Новый статус `awaiting_confirmation` («Ожидает подтверждения») для задач клиента (`client_tasks`). Когда клиент нажимает «Отметить выполненной», задача теперь не становится сразу «Выполнена», а переходит в статус «Ожидает подтверждения» с фиксацией даты и автора отметки.
  • Админ-интерфейс: на странице проекта у задачи в статусе «Ожидает подтверждения» появляются кнопки «Подтвердить» (задача становится «Выполнена», данные об отметке клиента сохраняются) и «Вернуть» (возврат в работу, отметка снимается). В форме редактирования задачи добавлен третий статус.
  • Клиентский кабинет: статус «Ожидает подтверждения» отображается клиенту с пояснением, что задача ожидает подтверждения администратором; кнопка повторной отметки скрыта до подтверждения.
  • Уведомления: при подтверждении администратором клиентам проекта создаётся уведомление «Задача подтверждена администратором» и отправляется письмо (ClientTaskMail, журналируется в MailLog).
  • Статусная колонка расширена до 30 символов (миграция) — значение `awaiting_confirmation` длиннее 20 символов.
  • Автотест `tests/Feature/ClientTaskConfirmationFeatureTest.php` (8 тестов): полный цикл отметка → ожидание → подтверждение/возврат, включая рендер страниц.
  • `APP_VERSION` изменён: `0.25.0` → `0.25.1` (`.env`, `.env.example`).
Открыть версию →
v0.25.0 06.08.2026 PATCH
Синхронизация производства и уведомления клиентов
Синхронизация с task-платформой: производство и шаги (Задание 83)
  • Нормализация экспорта: внешний экспорт `/api/export/full` отдаёт русскоязычные ключи (`ид_задачи`, `название`, `шаги` и т.д.). Добавлен `TaskExportNormalizer`, который приводит данные к единому формату — импорт снова работает корректно.
  • Импорт шагов: задачи теперь привозят шаги (`steps`) с признаком выполнения. Прогресс задачи и проекта считается по шагам и отображается клиенту («что сделано»).
  • Дедлайны и статусы: синхронизируются `дедлайн`, описание и статусы задач/проектов (активная → активна, в_работе → в работе, выполнена → выполнена и т.д.).
  • Только производство: по умолчанию синхронизируются только проекты и задачи направления «Производство» (направление 11) — у них заполнено поле «проект». Переключатель на странице синхронизации.
  • Аналитика синхронизации: после выполнения показывается, что добавлено и что изменено (по сущностям и по полям «было → стало»), в том числе по шагам.
  • Видимость клиенту: производственные задачи автоматически помечаются видимыми клиенту — клиент видит стадию производства, шаги, сроки и время обновления.
Уведомления клиентам о смене статусов (Задание 83)
  • При синхронизации отслеживаются изменения: добавлена задача, задача выполнена, изменён статус, выполнен шаг.
  • Клиенту создаются уведомления в кабинете (ClientNotification) и отправляется письмо на почту (TaskUpdateMail, журналируется в MailLog).
Задачи для клиента (обязательства клиента) (Задание 83)
  • Новая сущность **«Задачи для клиента»** (`client_tasks`): администратор создаёт задачи, которые должен выполнить клиент (прислать материалы, подписать договор, предоставить доступ и т.п.) — название, описание, срок, приоритет и внутренняя заметка.
  • Внутренняя заметка (`admin_note`) видна только администратору — клиент её не видит (рабочие заметки о клиенте остаются закрытыми).
  • Админ-интерфейс: на странице проекта (`/admin/projects/{id}`) — раздел «Задачи для клиента»: создание, редактирование, отметка «выполнено/вернуть в работу», удаление.
  • Клиентский кабинет: на странице проекта — раздел «Задачи для вас»: срок, описание, пометка «просрочено», кнопка «Отметить выполненной». Выполнение клиентом фиксируется в журнале.
  • Уведомления: при создании/изменении задачи для клиента (если администратор отметил «уведомить») клиентам проекта создаётся уведомление в кабинете (ClientNotification) и отправляется письмо (ClientTaskMail, журналируется в MailLog).
  • `APP_VERSION` изменён: `0.24.5` → `0.25.0` (`.env`, `.env.example`).
Открыть версию →
v0.24.5 06.08.2026 MINOR
Исправлено: тариф на странице проекта не сохранялся
Исправление: тариф не сохранялся при нажатии «Сохранить» (Задание 81)
  • Причина: на странице редактирования проекта (`/admin/projects/{id}/edit`) селект «Тариф» находился в отдельной форме «Оформить подписку по проекту», а кнопка «Сохранить» внизу страницы отправляла только основную форму проекта. Выбранный тариф никуда не передавался — система писала «сохранено», а по факту тариф не создавался.
  • Исправление: выбор тарифа (клиент, тариф, дата начала, окончание, дедлайн, оплата, комментарий) теперь находится внутри основной формы проекта и сохраняется обычной кнопкой «Сохранить». Если по проекту уже есть активная подписка — она обновляется, если нет — создаётся.
  • История подписок вынесена на отдельную вкладку «История подписок» — там статусы и удаление подписок работают как раньше.
  • Страница просмотра проекта (`/admin/projects/{id}`) теперь показывает тариф: в карточках добавлены «Тариф» (цветной бейдж), «Оплата», «Окончание (договор)» и «Дедлайн».
  • `APP_VERSION` поднят: `0.24.4` → `0.24.5` (`.env`, `.env.example`).
Открыть версию →
v0.24.4 06.08.2026 PATCH
Тариф и статус проекта в списке и на дашборде
Админ: тарифные колонки в списке проектов (Задание 81)
  • Список проектов (`/admin/projects`): добавлены колонки **«Тариф»**, **«Оплата»**, **«Подключён»**, **«Окончание»**, **«Дедлайн»** — теперь сразу видно, у кого какой тариф, когда подключили, когда заканчивается оплата и срок выполнения. Колонки входят в «Настройка полей» (можно скрывать/показывать), по умолчанию видны тариф, оплата, окончание и дедлайн.
  • Индикация в ячейках: тариф — цветной бейдж по цвету тарифа; оплата — «Оплачено»/«Не оплачено»; окончание — красный бейдж, если оплата истекла; дедлайн — жёлтый, если до срока ≤ 7 дней, красный — если просрочен.
  • Подписки (`subscriptions.tariff`) подгружаются в списке проектов, добавлен аксессор `Project::active_subscription` (активная подписка, последняя по дате старта).
Админ: индикаторы на дашборде (`/admin/dashboard`)
  • Секция «Требуют внимания» проекты с проблемами сгруппированы сверху — не внесена предоплата, оплата по тарифу истекла, дедлайн просрочен или близко, в проекте нет задач, задачи не обновлялись давно, синхронизация устарела. Красные бейджи — критично, жёлтые — предупреждение. Если проблем нет, выводится «Все проекты в порядке».
  • Карточки проектов обогащены: бейдж тарифа (цвет тарифа), статус оплаты, «до {дата}» окончания оплаты, дедлайн, а в футере — счётчик проблем/предупреждений или «OK».
  • `APP_VERSION` поднят: `0.24.3` → `0.24.4` (`.env`, `.env.example`).
Открыть версию →
v0.24.3 06.08.2026 PATCH
Расположение кнопок на странице проекта
Usability: кнопки на странице редактирования проекта (Задание 80)
  • «Сохранить» теперь в самом низу страницы на всех вкладках, включая «Тариф»: кнопка вынесена за пределы формы проекта (связь через `form="project-form"`) и стоит последней. Раньше на вкладке «Тариф» она оказывалась выше содержимого, а внизу была «Опасная зона» — пользователь машинально тянулся вниз и мог случайно удалить проект.
  • «Отмена» перенесена в верхний правый угол карточки (рядом с заголовком) — продублированная кнопка внизу удалена.
  • «Удалить проект» убрана со страницы редактирования (блок «Опасная зона» удалён) — она больше не висит под каждым табом.
  • Kebab-меню на карточке проекта (`/admin/projects/{id}`): в правом верхнем углу шапки добавлена кнопка «⋮», по нажатию — пункт «Удалить проект» с подтверждением. Удаление доступно только оттуда.
  • `APP_VERSION` поднят: `0.24.2` → `0.24.3` (`.env`, `.env.example`).
Открыть версию →
v0.24.2 06.08.2026 PATCH
Починено сохранение тарифа на странице проекта + дедлайн
Исправление: не сохранялась подписка по проекту (Задание 79)
  • Причина: вкладка «Тариф» на странице редактирования проекта находилась внутри основной формы сохранения проекта — браузер игнорирует вложенные `<form>`, и кнопка «Оформить подписку по проекту» отправляла форму обновления проекта без полей тарифа. Данные не сохранялись.
  • Исправление: панель «Тариф» (форма оформления и таблица подписок) вынесена из формы проекта — теперь обе формы работают независимо, подписка по проекту сохраняется корректно.
  • Поле «Дедлайн» (`deadline`) у подписки: в форме тарифа проекта вместо «Следующий платёж» теперь поле «Дедлайн (срок выполнения)» — к какому сроку выполнить задание / первую итерацию (по методологии Iterative Incremental Delivery). Поле добавлено и в форму на карточке пользователя.
  • Отображение дедлайна: колонка «Дедлайн» в таблицах подписок (вкладка «Тариф» проекта и карточка пользователя), а клиенту на странице «Тариф» (`/tariff`) показывается: тариф, факт внесения предоплаты (сумма) и дедлайн выполнения.
  • `APP_VERSION` поднят: `0.24.1` → `0.24.2` (`.env`, `.env.example`).
Открыть версию →
v0.24.1 06.08.2026 PATCH
Тариф на странице проекта
Тариф на странице редактирования проекта (Задание 78)
  • Админ: вкладка «Тариф» на странице редактирования проекта (`/admin/projects/{id}/edit`): можно сразу отметить тариф по проекту — выбрать клиента (по умолчанию владелец проекта), тариф, даты начала/окончания, следующий платёж, оплачено и комментарий админа. Подписка привязывается к проекту и клиенту.
  • Список подписок по проекту на той же вкладке: тариф, клиент, статус, даты, платёж, оплата; смена статуса и удаление подписки возвращают обратно на страницу проекта.
  • Клиент видит тариф: оформленная по проекту подписка попадает в личный кабинет клиента (раздел «Тариф» на `/tariff`) и в карточку пользователя в админке.
  • Связь `Project::subscriptions()` добавлена в модель.
  • `APP_VERSION` поднят: `0.24.0` → `0.24.1` (`.env`, `.env.example`).
Открыть версию →
v0.24.0 05.08.2026 PATCH
Тарифы и подписки
Тарифы и подписки (Задание 77)
  • Админ: раздел «Тарифы» (`/admin/tariffs`): полный CRUD тарифов — название, slug, описание, преимущества, базовая цена, рассрочка (месяцев × платёж), часовая ставка, время реакции, уровень поддержки, цвет, иконка, порядок, флаги (публичный/популярный/VIP), пререквизит для VIP-тарифа. Карточка тарифа в списке показывает цену, рассрочку, часовую ставку, статус, число подписок.
  • 5 тарифов из калькулятора перенесены и засеяны (`TariffSeeder`): Базовый запуск (3 000 BYN), Цифровая архитектура (6 000 BYN), Экосистема роста (12 000 BYN), Стратегическое партнёрство (15 000 BYN, VIP — доступен после тарифа 3), Итеративная инкрементная поставка (6 000 BYN).
  • Админ: блок «Тариф и подписка» в карточке пользователя (`/admin/users/{id}`): оформление подписки клиенту (тариф, проект, даты начала/окончания, следующий платёж, оплачено, комментарий), таблица подписок со сменой статуса (активна/отменена/завершена/истекла) и удалением.
  • Таблица `client_subscriptions` client_id, tariff_id, project_id, статус, оплачено, даты, ежемесячный платёж, сумма, число платежей, комментарий админа.
  • Клиент: страница «Тариф» (`/tariff`): карточки публичных тарифов с ценой, рассрочкой, преимуществами, временем реакции и уровнем поддержки; VIP-тариф показывается закрытым с указанием пререквизита; вверху — текущая активная подписка клиента (тариф и дата следующего платежа).
  • Меню: у клиента — пункт «Тариф», у админа — «Тарифы».
  • `APP_VERSION` поднят: `0.23.0` → `0.24.0` (`.env`, `.env.example`).
Открыть версию →
v0.23.0 05.08.2026 MINOR
Восстановление доступа и воронка писем
Восстановление доступа (Задание 76)
  • Кнопка «Забыли пароль?» на странице входа (`/login`): открывается форма восстановления доступа, где достаточно ввести email — на него отправляется 5-значный код.
  • Форма восстановления (`/login/forgot`): ввод email → отправка кода → ввод кода → вход в личный кабинет без пароля. Код действителен 5 минут, повторную отправку можно сделать через 60 секунд.
  • Письма с кодом восстановления (`password_reset`): шаблон письма с крупным кодом, названием проекта, кнопкой «Перейти на страницу проекта». Отправляется через SMTP-настройки платформы (вкладка «Почта» в настройках) или в лог в режиме разработки.
  • Воронка писем (`mail_logs`): каждая отправка фиксируется: `pending → sent/failed → delivered (принято сервером) → opened (пиксель-трекер) → clicked (переход по кнопке) → verified (ввод кода) → authed (вход в кабинет)`.
  • Пиксель-трекер открытия (`/p/{token}/mail-open/{logId}` — отдаёт 1×1 GIF) и **трекер кликов** (`/p/{token}/mail-click/{logId}` с перенаправлением на страницу проекта или вход).
  • Админ: раздел «Почта» (`/admin/mail`): статистика воронки (отправлено / доставлено / открыто / клики / подтверждено / входы / ошибки), список всех писем с фильтрами по типу и статусу, кнопка «Отправить тестовое письмо», удаление записей.
  • Клиент: раздел «Сообщения» (`/mail`): список всех писем, отправленных клиенту платформой, с типом, темой, статусом и статистикой.
  • Уведомления в кабинете: при подтверждении email и при восстановлении доступа клиенту приходит уведомление в личный кабинет.
  • Подтверждение email из личного кабинета: если email не подтверждён, на дашборде показывается баннер «Подтвердите ваш email» с кнопкой отправки кода и формой ввода — подтвердить почту можно, не переходя по ссылке из письма (`/settings/verify-email/send`, `/settings/verify-email/verify`).
  • Настройки → вкладка «Почта»: SMTP-сервер (хост, порт, логин, пароль, шифрование), отправитель, темы писем, вступительный текст и подпись.
  • `APP_VERSION` поднят: `0.22.2` → `0.23.0` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.22.2 05.08.2026 MINOR
Токены доступа сразу после ссылки для клиента
Расположение токенов на странице проекта (Задание 75)
  • Блок «Токены доступа» перемещён вверх теперь он идёт сразу после «Ссылка для клиента» и перед списком задач. Раньше токены были в самом низу страницы после 517 задач — приходилось долго скроллить. Теперь ссылка для клиента и генерация токенов рядом, без прокрутки.
  • Логика Алексея: «работаем с токенами — они должны быть рядышком». Блок токенов (создание/генерация, таблица токенов) сохранён без изменений, изменён только порядок секций.
  • `APP_VERSION` поднят: `0.22.1` → `0.22.2` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.22.1 05.08.2026 PATCH
Kebab menu в списке проектов и колонка «Платформы»
Kebab menu и настройка полей (Задание 74)
  • Kebab menu (три точки) в списке проектов (`/admin/projects`): вместо явных кнопок «Просмотр / Редактировать / Удалить» теперь одна компактная кнопка «⋮» с выпадающим меню. Внутри меню: Просмотр, Редактировать, История, Экспорт, а **Удалить — в самом низу отдельным красным пунктом** (защита от случайного нажатия). Кнопка удаления больше не висит рядом с часто используемым «Редактировать».
  • Колонка «Платформы» в настройках полей: в выпадающем меню «Настройка полей» появился пункт «Платформы» — при включении показывается колонка, где видно, каким платформам принадлежит каждый проект (бейджи с иконками платформ; для `production.ipd.by` — пометка «(скоро)»). По умолчанию колонка скрыта, как «Пользователи»/«Токен».
  • Поведение меню: открывается по клику, закрывается по клику вне меню, по Escape и при открытии другого кебаб-меню.
  • `APP_VERSION` поднят: `0.22.0` → `0.22.1` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.22.0 05.08.2026 PATCH
Платформы: единый центр экосистемы IPD
Платформы (Задание 73)
  • Новый раздел «Платформы» для клиентов (`/platforms`): единый центр экосистемы IPD, из которого клиент по своему аккаунту (email) переходит на другие платформы без повторной авторизации — аналог экосистемы Google.
  • Платформы привязываются к пользователям и к проектам: доступ к платформе клиент получает, если платформа привязана к его аккаунту напрямую или к его проектам (через владение или связь).
  • SSO-переход без повторной авторизации: для перехода создаётся одноразовый короткоживущий токен, привязанный к аккаунту клиента; клиент бесшовно перенаправляется на целевую платформу. Токены хранятся в отдельной таблице и имеют ограниченный срок действия.
  • Платформы:
  • Новые таблицы: `platforms` (name, slug, url, description, icon, color, is_active, is_client_accessible, sort_order), `client_platform` (привязка к клиентам), `project_platform` (привязка к проектам), `platform_sso_tokens` (SSO-токены).
  • Администрирование платформ (`/admin/platforms*`): CRUD платформ, привязка клиентов и проектов, статусы «Доступна клиентам» / «Активируется позже» / «Неактивна», сортировка, иконки и цвета. Все действия логируются в `activity_log` (`platform_created`, `platform_updated`, `platform_deleted`, `platform_enter`).
  • Интеграция с пользователями: на странице пользователя (`/admin/users/{id}`) секция «Платформы» с таблицей привязок; в форме редактирования — чекбоксы доступных платформ.
  • Интеграция с проектами: на странице проекта (`/admin/projects/{id}`) секция «Платформы» с бейджами статуса; в форме редактирования — таб «Платформы» с чекбоксами.
  • Сайдбар: пункт «Платформы» в клиентской навигации и «Платформы (Админ)» в администрировании.
  • `APP_VERSION` поднят: `0.21.2` → `0.22.0` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.21.2 05.08.2026 MINOR
Проекты у пользователя: кнопка редактирования и управление проектами
Проекты у пользователя (Задание 72)
  • Кнопка «Редактировать» на странице пользователя (`/admin/users/{id}`): теперь в шапке рядом с именем и внизу страницы есть кнопки «Редактировать» и «Безопасность», которые ведут на форму редактирования и настройки безопасности. Раньше кнопки редактирования на странице пользователя не было.
  • Управление проектами на странице пользователя: в таблицах «Проекты (владеет)» и «Проекты (доступ через связи)» у каждого проекта появились кнопки «Редактировать» (переход к редактированию проекта) и «Убрать» (снятие проекта с пользователя).
  • Снятие владения проектом в форме редактирования: добавлена секция «Проекты (владеет)» с чекбоксами — можно снять отметку с проекта, чтобы передать его в «без владельца» (при сохранении `client_id` проекта становится `null`, действие логируется в `activity_log`).
  • `APP_VERSION` поднят: `0.21.1` → `0.21.2` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.21.1 05.08.2026 PATCH
Исправление редактирования пользователя, toast-уведомления
Исправление редактирования пользователя (Задание 71)
  • Исправлен критический баг формы редактирования (`/admin/users/{id}/edit`): вложенные `<form>` (Подтвердить email/Telegram/телефон) внутри главной формы ломали HTML-структуру — браузер закрывал главную форму на первой вложенной, из-за чего чекбоксы «Активен» и «Проекты» и кнопка «Сохранить» оказывались вне формы и **сохранение не отправлялось**. Проверки перенесены в отдельные формы (`form`-атрибут кнопок), главная форма снова корректна.
  • Toast-уведомления: при любых действиях (сохранение, подтверждение email, ошибки) в правом верхнем углу появляется всплывающее сообщение (зелёное — успех, красное — ошибка, синее — инфо), исчезает через ~3,5 сек. Добавлены также стили для `alert-error` и `alert-info` (показ ошибок в верхней части контента).
  • `APP_VERSION` поднят: `0.21.0` → `0.21.1` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.21.0 05.08.2026 PATCH
Редактирование пользователя и логирование действий
Редактирование пользователя (Задание 70)
  • Исправлено сохранение имени/фамилии при редактировании пользователя (`/admin/users/{id}/edit`): изменения полей name, email, company, phone, telegram, role, is_active, пароль сохраняются и отображаются на странице пользователя.
  • Логирование изменений пользователя: при каждом обновлении в `activity_log` записывается действие `user_updated` с деталями изменённых полей (старое значение → новое), например: `name: «Егор» → «Егор Савинский»`.
  • Логирование всех действий администрирования пользователей: создание (`user_created`), удаление (`user_deleted`), подтверждение email/telegram/телефона (`user_email_verified` и др.), настройки безопасности (`user_security_updated`). В каждом логе — кто (администратор), когда, IP и детали.
  • Новый пункт меню «Логи» в разделе «Администрирование» сайдбара → страница `/admin/logs` (журнал действий по всей системе, с фильтром по действию и клиенту, пагинация).
  • `APP_VERSION` поднят: `0.20.4` → `0.21.0` (`.env`, `.env.example`, `config/app.php`).
Открыть версию →
v0.20.4 04.08.2026 MINOR
Восстановление пользователей и полный переимпорт данных
Восстановление данных (Задание 68)
  • Критическая находка: приложение VDS my-dev.ipd.by реально использует БД **`my_ipd_dev_app`** (v0.20.x), а не `my_ipd_dev` (v0.14.x), из которой данные были импортированы в v0.20.3.
  • Пользователи восстановлены: **9 клиентов** импортировано из актуальной БД (Администратор, Иван Петров, Тестовый Пользователь, Демо Клиент, **Егор** (real client, egor@jetpeel.club, +7 926 899 4992), Алексей, Анна Петрова, Иван Сидоров, Тестовый Клиент).
  • Привязки и токены: импортированы `client_project` (Егор → Бобер Боб), **4 client_tokens** (включая bbOiPf…, views 7), 5 `client_auth_known_accounts`.
  • Полный переимпорт из `my_ipd_dev_app`: 14 направлений, 13 проектов, **639 задач** (330 completed / 244 in_progress / 65 planned), **259 steps** — заменили неполные данные v0.20.3 (11/14/247).
  • Исправлены данные v0.20.3: проекты task.ipd.local / ipd.local / OSPanel / DOS заменены на реальные (Дизайн-проект, Mysteria ×2, Медтехника Гродно ×2, Бобер Боб и др.); `pending` → `planned`; пересчитаны tasks_count / tasks_total / tasks_completed / progress_pct.
  • `APP_VERSION` поднят: `0.20.3` → `0.20.4` (`.env`, `.env.example`, `config/app.php`).
Настройка полей проекта (Задание 69)
  • Новая колонка «Тотал командер» в списке `/admin/projects`: показывает наличие `tc_path` (иконка папки + имя последней папки пути, tooltip с полным путём) и доступна в выпадающем меню «Настройка полей».
  • Новая колонка «Редактирован» (`updated_at`): видна по умолчанию, доступна в «Настройка полей», добавлена в сортировку.
  • Сортировка по умолчанию — по дате редактирования (убыванию): последний редактируемый проект всегда сверху (`sort_by=updated_at`).
  • Сохранение видимости колонок: в localStorage — новые колонки сохраняют своё состояние как и остальные.
Открыть версию →
v0.20.3 04.08.2026 PATCH
Восстановление данных с VDS
Восстановление данных
  • Восстановлены реальные данные с VDS my-dev.ipd.by (v0.14.3) в локальную БД my_ipd_local (v0.20.3)
  • 11 направлений импортировано (Продажи, Производство, Развитие, Личное, AmoCRM, Маркетинг, Поддержка/сервис, Сайты, Автоматизация, Обучение, Финансы)
  • 14 проектов импортировано (Mysteria, Каменецкое, Медтехника Гродно, Алексей Гапеев, Бобер Боб, АгроБетон, AmoCRM, и др.)
  • 247 задач импортировано с привязкой к проектам и направлениям
  • Транслитерация статусов русские → английские (активно→active, завершена→completed и др.)
  • VDS-специфичные поля сохранены в JSON meta (risks, ai_note, horizon, completed_date, start_date)
  • ВАЖНО: в v0.20.4 данные этого раздела заменены на полный переимпорт из актуальной БД `my_ipd_dev_app` (этот раздел исторический)
Исправления
  • Исправлен инцидент TaskApiService.php на VDS (Undefined array key "status")
Открыть версию →
v0.20.0 03.08.2026 PATCH
Страница «О платформе»: полный редизайн по образцу
Страница «О платформе» (Задание 64)
  • Страница `/about` переписана полностью по образцу `admin-platform-heart.ipd.test/about` (платформа Admin Platform Heart, ООО «Студия ИПД»). Сохранена вся логика и архитектура образца, дизайн пересобран под фирменные токены IPD (синий акцент, светлая/тёмная тема, единый CSS).
  • Hero-блок: логотип IPD (белая плитка с тремя растущими барами — фирменный мотив), бейдж «Система управления проектами», версия платформы, заголовок, подзаголовок и описание.
  • Что это за платформа: сетка из шести ячеек с SVG-иконками (направления и проекты, задачи с шагами, гостевые ссылки, документы, синхронизация, админ-панель).
  • Информация о системе: платформа + версия, PHP, стек (Laravel + Vite/Tailwind), БД, авторизация, сервер, среда.
  • Кто развивает: блок ООО «Студия ИПД» с официальным юрлицом, сертификаты партнёра amoCRM (amoSTART, 31 июля 2026) с лайтбоксом для просмотра и поясняющей заметкой.
  • Контакты: фото Алексея Гапеева (`public/img/admin/aleksey-gapeev.jpg`), Telegram-бот, личный Telegram, два телефона, email — кликабельные ссылки (t.me/tel/mailto).
  • История версий: парсер changelog.md расширен — теперь показываются не только версия/дата/заголовок, но и разделы (`###`) с пунктами (`- **Жирное** текст`) и бейджи типа релиза (MAJOR/MINOR/PATCH).
  • Логика/архитектура взята из образца: новый контроллер `app/Http/Controllers/AboutController.php` (парсер changelog + данные platform/company/contacts/certificates/system), маршрут `/about` переведён на контроллер.
  • Стили в `app.css`: страница оформлена токенами дизайн-системы (hero с градиентом и декоративными radial-градиентами, карточки, сетки, info-строки, бейджи версий, лайтбокс). Без инлайн-`<style>` (требование теста `assertDontSee('</style>')`).
  • Сертификаты скопированы в `public/assets/certificates/` (4 webp: disp + full).
  • Проверено в headless Chrome (Playwright): hero с логотипом и версией, 6 ячеек, 7 info-строк, 2 сертификата с открытием лайтбокса, 5 контактов, история версий (45 записей с секциями), кнопки ссылок; без ошибок консоли; светлая и тёмная темы.
  • `APP_VERSION` поднят: `0.19.4` → `0.20.0` (`.env`, `.env.example`, `config/app.php`).
  • Тест `DesignSystemRenderTest::test_version_shows_0_19_4` → `test_version_shows_0_20_0`.
Открыть версию →
v0.19.4 03.08.2026 MINOR
Дизайн в зависимости от URL: z-index футера и смещение кебаба
Причина (Задание 63): две независимые проблемы, обе «привязаны» к страницам первого уровня
  • 1) `.version-footer` с `z-index: 1000` перекрывал контент на dashboard. Плашка версии (`partials/version-footer.blade.php`) — `position: fixed; bottom: 12px; left: 12px; z-index: 1000`. На страницах, где она есть (`/dashboard`), фиксированный элемент с z-index 1000 ложился поверх карточек/меню; при отключении z-index визуально всё приходило в норму (подтвердил Алексей, тестируя в DevTools). **Исправлено:** `z-index: 1000` убран из `.version-footer`.
  • 2) Инлайн-стили карточного кебаба перетекали на topbar-кебаб `#kebabWrap` → кнопка ⋮ смещалась на ~10–12px вниз. В `dashboard/index.blade.php` и `admin/index.blade.php` карточки проектов используют `.kebab-wrap { position: absolute; top: 12px; right: 12px; }` и `.kebab-btn { padding: 4px 6px; font-size: 18px; line-height: 1; }` (специфичность 0,1,0). Эти же классы совпадали с topbar-кебабом (`#kebabWrap`, `#kebabBtn`), который лежит в лэйауте **на всех app-страницах**. Правило `body.app-layout #kebabWrap { position: relative }` из `app.css` (специфичность 0,2,1) перебивало `position: absolute` (что хорошо — topbar-кебаб должен быть relative), но **не перебивало** `top: 12px` и `padding/font-size/line-height` у `.kebab-btn`, потому что в `app.css` эти свойства для topbar-кебаба не заданы вовсе. Итог: на `/dashboard` и `/admin` (страницы первого уровня, где есть карточные кебабы) topbar-кнопка ⋮ опускалась на 12px и получала лишний padding. На `/admin/sync`, `/admin/projects` и других глубоких страницах инлайн-блока с `.kebab-wrap` нет — смещения нет. Отсюда и «дизайн зависит от URL».
  • Исправление: инлайн-стили карточного кебаба заскоуплены под `.pr-card` в обоих файлах (`.pr-card .kebab-wrap`, `.pr-card .kebab-btn`, `.pr-card .kebab-menu`, ...). Теперь они влияют только на кебабы внутри карточек и не трогают topbar `#kebabWrap`/`#kebabBtn`.
  • Проверено в headless Chrome (Playwright): на `/dashboard` и `/admin` topbar-кнопка ⋮ выровнена по центру с колокольчиком и user-menu (cy=37, до фикса 49 — смещение устранено); карточный кебаб по-прежнему `position: absolute; top: 12px`; `version-footer` `z-index: auto`; ошибок консоли нет. `/admin/sync`, `/admin/projects` — без изменений (как и было).
  • `APP_VERSION` поднят: `0.19.3` → `0.19.4` (`.env`, `.env.example`, `config/app.php`).
  • Тест `DesignSystemRenderTest::test_version_shows_0_19_3` → `test_version_shows_0_19_4`.
Открыть версию →
v0.19.3 03.08.2026 PATCH
Исправление «слетевшего» дизайна на страницах первого уровня
Причина: конфликт CSS-специфичности у kebab-кнопок (Задание 62)
  • Симптом: на страницах первого уровня вложенности (`/dashboard`, `/admin`) «слетал» дизайн карточек: кнопка-«кебаб» (⋮) оказывалась в левом верхнем углу карточки как квадратная кнопка 36×36 с рамкой и заливкой, сдвигая контент вниз. На страницах 2–3-й глубины (`/admin/settings`, `/admin/projects`, ...) визуально всё было в порядке.
  • Гипотеза о кривых путях опровергнута: все `<link>`/`<script>`-ассеты абсолютные (`https://my.ipd.test/build/assets/...`), одинаковые на всех страницах, независимо от глубины URL. Относительных `src`/`href`/`action`/`url()` в HTML и CSS нет.
  • Настоящая причина — специфичность селекторов: для kebab-меню в шапке (`#kebabWrap`) в `resources/css/app.css` были общие правила `body.app-layout .kebab-wrap { position: relative }` и `body.app-layout .kebab-btn { width: 36px; ... border: 1px solid ... }` (специфичность 0,2,1). Эти же классы использовали карточки проектов на `/dashboard` и `/admin` со своими инлайн-стилями `.kebab-wrap { position: absolute; top: 12px; right: 12px }` и `.kebab-btn { background: none; border: none }` (специфичность 0,1,0). Правила из `app.css` выигрывали по специфичности и «ломали» карточный кебаб.
  • Исправление: стили topbar-кебаба в `resources/css/app.css` заскоуплены на `#kebabWrap` (`body.app-layout #kebabWrap ...`) — карточный кебаб теперь получает свои инлайн-стили: `position: absolute; top: 12px; right: 12px`, прозрачная кнопка без рамки, меню раскрывается в правом верхнем углу карточки.
  • Проверено в headless Chrome (Playwright): на `/dashboard` и `/admin` `.pr-card .kebab-wrap` имеет `position: absolute`, кнопка прозрачная (30×29px, без рамки), позиция в правом верхнем углу карточки; topbar `#kebabWrap` по-прежнему `position: relative` с кнопкой 36×36; меню открывается по клику; ошибок консоли нет. `/admin/settings` не содержит карточных кебабов — поэтому там дизайн и не «слетал».
  • `APP_VERSION` поднят: `0.19.2` → `0.19.3` (`.env`, `.env.example`, `config/app.php`).
  • Тест `DesignSystemRenderTest::test_version_shows_0_19_2` → `test_version_shows_0_19_3`.
Открыть версию →
v0.19.2 03.08.2026 PATCH
Сайт на HTTPS
HTTPS для локального сайта (Задание 61)
  • `my.ipd.test` переведён на HTTPS: `herd secure my.ipd.test` сгенерировал TLS-сертификат (валиден до 03.08.2027), подписанный локальным CA «Laravel Valet CA Self Signed» (доверен в хранилище Windows). Созданы `Certificates/my.ipd.test.crt|key` и nginx-конфиг `Nginx/my.ipd.test.conf`.
  • HTTP → HTTPS: запросы на `http://my.ipd.test` автоматически получают **301 → `https://my.ipd.test`** (nginx). Сайт открывается только по HTTPS.
  • SAN сертификата: `my.ipd.test` + `*.my.ipd.test`.
  • `APP_URL` обновлён: `http://my.ipd.test` → `https://my.ipd.test` (`.env`, `.env.example`) — все генерируемые ссылки, редиректы и формы теперь ведут на HTTPS.
  • `APP_VERSION` поднят: `0.19.0` → `0.19.2` (`.env`, `.env.example`, `config/app.php`).
  • Тест `DesignSystemRenderTest::test_version_shows_0_19_0` → `test_version_shows_0_19_2`.
  • Существующие сессии и «запомненный» вход сохранены: конфигурация куки не изменилась, авторизация пользователей не была сброшена при переходе на HTTPS.
Открыть версию →
v0.19.0 02.08.2026 PATCH
Экосистема дизайна
Дизайн-токены и единый CSS (Задание 59)
  • Весь CSS вынесен из `<style>`-блоков в `resources/css/app.css` и подключён через Vite (`@vite`). Больше не нужно править стили в 30 view-файлах: токены, типографика, sidebar, dropdowns, формы, бейджи — в одном месте.
  • Дизайн-токены унифицированы: оба неймспейса переменных (`--card-bg`/`--muted` для app и `--bg-card`/`--text-muted`/`--success` для guest) определены вместе в тёмной и светлой темах. Добавлены недостающие токены (`--bg-secondary`, `--radius-md/lg`, `--info`, `--tag-bg`), которые раньше не были определены и не работали.
  • Стили app- и guest-лэйаутов разграничены через классы `body.app-layout` и `body.guest-layout` — конфликт `.topbar`/`.main`/`.body` между лэйаутами исключён.
Авто-тема (light/dark/auto)
  • `prefers-color-scheme`: если пользователь не выбирал тему явно, сайт следует системной теме; при смене темы ОС сайт переключается на лету. Явный выбор в localStorage по-прежнему в приоритете.
  • Защита от «вспышки» темы: тема выставляется инлайн-скриптом в `<head>` до рендера, плюс CSS-фолбэк `html:not([data-theme])` для выключенного JS.
  • Логика темы и мобильного меню переехала из лэйаутов в `resources/js/app.js` (единая точка).
Blade-компоненты форм
  • Созданы **`x-input`, `x-textarea`, `x-select`, `x-button`, `x-checkbox`, `x-badge`** — единый API для форм: label + «*», подсказка, ошибка валидации, значение через `old()`.
  • Формы переведены на компоненты (admin users/projects/tasks — create и edit): локальные `<style>`-блоки удалены, стили взяты из глобального CSS. Новые страницы смогут собирать формы из компонентов без дублирования стилей.
  • Единый стандарт полей: высота 40px, focus-подсветка, стрелка у `select`, `color-scheme` под тему (календарь/скроллбар), `textarea` от 96px с `resize: vertical`.
Прочее
  • Публичные страницы переведены на guest-лэйаут: вход (`/login`), установка пароля, «О платформе», гостевая сводка `/s/{token}` больше не standalone-страницы со своими `<style>`-блоками — у них единая шапка, авто-тема, футер и глобальный CSS.
  • `APP_VERSION` поднят: `0.18.2` → `0.19.0` (`.env`, `.env.example`, `config/app.php`).
  • Создана документация **`DESIGN_SYSTEM.md`** (токены, лэйауты, компоненты, чеклист для агентов, доступность AA).
Открыть версию →
v0.18.2 02.08.2026 MINOR
Дизайн: читаемость, контраст, поля ввода
Поля ввода (Задание 58)
  • Textarea «Описание» на вкладке API key стала современной: вместо дефолтного «квадратика 170×40» — высота от 96px, ширина до 560px, скруглённые углы, `resize: vertical`, focus-подсветка (акцентная рамка + мягкое свечение). Один стандарт применён ко всем `textarea` в настройках и формах (admin projects/tasks/users).
  • Подсказки и метки полей подняты с 11px до 14px.
Типографика и контраст (рекомендации Google Material Design)
  • Минимум 14px для основного текста по всему сайту: убраны шрифты 9–13px у заголовков таблиц, меток, описаний, подписей, журналов, уведомлений, футеров. 13px оставлены только для мелких бейджей/кода.
  • Контраст текста повышен: серые оттенки заменены на более тёмные в светлой теме (`#64748b` → `#475569` для secondary-текста), захардкоженные цвета (`#94a3b8`, `#cbd5e1`, `#eab308`, `#60a5fa` и др.) заменены на переменные темы (`--muted`, `--text-secondary`, `--warning`, `--accent`, `--purple`, `--green`, `--red`).
Сайдбар и темы
  • Светлая тема — чёрный текст в боковой панели: введены переменные `--sidebar-text`, `--sidebar-text-hover`, `--sidebar-text-active` (тёмная: `#cbd5e1`/`#f8fafc`/`#fff`; светлая: `#1e293b`/`#0f172a`/`#0f172a`). Активное меню в светлой теме теперь чёрное (раньше только синяя подсветка).
  • При переключении темы цвет текста реально меняется (раньше в обеих темах sidebar был один и тот же серый).
  • Пройдены страницы: dashboard, проекты (dashboard/admin), пользователи, задачи, синхронизация, логи, настройки, API keys, токены, вкладка безопасности, guest-проект, вход, установка пароля, «О платформе», пагинация.
Открыть версию →
v0.18.1 02.08.2026 PATCH
API key: права доступа, платформы, история обмена
Вкладка «API key» как настоящая вкладка (Задание 57)
  • Вкладка «API key» теперь выглядит как остальные вкладки Настроек: панель табов (Основные / Безопасность / Интеграции / API key / Версии системы) видна всегда, а контент API-ключей обёрнут в тот же контейнер, что и другие вкладки. Раньше на вкладке «API key» табы вообще не показывались — она выглядела как отдельная страница.
  • Стили приведены в порядок: добавлены бейджи (статусы/права/платформы), кнопки `btn-sm`/`btn-accent`/`btn-red` — раньше классы были, а стилей для них в Настройках не было.
Права доступа (скоупы) для ключей
  • Новое поле `abilities` (JSON) в таблице `api_keys`: ключ теперь выдаётся с конкретными правами — `projects:read` (чтение проектов), `projects:write` (редактирование), `sync:run` (запуск синхронизации). В форме создания — чекбоксы с описанием каждого права, минимум одно.
  • Права ключа проверяются в единой точке middleware: запрос без соответствующего права отклоняется с кодом 403 и указанием нужного права. Устаревшие ключи без явно заданных прав проходят конвертацию в актуальную модель прав при первом обращении.
Платформа и описание ключа
  • Новое поле `platform` к какой платформе/агенту выдан ключ (n8n, ИИ-агент, внешняя платформа и т.д.), с подсказками через datalist. Отображается бейджем в списке и попадает в журнал.
  • Новое поле `description` произвольная заметка к ключу, показывается в списке и на странице ключа.
История обмена данными
  • Страница ключа (`/admin/api-keys/{id}`, кнопка «История» в списке): полная информация о ключе + таблица обращений — время, запрос (`GET /api/projects…`), результат (код 200/403/…), IP, User-Agent. Видно, как идёт обмен данными между платформами.
  • В лог добавляется `api_key_id` (новая колонка в `activity_log`): обращения привязаны к конкретному ключу; при удалении ключа история сохраняется (FK `SET NULL`).
  • Запросы с запретом прав логируются отдельно (`api_key_forbidden`) — видно, кто пытался делать то, что ему не разрешено.
Открыть версию →
v0.18.0 01.08.2026 PATCH
Создание API key
Раздел «Интеграции» → «API key» (Задание 56)
  • Новая вкладка «API key» в разделе «Интеграции» (Настройки → «API key»), где пользователь создаёт именованные API-ключи с названием проекта/платформы/агента. Система сама генерирует секретный ключ, показывая его один раз после создания.
  • Таблица `api_keys`: `client_id` (владелец ключа), `name` (название), `token` (SHA-256 хеш секрета — сырой ключ в БД не хранится), `prefix` (видимый идентификатор для списка), `is_active`, `last_used_at`, timestamps.
  • Ключ генерируется системой как криптостойкая случайная строка; в базе данных хранится только его необратимый хеш. Сырой ключ показывается один раз сразу после создания и в БД не сохраняется.
  • Управление ключами: активация/отзыв (без удаления истории), полное удаление; все действия пишутся в журнал активности (`api_key_created`, `api_key_revoked`, `api_key_activated`, `api_key_deleted`).
  • Доступ к API защищается ключами: система проверяет переданный ключ, отклоняет отозванные и неактивные, ведёт журнал обращений с привязкой к конкретному ключу — видно, какой пользователь что загружает и выгружает.
  • Журнал обращений по ключам: на вкладке «API key» показываются последние 20 событий по ключам (кто/что/когда).
Открыть версию →
v0.17.0 01.08.2026 MINOR
Управление проектом, Total Commander, API и синхронизация
Редактирование проекта в табах (Задание 55)
  • Страница редактирования переведена на вкладки (tabs) на всю ширину экрана вместо длинного списка на 640px: «Основное», «Клиенты и доступ», «Сайты проекта», «Total Commander / ИИ», «Данные». Поля распределены по категориям — открыл проект, сразу видишь, что часто редактируешь, а статичные данные (пользователи) спрятаны во вкладку, чтобы случайно не менять.
  • Основное открывается по умолчанию: название, статус и большое поле описания на всю ширину (220px высоты, resize) — удобно дописывать описание и добавлять логотип компании.
  • Вкладка «Данные»: External ID, источник, даты создания/обновления/последней синхронизации (только чтение) и переключатель «Проект активен».
Total Commander / ИИ (поле «искусственный интеллект»)
  • Новое поле `tc_path` (строка) в таблице `projects` — путь к папке проекта в Total Commander (первоисточник правды). Пример для Mysteria: `L:\Система\02 Клиенты\03 Активная работа\Mysteria\`.
  • Новое поле `meta` (JSON) с флагом `meta.ai_ready` — «Доступен ИИ-агентам (есть первоисточник)». Если включён, по проекту можно давать задания ИИ-агентам: они сканируют папку Total Commander и обновляют данные.
  • Новое поле `last_synced_at` (дата) — время последней синхронизации проекта; теперь проставляется автоматически при каждой синхронизации из папки.
  • Проект **Mysteria (ID 34):** заполнен `tc_path` = `L:\Система\02 Клиенты\03 Активная работа\Mysteria\`, `ai_ready = true`.
  • Страница проекта: блок «Total Commander / источник правды» с путём, индикатором «README.md найден/не найден» (+ дата изменения файла), бейджем «Доступен ИИ-агентам» и датой синхронизации.
Синхронизация из папки Total Commander (первоисточник правды)
  • Новый сервис синхронизации: читает `README.md` из папки, указанной в `tc_path`, и обновляет поля проекта: название (первая часть заголовка `#`), описание (цитата-блок под заголовком, кроме метаданных `**Ключ:**`), статус (строка `**Статус проекта:**`, маппинг эмодзи/слов), сайты (ссылки из таблиц README — пропускаются соцсети и нерабочие 🔴).
  • Кнопка «Синхронизировать сейчас» на странице проекта — мгновенная синхронизация одного проекта.
  • Artisan-команда `php artisan project:sync` синхронизация всех проектов с указанным `tc_path` (вывод: что обновлено); `--id=34` — только один проект.
  • Идемпотентность: повторная синхронизация без изменений в README не трогает данные (только обновляет `last_synced_at`).
  • Синхронизация фиксируется в журнале изменений (action `project_synced`).
API для ИИ-агентов (json + токен)
  • Новый API (`/api/projects`, защищён передаваемым ключом доступа из окружения): система может подключиться к платформе, получить и подправить данные проекта — то, что нужно n8n и ИИ-агентам.
  • `GET /api/projects` — список проектов (id, name, status, tc_path, ai_ready, links).
  • `GET /api/projects/{id}` — полный экспорт проекта (схема `ipd.project.export.v1`).
  • `PUT /api/projects/{id}` — обновление полей из JSON (name, description, status, external_id, tc_path, source, links, meta, is_active) с валидацией; логируется `project_updated_api`.
  • `POST /api/projects/{id}/sync` — триггер синхронизации из папки Total Commander.
  • Без токена или с неверным токеном — `401 Unauthorized`; несуществующий проект — `404`.
Экспорт / импорт JSON (экосистема синхронизации)
  • Экспорт: кнопка «Экспорт JSON» на странице проекта скачивает полный JSON проекта (схема `ipd.project.export.v1`): название, описание, статус, external_id, tc_path, links, meta, владелец, пользователи, даты. Общий сборщик payload вынесен в сервис `ProjectExporter` (используется экспортом и API).
  • Импорт: форма на странице проекта загружает JSON (выгруженный экспортом) и обновляет название, описание, статус, сайты, Total Commander, external_id, source. Валидация корректности JSON и допустимости статуса.
  • Импорт фиксируется в журнале изменений (action `project_imported`).
Техническое
  • `APP_VERSION`: `0.16.1` → `0.17.0` (`.env` и `config/app.php`).
  • Миграция `2026_08_01_110001_add_tc_and_meta_to_projects_table.php` (`tc_path`, `last_synced_at`, `meta`).
  • Маршруты: `GET /admin/projects/{id}/export`, `POST /admin/projects/{id}/import`, `POST /admin/projects/{id}/sync`, API `GET/PUT/POST /api/projects...`.
  • Сервисы: `app/Services/ProjectExporter.php`, `app/Services/ProjectSyncService.php`; команда `app/Console/Commands/SyncProjects.php`; middleware `app/Http/Middleware/ApiToken.php`.
Открыть версию →
v0.16.1 01.08.2026 MINOR
Имена 2: доверие и ссылки на сайты
Блок доверия на гостевой странице (Задание 54)
  • Имя с фамилией: «Алексей ведёт ваш проект» → «Здравствуйте! Я Алексей Гапеев — веду ваш проект». ФИО администратора обновлено в БД (name = «Алексей Гапеев»).
  • Фотография: на гостевой странице появилась фотография Алексея (`public/img/admin/aleksey-gapeev.jpg`), размещённая рядом с приветствием — страница стала более доброжелательной и доверительной.
  • Контакты по клику: по нажатию на имя «Алексей Гапеев» раскрывается блок «Связаться со мной» с Telegram-ботом (`@Aleksey_Gapeev_AI_bot`), двумя телефонами (+375 29 576-39-28, +375 29 698-83-70) и email (info@ipd.by). Контакты кликабельны (t.me, tel:, mailto:).
  • Контактные данные администратора (телефон, Telegram, публичный email) хранятся в настройках платформы и отображаются на публичных страницах для связи с клиентами.
Ссылки на сайты проекта
  • Новое поле `links` (JSON) в таблице `projects`: у каждого проекта теперь может быть несколько ссылок на сайты — пара «название + URL».
  • Админка: поле «Сайты проекта» в форме редактирования проекта (динамический список, кнопка «+ Добавить сайт») и вывод сайтов в виде чипов на странице проекта.
  • Гостевая страница: под приветствием выводятся чипы со ссылками на сайты проекта (открываются в новой вкладке).
  • Проект Mysteria (ID 34): заполнены 4 сайта — mysteria.ipd.by, osteopathy.mysteria.ipd.by, my.mysteria.ipd.by, adm.mysteria.ipd.by (источник правды: `L:\Система\02 Клиенты\03 Активная работа\Mysteria\README.md`). Описание обновлено на осмысленное из README (вместо «Тестовая среда dev.mysteria.ipd.by. Контентная итерация (121 файл).»).
Техническое
  • `APP_VERSION`: `0.16.0` → `0.16.1` (`.env` и `config/app.php`).
  • Миграция `2026_08_01_100001_add_links_to_projects_table.php`.
Открыть версию →
v0.16.0 31.07.2026 PATCH
Имена: гостевая страница проекта
Гостевая страница проекта /p/{token} (Задание 53)
  • Доброжелательное приветствие: вместо «Клиент приглашает вас ознакомиться с проектом» страница начинается с «Ваш личный проект» и блока «Алексей ведёт ваш проект. Ниже — что уже сделано и какие задачи сейчас в работе». Гость понимает, что это его проект, а ведёт его команда IPD.
  • Имя администратора: учётная запись администратора переименована с «Администратор» на «Алексей» — единое личное имя в админке, логах и приветствиях.
  • Заметные даты: в шапке страницы — «Проект ведётся с {дата}» и статус проекта; у каждой задачи — «создана {дата}» и срок; подписи укрупнены (13px вместо 11–12px) для читабельности.
  • Email-подтверждение перенесено в конец страницы и переработано в доброжелательный CTA: блок «Хотите быть в курсе ещё удобнее?», три шага (подтвердить email → войти в кабинет → настроить уведомления), кнопка «Подтвердить email — отправить код». Раньше форма с кодом была вверху и выглядела как требование персональных данных.
  • Мелкие серые тексты (8–11px «серым на сером») укрупнены и переведены на читаемые цвета: подписи сроков, сообщений, вложений, токена, подвал страницы.
  • Новый подвал страницы: «IPD Platform — ведение проектов для вашего бизнеса» + пояснение, что сервис ведёт этот проект (задачи, сроки, файлы, переписка).
Открыть версию →
v0.15.3 31.07.2026 MINOR
Роли: администратор и клиент
Администратор и клиент (Задание 52)
  • Разделение ролей: администратор больше не может быть владельцем проекта или участником. Администратор управляет платформой и мониторит проекты, владелец и участники — всегда клиенты (роль `client`/`test`).
  • Владелец проекта стал необязательным: при создании/редактировании проекта можно оставить «Без владельца» и назначить позже. Поле `client_id` теперь nullable в валидации и формах.
  • Управление на странице проекта: таблица «Пользователи» показывает владельца (бейдж «Владелец») и участников (бейдж «Участник»), с кнопками «Сделать владельцем», «Снять владельца», «+ Пользователь», «Уд.». Имя каждого пользователя — ссылка на его карточку.
  • Исключение администратора из выборов: в формах проекта (владелец, пользователи) и в форме добавления пользователя на странице проекта роль «Администратор» больше не появляется.
  • Проект «Mysteria» (ID 34): владелец изменён с администратора на клиента Владимира; администратор больше не фигурирует как владелец проекта.
  • Исправлен переход из кабинета клиента: карточки проектов на странице «Мои проекты» вели на админский маршрут `admin.projects.show` (недоступный клиенту) — теперь ведут на `client.projects.show`.
Открыть версию →
v0.15.2 31.07.2026 PATCH
Символы шагов → SVG-иконки
Дизайн, управление проектами (Задание 51)
  • Спецсимволы шагов задач заменены на SVG-иконки: на странице проекта в админке, на странице задачи (кнопки переключения), в личном кабинете клиента и в настройках безопасности.
  • Невыполненный шаг — иконка «кружок» `<x-icon name="circle">`, выполненный — «галочка» `<x-icon name="check">`; иконки векторные, наследуют цвет (зелёный для выполненных, вторичный для невыполненных).
  • Галочки верификации каналов связи (Email/Telegram/Телефон) на странице проекта заменены с `&#10003;`/`&#10007;` на `<x-icon name="check">` (зелёная) и `<x-icon name="x">` (красная); бейдж «Все каналы верифицированы 3/3» тоже использует иконку.
  • Размеры иконок: шаги 16px (админ-страница проекта) и 14px (кнопки/карточки).
Открыть версию →
v0.15.1 31.07.2026 PATCH
Дизайн форм задач + русификация
Дизайн форм задач (Задание 50)
  • Формы создания и редактирования задачи развёрнуты на всю ширину экрана (убран лимит `max-width: 640px`): компактные поля (название, статус, источник, приоритет, срок, получена) — сеткой в 3 колонки; «Что нужно от нас» / «Что нужно от клиента» — в 2 колонки; описание и первая запись — во всю ширину. Правка create автоматически подтянулась и в edit.
  • Приоритет теперь выбирается списком 0–10 («Без приоритета» … «10») вместо нативного числового поля `type="number"` (старое «маленькое окошко» высотой ~10px).
  • Иконка календаря у полей даты в тёмной теме стала белой — нативным полям добавлен `color-scheme: dark` (в светлой теме — `color-scheme: light`, иконка остаётся тёмной).
  • Кнопка «Выберите файл» переделана в современный стиль: пунктирная кнопка с иконкой загрузки, рядом отображается имя выбранного файла (JS). Тот же стиль применён к загрузке файла на странице задачи. Мультизагрузка не менялась — работает как раньше.
  • Дата добавления при редактировании: в шапке формы редактирования задачи показываются «Добавлена: дд.мм.гггг чч:мм · Обновлена: дд.мм.гггг чч:мм» (по-русски).
  • Общие улучшения полей: высота 42px, подсветка при фокусе (`box-shadow`), акцентные чекбоксы (`accent-color`), выпадающие списки с кастомной стрелкой, адаптивность (на узких экранах колонки схлопываются в одну).
Русификация интерфейса
  • Аксессоры статусов: `status_label` у `Task` (Запланирована/Активна/В работе/На паузе/Выполнена) и `Project` (Активен/Завершён/На паузе), `role_label` у `Client` (Администратор/Клиент/Тестовый).
  • Сырые английские статусы заменены на русские подписи по всему сайту: админ-дашборд, страницы и списки проектов, страницы пользователей (проекты владельца и по связям), гостевая страница проекта `/p/{token}`, личный кабинет клиента (список и детали проекта), страница задачи.
  • Роли пользователей в админке («актив»/`active` → роли): Администратор/Клиент/Тестовый.
  • Мелочи: бренд «IPD Platform» → «IPD» в шапке, подвале и `<title>` гостевого макета; «device:» → «устройство:» на странице безопасности; подпись «Email» → «Электронная почта» на странице входа.
Открыть версию →
v0.15.0 31.07.2026 PATCH
История проектов + Задачи, добавленные вручную
Задачи, добавленные вручную (Задание 49)
  • Миграция `2026_07_31_100001_add_task_sources_and_messages.php`:
  • Модели: `TaskMessage`, `TaskAttachment`, а также связи и аксессоры в `Task` (`messages`, `visibleMessages`, `attachments`, `visibleAttachments`, `is_manual`, `source_label`), `visibleTasks` в `Project`.
  • Администрирование (`AdminTaskController`):
  • Синхронизация (`SyncManager`): задачи из платформы создаются/обновляются только при `source=synced`; ручные задачи защищены от перезаписи (пропускаются с `skipped`). Импортированным задачам проставляется `source=synced` и `sync_origin`. Исправлена запись несуществующего поля `progress`.
  • Клиентские представления:
  • Кнопки «Копировать» ссылок проекта: устойчивый fallback для `http://my.ipd.test` (без secure context) через `execCommand`; при неудаче — окно-подсказка с готовой ссылкой для ручного копирования.
  • Срок действия ссылок: истёкшие токены явно помечаются (красный бейдж «Истекла» с датой) в админке и личном кабинете; в кабинете добавлена кнопка «Удалить» для истёкших/отозванных ссылок (`DELETE dashboard/projects/{id}/token/{tokenId}`).
  • Создание задачи сразу с первой записью и файлом: в форме задачи — текст записи (звонок/встреча/заметка/письмо/чат), видимость записи, файл (до 20 МБ) и его видимость.
  • Синхронизация: задачи без совпавшего локального проекта больше не создаются «висящими» без проекта (пропускаются с `skipped` — данные не теряются); в `sync_origin` записывается версия платформы (`Платформа · версия X`) и обновляется при каждой синхронизации.
  • Миграция `2026_07_31_110000_add_task_work_fields.php`: у задач новые поля `need_from_us` («что нужно от нас»), `need_from_client` («что нужно от клиента») и флаг `protected_from_sync` (защита от перезаписи импортом). Защищённые задачи пропускаются синхронизацией (`skipped`), как и ручные.
  • Клиентские страницы: задача показывает блоки «Нам нужно» / «Нужно от вас»; источник показывается нейтрально (Звонок/Встреча/Заказ/От клиента) без внутреннего ярлыка «Из платформы».
Добавлено
  • `app/Services/ActivityLogger.php` единый сервис записи активности (`client_id`, `project_id`, `action`, `details`, `ip`, `user_agent`) с защитой от ошибок журналирования.
  • Логирование действий администратора:
  • Страница истории проекта маршрут `GET /admin/projects/{id}/history`, метод `AdminProjectController@history`, вьюха `resources/views/admin/projects/history.blade.php` (пагинация по 50 записей, колонки: дата, пользователь, действие, детали, IP).
  • Секция «Последние изменения» на странице проекта — последние 10 записей активности со ссылкой «Вся история →».
Исправлено
  • `app/Services/Sync/SyncManager.php` — `logSync` писал в несуществующие колонки (`entity_type`, `entity_id`, `entity_name`, `old_value`, `new_value`), которые отбрасывались массовым назначением. Теперь пишет в `project_id` (null) и `details` (JSON со статистикой и ошибкой).
  • `importTasks` не писал несуществующую колонку `progress` (массовое назначение падало при синхронизации задач); поле удалено из `config/sync.php` (`entity_types.tasks.fields`).
Открыть версию →
v0.14.3 29.07.2026 MINOR
Страница проектов: сортировка, источник, настройка полей; Автоматическая синхронизация по расписанию
Добавлено
  • Сортировка по колонкам клик по заголовку таблицы (ID, Название, Клиент, Статус, Прогресс, Задач, Источник, Создан) сортирует по возрастанию/убыванию. Активная сортировка отмечена стрелкой ▲/▼.
  • Колонка «Источник» показывает, откуда проект: «Локальный» (создан вручную) или «Синхронизирован» (импортирован с другой площадки). Цветовые метки: зелёный / фиолетовый.
  • Кнопка «Настройка полей» выпадающий список с чекбоксами для скрытия/показа колонок. Выбор сохраняется в localStorage между сессиями.
  • Переданы `sort_by`, `sort_dir`, `per_page` через `appends()` в пагинацию — параметры сохраняются при перелистывании страниц.
  • `withCount('tasks')` — оптимизация для колонки «Задач» (без загрузки всей коллекции).
Изменено
  • `AdminProjectController@index` — поддержка `sort_by` (id, name, client, status, progress_pct, tasks_count, source, created_at) и `sort_dir` (asc/desc). Сортировка по клиенту через подзапрос `ORDER BY (SELECT name FROM clients WHERE ...)`.
  • `resources/views/admin/projects/index.blade.php` — полная переработка: динамические заголовки, чекбоксы колонок, скрипт localStorage, иконка глаза в кнопке.
Добавлено
  • `app/Console/Commands/SyncRun.php` — Artisan command `sync:run`
  • `routes/console.php` — `Schedule::command('sync:run')->hourly()->withoutOverlapping()`
  • `config/logging.php` — канал `sync` (daily, 30 дней хранения)
Открыть версию →
v0.14.2 29.07.2026 PATCH
Пагинация: русский язык, SVG-стрелки, выбор количества
Изменено
  • `resources/views/vendor/pagination/bootstrap-5.blade.php` — полная переработка: русский текст, SVG-иконки (`<x-icon name="arrow-right">`) вместо HTML-сущностей, компактный размер (32px), hover-эффекты, селектор количества записей на страницу
  • `app/Providers/AppServiceProvider.php` — зарегистрирован `Paginator::defaultView()` для использования кастомного шаблона
  • `app/Http/Controllers/Admin/AdminProjectController.php` — `paginate(20)` → `paginate(min($perPage, 100))` с поддержкой `?per_page=` из URL
  • `lang/ru/pagination.php` — создан файл русских переводов для пагинации
  • `resources/views/admin/projects/index.blade.php` — удалён старый CSS пагинации (стили теперь в шаблоне)
Исправлено
  • `config/sync.php` не подгружался из-за кэша конфигурации — `php artisan config:cache`
  • `resources/views/admin/sync/index.blade.php` — `route("admin.sync.preview", "")` падал с `UrlGenerationException` из-за пустого параметра `{platform}`. Заменено на `url("/admin/sync/preview")`
  • `app/Services/Sync/PlatformRegistry.php` — HTTP timeout для discovery уменьшен с 10s до 3s, чтобы страница не зависала при недоступных площадках
Открыть версию →
v0.13.4 29.07.2026 MINOR
SVG-иконки, типографика, контрастность
Added
  • Компонент `<x-icon>` (`resources/views/components/icon.blade.php`) — 14 SVG-иконок: eye, lock, link, arrow-right, kebab, refresh, trash, x, check, clipboard, circle, check-circle, mail, edit, users, settings
  • CSS-переменная `--text-secondary` (#cbd5e1 dark / #334155 light) для читаемого вторичного текста
  • CSS-переменные размеров `--fs-lg`, `--fs-xl`, `--fs-2xl`
Changed
  • Все HTML-emoji (&#128065;, &#128274;, &#128279;, &#8942;, &#8635;, &#128465;, &#10005;, &#8594;) заменены на `<x-icon>`
  • Все Unicode-emoji (✓, ✗, 🟢, 🟡, ⚪, 🔗, 📋, ✅, ○, ⚠, 📅) заменены на `<x-icon>`
  • Размер шрифта 11px → 12px во всех badge, label, hint, meta, footer
  • Размер шрифта 10px → 11px в таблицах (даты, метки)
  • Размер шрифта 9px → 11px в sidebar role-badge
  • Цвет текста `#64748b` и `#94a3b8` → `var(--text-secondary)` и `var(--muted)`
  • `th` заголовки цвет с `var(--muted)` на `var(--text-secondary)` для контраста
  • Ссылки с dashboard все ведут на `/admin/projects/{id}`, старый `/dashboard/projects/{id}` редиректит админа
  • Версия bump 0.13.3 → 0.13.4
Files Changed
  • `resources/views/components/icon.blade.php` — новый компонент
  • `resources/views/layouts/app.blade.php` — CSS-переменные, 9px/10px → 11px
  • `resources/views/dashboard/index.blade.php` — SVG + font-size 12px
  • `resources/views/admin/index.blade.php` — SVG + font-size 12px
  • `resources/views/admin/projects/show.blade.php` — SVG + font-size 12px
  • `resources/views/admin/projects/index.blade.php` — SVG + font-size 12px
  • `resources/views/admin/tokens/index.blade.php` — SVG + font-size 12px
  • `resources/views/dashboard/projects/show.blade.php` — font-size 12px
  • `resources/views/dashboard/projects/index.blade.php` — SVG
  • `resources/views/guest/project.blade.php` — SVG
  • `resources/views/about.blade.php` — SVG
  • `resources/views/settings/security.blade.php` — SVG
  • `resources/views/admin/users/security.blade.php` — SVG
  • `config/app.php` — version 0.13.4
  • `.env` — version 0.13.4
Открыть версию →
v0.13.3 29.07.2026 PATCH
Dashboard: kebab-меню, пользователи, токены на карточках проектов
Added
  • Карточки проектов на dashboard переработаны: показывают владельца/направление, прогресс-бар, количество задач
  • Блок пользователей на каждой карточке — список привязанных пользователей (до 3, остальные — «+N ещё»), статус email (✓/✗), дата последнего входа
  • Блок токенов статус: «Токен активен» (с датой истечения), «Токен истёк/отозван», «Токен не создан»
  • Kebab-меню на каждой карточке: Просмотр проекта, Админка проекта, Сгенерировать токен
  • Кликабельность вся карточка ведёт на страницу проекта
  • API-проекты показаны как fallback, если нет локальных проектов
Changed
  • Версия платформы: 0.13.2 → 0.13.3
  • `resources/views/dashboard/index.blade.php` — полная переработка: kebab-меню, пользователи, токены, кликабельность
  • `app/Http/Controllers/Dashboard/DashboardController.php` — для админа: все локальные проекты с clients+tokens; для клиента: привязанные проекты
Открыть версию →
v0.13.2 29.07.2026 PATCH
Админ-панель: проекты на dashboard, пароль в открытом виде, улучшение UX привязки проектов
Added
  • Админ dashboard блок «Проекты (последние 10)» с карточками: название (кликабельное), владелец, статус, направление, прогресс-бар, дата создания
  • Kebab-меню на каждой карточке проекта: Просмотр, Редактировать, Токены
  • Пароль в открытом виде поля пароля на формах создания и редактирования пользователя теперь `type="text"` (видимый) с кнопкой «Скрыть/Показать»
  • Информативные чекбоксы проектов при привязке проектов к пользователю теперь отображается: владелец, статус (бейдж), направление; подсветка выбранных проектов
  • Клиент dashboard проект стал кликабельным (ссылка на страницу проекта), если привязан к локальному проекту
Changed
  • Версия платформы: 0.13.1 → 0.13.2
  • `resources/views/admin/users/edit.blade.php` — projects checklist: +владелец, +статус, +направление; password: type=text + toggle
  • `resources/views/admin/users/create.blade.php` — +поле пароля (type=text), projects checklist: +владелец, +статус, +направление
  • `resources/views/admin/index.blade.php` — +блок проектов с карточками и kebab-меню
  • `resources/views/dashboard/index.blade.php` — проект стал кликабельным (если есть локальный)
  • `app/Http/Controllers/Admin/AdminController.php` — +проекты в view data
  • `app/Http/Controllers/Dashboard/DashboardController.php` — +externalIdMap для ссылок на локальные проекты
Открыть версию →
v0.13.1 29.07.2026 PATCH
Исправление: токен проекта показывал email администратора вместо клиента
Fixed
  • Токен проекта 40 («Бобер Боб») `client_id` изменён с 1 (admin) на 5 (Егор). Теперь гостевая страница показывает email egor@jetpeel.club
  • Приветствие на гостевой странице убрано слово «Администратор», теперь просто «Егор приглашает вас ознакомиться с проектом»
Changed
  • Версия платформы: 0.13.0 → 0.13.1
  • `resources/views/guest/project.blade.php` — welcome-card: убрано фиксированное «Администратор», теперь динамически подставляет имя владельца проекта
Открыть версию →
v0.13.0 29.07.2026 PATCH
Гостевая страница проекта: редизайн, email-верификация, темы
Added
  • Гостевой layout `layouts/guest.blade.php`: CSS-переменные (dark/light), переключатель темы (localStorage), мобильное меню (hamburger), навигация (Проект, О платформе, Войти), footer с версией
  • Email-верификация на гостевой странице: сервер генерирует короткий код и отправляет его на email клиента (через SMTP); код подтверждается на странице через отдельные маршруты отправки и проверки.
  • EmailVerificationController sendCode (генерация + сохранение + логгирование кода), verifyCode (проверка + установка email_verified_at + очистка кода)
  • Миграция 100006 колонки `email_verification_code` (varchar 10) и `email_verification_code_sent_at` (timestamp) в таблицу clients
  • Дизайн токен-страницы welcome-card с приветствием от администратора, email-секция с индикацией статуса, прогресс-бар проекта, задачи с дедлайнами и процентами, индикация просроченных задач, действия после верификации (установить пароль / войти)
Changed
  • Версия платформы: 0.12.0 → 0.13.0
  • `resources/views/guest/project.blade.php` — полный редизайн: использует layouts.guest, улучшенная типографика, email-верификация, прогресс-карточка, таски с датами/дедлайнами, mobile-first responsive
  • `app/Http/Controllers/Guest/ProjectTokenController.php` — передаёт emailVerified, hasPassword, project.direction, tokenModel для отображения
  • `app/Models/Client.php` — fillable: +email_verification_code, email_verification_code_sent_at; casts: +email_verification_code_sent_at
  • `routes/web.php` — +2 маршрута: send-code, verify-code
Files
  • `database/migrations/2026_07_29_100006_add_email_verification_to_clients_table.php` — новый
  • `resources/views/layouts/guest.blade.php` — новый гостевой layout
  • `app/Http/Controllers/Guest/EmailVerificationController.php` — новый контроллер верификации
  • `resources/views/guest/project.blade.php` — переработан
  • `app/Http/Controllers/Guest/ProjectTokenController.php` — обновлён
  • `routes/web.php` — +2 маршрута
Открыть версию →
v0.12.0 29.07.2026 MINOR
Passwordless registration, интеграции и UX
Added
  • Passwordless registration: пароль стал необязательным при создании; при его отсутствии формируется защищённая ссылка-приглашение, по которой пользователь сам задаст пароль. Форма создания пользователя: поле пароля заменено подсказкой «Оставьте пустым — пользователь сам задаст пароль»
  • SetPasswordController GET /set-password/{token} + POST /set-password/{token}: показывается форма, где пользователь вводит пароль → после установки автоматический вход в dashboard. Сообщение: «Администратор уже зарегистрировал вас на платформе IPD»
  • Проверка passwordless в login если password = null, выводится ошибка «Вы ещё не установили пароль. Используйте ссылку-приглашение»
  • Колонка «Пользователи» на /admin/projects AdminProjectController index: withCount('clients'). Таблица: новая колонка «Пользователи» с счётчиком и склонением (пользователь/пользователя/пользователей)
  • Индикатор каналов на странице проекта новая колонка «Каналы»: красный бейдж «0 каналов» (нет верифицированных), жёлтый «N/3» (частично), зелёный «✓ 3/3» (все)
  • Кнопка «Отправить подтверждение» email POST /admin/users/{id}/send-email-verification: устанавливает email_verified_at, метод-заглушка для будущей отправки письма
  • Фундамент настройки Telegram-бота в разделе «Интеграции»: параметры подключения бота и привязка чата к клиенту с кодом верификации.
  • Фундамент SMS Gateway в разделе «Интеграции»: параметры подключения шлюза, имя отправителя и код верификации телефона клиента с меткой времени.
  • Модель Client дополнена полями верификации (телефон, Telegram) и флагом установки пароля, добавлен вспомогательный метод.
Changed
  • Версия платформы: 0.11.0 → 0.12.0
  • `app/Http/Controllers/Admin/AdminUserController.php` — store: password nullable, при отсутствии генерируется verification_token, email_verified_at не ставится. Добавлен sendEmailVerification()
  • `app/Http/Controllers/Admin/AdminProjectController.php` — index: withCount('clients')
  • `app/Http/Controllers/Admin/SettingsController.php` — добавлен таб «Интеграции» с настройками подключения Telegram и SMS.
  • `app/Http/Controllers/Auth/ClientAuthController.php` — login: проверка что password не null, иначе сообщение о ссылке-приглашении
  • `resources/views/admin/users/create.blade.php` — поле пароля заменено на подсказку
  • `resources/views/admin/projects/index.blade.php` — колонка «Пользователи» с clients_count
  • `resources/views/admin/projects/show.blade.php` — колонка «Каналы» с индикатором верификации
  • `resources/views/admin/users/show.blade.php` — кнопка «Отправить» для email
  • `resources/views/admin/settings.blade.php` — новый таб «Интеграции» с полями Telegram и SMS
  • `routes/web.php` — 3 новых маршрута: set-password (GET+POST), send-email-verification
  • `config/app.php` — APP_VERSION: 0.11.0 → 0.12.0
Files
  • `database/migrations/2026_07_29_100004_add_passwordless_fields_to_clients_table.php` — password nullable, verification_token, password_set_at
  • `database/migrations/2026_07_29_100005_add_verification_codes_to_clients_table.php` — поля кодов верификации (Telegram, телефон).
  • `app/Http/Controllers/Auth/SetPasswordController.php` — установка пароля по токену
  • `resources/views/auth/set-password.blade.php` — форма установки пароля
Открыть версию →
v0.11.0 29.07.2026 MINOR
Связывание проектов и пользователей; Связывание проектов и пользователей, каналы связи
Added
  • Привязка пользователей к проекту в create/edit проекта добавлен чеклист `clients[]` с синхронизацией через sync в store/update
  • AdminProjectController attachClient, detachClient с логированием в activity_log
  • Каналы связи миграция 100003: колонки telegram, telegram_verified_at, phone_verified_at в clients
  • Каналы связи UI на /admin/users/{id}/show — таблица «Каналы связи» с индикацией и кнопками; на /admin/users/{id}/edit — поле Telegram + кнопки подтверждения
  • Индикация на странице проекта в таблице пользователей: зелёный ✓ / красный ✗ для каждого канала
  • Client модель fillable: telegram, telegram_verified_at, phone_verified_at; casts: datetime для verified_at. Helpers: isEmailVerified, isTelegramVerified, isPhoneVerified, verifiedChannelsCount
  • Routes verify-email, verify-telegram, verify-phone, attach-client, detach-client
Changed
  • Версия платформы: 0.10.1 → 0.11.0
  • AdminProjectController.show/edit — загрузка clients; create/edit views — чеклист
  • AdminUserController.show — секция «Каналы связи»; edit — поле Telegram + кнопки верификации
  • routes/web.php — 5 новых маршрутов
  • config/app.php — APP_VERSION: 0.10.1 → 0.11.0
Added
  • Управление пользователями проекта на странице `/admin/projects/{id}` новая секция «Пользователи» с таблицей (имя, email, Telegram, телефон, роль, статус верификации), кнопкой «+ Пользователь» (выбор из списка) и «Удалить» для каждого
  • Выбор пользователей при создании/редактировании проекта чеклист пользователей в формах create/edit проекта (соответствует аналогичному чеклисту проектов у пользователя)
  • AdminProjectController: attachClient/detachClient два новых метода для добавления/удаления пользователей проекта, с логированием в activity_log
  • Каналы связи (Client) колонки `telegram`, `telegram_verified_at`, `phone_verified_at` в таблице `clients`
  • Методы Client model `isEmailVerified()`, `isTelegramVerified()`, `isPhoneVerified()`, `verifiedChannelsCount()`
  • Каналы связи на странице пользователя `/admin/users/{id}`: новая секция «Каналы связи» с таблицей (Email, Telegram, телефон) и кнопками «Подтвердить»/«Снять» для каждого канала
  • Редактирование каналов связи в `/admin/users/{id}/edit` добавлено поле Telegram и кнопки подтверждения каналов
  • AdminUserController: verifyEmail/verifyTelegram/verifyPhone три новых метода для переключения статуса верификации
  • Routes 5 новых: verify-email, verify-telegram, verify-phone, attach-client, detach-client
Changed
  • Версия платформы: 0.10.1 → 0.11.0
  • `app/Http/Controllers/Admin/AdminProjectController.php` — store/update теперь синхронизируют `clients` pivot; добавлены attachClient/detachClient
  • `app/Http/Controllers/Admin/AdminUserController.php` — store/update принимают telegram; добавлены verifyEmail/verifyTelegram/verifyPhone
  • `app/Models/Client.php` — добавлены `telegram`, `telegram_verified_at`, `phone_verified_at` в fillable + casts; добавлены 4 helper-метода для верификации
  • `resources/views/admin/projects/show.blade.php` — новая секция «Пользователи» с таблицей и кнопкой «+ Пользователь»
  • `resources/views/admin/projects/edit.blade.php` — чеклист пользователей с выбором доступа
  • `resources/views/admin/projects/create.blade.php` — чеклист пользователей при создании
  • `resources/views/admin/users/show.blade.php` — новая секция «Каналы связи» с таблицей
  • `resources/views/admin/users/edit.blade.php` — поле Telegram + кнопки подтверждения каналов
  • `resources/views/admin/users/create.blade.php` — поле Telegram
  • `routes/web.php` — 5 новых маршрутов
Files
  • `database/migrations/2026_07_29_100003_add_communication_channels_to_clients_table.php` — новый
Открыть версию →
v0.10.1 29.07.2026 MINOR
Исправление выхода; Исправление: кнопка «Выйти» и тестирование мультиаккаунтов
Fixed
  • Механизм выхода полностью очищает состояние сессии на устройстве, гарантируя, что пользователь не будет автоматически восстановлен при повторном входе
  • guest:client middleware убран с /login — login page показывает блок «уже вошёл» для аутентифицированных пользователей
  • Миграция 100002 исправлен duplicate auto_login в up()
Fixed
  • Механизм выхода очищает состояние «запомненного устройства», предотвращая автоматическое восстановление сессии после явного выхода
  • Миграция 100001 удалено дублирование колонки `auto_login` (колонка добавляется только в миграции 100002)
Changed
  • Версия платформы: 0.10.0 → 0.10.1
  • `app/Http/Controllers/Auth/ClientAuthController.php` — `logout()` удаляет known_account перед выходом
  • `database/migrations/2026_07_29_100001_create_client_auth_known_accounts_table.php` — убран лишний `Schema::table('clients', ...)` с добавлением `auto_login`
  • `app/Models/Client.php` — добавлен `knownAccounts()` HasMany relation для удобства
Открыть версию →
v0.10.0 29.07.2026 PATCH
Мультиаккаунты («Вход как в Google»)
Added
  • Мультиаккаунты (Google-style) login.blade.php переработан: при входе отображаются известные аккаунты (аватар, имя, email) → клик для быстрого переключения → «+ Другой аккаунт» → форма email/пароль. «× Выйти из всех аккаунтов» на странице логина и в /settings/security
  • Таблица `client_auth_known_accounts` хранит «запомненные» устройства (привязку аккаунта к устройству) с уникальными индексами для корректного переключения между аккаунтами
  • Реализован флаг «Запомнить устройство» на форме входа: при включении устройство считается доверенным, и сессия сохраняется между визитами.
  • Устройству клиента присваивается анонимный долговременный идентификатор, который связывает «запомненные» аккаунты на этом устройстве
  • ClientAuthController методы getDeviceId(), saveKnownAccount(), switchAccount(), forgetAccount(), logoutAll(), knownAccounts() (API), securitySettings(), toggleAutoLogin()
  • Реализован безопасный механизм «запомненного устройства»: для доверенных устройств пользователя сессия восстанавливается автоматически, повторный ввод пароля не требуется. Middleware зарегистрирован в глобальной цепочке обработки запросов.
  • Dropdown профиля — «Сменить пользователя» в app.blade.php profile dropdown секция с загруженными через /api/auth/known-accounts аккаунтами + кнопка «×» забыть аккаунт для каждого
  • Админ-страница безопасности `/admin/users/{id}/security/`: управление «запоминанием устройства», принудительное завершение сессий, просмотр и очистка известных устройств
  • Страница `/settings/security`: карточка учётной записи (имя, email, роль, последний вход), переключатель «запомнить устройство», список известных устройств с кнопкой удаления, кнопка «Выйти из всех аккаунтов»
  • Routes POST /login/switch/{id}, POST /login/forget/{id}, POST /login/logout-all, GET /settings/security, POST /settings/security/toggle-auto-login, GET /api/auth/known-accounts, GET+POST /admin/users/{id}/security
Changed
  • Версия платформы: 0.9.0 → 0.10.0
  • `app/Http/Controllers/Auth/ClientAuthController.php` — полный рефакторинг: добавлены мультиаккаунт-методы и управление запоминанием устройств
  • `resources/views/auth/login.blade.php` — переработан: два состояния (список аккаунтов / форма входа), анимация переключения, кнопка «Выйти из всех»
  • `resources/views/layouts/app.blade.php` — добавлена секция «Сменить пользователя» в user dropdown + JavaScript fetch known-accounts + forget buttons
  • `routes/web.php` — добавлены 8 новых маршрутов для мультиаккаунтов, безопасности и админ-безопасности
  • `resources/views/admin/users/edit.blade.php` — добавлена кнопка «Безопасность» в actions
  • `config/app.php` — `APP_VERSION` по умолчанию: `0.9.0` → `0.10.0`
  • `.env` — `APP_VERSION=0.9.0` → `0.10.0`
  • `bootstrap/app.php` — зарегистрирован AutoLogin middleware в web-группе
Files
  • `database/migrations/2026_07_29_100001_create_client_auth_known_accounts_table.php` — создание таблицы known_accounts
  • `database/migrations/2026_07_29_100002_add_auto_login_to_clients_table.php` — добавление колонки auto_login
  • `app/Models/ClientAuthKnownAccount.php` — модель для known_accounts
  • `app/Http/Middleware/AutoLogin.php` — middleware автоматического входа
  • `app/Http/Controllers/Auth/ClientAuthController.php` — рефакторинг с мультиаккаунтами
  • `app/Http/Controllers/Admin/AdminUserController.php` — добавлены editSecurity/updateSecurity
  • `resources/views/auth/login.blade.php` — переработан с account chooser
  • `resources/views/settings/security.blade.php` — новая страница безопасности
  • `resources/views/admin/users/security.blade.php` — новая админ-страница безопасности
  • `resources/views/layouts/app.blade.php` — секция смены пользователя + forget buttons
  • `resources/views/admin/users/edit.blade.php` — кнопка «Безопасность»
  • `routes/web.php` — новые маршруты
  • `bootstrap/app.php` — регистрация AutoLogin middleware
Открыть версию →
v0.9.0 28.07.2026 MINOR
Верхнее правое меню: уведомления, профиль, kebab-меню, тема
Added
  • Колокольчик уведомлений в topbar-right: SVG колокольчик, красный badge с количеством непрочитанных, dropdown при клике (список уведомлений, «Пометить все прочитанными», ссылка «Все → /notifications»)
  • Система уведомлений таблица `client_notifications` (type, title, description, url, read_at), модель `ClientNotification`, контроллер `NotificationController` (index, apiList, markRead, markAllRead), 3 API-эндпоинта (GET /api/notifications, POST /api/notifications/read, POST /api/notifications/read-all)
  • Страница уведомлений `/notifications`: список карточек с иконками по типу (warning/error/success/info), unread-индикатор, «Пометить все прочитанными», пустое состояние
  • Dropdown профиля аватар с именем (pill-кнопка), при клике: header (аватар-xl, имя, email), «Настройки», переключатель «Тёмная тема» (switch), «Выйти»
  • Kebab-меню (⋮) трёхточечная кнопка рядом с уведомлениями: «Иструкция» → /about, «Поддержка» → mailto:support@ipd.by, «Выйти»
  • Переключатель темы в dropdown профиля: switch с label «Тёмная тема», сохраняет выбор в localStorage, применяет CSS-переменные [data-theme="light|dark"] на <html>, работает на всех страницах (layout)
  • Light theme CSS-переменные `[data-theme="light"]` overrides: bg #f1f5f9, card-bg #fff, border #e2e8f0, text #0f172a, muted #475569, accent #2563eb, green #16a34a, red #dc2626
Changed
  • Версия платформы: 0.8.0 → 0.9.0
  • `resources/views/layouts/app.blade.php` — полная переработка topbar-right: роль-тейг и кнопка «Выти» заменены на notifications bell + kebab menu + user dropdown. Добавлены CSS для: .notif-wrap, .notif-bell, .notif-badge, .notif-dropdown, .notif-item, .user-dd, .user-dd__trigger, .user-dd__dropdown, .kebab-wrap, .kebab-btn, .kebab-dropdown. Добавлены JS: toggle dropdowns, loadNotifications (fetch /api/notifications), markNotifReadDD, markAllNotifRead, updateNotifBadge, toggleLayoutTheme
  • `routes/web.php` — добавлены 4 роута: GET /notifications, GET /api/notifications, POST /api/notifications/read, POST /api/notifications/read-all
  • `config/app.php` — `APP_VERSION` по умолчанию: `0.8.0` → `0.9.0`
  • `.env` — `APP_VERSION=0.8.0` → `0.9.0`
Files
  • `database/migrations/2026_07_28_100001_create_client_notifications_table.php` — новый
  • `app/Models/ClientNotification.php` — новый
  • `app/Http/Controllers/Dashboard/NotificationController.php` — новый
  • `resources/views/notifications.blade.php` — новый
  • `resources/views/layouts/app.blade.php` — обновлён (topbar-right, CSS, JS, theme)
Migration
  • `2026_07_28_100001_create_client_notifications_table.php` — таблица client_notifications
Открыть версию →
v0.8.0 25.07.2026 MINOR
Публичная страница «О платформе», переработка авторизации
Added
  • Страница «О платформе» новая страница `/about` (публичная, без авторизации): gradient-шапка с логотипом, карточка «О платформе» (версия, среда, время, статус), описание возможностей, ссылки (вход, история версий), блок последних версий из changelog.md, кнопка «Войти в систему»
  • Переработанная страница входа новый дизайн: inline SVG логотип, заголовок «IPD Platform», подзаголовок «Управление проектами», описание назначения, ссылка «Войти в систему» → /about, версия с ссылкой на /about
  • Переключатель темы кнопка в правом верхнем углу (☀️/🌙) на страницах входа и /about, сохраняет выбор в localStorage, работает без JavaScript-фреймворков
  • Route GET /about публичный маршрут без middleware авторизации, парсит changelog.md для отображения истории версий
Changed
  • Версия платформы: 0.7.3 → 0.8.0
  • `resources/views/auth/login.blade.php` — полная переработка дизайна: добавлены логотип SVG, описание, theme switcher, ссылка на /about
  • `config/app.php` — `APP_VERSION` по умолчанию: `0.7.3` → `0.8.0`
  • `.env` — `APP_VERSION=0.7.3` → `0.8.0`
Files
  • `resources/views/about.blade.php` — новый файл: публичная страница «О платформе»
  • `resources/views/auth/login.blade.php` — переработка дизайна
  • `routes/web.php` — добавлен route `GET /about`
  • `config/app.php` — обновлена версия
Открыть версию →
v0.7.3 25.07.2026 MINOR
Токены: UX-улучшения, доступность, часовой пояс
Added
  • Dropdown срока токена вместо числового поля теперь выпадающий список: 24ч, 48ч (по умолчанию), 72ч, 1 неделя, 1 месяц
  • Кнопка «Копировать» рядом с URL гостевой ссылки, копирует полный URL в буфер обмена с визуальной обратной связью (изменение текста и цвета на 2 сек)
  • Индикатор токенов на странице проектов в таблице `/admin/projects` добавлена колонка «Токен»: зелёный бейдж с количеством активных токенов, жёлтый если токены неактивны, серое тире если нет токенов
Changed
  • Версия платформы: 0.7.2 → 0.7.3
  • Часовой пояс `config/app.php`: `UTC` → `Europe/Minsk` для корректного отображения дат/времени без ручной конвертации
  • Контрастность текста CSS-переменная `--muted` изменена с `#64748b` (контраст ~2.7:1) на `#94a3b8` (контраст ~5.1:1, WCAG AA)
  • Размер мелкого текста `--fs-xs` увеличен с 12px до 13px для лучшей читаемости
  • `AdminProjectController@index` — добавлен eager-load `tokens` для индикатора токенов
  • `admin/projects/show.blade.php` — обе формы создания токена используют dropdown вместо number input
Открыть версию →
v0.7.2 25.07.2026 PATCH
Токены: аналитика, логирование, центр управления
Added
  • Аналитика токенов новая страница `/admin/tokens` с дашбордом: общая статистика (всего, активных, истёкших, отозванных, просмотров), конверсия по проектам (прогресс-бары), таблица всех токенов сгруппированная по проектам, история последних действий
  • Токены в sidebar новый пункт «Токены» (иконка ключа) в боковом меню администратора между «Проекты (Админ)» и «Настройки»
  • Логирование действий с токенами все операции (создание, отзыв, обновление, удаление) записываются в `activity_log` с указанием проекта, замаскированного токена, IP-адреса и user-agent
  • AdminTokenController контроллер для страницы аналитики токенов
  • Аналитика по проектам для каждого проекта отображается количество токенов, просмотров и процент активных токенов (конверсия)
Changed
  • Версия платформы: 0.7.1 → 0.7.2
  • `AdminProjectController` — методы `generateToken`, `revokeToken`, `regenerateToken`, `destroyToken` теперь записывают логи в `activity_log`
  • `routes/web.php` — добавлен 1 роут: `GET /admin/tokens`
  • Sidebar — добавлена ссылка «Токены» (`/admin/tokens`)
Открыть версию →
v0.7.1 25.07.2026 PATCH
Безопасность токенов: защищённые ссылки, трекинг просмотров
Added
  • Безопасная генерация токенов: токены теперь создаются как криптостойкие случайные строки повышенной длины вместо простых числовых значений.
  • Трекинг просмотров новые поля `views_count` и `last_used_at` в таблице `client_tokens` для отслеживания активности ссылок
  • Управление токенами из админки на странице проекта (`/admin/projects/{id}`): создание, обновление (regenerate), отзыв, удаление токенов
  • Форма создания токена метка, срок действия (часы), выбор клиента
  • Маскировка токенов в таблице отображается маска `xxxx...xxxx` вместо полного токена
  • Регенерация существующих токенов автоматическая миграция заменяет числовые/короткие токены на безопасные 64-символьные
  • Статус токенов три состояния: Активен (зелёный), Истёк (жёлтый), Отозван (красный)
  • Индикаторы статуса визуальные бейджи для каждого токена в таблице
Changed
  • Версия платформы: 0.7.0 → 0.7.1
  • `ClientToken` модель — добавлены поля `views_count`, `last_used_at` в fillable/casts; методы `isExpired()`, `regenerate()`, `incrementViews()`, `generateSecureToken()`, accessor `masked_token`
  • `AdminProjectController` — добавлены методы: `generateToken()`, `revokeToken()`, `regenerateToken()`, `destroyToken()`
  • `ProjectTokenController@guest` — теперь вызывает `incrementViews()` при каждом открытии гостевой страницы
  • `routes/web.php` — добавлены 4 роута для управления токенами
Migration
  • `2026_07_25_100001_add_security_fields_to_client_tokens_table.php` — добавление `views_count`, `last_used_at`
  • `2026_07_25_100002_regenerate_insecure_tokens.php` — замена числовых/коротких токенов на безопасные
Открыть версию →
v0.7.0 24.07.2026 PATCH
Синхронизация данных: импорт из task.ipd.by
Added
  • Направления новая таблица `directions` (external_id, name, description, status, priority, tasks_count, source) + модель `Direction`
  • Синхронизация данных `SyncService` импортирует направления, проекты, задачи и шаги из внешнего API (`task.ipd.by/api/export/full`)
  • Страница синхронизации `/admin/sync` — интерфейс запуска синхронизации с отображением статистики (направления, проекты, задачи, шаги) и статуса последнего запуска
  • AdminSyncController `index()` для отображения страницы, `run()` для AJAX-запуска синхронизации
  • Upsert логика при синхронизации существующие записи обновляются, новые создаются, удалённые из источника удаляются локально
  • Привязка проектов к направлениям `direction_id` добавлен в таблицу `projects` (nullable FK)
  • Метка источника поле `source` ('local'/'synced') в таблице `projects` для разделения локальных и импортированных проектов
Changed
  • Версия платформы: 0.6.2 → 0.7.0
  • `TaskApiService` — `baseUrl` по умолчанию изменён с `task.ipd.local` на `task.ipd.by`
  • `Project` модель — добавлены `direction_id`, `source`, `is_active` в fillable; добавлена связь `direction()` BelongsTo
  • `Task` модель — добавлен `external_id` в fillable
  • Боковая панель — добавлены ссылки: «Синхронизация» и «Проекты (Админ)»
  • `routes/web.php` — добавлены 2 роута: `GET /admin/sync`, `POST /admin/sync/run`
Migration
  • `2026_07_24_100001_create_directions_table.php` — таблица направлений
  • `2026_07_24_100002_add_direction_id_to_projects_table.php` — direction_id, source, is_active в projects
Открыть версию →
v0.6.2 24.07.2026 MINOR
Проекты: CRUD, задачи, шаги, ссылки для клиентов
Added
  • CRUD проектов создание, редактирование, удаление проектов через админ-панель (`AdminProjectController`: create, store, edit, update, destroy)
  • Форма создания проекта `admin/projects/create.blade.php`: название, описание, владелец (клиент), статус, external_id
  • Форма редактирования проекта `admin/projects/edit.blade.php`: те же поля + Danger Zone (удаление)
  • Локальные задачи новая таблица `tasks` (project_id, name, description, status, priority, due_date, sort_order) + модель `Task`
  • CRUD задач в проектах `AdminTaskController`: create, store, show, edit, update, destroy (вложенные под проектом)
  • Локальные шаги новая таблица `steps` (task_id, name, description, is_completed, sort_order) + модель `Step`
  • Управление шагами `AdminStepController`: добавление, переключение (toggle), удаление шагов в задаче
  • Прогресс задач автоматический расчёт `progress_pct` на основе выполненных шагов
  • Прогресс проекта автоматический `syncProjectCounts` при изменении задач
  • Ссылка для клиента на странице проекта отображается активная ссылка (`/p/{token}`) для клиента
  • Обновлён guest/project.blade.php теперь показывает локальные задачи + шаги (а не только внешний API)
  • Admin tasks CRUD views create, edit, show (с чекбоксами шагов и формой добавления)
Changed
  • Версия платформы: 0.6.1 → 0.6.2
  • `AdminProjectController` — расширен с 2 методов (index, show) до 7 (full CRUD)
  • `Project` модель — добавлена связь `tasks()` HasMany
  • `routes/web.php` — добавлены CRUD роуты для projects, tasks, steps (16 роутов total)
  • `.env`: `APP_VERSION=0.6.1` → `0.6.2`
Открыть версию →
v0.6.1 22.07.2026 PATCH
Пользователи: CRUD — создание, редактирование, удаление, привязка проектов
Added
  • Создание пользователя `GET /admin/users/create` + `POST /admin/users` — форма создания с полями: имя, email, пароль, роль, компания, телефон, статус, выбор проектов
  • Редактирование пользователя `GET /admin/users/{id}/edit` + `PUT /admin/users/{id}` — форма редактирования с теми же полями; пароль опциональный (оставить пустым = не менять)
  • Удаление пользователя `DELETE /admin/users/{id}` — удаление с подтверждением (confirm-dialog), cascade: detach проектов, удаление токенов, настроек, логов
  • Кнопки действий в таблице «Просмотр», «Редактировать», «Удалить» для каждого пользователя в списке
  • Кнопка «+ Добавить» в шапке страницы пользователей
  • Проекты (доступ) — чеклист при создании/редактировании пользователя отображается список проектов с чекбоксами для привязки через pivot `client_project`
  • Danger Zone блок удаления внизу формы редактирования
Changed
  • Версия платформы: 0.6.0 → 0.6.1
  • `AdminUserController` — добавлены методы: `create()`, `store()`, `edit()`, `update()`, `destroy()`
  • `routes/web.php` — добавлены CRUD роуты для users
  • `.env`: `APP_VERSION=0.6.0` → `0.6.1`
Открыть версию →
v0.6.0 21.07.2026 PATCH
Пользователи: управление, связь с проектами, last login
Added
  • Admin-панель «Пользователи» новый контроллер `AdminUserController` с index (список) и show (детально)
  • Просмотр пользователей страница `/admin/users` с таблицей: имя, email, роль, статус, количество проектов, последний вход, дата создания
  • Детальная страница пользователя `/admin/users/{id}` с профилем, проектами (владеет и имеет доступ), логами активности
  • Связь пользователей и проектов (Many-to-Many) новая таблица `client_project` с unique-ограничением и timestamps
  • `Client->ownedProjects()` — HasMany проектов, где пользователь — владелец (через `client_id`)
  • `Client->projects()` — BelongsToMany проектов через pivot `client_project`
  • `Project->clients()` — BelongsToMany клиентов через pivot `client_project`
  • Отслеживание последнего входа поле `last_login_at` в таблице `clients`, обновляется при авторизации
  • Sidebar: активная ссылка «Пользователи» обновлена с `#` на `route('admin.users.index')` с active-классом
  • User counts на админ-дашборде теперь отображается количество пользователей
Changed
  • Версия платформы: 0.5.1 → 0.6.0
  • `ClientAuthController@login` — теперь записывает `last_login_at` при входе
  • `Client` модель — добавлен `BelongsToMany` для связи с проектами
  • `Project` модель — добавлен `BelongsToMany` для связи с клиентами
  • `.env`: `APP_VERSION=0.5.1` → `0.6.0`
Открыть версию →
v0.5.0 21.07.2026 MINOR
Управление проектами: локальные проекты, шаряемые ссылки, логирование
Added
  • Локальное управление проектами новая таблица `projects` с полями: name, description, client_id, status, external_id, progress_pct, tasks_total, tasks_completed
  • Страница «Мои проекты» `/dashboard/projects` с карточками проектов, прогресс-барами, статусами, количеством задач
  • Детальная страница проекта `/dashboard/projects/{id}` с задачами из внешней системы, прогрессом, шаряемыми ссылками
  • Шаряемые ссылки на проекты `/p/{token}` — новый гостевой роут для временного доступа к проекту; токен с истечением (настраиваемые часы), меткой и возможностью отзыва
  • Генерация проектных токенов форма на детальной странице проекта: количество часов, метка, кнопка «Сгенерировать» и «Отозвать»
  • Система логирования таблица `activity_log` с полями: client_id, project_id, action, details, ip_address, user_agent
  • Логирование входа запись `login` в activity_log при авторизации клиента
  • Логирование просмотров проектов запись `view_project` при открытии детальной страницы проекта
  • Гостевая страница проекта `/p/{token}` с информацией о проекте, задачами, тарифом; с призывом авторизоваться
  • Связь токенов с проектами поле `project_id` в `client_tokens`, модель ClientToken теперь belongsTo Project
  • Sidebar: Мои проекты исправлена ссылка, ведёт на `/dashboard/projects` с active-классом
  • Seed-данные: 5 демо-проектов для каждого не-администраторского клиента и проектный токен для демонстрационного аккаунта.
Changed
  • Версия платформы: 0.4.1 → 0.5.0
  • Client модель: добавлены методы `projects()`, `logs()`, `log()` (статический хелпер для записи activity)
  • ClientToken модель: добавлена связь `project()`, поле `project_id` в fillable
  • DatabaseSeeder: расширен — создаёт проекты и проектные токены
Открыть версию →
v0.4.1 21.07.2026 MINOR
Админ-панель: /admin/ индекс, шаряемые URL-табы настроек
Added
  • Главная страница админ-панели `/admin/` новая точка входа для администраторов с карточками (настройки, пользователи, окружение) и быстрыми ссылками
  • Route `admin.dashboard` `AdminController@index` с приветствием, ролью, версией
Changed
  • Табы настроек теперь шаряемые URL вместо `<button onclick="switchTab(...)">` используются `<a href="{{ route('admin.settings', ['tab' => '...']) }}">` — каждый таб имеет собственный URL (`/admin/settings/general`, `/admin/settings/security`, `/admin/settings/versions`), который можно открыть по прямой ссылке или закладке
  • Удалена JS-функция `switchTab()` переключение вкладок теперь происходит через нативные ссылки (GET-запросы с параметром tab)
  • Боковое меню админа добавлена ссылка «Админ-панель» (`/admin/`) над «Настройки»
  • Версия платформы: 0.4.0 → 0.4.1
Открыть версию →
v0.4.0 21.07.2026 PATCH
Ролевая система: админ, клиент, тестовый доступ + боковое меню
Added
  • Ролевая система (admin / client / test): новая колонка `role` в таблице `clients`, константы и методы проверки в модели `Client`
  • Middleware `role`: фильтр доступа к роутам по роли — `/admin/*` только для `admin`
  • Для проверки ролевой модели добавлены отдельные учётные записи с ролями «администратор», «клиент» и «тестовая». Логины и пароли хранятся только в локальном окружении и не публикуются.
  • Постоянное боковое меню: единый layout `layouts.app` с фиксированным левым сайдбаром, роль отображается в топбаре (цветной тег)
  • Ролевая навигация: admin видит «Настройки» + «Пользователи», client/test видят только «Панель управления» и «Мои проекты»
  • Dashboard переведён на единый layout: используется `layouts.app` вместо самописного
Changed
  • Версия платформы: 0.3.0 → 0.4.0
  • ClientSeeder: переработан — 4 аккаунта с разными ролями, обновлены сиды токенов
Открыть версию →
v0.3.0 20.07.2026 MINOR
Админ-панель: настройки, безопасность, левый сайдбар
Added
  • Админ-панель с левым сайдбаром единый layout `layouts.admin` с навигацией (Панель управления, Настройки), версией в футере, формой выхода
  • Страница настроек `/admin/settings` с табами три вкладки: Основные, Безопасность, Версии системы (паттерн как в task.ipd)
  • Вкладка «Безопасность» переключатели: требования к сложности пароля, 2FA, автоматический выход по таймеру, лимит попыток входа, отображение служебных параметров среды (в настройках администратора)
  • Вкладка «Основные» название сайта, email администратора, язык, часовой пояс
  • Вкладка «Версии системы» переехала из отдельного роута в таб настроек
  • Система настроек пользователя таблица `user_settings` (key-value EAV), модель `UserSetting`, трекинг изменений через `settings_history`
  • Методы User model `getSetting()`, `getAllSettings()`, `setSetting()`, `setSettings()` для работы с настройками
Changed
  • Версия платформы 0.2.1 → 0.3.0
  • Version-footer ссылка ведёт на `route('admin.settings', ['tab' => 'versions'])` (через сайдбар)
  • Удалён отдельный route `/admin/settings/versions` заменён на таб в `admin.settings`
Открыть версию →
v0.2.0 20.07.2026 MINOR
MVP платформы
Added
  • Dashboard клиента: отображение статистики задач (всего, в работе, выполнено, прогресс), список проектов, информация о тарифе
  • Гостевой доступ: публичная страница `/s/{token}` для просмотра задач без авторизации
  • Авторизация: форма входа с email/паролем, middleware аутентификации, редирект на dashboard
  • Интеграция с task.ipd.by: API-сервис для получения задач, проектов, направлений через `/api/export/full`
  • Тарифы: 4 тарифа (Минимум, Стандарт, Полный, VIP) с фичами и временем ответа
  • Система клиентов: 4 таблицы (users, clients, tariffs, client_tokens), сиды с демо-данными
  • Версия платформы: отображение версии в левом нижнем углу с попапом истории изменений
Changed
  • Архитектура: сайт перенесён с OSPanel (старая версия) на Laravel Herd (PHP 8.4, MariaDB 10.11)
  • Кодовая база: полная переработка с кастомного PHP на Laravel 13
Открыть версию →
v0.1.0 13.07.2026 MINOR
Первая версия платформы
Added
  • Первая версия платформы: создана Помощником (System 4) на базе Laravel
  • Базовая структура: авторизация, маршруты, контроллеры, Blade-шаблоны
  • Конфигурация окружения: .env, подключение к БД, настройки сессий
  • Демо-данные: демонстрационный клиентский аккаунт, тариф «Полный», гостевой токен доступа.
  • Интеграция с task.ipd.by: первичная настройка API-клиента
Architecture
  • Laravel 13, PHP 8.3+, MariaDB, Blade, middleware аутентификации
  • TaskApiService для получения данных из внешней системы задач
  • ClientAuthController с guard `client` и bcrypt-паролями
Открыть версию →