REPOSITORY / ScuroNeko/Laniakea

Wiki

KNOWLEDGE REPOSITORY
10
Framework Backlog RU
ScuroNeko edited this page 2026-05-20 13:28:29 +03:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Framework Backlog

Эта страница отслеживает список задач уровня фреймворка, связанных с отсутствующими концепциями в библиотеке, а не просто с нехваткой документации.

Done

[1.0.0]

Major — закрыто до тега 1.0.0

  • M1. BotPayloadType* были var, должны быть const.
  • M2. Асимметрия именования методов ObserverOnReceiveUpdateOnUpdateReceived; OnHandledUpdateOnUpdateHandled.
  • M3. Uploader возвращал ad-hoc строку ошибки вместо *ResponseError.
  • M4. BotOptsFileJSON не сохранял PollTimeout — поле терялось при round-trip.
  • M5. Устаревший godoc Bot.Updates — утверждал "30-second timeout" и "empty slice if none".
  • M6. Противоречивый godoc NewRandomDraftProvider — говорил "cryptographically secure", но использовал math/rand/v2.
  • M7. Godoc Draft.Delete говорил "internal method" — метод экспортирован.
  • M8. Русские комментарии в production-кодеmsg_handler.go, tgapi/uploader_api.go.
  • M9. Godoc MessageContext.Error ссылался на неэкспортированный хелпер.
  • M10. Scene и SceneSession смешивали экспортированные поля с setter-амиScene.PluginName закрыт, SceneSession.Data закрыт.
  • M11. Constant-time compare для webhook secret — использован subtle.ConstantTimeCompare.

Minor — закрыто до тега 1.0.0

  • Убраны godoc-комментарии с неэкспортированных функций.
  • Godoc Plugin.AddCommand ссылался на .command.
  • Builder раннеров: Onetime/TimeoutEvery/Async; Once() удалён.
  • Опечатка в webhook: "must between" → "must be between".
  • Inline errors.New(...) в webhook → Err* sentinel-ы.
  • Добавлен godoc для tgapi.UpdateTypeManagedBot, Bot.GetAPI, Bot.GetUploader, InlineKeyboard.GetMaxRow.
  • Godoc Bot.L10n исправлен — возвращает ключ, а не пустую строку.
  • Panic в Bot.handle теперь эмитирует ErrorEvent через observer.
  • Выравнена логика plugin-logger в handleCallback и handleMessage.
  • Godoc SetCallbackData уточняет поведение zero BotPayloadType.
  • commands.go пустой case CommandValueAny: объединён с default.
  • Bot.SetDebug не вызывает configMutable — задокументировано в godoc.

Тесты, добавленные после правок

  • Round-trip BotOptsFileJSON для PollTimeout.
  • Uploader 4xx/429 возвращает *tgapi.ResponseError.
  • Panic в Bot.handle → observer получает ErrorEvent.
  • Webhook /status с неверным SecretToken возвращает 404, smoke-тест constant-time compare.
  • Table-driven тесты parseCommand для /cmd@botname.

[1.0.0-rc.14] Модель выполнения webhook

Текущее состояние:

  • В репозитории уже есть низкоуровневые API для настройки webhook на уровне tgapi: SetWebhook(...), DeleteWebhook(...), GetWebhookInfo(...), а также поддержка загрузки сертификата через uploader.
  • Во фреймворке теперь есть полноценные bot-level точки входа webhook runtime: RunWebhookWithContext(...) и RunWebhook(...).
  • Webhook-доставка теперь использует ту же внутреннюю очередь update-ов, тот же worker pool, тот же запуск runners и тот же single-use runtime contract, что и polling.
  • Поведение webhook runtime, security-модель и правила перехода обратно на polling теперь описаны в основной документации и wiki.

Почему это важно:

  • Одной только поддержки webhook-транспорта на уровне API-клиента было недостаточно; пользователю всё ещё нужен был framework-owned runtime path, сопоставимый с polling.
  • Полноценный runtime mode выравнивает worker scheduling, lifecycle behavior, правила конфигурации и shutdown semantics между двумя ingress-моделями.
  • Фреймворку также нужна явная история перехода с webhook-доставки обратно на polling deployment.

