В списке колонка «Сообщений» показывала метод словаря вместо числа: SQL-алиас items переименован в item_count, и шаблон больше не натыкается на dict.items. Заодно в интерфейсе и README раздел называется «Шаблоны сообщений», а одинаковое название и описание больше не дублируются в списке.
Появился раздел «Звания»: название, цена и видимость; изменения сразу видит бот, потому что читает bot.titles напрямую. Удалить можно только звание, которое ни у кого не стоит, иначе предлагается скрыть — данные игроков не ломаются.
Миграция V24 создаёт последовательность из каждого старого шаблона, а команды, магазин и рассылки теперь отправляются через общий sender: один и тот же формат с картинками и кнопками. Старые шаблоны остаются фолбэком в коде, поэтому сбой БД не оставит бота без текстов. Раздел «Сообщения» убран — редактирование только в «Последовательностях», предпросмотр вынесен в общий /preview.
Появился раздел «Отправить»: текст с тем же редактором, картинка и URL-кнопки, предпросмотр и подтверждение. Отправка идёт в основной чат через Bot API; успешные и неуспешные попытки пишутся в bot.admin_messages (кто, когда, что и какая ошибка).
Вместо трёх жёстко зашитых шаблонов теперь есть последовательности: сообщения по порядку, у каждого свой текст, картинка из общего volume media и несколько кнопок. Приветствие миграцией перенесено в последовательность welcome (короткая подпись к фото + остальной текст), а если последовательность недоступна — бот откатывается на старые шаблоны из кода. В админке появился раздел «Последовательности» и редактор текста с тулбаром: жирный, курсив, подчёркивание, зачёркивание, код, цитата, спойлер и ссылка, со счётчиком символов и предпросмотром.
Раздел «Логи» читает analytics.events из ClickHouse: фильтры по типу события, пользователю (ID или username) и датам, по 50 строк на страницу, время в часовом поясе админки. Payload раскрывается как JSON, ID ведёт в карточку игрока. Чтение идёт отдельным ленивым клиентом: если ClickHouse лежит, страница сообщает об этом и не роняет админку. Боту для этого ничего не меняли.
Искать можно по нику, username, имени и Telegram-ID; в карточке видно уровень, опыт с серией, баланс (SUM(money.amount)), яички, сообщения, очищения, подписку и последние операции по балансу. Страница пока только читает PostgreSQL: правку ника, звания и подписки включим следующим шагом, когда посмотрим на реальные данные.
В админке появился раздел «Расписания»: время, дни недели, таймзона, шаблон и вкл/выкл, с историей изменений и удалением. Бот раз в минуту читает активные строки из БД, поэтому правки применяются без перезапуска; при сбое базы он переживает его на последнем прочитанном наборе или на расписании из кода. Стартовые рассылки перенесены миграцией V16, так что поведение не меняется. Заодно в зависимости добавлен tzdata: в slim-образах без него падает ZoneInfo на Europe/Moscow.
Появились таблицы шаблонов, истории правок и расписаний: тексты по умолчанию переехали в миграцию-сид, а раздел «Сообщения» показывает список, даёт отредактировать текст с проверкой тегов и предпросмотром через тот же рендерер, что у бота. Каждое сохранение пишет старую и новую версию в историю — это аудит и заготовка для отката. Бот пока читает тексты из кода: переключение на базу — следующий шаг (4.5).
Каркас FastAPI живёт в admin/ и собирается отдельным образом: главная страница со списком будущих разделов и /healthz для healthcheck, пока без БД и логина. Сервис добавлен в оба compose (порт только на loopback до появления домена), CI теперь собирает и публикует два образа — бота и админку. Настройки админки наследуют общие, но не требуют BOT_TOKEN: сервис запускается, даже пока токен не заполнен.