> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bedolagam.ru/llms.txt
> Use this file to discover all available pages before exploring further.

# Редактор меню

> Визуальная настройка структуры меню Cabinet через drag-and-drop

## Обзор

Редактор меню позволяет администраторам полностью настраивать структуру навигации Cabinet: расположение кнопок, количество кнопок в ряду, стили, иконки, локализованные подписи и добавление кастомных URL-кнопок. Все изменения применяются мгновенно без перезапуска.

### Возможности

* **Drag-and-drop** сортировка рядов
* Перемещение кнопок внутри ряда (вверх/вниз)
* Настройка **1–3 кнопок** на ряд
* 8 встроенных секций (home, subscription, balance, referral, support, info, admin, language)
* **Кастомные URL-кнопки** с выбором режима открытия
* Цветовые стили: `primary`, `success`, `danger`, `default`
* Кастомные emoji-иконки (Telegram Custom Emoji ID)
* Мультиязычные подписи (ru, en, ua, zh, fa)
* Включение/отключение отдельных кнопок
* Сброс к настройкам по умолчанию

<Warning>
  Для работы редактора меню необходимо:

  1. `CABINET_ENABLED=true`
  2. `MENU_LAYOUT_ENABLED=true` в настройках бота
  3. RBAC-разрешение `settings:edit` для редактирования, `settings:read` для просмотра
</Warning>

***

## Включение

```env theme={null}
MENU_LAYOUT_ENABLED=true
```

