diff --git a/BotPages.Core/Abstractions/IMessengerAdapter.cs b/BotPages.Core/Abstractions/IMessengerAdapter.cs
index bc1abbb..6d4da71 100644
--- a/BotPages.Core/Abstractions/IMessengerAdapter.cs
+++ b/BotPages.Core/Abstractions/IMessengerAdapter.cs
@@ -51,7 +51,7 @@ public interface IMessengerAdapter
///
/// Контракт конфигурации адаптера.
///
-public interface IMessangerAdapterSetup : IMessengerAdapter
+public interface IMessengerAdapterSetup : IMessengerAdapter
{
///
/// Запуск работы адаптера
diff --git a/BotPages.Core/Abstractions/IMessengerAdapterFactory.cs b/BotPages.Core/Abstractions/IMessengerAdapterFactory.cs
index 0a1e1da..2235438 100644
--- a/BotPages.Core/Abstractions/IMessengerAdapterFactory.cs
+++ b/BotPages.Core/Abstractions/IMessengerAdapterFactory.cs
@@ -4,14 +4,14 @@ namespace BotPages.Core.Abstractions;
///
/// Фабрика адаптеров мессенджеров.
-/// Используется для разрешения конкретного по типу мессенджера.
+/// Используется для разрешения конкретного по типу мессенджера.
///
public interface IMessengerAdapterFactory
{
///
/// Список зарегистрированных адаптеров.
///
- Dictionary Adapters { get; }
+ Dictionary Adapters { get; }
///
/// Зарегистрировать адаптер для указанного типа мессенджера.
@@ -23,9 +23,9 @@ public interface IMessengerAdapterFactory
/// Экземпляр адаптера, реализующий .
///
///
- /// Текущий экземпляр для цепочки вызовов.
+ /// Текущий экземпляр для цепочки вызовов.
///
- IMessengerAdapterFactory Register(string messengerType, IMessangerAdapterSetup adapter);
+ IMessengerAdapterFactory Register(string messengerType, IMessengerAdapterSetup adapter);
///
/// Получить адаптер для указанного мессенджера.
diff --git a/BotPages.Core/Abstractions/MultiAdapterFactory.cs b/BotPages.Core/Abstractions/MultiAdapterFactory.cs
index 4be6bfc..ddf47fd 100644
--- a/BotPages.Core/Abstractions/MultiAdapterFactory.cs
+++ b/BotPages.Core/Abstractions/MultiAdapterFactory.cs
@@ -6,12 +6,12 @@
///
public sealed class MultiAdapterFactory : IMessengerAdapterFactory
{
- private readonly Dictionary _adapters = new(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary _adapters = new(StringComparer.OrdinalIgnoreCase);
///
/// Список зарегистрированных адаптеров.
///
- public Dictionary Adapters => _adapters;
+ public Dictionary Adapters => _adapters;
///
/// Зарегистрировать адаптер для указанного типа мессенджера.
@@ -25,7 +25,7 @@ public sealed class MultiAdapterFactory : IMessengerAdapterFactory
///
/// Текущий экземпляр для цепочки вызовов.
///
- public IMessengerAdapterFactory Register(string messengerType, IMessangerAdapterSetup adapter)
+ public IMessengerAdapterFactory Register(string messengerType, IMessengerAdapterSetup adapter)
{
_adapters[messengerType] = adapter;
return this;
diff --git a/BotPages.Core/BotPagesApp.cs b/BotPages.Core/BotPagesApp.cs
index c060ae4..79174e7 100644
--- a/BotPages.Core/BotPagesApp.cs
+++ b/BotPages.Core/BotPagesApp.cs
@@ -40,7 +40,7 @@ public sealed class BotPagesApp
///
/// Добавить адаптер.
///
- public BotPagesApp AddAdapter(string messengerType, IMessangerAdapterSetup adapter)
+ public BotPagesApp AddAdapter(string messengerType, IMessengerAdapterSetup adapter)
{
_adapterFactory.Register(messengerType, adapter);
return this;
diff --git a/README.md b/README.md
index 1f67574..c1bb019 100644
--- a/README.md
+++ b/README.md
@@ -1,92 +1,96 @@
-# BotPages Framework
+# BotPages
-BotPages — это архитектурный фреймворк для построения Telegram/MAX‑ботов с чистыми слоями, расширяемыми API и удобным developer experience.
+BotPages — кроссплатформенный фреймворк для создания диалоговых ботов с системой страниц (page‑based conversational framework).
-## ✨ Возможности
-- **Навигация через страницы**: каждая страница — отдельный обработчик логики.
-- **Единый метод GoToAsync**: автоматически поддерживает как `SingletonPage`, так и `StatefulPage`.
-- **StatefulPage**: свойства автоматически сохраняются в `StateStorage`.
-- **SingletonPage**: один экземпляр на всё приложение, без состояния.
-- **Middleware**: подключение промежуточных обработчиков (логирование, обработка ошибок).
-- **Автоматическая регистрация страниц**: через рефлексию.
-- **Роутинг страниц**: возможность устанавливать пути вызова для страниц.
-- **Команды**: возможность установки команд, которые работают приоритетнее обработчиков страниц.
-- **Минимум boilerplate**: декларативные интерфейсы и fluent API.
+Цели проекта:
+- Простая модель страниц и навигации.
+- Портируемость между мессенджерами через адаптеры.
+- Поддержка middleware и декларативной системы команд.
+- Минимум boilerplate и удобный developer experience.
+
+Структура репозитория
+
+- `BotPages.Core` — ядро фреймворка: навигация, страницы, маршрутизация, реестр команд, middleware, абстракции адаптеров и хранилища состояния.
+- `BotPages.Telegram` — адаптер для Telegram Bot API (реализация `IMessangerAdapterSetup`/`IMessengerAdapter`).
+- `Demo` — пример приложения с несколькими страницами и конфигурацией адаптера.
+- `BotPages` — мета‑проект для упаковки библиотек.
+- `docs/` — внутренняя документация проекта (Quickstart, API reference и т.д.).
+
+Требования
+
+- .NET 8 SDK
+- C# 12
+
+Быстрый старт (локально)
+
+1. Клонируйте репозиторий:
+
+```bash
+git clone https://git.frigat.duckdns.org/FrigaT/BotPages.git
+cd BotPages
+```
+
+2. Соберите решения:
+
+```bash
+dotnet build
+```
+
+3. Запуск демо (Telegram):
+
+- Установите переменную окружения `TELEGRAM_TOKEN` с токеном бота.
+
+```bash
+setx TELEGRAM_TOKEN "" # Windows
+export TELEGRAM_TOKEN="" # Linux/macOS
+```
+
+- Запустите demo:
+
+```bash
+dotnet run --project Demo
+```
+
+Основные концепции
+
+- `BotPagesApp` — точка конфигурации приложения: регистрация адаптеров, middleware, маршрутов и команд, запуск.
+- `Page`, `StatefulPage`, `SingletonPage` — модели страниц с жизненным циклом (`OnEnter`, `OnUpdate`, `OnText`, `OnButton`, `OnFile`, `OnError`).
+- `NavigationService` — управление переходами между страницами и определение текущей страницы по сессии.
+- `CommandsRegistry` — шаблоны команд вида `/cmd {arg} {opt?}` с поддержкой именованных и опциональных аргументов.
+- `IPageMiddleware` — middleware-конвейер, выполняющийся для каждого апдейта.
+- `IMessangerAdapterSetup` / `IMessengerAdapter` — интерфейсы, позволяющие подключать новые мессенджеры.
+
+Документация
+
+Полная внутренняя документация находится в `docs/`:
+- `docs/GETTING_STARTED.md` — быстрый старт и примеры конфигурации.
+- `docs/API_REFERENCE.md` — краткий reference публичных API.
+- `docs/PROJECT_DOCUMENTATION.md` — обзор архитектуры и компонентов.
+
+XML‑документация генерируется при сборке (опция `GenerateDocumentationFile` в `.csproj`), её можно использовать для генерации HTML‑референса (docfx, MkDocs и т.п.).
+
+Примеры использования
-## 🚀 Быстрый старт
```csharp
-var app = new BotPagesApp(factory, state, logger)
- .UseDefaultPage()
+var app = new BotPagesApp(stateStorage, logger)
+ .AddAdapter("telegram", new TelegramAdapterSetup(token))
+ .AddDefaultPage()
.MapCommand("/start")
- .AddMiddleware(new LoggingMiddleware(logger))
- .AddMiddleware(new ErrorHandlingMiddleware(logger));
+ .AddMiddleware(new LoggingMiddleware(logger));
+
+await app.Build(CancellationToken.None);
```
-## 📄 Пример страниц
+Вклад и тестирование
-### StatefulPage
-```csharp
-public sealed class WelcomePage : StatefulPage
-{
- [Statefull("visitCount")]
- private int VisitCount;
+- Принимам пулл‑реквесты. Описание PR должно содержать цель и краткое описание изменения.
+- Следуйте единому стилю кода и включённым nullable-аннотациям.
- private PageContext? Context { get; set; }
+Лицензия
- public override async Task OnEnter(PageContext ctx, CancellationToken ct)
- {
- Context = ctx;
+Проект распространяется под лицензией MIT. Смотрите файл `LICENSE`.
- LoadState();
- VisitCount++;
- SaveState();
+Контакты
- await ctx.SendTextAsync($"Добро пожаловать 🚀. Вы заходили сюда {VisitCount} раз(а).", ct: ct);
- }
-}
-```
-
-### SingletonPage
-```csharp
-public sealed class HelpPage : SingletonPage
-{
- public override Task OnEnter(PageContext ctx, CancellationToken ct)
- => ctx.SendTextAsync("Это справка 📖", ct: ct);
-}
-```
-
-## 🧩 Навигация
-```csharp
-await ctx.Navigation.GoToAsync(ctx, ct); // Stateful
-await ctx.Navigation.GoToAsync(ctx, agrs, ct); // Stateful with arguments
-await ctx.Navigation.GoToAsync(ctx, ct); // Singleton
-await ctx.Navigation.GoToHome(ctx, ct); // Stateful
-```
-
-## ⚙️ Middleware
-```csharp
-public sealed class LoggingMiddleware : IPageMiddleware
-{
- private readonly ILogger _logger;
- public LoggingMiddleware(ILogger logger) => _logger = logger;
-
- public async Task InvokeAsync(PageContext ctx, Func next, CancellationToken ct)
- {
- _logger.Log(LogLevel.Info, $"Update: {ctx.Update.Kind}");
- await next();
- }
-}
-```
-
-## 🏗 Архитектурные принципы
-- **Separation of concerns**: страницы не знают о транспорте, всё через адаптеры.
-- **Расширяемость**: новые страницы и middleware подключаются декларативно.
-- **Прозрачность**: минимум скрытой логики, всё явно через контекст.
-- **Developer Experience**: удобные API, автоматическая регистрация, документация через `///summary`.
-
-## 📌 Итог
-BotPages позволяет писать чистые, расширяемые и удобные для команды боты:
-- минимум boilerplate,
-- декларативные интерфейсы,
-- прозрачная навигация,
-- автоматическое управление состоянием.
\ No newline at end of file
+Автор: FrigaT
+Репозиторий: https://git.frigat.duckdns.org/FrigaT/BotPages
\ No newline at end of file
diff --git a/docfx.json b/docfx.json
new file mode 100644
index 0000000..719b8ff
--- /dev/null
+++ b/docfx.json
@@ -0,0 +1,30 @@
+{
+ "metadata": [
+ {
+ "src": [
+ { "files": ["BotPages.Core/BotPages.Core.csproj"] },
+ { "files": ["BotPages.Telegram/BotPages.Telegram.csproj"] },
+ { "files": ["BotPages/BotPages.csproj"] }
+ ],
+ "dest": "api",
+ "properties": {
+ "TargetFramework": "net8.0"
+ }
+ }
+ ],
+ "build": {
+ "content": [
+ { "files": ["docs/**.md"] },
+ { "files": ["README.md"] },
+ { "files": ["api/**.yml"], "dest": "api" }
+ ],
+ "resource": [
+ { "files": ["docs/**.png", "docs/**.jpg", "docs/**.svg"] }
+ ],
+ "dest": "_site",
+ "globalMetadata": {
+ "_enableSearch": true
+ },
+ "template": [ "default" ]
+ }
+}
diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md
new file mode 100644
index 0000000..a24eb23
--- /dev/null
+++ b/docs/API_REFERENCE.md
@@ -0,0 +1,57 @@
+# API Reference ()
+
+ API .
+
+## BotPages.Core
+
+### `BotPagesApp`
+- `AddAdapter(string messengerType, IMessangerAdapterSetup adapter)` .
+- `AddDefaultPage() where TPage : SingletonPage` "" .
+- `AddMiddleware(TMiddleware instance) where TMiddleware : IPageMiddleware` middleware .
+- `MapCommand(string commandTemplate) where TPage : Page` , .
+- `MapCommand(string template, CommandHandler handler)` .
+- `MapRoute(string template) where TPage : Page` .
+- `AutoMapRoute()` Page- .
+- `HandleUpdateAsync(UpdateContext update, CancellationToken ct)` ( ).
+- `Build(CancellationToken ct)` .
+
+###
+- `Page` .
+- `StatefulPage` .
+- `SingletonPage` .
+
+###
+- `NavigationService` .
+ - `GoToAsync(PageContext ctx, CancellationToken ct)`
+ - `GoToHomeAsync(PageContext ctx, CancellationToken ct)`
+
+###
+- `CommandsRegistry` (). .
+
+### Middleware
+- `IPageMiddleware` middleware.
+ - `InvokeAsync(PageContext ctx, Func next, CancellationToken ct)`
+
+###
+- `IMessangerAdapterSetup` .
+- `IMessengerAdapter` , `StartAdapterAsync(Func onUpdate, List commands, CancellationToken ct)`.
+- `IMessengerAdapterFactory` / (`MultiAdapterFactory` ).
+
+###
+- `IStateStorage` .
+
+## BotPages.Telegram
+- Telegram `Telegram.Bot`.
+- `TelegramUpdateMapper` Telegram `UpdateContext`.
+- `TelegramAlbumBuilder` - .
+- `TelegramAdapter` , `StartAdapterAsync`.
+
+
+#
+
+ `docfx` `Doxygen` HTML- XML-, (. `GenerateDocumentationFile` `.csproj`).
+
+
+#
+
+ API. reference XML- .
\ No newline at end of file
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 0000000..c9aa433
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,19 @@
+# Contributing to BotPages
+
+ ! , PR , :
+
+- : `dotnet build`.
+- / , .
+- nullable-.
+
+ `docfx`. . `docfx.json` `scripts/`.
+
+ :
+
+```bash
+# Unix
+./scripts/generate-docs.sh
+
+# Windows PowerShell
+./scripts/generate-docs.ps1
+```
diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md
new file mode 100644
index 0000000..fc48e5a
--- /dev/null
+++ b/docs/GETTING_STARTED.md
@@ -0,0 +1,47 @@
+# BotPages
+
+ .
+
+
+- .NET 8 SDK
+- Telegram ( Telegram-)
+
+
+```bash
+dotnet build
+```
+
+
+1. `Demo`.
+2. Telegram ( ) Demo.
+3. :
+```bash
+dotnet run --project Demo
+```
+
+
+```csharp
+var app = new BotPagesApp(stateStorage, logger)
+ .AddAdapter("telegram", new TelegramAdapterSetup(""))
+ .AddDefaultPage()
+ .MapCommand("/start")
+ .AddMiddleware(new LoggingMiddleware(logger));
+
+await app.Build(CancellationToken.None);
+```
+
+
+- `StatefulPage` - .
+- `SingletonPage` .
+- `OnEnter`, `OnUpdate`, `OnText`, `OnButton`, `OnFile`, `OnError` .
+- `AutoMapRoute()`.
+
+
+- `BotPagesApp.MapCommand`.
+- : `/cmd {a} {b?}`.
+
+
+- Middleware , `BotPagesApp`.
+- ( `/`).
+
+ API `docs/API_REFERENCE.md`.
\ No newline at end of file
diff --git a/docs/PROJECT_DOCUMENTATION.md b/docs/PROJECT_DOCUMENTATION.md
new file mode 100644
index 0000000..de68c16
--- /dev/null
+++ b/docs/PROJECT_DOCUMENTATION.md
@@ -0,0 +1,114 @@
+# BotPages
+
+ . , , .
+
+##
+
+- `BotPages.Core` .
+ - : `NavigationService`, : `Page`, `StatefulPage`, `SingletonPage`.
+ - : `RoutesRegistry` ( `AutoMapRoute`).
+ - : `CommandsRegistry` ( , `TryDispatch`).
+ - Middleware: `IPageMiddleware` `LoggingMiddleware`.
+ - /-: `IMessangerAdapterSetup`, `IMessengerAdapterFactory` ( `MultiAdapterFactory`).
+ - : `IStateStorage`.
+
+- `BotPages.Telegram` Telegram ( `Telegram.Bot`).
+
+- `Demo` .
+
+- `BotPages` -/ .
+
+##
+
+- `BotPagesApp` .
+ - : `AddAdapter(string messengerType, IMessangerAdapterSetup adapter)`.
+ - middleware: `AddMiddleware(T instance)`.
+ - : `MapCommand(string template)` `MapCommand(string template, CommandHandler handler)`.
+ - : `MapRoute(string template)` `AutoMapRoute()` .
+ - : `Build(CancellationToken)` .
+
+- :
+ - `Page` () (`OnEnter`, `OnUpdate`, `OnText`, `OnButton`, `OnFile`, `OnError`).
+ - `StatefulPage` `IStateStorage` ( , stateful-).
+ - `SingletonPage` , per-session .
+
+- : `NavigationService` ( `PageContext.SessionKey`) `GoToAsync`, `GoToHomeAsync`.
+
+- : `/cmd {arg} {opt?}`. `CommandsRegistry.ToRegex` . `CommandHandler(PageContext, IDictionary, CancellationToken)`.
+
+- Middleware: `IPageMiddleware.InvokeAsync(PageContext, Func next, CancellationToken ct)`; ().
+
+##
+
+- `UpdateContext` : `MessengerType`, `Chat`, `User`, `Kind` ( `Text`, `Button`, `File`), `Text`, `Files`.
+- `BotPagesApp.HandleUpdateAsync` `PageContext` :
+ 1. ( `/`) .
+ 2. pipeline middleware.
+ 3. `DispatchToPageAsync`.
+
+##
+
+- , `IMessangerAdapterSetup`/`IMessengerAdapter` `BotPagesApp.AddAdapter`.
+- `MultiAdapterFactory` `messengerType`.
+
+##
+
+:
+- .NET 8 SDK
+
+ :
+
+```bash
+dotnet build
+```
+
+ :
+
+```bash
+dotnet run --project Demo
+```
+
+ Telegram- `Demo` ( ).
+
+## API
+
+XML- `GenerateDocumentationFile` `.csproj` . (, `docfx`, `doxygen` `MkDocs` XML).
+
+##
+
+- :
+
+```csharp
+var app = new BotPagesApp(stateStorage, logger)
+ .AddAdapter("telegram", new TelegramAdapterSetup(token))
+ .AddMiddleware(new LoggingMiddleware(logger))
+ .MapCommand("/start")
+ .AddDefaultPage();
+
+await app.Build(CancellationToken.None);
+```
+
+- :
+
+```csharp
+public sealed class WelcomePage : StatefulPage
+{
+ public override async Task OnEnter(PageContext ctx, CancellationToken ct)
+ {
+ await ctx.SendTextAsync(" ", ct: ct);
+ }
+}
+```
+
+##
+
+- PR . PR.
+- null-safe (`Nullable` ).
+
+##
+
+ MIT (. `.csproj` `LICENSE`).
+
+---
+
+ . Reference API ( ) .
\ No newline at end of file
diff --git a/docs/docfx_project/docfx.css b/docs/docfx_project/docfx.css
new file mode 100644
index 0000000..1e62930
--- /dev/null
+++ b/docs/docfx_project/docfx.css
@@ -0,0 +1,2 @@
+/* Minimal styling overrides for docfx output */
+body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif; }
diff --git a/docs/docfx_project/docfx.js b/docs/docfx_project/docfx.js
new file mode 100644
index 0000000..5fcf1aa
--- /dev/null
+++ b/docs/docfx_project/docfx.js
@@ -0,0 +1,7 @@
+module.exports = {
+ "templates": {
+ "global": {
+ "favicon": "favicon.ico"
+ }
+ }
+};
\ No newline at end of file
diff --git a/scripts/generate-docs.ps1 b/scripts/generate-docs.ps1
new file mode 100644
index 0000000..7b724f1
--- /dev/null
+++ b/scripts/generate-docs.ps1
@@ -0,0 +1,22 @@
+Param(
+ [string]$DocfxPath = "docfx",
+ [string]$WorkingDir = "$(Resolve-Path .)"
+)
+
+$ErrorActionPreference = 'Stop'
+
+Write-Host "Generating docfx documentation..."
+
+if (-not (Get-Command $DocfxPath -ErrorAction SilentlyContinue)) {
+ Write-Host "Docfx not found on PATH. Install docfx or provide full path to docfx.exe" -ForegroundColor Yellow
+}
+
+Push-Location $WorkingDir
+try {
+ & $DocfxPath metadata docfx.json
+ & $DocfxPath build docfx.json
+ Write-Host "Docfx build complete. Output in _site folder" -ForegroundColor Green
+}
+finally {
+ Pop-Location
+}
diff --git a/scripts/generate-docs.sh b/scripts/generate-docs.sh
new file mode 100644
index 0000000..8183d79
--- /dev/null
+++ b/scripts/generate-docs.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+DOCFX_PATH=${DOCFX_PATH:-docfx}
+WORKING_DIR=$(pwd)
+
+if ! command -v "$DOCFX_PATH" >/dev/null 2>&1; then
+ echo "docfx not found. Install it or set DOCFX_PATH to the executable path."
+fi
+
+pushd "$WORKING_DIR" > /dev/null
+$DOCFX_PATH metadata docfx.json
+$DOCFX_PATH build docfx.json
+popd > /dev/null
+
+echo "Docfx build complete. Output in _site folder"