Что теперь есть:

  • BotWebhookOpts, NewBotWebhookOpts() и fluent helper-методы для webhook-конфигурации.
  • RunWebhookWithContext(...) и RunWebhook(...) как bot-owned точки входа runtime.
  • Общая queued dispatch-модель, worker-pool обработка, запуск runners и single-use semantics для polling и webhook mode.
  • Fallback webhook AllowedUpdates к bot-level конфигурации типов update.
  • Валидация webhook path и количества TLS-файлов до remote webhook setup.
  • Явное удаление remote webhook через CloseWebhook() или низкоуровневый tgapi.DeleteWebhook(...) при переходе deployment с webhook-доставки обратно на polling.
  • Регрессионные тесты на queue delivery, запуск runners, single-use behavior, rejection слишком большого body, path/TLS validation и auth-поведение status endpoint.

Практическая цель:

  • Считать webhook-доставку полноценным runtime mode фреймворка, а не оставлять её только низкоуровневой transport primitive из tgapi.

[1.0.0-rc.13] Модель наблюдаемости

Текущее состояние:

  • Во фреймворке теперь есть полноценная Observer-модель с типизированными runtime-событиями и panic-safe dispatch через runtime бота.
  • Observer hooks теперь покрывают получение и завершение update-ов, command и payload handlers, generic update handlers, lifecycle сценовых обработчиков, scene transitions, policy checks, завершение runners, polling retries и централизованный error routing.
  • Инструментирование остаётся best-effort и не создаёт второй execution pipeline, а также не требует протаскивать app data через observer callbacks.

Почему это важно:

  • Одного логирования недостаточно, чтобы получить стабильный runtime-facing observability contract для метрик, tracing-адаптеров и структурированного сбора событий.
  • Framework-owned hooks делают поведение runtime видимым без необходимости патчить внутренние пути маршрутизации или дублировать инструментирование вокруг команд, payload, сцен и polling.
  • Типизированная event model остаётся понятной в godoc и тестах, при этом не перегружая интеграцию observer.

Что теперь есть:

  • Observer как публичный интерфейс инструментирования.
  • Типизированные события для update, handler, scene, policy, runner, polling и error flows.
  • Безопасный dispatch событий через safeEmitEvent(...), включая recovery от panic.
  • Runtime emission в command, payload, generic update и scene flows.
  • События проверки политик через PolicyCheckedEvent.
  • Наблюдаемость runners и polling через RunnerFinishedEvent, PollingRetryEvent и observer ErrorEvent.
  • Регрессионные тесты для observer configuration, lifecycle command/payload handlers, lifecycle и transitions сцен, ошибок update handlers, ошибок callback decode, завершения runners, polling retries и policy checks.

Практическая цель:

  • Считать наблюдаемость полноценной возможностью фреймворка, а не оставлять инструментирование на уровне случайного логирования и внешних обёрток.

[1.0.0-rc.13] Модель авторизации и политик

Текущее состояние:

  • Во фреймворке теперь есть Policy[T] как явная переиспользуемая модель правила доступа, работающая поверх нормализованного MessageContext и общих данных приложения.
  • Политики интегрируются в уже существующую модель выполнения через RequirePolicy(...), поэтому авторизация остаётся на middleware-пути и не создаёт второй pipeline маршрутизации.
  • У бота и плагинов появились явные helpers для регистрации политик на уровне конфигурации.

Почему это важно:

  • Проверки доступа почти всегда нужны Telegram-ботам, но одних ad-hoc middleware недостаточно, чтобы это стало стабильной framework concept.
  • Переиспользуемые policy helpers делают ограничения по типу чата, правам администратора и callback-контексту видимыми и компонуемыми, вместо того чтобы размазывать их по внутренностям обработчиков.
  • Сохранение выполнения политик в рамках существующего middleware-пути позволяет добавить отдельный язык авторизации, не ломая текущую runtime model.

Что теперь есть:

  • Policy[T] как публичная абстракция авторизации.
  • RequirePolicy(...) для адаптации политик в блокирующие middleware.
  • Bot.UsePolicy(...) и Plugin.UsePolicy(...) для удобной регистрации.
  • Встроенные Telegram-aware helpers: RequirePrivateChat(...), RequireGroupChat(...), RequireSupergroupChat(...), RequireChatAdmin(...), RequireChatCreator(...), RequireBotAdmin(...) и RequireCallbackFromUser(...).
  • Комбинаторы AllPolicies(...), AnyPolicy(...) и NotPolicy(...).
  • Расширенная нормализация MessageContext для Chat и ChatID, а также регрессионные тесты на поведение политик и нормализованного контекста.

