docs: Update docs for the correctness (#13)

This commit is contained in:
deytenit authored and GitHub committed 2026-04-15 00:48:06 +03:00
1 parent 8dba55272c
commit 51a783f93a
60 files changed
+2456 -380

No files matched your search

+35
View File
@@ -0,0 +1,35 @@
---
title: Quetza Bot
description: Модульный фреймворк для Discord-ботов.
weight: 1
type: docs
cascade:
type: docs
---
**Quetza** — это модульный фреймворк для Discord-ботов, построенный на TypeScript, который позволяет разработчикам создавать многофункциональные приложения для Discord с помощью самодостаточных, композитных модулей.
Фреймворк обеспечивает архитектурный фундамент, который превращает разработку функций из модификации ядра в добавление модулей.
## Основные возможности
- **Обнаружение модулей на основе соглашений**: Просто создайте папку, и Quetza загрузит ее как функциональный модуль.
- **Изоляция контроллеров**: Управляйте состоянием на уровне сервера (guild), предотвращая утечки данных между серверами.
- **Декларативные команды**: Определяйте Slash-команды Discord с помощью простого, типизированного интерфейса.
- **Реактивные события**: Подписывайтесь на любые события Discord.js внутри ваших модулей.
## Разделы
{{% cards %}}
{{< card link="getting-started" title="Начало работы" icon="lightning-bolt" subtitle="Поймите философию и архитектуру Quetza." >}}
{{< card link="concepts" title="Концепции" icon="light-bulb" subtitle="Глубокое погружение в модульную систему и структуру контроллеров." >}}
{{< card link="guides" title="Руководства" icon="book-open" subtitle="Пошаговые инструкции по разработке модулей и деплою." >}}
{{< card link="troubleshooting" title="Устранение неполадок" icon="shield-exclamation" subtitle="Диагностика распространенных проблем в разработке модулей." >}}
{{% /cards %}}
---
**See also:**
- [GitHub: Quetza](https://github.com/deytenit/Quetza)
- [Discord.js Documentation](https://discord.js.org/)
@@ -0,0 +1,6 @@
---
title: Концепции
weight: 2
---
В этом разделе описываются архитектурные принципы, на которых построена Quetza. Понимание этих концепций поможет вам проектировать более надежные и поддерживаемые модули.
@@ -0,0 +1,45 @@
---
title: Архитектура и Философия
weight: 1
---
**Цель:** Понять основные принципы проектирования, лежащие в основе модульности Quetza.
## Философия проектирования
### Соглашение важнее конфигурации (Convention Over Configuration)
Quetza минимизирует шаблонный код, полагаясь на строгую структуру папок.
- **Никакого центрального реестра:** Сама файловая система _является_ реестром.
- **Результат:** Вам не нужно обновлять файл конфигурации, чтобы добавить модуль; вы просто создаете папку.
### Композиция важнее наследования (Composition Over Inheritance)
Модули состоят из возможностей (capabilities), а не наследуются от базового класса.
- **Гибкость:** Модули могут использовать любую внутреннюю архитектуру (Функциональную, ООП), пока они экспортируют необходимые интерфейсы.
### Изоляция важнее интеграции (Isolation Over Integration)
Модули не могут напрямую вызывать друг друга.
- **Почему:** Это предотвращает сильную связность (tight coupling).
- **Преимущество:** Вы можете удалить любой модуль, не сломав остальную часть бота.
## Основные сущности
| Сущность | Роль | Жизненный цикл |
| :--- | :--- | :--- |
| **Client** | Локатор сервисов и оркестратор | Синглтон. Руководит всем. |
| **Module** | Пространство имен для функций | Загружается при запуске. |
| **Command** | Конечная точка взаимодействия с пользователем | Без состояния (Stateless). Запрос/Ответ. |
| **Event** | Реактивный наблюдатель (Observer) | Подписывается при запуске. |
| **Controller** | Менеджер состояния | Сохраняется между взаимодействиями. |
---
**См. также:**
- [Паттерн Service Locator](https://ru.wikipedia.org/wiki/Локатор_служб)
- [Паттерн Observer](https://ru.wikipedia.org/wiki/Наблюдатель_(шаблон_проектирования))
@@ -0,0 +1,67 @@
---
title: Модульная система
weight: 2
---
**Цель:** Определить словарь и механизмы основной абстрактной единицы Quetza.
## Системный словарь
### Объявление модуля (Module Declaration)
Файл `module.ts` выступает в качестве манифеста. Это точка входа для обнаружения.
```typescript
export const name = 'my-module'; // ID
export const description = '...'; // Документация
```
### Регистрация команд (Command Registration)
Происходит во время события `ready`.
1. Quetza сканирует все папки `commands/`.
2. Компилирует `ApplicationCommandData`.
3. Отправляет (PUT) данные в API Discord.
### Внедрение контроллера (Controller Injection)
Состояние внедряется (injected), а не импортируется.
```typescript
// Фреймворк вызывает это:
execute(client, interaction, controller);
```
- **Зачем?** Позволяет фреймворку управлять жизненным циклом контроллера (синглтон на каждый модуль).
## Философия управления состоянием
### Эфемерность по умолчанию
Quetza **не предоставляет встроенной базы данных**.
- **Память:** Контроллеры хранят состояние в JS объектах `Map` или `Set`.
- **Перезапуск:** Все состояние теряется при завершении процесса.
- **Постоянство:** Должно быть реализовано вручную (например, SQLite, Redis) внутри Контроллера.
### Область видимости как ключ
Состояние должно быть ключировано по его границам.
- `Map<GuildID, ...>` - Специфично для сервера (Наиболее частое).
- `Map<UserID, ...>` - Специфично для пользователя (Боты для личных сообщений - DM).
## Модель обработки ошибок
**Быстрый и дружелюбный отказ (Fail Fast & Friendly).**
- **Валидация:** Проверяйте права/вводы немедленно.
- **Для пользователя:** "У вас нет прав" (а не "Ошибка: 403").
- **Изоляция:** Сбой в `/ping` перехватывается сам по себе и не "убивает" бота.
---
**См. также:**
- [Жизненный цикл взаимодействия Discord (Interaction Lifecycle)](https://discord.com/developers/docs/interactions/receiving-and-responding)
@@ -0,0 +1,66 @@
---
title: Начало работы
weight: 1
---
**Quetza** — это модульный фреймворк для Discord-ботов, построенный на TypeScript, который позволяет разработчикам создавать многофункциональные приложения для Discord с помощью самодостаточных, композитных модулей.
## Что такое Quetza?
Quetza предоставляет архитектурный фундамент, который превращает разработку функций из модификации ядра в добавление модулей. Он решает проблему жесткого дизайна ботов за счет инверсии структур зависимостей: ядро ничего не знает о модулях, однако модули имеют полный доступ к возможностям через определенные контракты.
## Основная философия
### Проблема
Традиционные монолитные боты страдают от хрупкости. Добавление функций требует изменения логики ядра, переплетения зависимостей и управления растущими базами кода, которые трудно тестировать или изменять.
### Решение
Quetza рассматривает модули как плагины.
- **Расширение без правки ядра:** Добавляйте функции, создавая папку. Модификация кода ядра не требуется.
- **Изоляция:** Модули работают независимо.
- **Композиция:** Включайте или выключайте функции, просто добавляя или удаляя папки модулей.
## Высокоуровневая архитектура
Quetza состоит из трех основных уровней:
1. **Базовый уровень (Foundation Layer)**: Клиент `Discord.js`, расширенный реестрами модулей (команды, события, модули). Он действует как сервис-локатор.
2. **Модульный уровень (Module Layer)**: Самодостаточные пакеты функций. Каждый модуль предоставляет собственные команды и события через стандартизированную структуру файлов.
3. **Сервисный уровень (Service Layer)**: Опциональные **Контроллеры**, которые управляют состоянием бизнес-логики (например, аудиоплееры, контекст разговора) на разных серверах (guilds).
## Ключевые концепции
### Ментальная модель
Для эффективной работы с Quetza примите следующую парадигму:
- **Модули — это плагины:** Независимые папки, обнаруживаемые во время выполнения.
- **Команды — это конечные точки (Endpoints):** Обработчики без сохранения состояния, действующие подобно эндпоинтам REST API.
- **События — это наблюдатели (Observers):** Реактивная логика, подписывающаяся на события жизненного цикла Discord.
- **Контроллеры — это сервисы:** Менеджеры состояния, восполняющие пробел между командами без состояния и постоянным поведением.
### Границы системы
Понимание ограничений критически важно для проектирования:
- **Отсутствие постоянства (Persistence):** Состояние в памяти теряется при перезагрузке. Для постоянного хранения требуется внешняя база данных.
- **Отсутствие межмодульного взаимодействия:** Модули не могут напрямую вызывать друг друга, что обеспечивает слабую связанность.
- **Отсутствие динамической загрузки:** Модули загружаются только при запуске.
## Архитектурные инварианты
Quetza жертвует гибкостью ради предсказуемости с помощью строгих соглашений:
- **Обнаружение на основе соглашений:** Модули _обязаны_ следовать структуре директорий (`module.ts`, `commands/`, `events/`) для загрузки.
- **Однофазная инициализация:** Вся загрузка происходит до установления соединения с Discord.
- **Соблюдение интерфейсов:** Все команды и события должны экспортировать специфические интерфейсы для их регистрации.
---
**See also:**
- [Discord.js Documentation](https://discord.js.org/)
- [TypeScript Documentation](https://www.typescriptlang.org/)
@@ -0,0 +1,6 @@
---
title: Руководства
weight: 3
---
Пошаговые инструкции и руководства по реализации функций в Quetza.
@@ -0,0 +1,56 @@
---
title: Интеграция разговорного ИИ
weight: 4
---
**Цель:** Интегрировать большие языковые модели (LLM), управляя контекстом и ограничениями тайм-аута Discord.
## 1. Стратегия управления контекстом
Разговоры требуют истории, чтобы быть связными.
- **Область видимости (Scoping):** `Map<GuildID, Map<UserID, Message[]>>`
- **Ключ гильдии (Guild Key):** Предотвращает утечки между серверами.
- **Ключ пользователя (User Key):** Предотвращает путаницу между пользователями в публичных каналах.
- **Жизненный цикл:** Реализуйте "скользящее окно" (например, последние 50 сообщений) для предотвращения разрастания контекста.
## 2. Потоковая передача ответов
LLM работают медленно, а Discord требует быстрых ответов (тайм-аут 3 секунды).
{{% steps %}}
### Шаг 1: Отложенное взаимодействие (Defer Interaction)
Немедленно вызовите `interaction.deferReply()`. Это даст вам 15 минут.
### Шаг 2: Вызов LLM
Асинхронно вызовите ваш ИИ-сервис.
### Шаг 3: Редактирование ответа
Когда данные поступят, используйте `interaction.editReply(content)`.
{{% /steps %}}
## 3. Пример реализации
```typescript
// commands/chat.ts
export async function execute(interaction, controller) {
// 1. Отложить ответ
await interaction.deferReply();
// 2. Обработка
const history = controller.getHistory(interaction.guildId, interaction.user.id);
const response = await aiService.generate(interaction.options.getString('prompt'), history);
// 3. Ответ
await interaction.editReply(response);
controller.updateHistory(interaction.guildId, interaction.user.id, response);
}
```
> [!WARNING]
> **Затраты на API:**
> API ИИ часто тарифицируются по токенам. Внедрите строгие лимиты запросов (rate limits) для пользователей в вашем Контроллере, чтобы предотвратить злоупотребления.
@@ -0,0 +1,77 @@
---
title: Развертывание и эксплуатация
weight: 2
---
**Цель:** Настроить, развернуть и мониторить экземпляр бота Quetza.
## 1. Подготовка окружения
Quetza полагается на переменные окружения для конфигурации. **Никогда** не сохраняйте их в систему контроля версий.
| Переменная | Описание | Обязательно |
| :--- | :--- | :--- |
| `DISCORD_TOKEN` | Токен бота из Discord Developer Portal | **Да** |
| `CLIENT_ID` | ID приложения для регистрации slash-команд | **Да** |
| `LLAMA_API_KEY` | Требуется при использовании модуля ИИ | Нет |
## 2. Стратегии развертывания
{{< tabs >}}
{{< tab name="Docker (Рекомендуется)" >}}
**Docker** обеспечивает стабильное окружение выполнения.
1. **Сборка** образа:
```bash
docker build -t quetza-bot .
```
2. **Запуск** контейнера:
```bash
docker run -d \
--env-file .env \
--name quetza \
quetza-bot
```
{{< /tab >}}
{{< tab name="Из исходников (Source)" >}}
Развертывание **из исходников** полезно для разработки.
1. **Установка** зависимостей:
```bash
pnpm install
```
2. **Сборка** проекта:
```bash
pnpm build
```
3. **Запуск** бота:
```bash
pnpm start
```
{{< /tab >}}
{{< /tabs >}}
## 3. Операционный мониторинг
После запуска используйте следующие механизмы для проверки работоспособности:
- **Логи:** Проверьте стандартный вывод (логи Docker) на наличие ошибок инициализации.
- **Команда `/ping`:** Проверяет задержку сети и отзывчивость API.
- **Команда `/modules`:** Перечисляет все загруженные модули, чтобы подтвердить доступность функций.
> [!WARNING]
> **Ограничение масштабирования:**
> Quetza следует модели "один экземпляр на один токен". Не запускайте несколько экземпляров с одним и тем же токеном, так как это вызовет конфликты WebSocket.
---
**См. также:**
- [Документация Docker](https://docs.docker.com/)
- [Discord Developer Portal](https://discord.com/developers/applications)
@@ -0,0 +1,105 @@
---
title: Процесс разработки модуля
weight: 1
---
**Цель:** Создать новую функцию для бота Quetza путем реализации самодостаточного модуля.
## 1. Фаза концептуализации
Перед написанием кода определите архитектуру модуля:
- **Простая команда:** Требуется только папка `commands/` (например, служебные команды).
- **Реактивная логика:** Нужна папка `events/` для прослушивания жизненного цикла Discord (например, приветственные сообщения).
- **Функция с состоянием:** Требуется **Контроллер** (Controller) для управления состоянием на разных серверах (например, музыкальный плеер).
## 2. Создание структуры
Создайте структуру директорий модуля. Наличие этих файлов запускает автоматическое обнаружение.
{{< filetree/container >}}
{{< filetree/folder name="src" state="open" >}}
{{< filetree/folder name="modules" state="open" >}}
{{< filetree/folder name="my-feature" state="open" >}}
{{< filetree/file name="module.ts" >}}
{{< filetree/folder name="commands" >}} {{< /filetree/folder >}}
{{< filetree/folder name="events" >}} {{< /filetree/folder >}}
{{< filetree/folder name="lib" >}} {{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
## 3. Шаги реализации
{{% steps %}}
### Шаг 1: Создание манифеста
Создайте `module.ts` для объявления модуля.
```typescript
// src/modules/my-feature/module.ts
export const name = 'my-feature';
export const description = 'Добавляет крутые возможности';
// Опционально: export const controller = new MyFeatureController();
```
### Шаг 2: Реализация команд
Создайте файлы команд в папке `commands/`. Каждый файл экспортирует данные и функцию-исполнитель (executor).
```typescript
// src/modules/my-feature/commands/ping.ts
import { SlashCommandBuilder } from 'discord.js';
export const data = new SlashCommandBuilder().setName('ping').setDescription('Отвечает Pong!');
export async function execute(interaction) {
await interaction.reply('Pong!');
}
```
### Шаг 3: Реализация событий (Опционально)
Создайте обработчики событий в `events/` для отслеживания состояния Discord.
```typescript
// src/modules/my-feature/events/ready.ts
import { Events } from 'discord.js';
export const name = Events.ClientReady;
export const once = true;
export function execute(client) {
console.log(`Ready! Logged in as ${client.user.tag}`);
}
```
### Шаг 4: Определение контроллера (Опционально)
Для логики, требующей сохранения состояния, реализуйте контроллер в папке `lib/` и экспортируйте его в `module.ts`.
### Шаг 5: Валидация
Перезапустите бота.
1. Проверьте логи на наличие "Loaded module: my-feature".
2. Убедитесь, что команда `/ping` появилась в Discord.
{{% /steps %}}
## Шаблоны интеграции
| Паттерн | Сценарий использования | Компоненты |
| :--- | :--- | :--- |
| **Простая команда** | Утилиты без состояния (Ping, Бросок кубиков) | Только `commands/` |
| **Сервис с состоянием** | Музыка, RPG, Экономика | `commands/` + `lib/Controller` |
| **Событийно-ориентированный** | Автомодерация, Логирование | Только `events/` |
| **Гибридный** | Сложные функции (ИИ-чат) | Все компоненты |
---
**См. также:**
- [Руководство Discord.js: Slash-команды](https://discordjs.guide/creating-your-bot/slash-commands.html)
@@ -0,0 +1,63 @@
---
title: Интерактивные голосовые функции
weight: 3
---
**Цель:** Реализовать сложные голосовые взаимодействия, которые учитывают границы серверов (гильдий) и управляют временными ресурсами.
## 1. Стратегия ограничения ресурсов
Голосовые функции **ОБЯЗАТЕЛЬНО** должны быть ограничены рамками Гильдии (Guild).
- **Паттерн:** Контроллер поддерживает `Map<GuildID, Player>`.
- **Поведение:**
- **Подключение (Join):** Создать Player для `Гильдии A`, если он еще не существует.
- **Отключение (Leave):** Уничтожить Player и освободить соединения.
- **Изоляция:** Команды в `Гильдии B` никогда не влияют на `Гильдию A`.
## 2. Оркестрация команд
Голосовые функции требуют набора команд, координируемых через Контроллер.
| Команда | Действие | Логика Контроллера |
| :--- | :--- | :--- |
| `/join` | Подключиться к каналу | `createPlayer(guildId, channelId)` |
| `/play` | Добавить трек в очередь | `getPlayer(guildId).enqueue(track)` |
| `/stop` | Отключиться | `destroyPlayer(guildId)` |
## 3. Сохранение состояния
Аудиосессии эфемерны.
- **Временное состояние:** Активный аудиопоток (Теряется при отключении).
- **Постоянное состояние:** Очередь / Плейлист (Сохраняется в Контроллере до перезапуска).
> [!TIP]
> **Устойчивость:** Разделяйте логику _Очереди_ и логику _Голосового соединения_. Это позволяет боту переподключаться без потери плейлиста пользователя.
## 4. Пример реализации
```typescript
// lib/MusicController.ts
class MusicController {
private players = new Map<string, AudioPlayer>();
getPlayer(guildId: string): AudioPlayer {
if (!this.players.has(guildId)) {
this.players.set(guildId, new AudioPlayer());
}
return this.players.get(guildId);
}
destroyPlayer(guildId: string) {
this.players.get(guildId)?.disconnect();
this.players.delete(guildId);
}
}
```
---
**См. также:**
- [Руководство Discord.js Voice](https://discordjs.guide/voice/)
@@ -0,0 +1,12 @@
---
title: Устранение неполадок
weight: 5
---
Устранение неполадок в **Quetza** фокусируется на диагностике структурных и концептуальных проблем. Из-за его природы, основанной на соглашениях (convention-based), большинство ошибок протекают бесшумно (отсутствующие файлы), а не с шумом (трассировка стека/stack traces).
## Основные категории проблем
{{% cards %}}
{{< card link="diagnostics" title="Руководство по диагностике" icon="exclamation" subtitle="Решения для обнаружения модулей, регистрации команд и утечек состояния." >}}
{{% /cards %}}
@@ -0,0 +1,73 @@
---
title: Диагностика
weight: 1
---
**Цель:** Определить и устранить распространенные ловушки при разработке Quetza.
## 1. Сбои при обнаружении модулей
**Симптом:** Бот запускается, но ваш модуль игнорируется.
**Причина:** Нарушение соглашений файловой системы.
{{% details title="Чек-лист: Структура директорий" closed="false" %}}
- [ ] Существует ли `src/modules/<name>/`?
- [ ] Экспортирует ли `module.ts` переменную `name`?
- [ ] Находятся ли команды в `commands/` (а не в `cmds/`)?
- [ ] Запустили ли вы `pnpm build`? (Quetza запускается из `dist/`).
{{% /details %}}
## 2. Проблемы с регистрацией команд
**Симптом:** Команда `/command` не появляется в Discord.
### Глобальная регистрация против регистрации в тестовой гильдии (Guild)
- **Глобальная:** Команды, отправленные в приложение глобально, могут обновляться до 1 часа и подчиняются более строгим ограничениям скорости (rate limits).
- **Тестовая гильдия:** Quetza автоматически отправляет команды в конкретную гильдию в режиме разработки для мгновенного обновления.
- **Требование:** Убедитесь, что `NODE_ENV=development` и `DEV_GUILD_ID` корректно установлены в вашем `.env`.
### Ограничения скорости (Rate Limits)
Частые обновления глобальных команд могут вызвать ограничения скорости со стороны Discord. Используйте тестовую гильдию для итеративной разработки.
## 3. Ошибки взаимодействия (Interaction Failures)
**Симптом:** «Приложение не отвечает».
**Причина:** Выполнение команды заняло более 3 секунд без отложенного ответа (deferral).
**Решение:**
```typescript
// ПЛОХО
await longRunningTask();
await interaction.reply('Готово'); // Слишком поздно!
// ХОРОШО
await interaction.deferReply();
await longRunningTask();
await interaction.editReply('Готово');
```
## 4. Утечки состояния
**Симптом:** Потребление памяти ботом растет; странности во взаимодействии между серверами.
**Причина:** Хранение состояния глобально вместо уровня гильдии.
**Диагностика:**
Проверьте ваш контроллер.
- ❌ `private player: AudioPlayer;` (Общий для всех!)
- ✅ `private players = new Map<string, AudioPlayer>();` (Разделен по ID гильдии).
## 5. Обработка событий
**Симптом:** События срабатывают несколько раз или не срабатывают вовсе.
- **Несколько раз:** События являются аддитивными. Не зарегистрировали ли вы один и тот же обработчик в двух модулях?
- **Ни разу:** Правильно ли вы экспортировали `name` и `execute`?
> [!TIP]
> **Debug Mode:**
> Включите подробное логирование, чтобы точно увидеть, какие модули и команды загружаются при запуске.