## Получить статус подготовки хоста

`GET /v1/infra/servers/:id/app-db/prepare`

Возвращает состояние подготовки хоста галактики для работы с базой приложения: каких компонентов не хватает и на каком шаге идёт установка. Запрос только читает состояние и подготовку не запускает.

## Параметры

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|----------|
| `id` (path) | string (UUID) | да | ID приложения с `kind` равным `GALAXY_APP`. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) |

Параметры строки запроса не принимаются: любой отклоняется с `400 VALIDATION_ERROR`.

## Примеры

### curl — личный ключ

```bash
curl "https://vibecode.bitrix24.tech/v1/infra/servers/APP_ID/app-db/prepare" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth-приложение

```bash
curl "https://vibecode.bitrix24.tech/v1/infra/servers/APP_ID/app-db/prepare" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — личный ключ

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${appId}/app-db/prepare`,
  { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
const { success, data, error } = await res.json()
if (!success) throw new Error(error.code)
console.log(data.state, data.missing)
```

### JavaScript — OAuth-приложение

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${appId}/app-db/prepare`,
  {
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  }
)
const { success, data, error } = await res.json()
```

## Поля ответа

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | `true` при успешном чтении состояния |
| `data.state` | string | `not_prepared` — компонентов не хватает, подготовка не идёт. `preparing` — подготовка идёт. `ready` — все компоненты на месте. `failed` — последняя подготовка завершилась ошибкой, причина в `data.errorCode` |
| `data.steps` | array | Семь шагов в фиксированном порядке: `disk`, `python3`, `zstd`, `age`, `curl`, `image`, `verify` |
| `data.steps[].id` | string | Шаг: `disk` — проверка свободного места и пакетного менеджера, `python3`, `zstd`, `age`, `curl` — установка пакета, `image` — загрузка служебного образа для чтения базы, `verify` — итоговая проверка |
| `data.steps[].state` | string | `pending` — шаг не начат, `running` — выполняется, `done` — выполнен, `present` — компонент уже был на хосте, `failed` — шаг завершился ошибкой |
| `data.missing` | string[] | Компоненты, которых сейчас нет на хосте: `python3`, `zstd`, `age`, `curl`, `image`. При `ready` массив пуст |
| `data.errorCode` | string | Только при `failed`: `LOW_DISK`, `DPKG_BROKEN`, `APT_PLAN_UNSAFE`, `APT_FAILED`, `PULL_FAILED`, `VERIFY_FAILED` или `UNSUPPORTED_HOST`. Что делать с каждым кодом — в разделе «Известные особенности» |
| `data.freeBytes` | integer | Меньшее из свободного места на корневом разделе и на разделе образов Docker, в байтах. Приходит при `preparing` и `failed`, если замер был |

## Пример ответа

Подготовка не запускалась, на хосте не хватает только служебного образа:

```json
{
  "success": true,
  "data": {
    "state": "not_prepared",
    "steps": [
      { "id": "disk", "state": "pending" },
      { "id": "python3", "state": "present" },
      { "id": "zstd", "state": "present" },
      { "id": "age", "state": "present" },
      { "id": "curl", "state": "present" },
      { "id": "image", "state": "pending" },
      { "id": "verify", "state": "pending" }
    ],
    "missing": ["image"]
  }
}
```

Хост подготовлен:

```json
{
  "success": true,
  "data": {
    "state": "ready",
    "steps": [
      { "id": "disk", "state": "done" },
      { "id": "python3", "state": "present" },
      { "id": "zstd", "state": "present" },
      { "id": "age", "state": "present" },
      { "id": "curl", "state": "present" },
      { "id": "image", "state": "present" },
      { "id": "verify", "state": "done" }
    ],
    "missing": []
  }
}
```

## Пример ответа при ошибке

400 — в запросе передан параметр строки запроса, а эндпоинт параметров не принимает:

```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid preparation parameters"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `VALIDATION_ERROR` | Передан параметр строки запроса |
| 400 | `APP_DB_UNSUPPORTED_PLACEMENT` | Приложение размещено не в Галактике |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Ключ не опознан |
| 402 | `BILLING_FROZEN` | Хост галактики спит, а счёт портала заморожен: разбудить хост нельзя |
| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |
| 403 | `APP_DB_DISABLED` | Работа с базой приложения не включена для портала |
| 403 | `SERVER_WAKE_BLOCKED` | Хост галактики спит, а его пробуждение запрещено |
| 404 | `NOT_FOUND` | Приложение или его хост не найдены, удалены или недоступны этому ключу |
| 409 | `APP_DB_BUSY` | Хост не успел проснуться за 10 секунд или занят другой операцией. Повторите после паузы из `Retry-After` |
| 429 | `RATE_LIMITED` | Превышен лимит запросов на чтение для портала — [Лимиты](/docs/infra/database#лимиты). Пауза — в заголовке `Retry-After` |
| 503 | `APP_DB_TOOL_UNAVAILABLE` | Служебный канал к хосту недоступен, или хост вернул некорректное состояние. Повторите после паузы из `Retry-After` |
| 503 | `user_self_deletion_pending` | Владелец ключа удаляет свой аккаунт на портале |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

**Запуск — отдельным вызовом.** При `not_prepared` и `failed` подготовку запускает [`POST /app-db/prepare`](/docs/infra/database/prepare) по тому же адресу.

**Опрос будит спящий хост** — см. [Когда база доступна](/docs/infra/database#когда-база-доступна).

**Как опрашивать.** После запуска подготовки опрашивайте этот адрес раз в 3 секунды, а при `409`, `429` и `503` выдерживайте паузу из `Retry-After`, если она длиннее. При `ready` перечитайте базу, при `failed` остановите опрос и покажите причину из `data.errorCode`. `not_prepared` во время опроса означает, что подготовка не идёт: остановите опрос и запустите её снова. В интерфейсе приостанавливайте опрос, пока вкладка скрыта, а при смене приложения или закрытии экрана отменяйте запросы.

**Что делать при `failed`.** Повторный запуск пропускает уже установленные компоненты.

- `LOW_DISK` — на корневом разделе или разделе образов Docker меньше 6 ГиБ свободного места. Освободите место в данных приложений или обратитесь в поддержку.
- `DPKG_BROKEN` — пакетный менеджер хоста в неисправном состоянии. Обратитесь в поддержку.
- `APT_PLAN_UNSAFE` — установка потребовала бы обновить или удалить уже установленные пакеты, и платформа её остановила. Обратитесь в поддержку.
- `UNSUPPORTED_HOST` — на хосте не Ubuntu 24.04 или нет нужных системных утилит. Обратитесь в поддержку.
- `APT_FAILED`, `PULL_FAILED`, `VERIFY_FAILED` — не удалось установить пакет, загрузить служебный образ или пройти итоговую проверку. Повторите `POST /app-db/prepare`.

**Цикл ожидания готовности (готовый пример):**

```javascript
async function waitForPreparation(url, headers, signal) {
  while (!signal.aborted) {
    const response = await fetch(url, { headers, signal })
    const retry = Number(response.headers.get('Retry-After'))
    const waitMs = Math.max(3000, Number.isFinite(retry) ? retry * 1000 : 0)
    if (response.ok) {
      const { data } = await response.json()
      // ready, failed и not_prepared — конечные для опроса состояния
      if (data.state !== 'preparing') return data
    } else if (![409, 429, 503].includes(response.status)) {
      throw new Error(`HTTP ${response.status}`)
    }
    await new Promise((resolve, reject) => {
      const cancel = () => {
        clearTimeout(timer)
        reject(signal.reason)
      }
      const timer = setTimeout(() => {
        signal.removeEventListener('abort', cancel)
        resolve()
      }, waitMs)
      signal.addEventListener('abort', cancel, { once: true })
    })
  }
  throw signal.reason
}
```

## Смотрите также

- [Подготовить хост](/docs/infra/database/prepare)
- [Получить сведения о базе](/docs/infra/database/info)
- [Создать копию базы](/docs/infra/database/snapshot)
- [База данных приложения](/docs/infra/database)