Практическая цель:

  • Считать правила доступа полноценной концепцией фреймворка, а не оставлять контроль доступа только на уровне случайного паттерна middleware.

[1.0.0-rc.13] Модель пользовательских и внутренних ошибок

Текущее состояние:

  • У фреймворка по-прежнему один централизованный путь ошибок из обработчиков, но теперь он поддерживает явное разделение на пользовательские и внутренние ошибки.
  • Неразмеченные возвращённые ошибки остаются пользовательскими ради обратной совместимости.
  • Внутренние сбои теперь можно логировать без автоматической отправки их сырого текста пользователю.

Почему это важно:

  • Единый поток ошибок полезен, но не каждая ошибка должна превращаться в ответ пользователю.
  • Сбои инфраструктуры, нарушения внутренних инвариантов и ошибки маршрутизации часто важны для операторов, но только засоряют или портят пользовательский UX.
  • Без такой классификации пользователю либо начинают утекать внутренние ошибки, либо приходится полностью обходить централизованный путь.

Что теперь есть:

  • AsUserError(...) и AsInternalError(...) для явной классификации возвращаемых ошибок.
  • IsUserError(...) и IsInternalError(...) для проверки этой классификации на стороне фреймворка.
  • Обновлённое поведение MessageContext.Error(...): все ошибки по-прежнему логируются, но для внутренних ошибок автоматический ответ пользователю подавляется.
  • Регрессионные тесты для message и callback потоков.

Практическая цель:

  • Сохранить централизованный error flow, но сделать пользовательские и операторские ошибки действительно разными по поведению.

[1.0.0-rc.13] Модель фиксации конфигурации

Текущее состояние:

  • Фреймворк теперь считает конфигурацию бота структурно завершённой после начала первого runtime entry point: Run(), RunWithContext(...) или RunWebhookWithContext(...).
  • Поздние bot-level попытки мутации больше не применяются частично после старта runtime.
  • Границы между регистрацией плагинов, стартом runtime и фиксацией конфигурации теперь оформлены как явное поведение фреймворка и закреплены тестами.

Почему это важно:

  • Runtime-мутация prefixes, middleware, payload policy, локализации, runners или общих зависимостей слишком трудно поддаётся безопасному пониманию.
  • У фреймворка уже были реальные точки фиксации вроде AddPlugins(...); теперь они оформлены как явный контракт, а не как скрытая деталь реализации.

Что теперь есть:

  • Bot-level конфигурационные методы игнорируют поздние вызовы после старта runtime.
  • Правила жизненного цикла и freeze-модели задокументированы как полноценная концепция.
  • Регрессионные тесты закрепляют игнорирование поздних мутаций.

Практическая цель:

  • Сделать старт, runtime и владение конфигурацией достаточно предсказуемыми для стабильного контракта фреймворка.

[1.0.0-rc.13] Контракт схемы обновлений

Текущее состояние:

  • Нормализация обновлений уже существовала, но теперь она описана и протестирована как явный контракт уровня фреймворка.
  • Категории маршрутизации и гарантии заполнения MessageContext теперь рассматриваются как полноценная часть публичной модели.

Почему это важно:

  • Код обработчиков должен понимать, на какие поля MessageContext можно безопасно опираться в каждом потоке обновлений.
  • Без явного контракта обработка обновлений остаётся понятной только через чтение реализации.

Что теперь есть:

  • Задокументированная модель маршрутизации для command flow, payload flow и generic update handlers.
  • Явные комментарии на полях MessageContext, описывающие гарантии для update-backed, callback-backed и message-backed контекстов.
  • Table-driven регрессионные тесты для нормализованного update contract, включая callback target semantics и non-command update flows.

Практическая цель:

  • Сделать маршрутизацию обновлений и гарантии MessageContext достаточно явными, чтобы на них можно было опираться как на стабильный контракт 1.0.

[1.0.0-rc.12] Conversation / Scene Model

Текущее состояние:

  • Фреймворк хорошо обрабатывает одно обновление через команды, данные callback, middleware и обработчики обновлений.
  • В нём уже есть полезные низкоуровневые строительные блоки: MessageContext, черновики, маршрутизация данных callback, плагины и обработчики обновлений.
  • Теперь в нём уже есть реализованная начальная модель сцен для долгоживущих интерактивных сценариев: сцены можно регистрировать в плагинах, запускать через MessageContext, сохранять через SessionStore и маршрутизировать раньше обычной обработки команд.

