Skip to content

v1.1.4

Choose a tag to compare

@geekcodev geekcodev released this 30 Sep 18:04
· 8 commits to main since this release
b8b14aa

v1.1.4 — Метаданные чатов, телефон из контакта, обновление схемы

Релиз адаптера geekcodev/laravel-max-client поверх ядра geekcodev/max-php-client: ^1.1.8. Предыдущий тег — v1.1.3.
Версия PATCH: только аддитивные изменения и исправления, за исключением двух конструкторов, перечисленных в разделе
«Изменение (BC)».

Новое

  • Метаданные чатов в max_chats: колонки title, description, link, icon_url,
    title_checked_at. Заполняются из getChat() при bot_added/bot_started и из самого апдейта при
    chat_title_changed. Один ответ getChat пишется во все записи чата, поэтому в группе на 50 участников делается один
    запрос, а не пятьдесят. Пустой ответ не затирает уже известное значение.
  • MaxChatProfileService: sync(), ensureMetadata(), inheritKnownMetadata(), refresh(),
    pendingChatIds(), fetch(), chatTypeFor(), activeChatIds(), forgetChatCache(),
    hasKnownTitle(). Настройки chats.fetch_metadata (MAX_CHATS_FETCH_METADATA, по умолчанию true) и
    chats.title_check_interval (MAX_CHATS_TITLE_CHECK_INTERVAL, 0 — проверять все чаты).
  • MaxContactService: проверка целостности contact-вложения ядром (ContactVerifier) и извлечение телефона
    (ContactPhoneExtractor, с v1.1.7). Входящего поля vcf_phone в апдейтах нет, телефон разбирается из vcf_info.
  • Телефон в max_users: поле phone_verified_at и сохранение номера из подтверждённого
    request_contact. Отдельного флага включения нет — запись заводится, если её не было, отличающийся номер
    перезаписывается (смена номера аккаунта), совпадающий обновляет только отметку проверки. Значение сохраняется как
    есть, без канонизации; телефон и vcf_info в лог не попадают.
  • php artisan max:chats:refresh [--all|--chat=ID]: дозаполнение и перепроверка метаданных чатов.
  • php artisan max:upgrade [--dry-run]: идемпотентная проверка и дополнение схемы реестров для
    рассинхронизированных или ранее опубликованных миграций. В штатном обновлении не нужен.
  • Индекс по chat_id в max_chats отдельной миграцией.
  • Additive-миграции вместо правки create-миграций: 0001_01_01_000003_add_phone_verified_at_to_max_users_table,
    0001_01_01_000004_add_chat_id_index_to_max_chats_table,
    0001_01_01_000005_add_chat_metadata_to_max_chats_table. Ранее выполненные create-миграции больше не правятся на
    месте. Миграции загружаются провайдером (loadMigrationsFrom), публикация не требуется.

Изменение (BC)

  • Ничего не удалено: сверка публичного API с тегом v1.1.3 даёт 0 удалённых методов.
  • Два конструктора изменились — документированное исключение из правила «в patch-релизе сигнатуры не меняются».
    Сохранение прежних сигнатур потребовало бы держать в PersistMaxChatListener
    зависимость ApiClient, которая больше не используется, поэтому решено оставить чистые сигнатуры и пометить классы
    как внутренние:
Класс v1.1.3 v1.1.4
Listeners\PersistMaxChatListener (Config, ApiClient) (Config, MaxChatProfileService)
Services\MaxUserProfileService (ApiClient, Config, Logger) (ApiClient, Config, Logger, MaxChatProfileService)

Оба класса собираются контейнером, и правка в MaxServiceProvider внесена для каждого по-своему:
MaxUserProfileService получает четвёртую зависимость в привязке register(), а
PersistMaxChatListener в привязке не участвует — он регистрируется как класс слушателя в boot(), поэтому
переопределять его нужно подменой привязки на MaxUpdateReceived, а не подменой класса. Кто собирает любой из двух
классов вручную, обязан передавать новый набор зависимостей.

  • Поведение bot_stopped/bot_removed исправлено (см. «Затронутые сценарии»), обратная совместимость не нарушена: для
    апдейтов с user поведение прежнее.
  • Config::usersCapturePhone() не выпускался ни в одном теге, поэтому его удаление вместе с
    MAX_USERS_CAPTURE_PHONE не является ломающим изменением.

Исправления

  • bot_removed без user больше не теряется. bot_added/bot_started/bot_stopped/bot_removed — события о
    боте в чате, а не о пользователе, поэтому user в них может отсутствовать. Прежде слушатель пропускал такой апдейт,
    чат навсегда оставался status = active, activeChatIds() продолжал его возвращать, а max:chats:refresh бесконечно
    опрашивал getChat. Теперь при userId === null строка не создаётся (user_id часть уникального ключа), но
    status, last_activity_at и chat_type
    обновляются во всех записях с этим chat_id.
  • Новая запись участника наследует метаданные чата без запроса. Проверка перед запросом отвечала на вопрос «есть ли
    хоть одна заполненная строка», а заполнение шло по всем строкам с chat_id, поэтому все участники после первого
    оставались без названия. Правило в три состояния: неизвестно нигде →
    getChat и запись всем; часть пуста → наследование без запроса; заполнены все → ничего. Существующие значения не
    затираются, title_checked_at переносится вместе с данными.
  • phone не затирается в upsertUser() и MaxUserProfileService::upsertFromMember() — там перечислены явно
    обновляемые поля.

Затронутые сценарии

  • Обновление существующей установки: достаточно php artisan migrate. Аддитивные миграции видны как невыполненные,
    данные сохраняются. php artisan max:upgrade — страховка для рассинхронизированной или ранее опубликованной схемы,
    идемпотентна.
  • Новая установка: публиковать миграции не нужно, loadMigrationsFrom подхватывает их из пакета.
  • Удаление бота из чата: чат переходит в removed независимо от наличия user в апдейте, и больше не опрашивается
    max:chats:refresh.
  • Группа с несколькими участниками: один запрос getChat на чат, метаданные у всех записей, включая записи
    участников, пришедших позже.
  • Контакт в сообщении: телефон из подтверждённого request_contact попадает в max_users.phone; неподтверждённое
    вложение игнорируется; пересланные контакты приходят файлами и в этот путь не попадают.
  • Слушатели: PersistMaxUserPhoneListener регистрируется всегда и независимо от chats.enabled. Приложения,
    полагавшиеся на отсутствие listeners для MaxUpdateReceived (например, на ручную постановку в очередь), учитывают это
    при обновлении.

Качество

  • PHP 8.4, declare(strict_types=1), PSR-12, PHPStan level max.
  • composer run lint — 0 файлов с правками (62 файла).
  • vendor/bin/phpstan analyse — 0 ошибок.
  • vendor/bin/phpunit — 298 тестов, 732 утверждения, все зелёные.
  • composer run coverage — 98.11% строк (1041/1061), 90.97% методов, порог 95%.
  • composer audit — 0 уязвимостей.
  • Guard-тесты схемы: testCreateMigrationsStayFrozen (create-миграции не правятся),
    testNewColumnsAreDeclaredInAdditiveMigrationsOnly, testChatIdIndexHasItsOwnMigration, сценарий обновления
    установленной версии с сохранением данных и rollback --step 3.
  • Проверено сравнением публичного API с тегом v1.1.3: удалённых методов 0.