При включении структура меню управляется через редактор, а не задаётся статически в коде. Подробнее о режимах меню: [Интерфейс и брендирование → Динамическое меню](/bot/interface-settings#динамическое-меню).

***

## Использование

### Открытие редактора

Cabinet → Админ-панель → **Настройки** → вкладка **Редактор меню**

### Работа с рядами

<CardGroup cols={3}>
  <Card title="Перетаскивание" icon="arrows-up-down">
    Захватите ряд за ручку и перетащите для изменения порядка
  </Card>

  <Card title="Кнопок в ряду" icon="table-columns">
    Выберите 1, 2 или 3 кнопки на ряд через селектор в заголовке
  </Card>

  <Card title="Удаление ряда" icon="trash">
    Ряды, содержащие только кастомные кнопки, можно удалить целиком
  </Card>
</CardGroup>

### Настройка кнопки

Нажмите на кнопку для раскрытия настроек:

| Параметр           | Описание                                                                   | Доступно для     |
| ------------------ | -------------------------------------------------------------------------- | ---------------- |
| **Стиль**          | Цвет кнопки: primary (синий), success (зелёный), danger (красный), default | Все кнопки       |
| **Emoji ID**       | Telegram Custom Emoji ID для иконки                                        | Все кнопки       |
| **Вкл/Выкл**       | Показывать или скрыть кнопку                                               | Все кнопки       |
| **Подписи**        | Локализованные названия (ru, en, ua, zh, fa), макс. 100 символов           | Все кнопки       |
| **URL**            | Ссылка для перехода (http\:// или https\://)                               | Только кастомные |
| **Режим открытия** | `external` (браузер) или `webapp` (Telegram WebApp)                        | Только кастомные |

<Note>
  Встроенные кнопки нельзя удалить — только отключить или переместить. Кастомные кнопки можно удалить через иконку корзины.
</Note>

### Добавление кнопки

1. В нужном ряду нажмите **Добавить кнопку**
2. Выберите из списка:
   * **Встроенную секцию** — доступны только ещё не использованные
   * **URL-кнопку** — создаёт кастомную кнопку с настраиваемой ссылкой

### Сохранение и сброс

* **Сохранить** — применяет все изменения атомарно (один запрос)
* **Отменить** — возвращает к последнему сохранённому состоянию
* **Сбросить** — восстанавливает расположение по умолчанию (с подтверждением)

***

## Кастомные URL-кнопки

Кастомные кнопки позволяют добавлять внешние ссылки в меню Cabinet.

### Режим открытия (`open_in`)

| Значение   | Описание                                      | Требования             |
| ---------- | --------------------------------------------- | ---------------------- |
| `external` | Открывает URL в браузере                      | http\:// или https\:// |
| `webapp`   | Открывает URL как Telegram WebApp внутри бота | **Только** https\://   |

<Warning>
  При выборе `webapp` URL **обязательно** должен начинаться с `https://`. HTTP-ссылки будут отклонены при сохранении.
</Warning>

### Примеры использования

* Ссылка на сайт проекта (`external`)
* Ссылка на FAQ или документацию (`external`)
* Встроенная веб-форма обратной связи (`webapp`)
* Внешний сервис мониторинга (`webapp`)

***

## Расположение по умолчанию

| Ряд | Кнопки                | Кнопок в ряду |
| --- | --------------------- | ------------- |
| 1   | home                  | 1             |
| 2   | subscription, balance | 2             |
| 3   | referral, support     | 2             |
| 4   | info, language        | 2             |
| 5   | admin                 | 1             |

Встроенные секции:

| ID             | Описание                                    |
| -------------- | ------------------------------------------- |
| `home`         | Главная страница                            |
| `subscription` | Управление подпиской                        |
| `balance`      | Баланс и пополнение                         |
| `referral`     | Реферальная программа                       |
| `support`      | Тикеты поддержки                            |
| `info`         | Информация (FAQ, правила)                   |
| `admin`        | Админ-панель (видна только администраторам) |
| `language`     | Выбор языка                                 |

***

## Ограничения

| Параметр            | Лимит                         |
| ------------------- | ----------------------------- |
| Максимум рядов      | 20                            |
| Кнопок в ряду       | 1–3                           |
| Длина подписи       | 100 символов                  |
| Длина Emoji ID      | 100 символов                  |
| URL кнопки          | http\:// или https\://        |
| ID кастомной кнопки | Должен начинаться с `custom_` |

***

## API эндпоинты

### GET /cabinet/admin/menu-layout

Возвращает текущую конфигурацию меню (объединяет layout и стили).

**Ответ:**

```json theme={null}
{
  "rows": [
    {
      "id": "row_1",
      "max_per_row": 1,
      "buttons": [
        {
          "id": "home",
          "type": "builtin",
          "style": "primary",
          "icon_custom_emoji_id": "5368324343330516923",
          "enabled": true,
          "labels": {"ru": "Главная", "en": "Home"},
          "url": null,
          "open_in": "external"
        }
      ]
    },
    {
      "id": "row_custom_1",
      "max_per_row": 2,
      "buttons": [
        {
          "id": "custom_12345",
          "type": "custom",
          "style": "success",
          "icon_custom_emoji_id": "",
          "enabled": true,
          "labels": {"ru": "Наш сайт", "en": "Our Website"},
          "url": "https://example.com",
          "open_in": "external"
        }
      ]
    }
  ]
}
```

### PUT /cabinet/admin/menu-layout

Сохранение полной конфигурации. Тело запроса — тот же формат, что и ответ GET.

Сервер атомарно обновляет две системные настройки:

* `CABINET_MENU_LAYOUT` — расположение рядов и кастомные кнопки
* `CABINET_BUTTON_STYLES` — стили встроенных секций

### POST /cabinet/admin/menu-layout/reset

Сброс к расположению по умолчанию. Требует подтверждения на фронтенде.

***

## Кэширование

Конфигурация меню кэшируется в памяти для быстрого доступа:

* **Загрузка** — при старте бота (`load_menu_layout_cache()`, `load_button_styles_cache()`)
* **Обновление** — автоматически после каждого сохранения через API
* **Формат** — deep copy из кэша для защиты от мутаций

Если кэш не загружен, используются значения по умолчанию.

***

## Устранение проблем

### Вкладка редактора не отображается

1. `MENU_LAYOUT_ENABLED=true`?
2. У пользователя есть RBAC-разрешение `settings:read`?
3. Пользователь является администратором (`ADMIN_IDS` или `ADMIN_EMAILS`)?

### Кнопка webapp не работает

1. URL начинается с `https://`? HTTP не поддерживается для webapp-режима
2. Сайт по URL доступен и не блокирует iframe?
3. Telegram WebApp поддерживает URL? (некоторые домены могут быть заблокированы)

### Изменения не применяются

1. Нажали **Сохранить** после внесения изменений?
2. Проверьте логи бота на ошибки валидации:
   ```bash theme={null}
   docker logs <bot_container> 2>&1 | grep -i "menu_layout"
   ```
3. Попробуйте **Сбросить** и настроить заново