Почему это важно:

  • Многие Telegram-боты быстро перерастают из изолированных команд в многошаговые сценарии с сохранением состояния.
  • Реальным ботам часто нужны концепции вроде "подождать следующее сообщение пользователя", "пользователь сейчас на шаге 3 из 5" или "нажатие кнопки переводит пользователя в следующее состояние сцены".
  • Без модели сцен пользователи библиотеки начинают строить свой мини-фреймворк поверх Laniakea.

Что уже есть:

  • Маршрутизация активной сцены раньше обычной маршрутизации команд.
  • Области действия сессии на пользователя, чат и пару пользователь-чат.
  • Явный вход и выход через MessageContext.
  • Обработчики шагов, локальные команды сцены и OnMessage(...).
  • Встроенное in-memory-хранилище по умолчанию и интерфейс SessionStore для собственного постоянного хранения.

Что ещё отсутствует или не до конца определено:

  • Локальная маршрутизация данных callback внутри сцены.
  • Ясное решение о том, нужен ли вообще дополнительный публичный API для просмотра состояния сцен.
  • Дальнейшие расширения поверх текущей модели сцен, ориентированной на сообщения.

Текущее направление API:

  • Scene, SceneContext, SceneSession и SessionStore.
  • Plugin.NewScene(...) и Plugin.AddScene(...).
  • MessageContext.EnterScene(...), EnterSceneStep(...) и ExitScene(...).
  • SceneContext.Stay(), Next(...), Exit(), Pass(), BindData(...) и SaveData(...).
  • Состояние на пользователя или чат с хранением в SessionStore и чистым интерфейсом для собственного постоянного хранения.

Важные ограничения дизайна:

  • Это должно быть опциональным и расширяющим текущую модель.
  • Это не должно заменять плагины, команды или обработчики как обычные точки входа во фреймворк.
  • Это должно работать поверх существующих middleware и MessageContext, а не вводить вторую несовместимую модель выполнения.

Практическая цель:

  • Расширять текущую полноценную модель сцен только там, где это реально добавляет ценность.
  • Сохранять поддержку и пошаговых форм, и модальных чат-сценариев без необходимости строить пользовательские слои маршрутизации вокруг активных сессий.

[1.0.0-rc.12] Typed Handler Input Model

Текущее состояние:

  • Команды и данные callback сейчас отдают разобранный текст через ctx.Text и ctx.Args.
  • CommandArg даёт базовую проверку аргументов и их формы.
  • Обработчики всё ещё делают большую часть нетривиального разбора вручную.

Почему это важно:

  • По мере роста бота обработчики часто начинают с повторяющегося шаблонного кода для разбора ctx.Args.
  • Логика валидации расползается по обработчикам вместо того, чтобы жить в одном предсказуемом слое привязки.
  • Текущая модель проста и честна, но помогает недостаточно, когда команды становятся более структурированными.

Чего не хватает:

  • Полноценный способ привязывать аргументы команды или данные callback к типизированному Go-значению.
  • Паттерн уровня фреймворка для ошибок преобразования и ошибок валидации вместо чистой работы со строками.
  • Низкопороговый путь перехода от позиционных аргументов к структурированному входному объекту.

Возможное направление API:

  • Лёгкий API привязки вроде ctx.BindArgs(&input).
  • Или явная регистрация типизированных команд вроде NewCommandTyped(...).
  • Позиционное отображение в структуры, optional-поля, базовая поддержка преобразований и интеграция с текущим потоком валидации.
  • Единые ошибки привязки и валидации, которые идут через существующий централизованный путь обработки ошибок.

Пример пользовательского кода, который это должно сделать удобным:

type BanInput struct {
	UserID int
	Reason string
}

func ban(ctx *laniakea.MessageContext, db *App) error {
	var input BanInput
	if err := ctx.BindArgs(&input); err != nil {
		return err
	}
	return db.Ban(input.UserID, input.Reason)
}

Важные ограничения дизайна:

  • Избегать тяжёлой зависимости от reflection и слишком "магической" подсистемы.
  • Сохранять текущую модель ctx.Args как минимальную базовую модель.
  • Относиться к типизированной привязке как к удобному слою поверх текущей модели команд, а не как к её замене.

Практическая цель:

  • Убрать повторяющийся код разбора, сохранив явный и Go-подобный характер фреймворка.

[1.0.0-rc.12] Request Context / Cancellation Model

Текущее состояние:

  • RunWithContext(...) и RunWebhookWithContext(...) управляют жизненным циклом выполнения бота и корректным завершением.
  • tgapi уже поддерживает методы, принимающие context.Context.
  • Обычные обработчики не получают полноценный context.Context, привязанный к обработке конкретного запроса.

Почему это важно:

  • Бизнес-логика обработчиков часто требует вызовов базы данных, HTTP-вызовов или обращений к нижележащим сервисам с поддержкой отмены.
  • У фреймворка уже есть хорошая история с отменой выполнения на уровне механизма выполнения, но она пока не доходит естественным образом до пользовательского кода внутри обработчиков.
  • В современном Go API context.Context — стандартная часть корректного управления выполнением.

Чего не хватает:

  • Чистый context.Context, который сопровождает каждое обновление через всё выполнение обработчика.
  • Стандартный способ для кода приложения остановить работу, когда бот завершает работу или когда контекст обработки обновления отменён.
  • Прямой мост между управлением жизненным циклом бота и отменой в сервисном слое.

Возможное направление API:

  • Предпочесть non-breaking подход и выдавать context через MessageContext, например ctx.Context().
  • Строить context из жизненного цикла обработки обновления, чтобы он оставался полезным во время корректного завершения.
  • Сделать естественной передачу этого context в методы базы данных, HTTP-клиенты и tgapi.WithContext(...).

Почему это, скорее всего, не должно быть изменением сигнатуры:

  • Изменение сигнатур обработчиков на прямой context.Context было бы публичным ломающим изменением.
  • Аксессор на MessageContext сохраняет совместимость и при этом даёт обработчикам идиоматичный Go-путь для отмены выполнения.

Практическая цель:

  • Позволить коду обработчиков естественно участвовать в отмене выполнения и корректном завершении, не заставляя пользователей строить собственную передачу context.

Связанные страницы:

Ideas

Пункты в этом разделе намеренно остаются теоретическими. Они могут позже превратиться в реальные задачи беклога, а могут так и остаться design notes, если текущей модели фреймворка окажется достаточно.

Модель сервисного слоя и графа зависимостей

Текущее состояние:

  • SetAppData(...) уже даёт фреймворку простую модель общих зависимостей через generic-параметр типа бота.
  • Эта модель намеренно лёгкая и хорошо подходит ботам, которым нужен только небольшой набор долгоживущих общих зависимостей.

Почему это пока только идея:

  • В репозитории сейчас нет достаточно сильных признаков того, что нужен более тяжёлый service container или scoped dependency model.
  • Framework-owned граф зависимостей добавит сложность в API и lifecycle, поэтому такой пункт стоит переносить в активный backlog только тогда, когда повторяющееся реальное использование покажет, что AppData уже недостаточно.

Что это могло бы значить позже, если станет нужно:

  • Полноценный service registry поверх одного общего значения AppData.
  • Опциональную валидацию требуемых сервисов до старта runtime.
  • Более явные lifecycle- или scope-правила для сервисов, которыми управляет сам фреймворк.

Контракт композиции плагинов

Текущее состояние:

  • Плагины уже не являются просто "мешком команд": регистрация через AddPlugins(...) делает snapshot plugin state, считает регистрацию точкой фиксации и документирует post-registration mutation как неподдерживаемую.
  • Это уже даёт фреймворку осмысленный базовый контракт вокруг владения конфигурацией плагина и его неизменяемости во время runtime.

Почему это пока только идея:

  • Текущее состояние репозитория пока не показывает достаточно сильного давления в сторону более богатой framework-level модели зависимостей или capabilities между плагинами.
  • Дополнительный composition contract увеличит API surface и число правил валидации, поэтому его стоит держать как опциональное направление дизайна, пока реальные сценарии повторяющихся взаимодействий между плагинами не покажут, что он действительно нужен.

Что это могло бы значить позже, если станет нужно:

  • Явные зависимости между плагинами.
  • Декларации общих возможностей или требований между плагинами.
  • Модель композиции уровня фреймворка для валидации и координации отношений между плагинами.