# Хранилище исходного кода

Хранилище исходного кода автоматически сохраняет снимки кода вашего приложения при каждом деплое. Если над приложением начинает работать другой человек или новая AI-сессия, последнюю версию можно скачать и продолжить с того же места — код не потеряется.

## Разделы документации

- [Автоматическое сохранение при деплое](/docs/source-storage/auto-save) — что попадает в снапшот само, блок `source` в ответе деплоя, деплой из сохранённой версии
- [Снапшот перед публикацией](/docs/source-storage/publish) — что проверяется перед публикацией, отказ `409 SNAPSHOT_REQUIRED`, публикация исходников с сервера
- [Сохранить снапшот](/docs/source-storage/save) — `POST /v1/apps/:id/sources`, заголовки метаданных, дедупликация
- [Список версий и скачивание](/docs/source-storage/versions) — история версий, метаданные одной версии, подписанная ссылка на архив
- [Теги и комментарии версии](/docs/source-storage/metadata) — `PATCH` метаданных и постановка тега
- [Удаление версий](/docs/source-storage/delete) — удаление одной версии и массовая очистка
- [Срок жизни версий и очистка](/docs/source-storage/retention) — политика хранения, версии удалённого сервера, объекты в хранилище
- [Серверные эндпоинты исходников](/docs/source-storage/servers) — то же семейство с ключом сервера
- [Реестр исходников и состояние портала](/docs/source-storage/registry) — `GET /v1/me/sources`, страница кабинета, `capabilities.apps.sourceStorage`

## Зачем это нужно

Когда вы дорабатываете приложение, важно не потерять рабочую версию кода. Хранилище делает это автоматически: при каждом успешном деплое платформа сохраняет снимок исходников. Если позже над приложением начнёт работать другой человек или новая AI-сессия — он скачает последнюю версию и продолжит с того же места, без ручной пересылки архивов.

Снимок привязан к приложению, а не к конкретному разработчику: код остаётся у приложения, даже если меняется команда.

## Чем это отличается от Git и GitHub

Это не система контроля версий и не замена Git. Хранилище решает более узкую задачу — страховка и передача проекта.

| | Хранилище исходного кода | Git / GitHub |
|---|---|---|
| Что хранит | целые снимки архива кода | историю изменений построчно |
| Когда сохраняет | автоматически при каждом деплое | вручную, по команде разработчика |
| Нужны ли навыки Git | нет | да |
| Ветки, слияния, сравнение версий | нет | да |

Нужна командная разработка с ветками и историей — используйте Git. Нужно просто не терять рабочий код и уметь вернуться к прошлой версии — достаточно хранилища.

## Как это работает

1. Вы дорабатываете приложение и запускаете деплой.
2. Платформа сама сохраняет снимок исходников — очередную версию: `v1`, `v2`, `v3`, …
3. В любой момент смотрите список версий и скачиваете нужную.
4. Перед публикацией приложения платформа проверяет, что снимок сохранён.

```
правка кода  →  деплой  →  снимок vN сохранён автоматически
                                      ↓
        список версий  →  скачать любую  →  продолжить работу
```

## Основные понятия

- **Снимок (снапшот)** — заархивированная копия исходного кода приложения на момент сохранения.
- **Версия `vN`** — порядковый номер снимка (`v1`, `v2`, …). Самый свежий считается текущим.
- **Тег** — метка `manual` или `published`: помечает версию как важную, чтобы её не удалила автоматическая очистка.
- **Дедупликация** — если код не изменился, новый снимок не создаётся, возвращается уже существующая версия. Действует в пределах одного владельца — сервера или приложения.

## Доступ и эндпоинты

**Базовый URL:** `https://vibecode.bitrix24.tech/v1`  
**Авторизация:** заголовок `X-Api-Key`. Управлять снапшотами могут ключ авторизации приложения (`vibe_app_*`), личный ключ автора приложения (`vibe_api_*`) или администратор портала.  
**Допустимые форматы архива:** `application/gzip`, `application/x-tar`, `application/zip`, `application/octet-stream`.  
**Лимит тела:** 500 МБ на один запрос.

**Снапшоты приложения:**

| Метод | Путь | Действие |
|-------|------|----------|
| `POST` | `/v1/apps/:id/sources` | [Сохранить снапшот](/docs/source-storage/save) |
| `GET` | `/v1/apps/:id/sources` | [Список версий](/docs/source-storage/versions#список-версий) |
| `GET` | `/v1/apps/:id/sources/:versionId` | [Метаданные одной версии](/docs/source-storage/versions#метаданные-одной-версии) |
| `GET` | `/v1/apps/:id/sources/:versionId/download` | [Подписанная ссылка на скачивание](/docs/source-storage/versions#скачивание-архива) |
| `PATCH` | `/v1/apps/:id/sources/:versionId` | [Обновить теги / комментарий](/docs/source-storage/metadata#обновление-метаданных-версии) |
| `POST` | `/v1/apps/:id/sources/:versionId/tag` | [Добавить или снять тег](/docs/source-storage/metadata#постановка-и-снятие-тега) |
| `DELETE` | `/v1/apps/:id/sources/:versionId` | [Удалить версию](/docs/source-storage/delete#удаление-версии) |
| `POST` | `/v1/apps/:id/sources/cleanup` | [Массовая очистка](/docs/source-storage/delete#массовая-очистка) |

**Снапшоты сервера** — то же семейство с ключом сервера, отличия и полный список путей на странице [Серверные эндпоинты исходников](/docs/source-storage/servers).

**Сводный реестр:** `GET /v1/me/sources` — все владельцы снапшотов, доступные ключу, [Реестр исходников](/docs/source-storage/registry).

## Контракт сохранения

Тело `POST …/sources` — **сырые байты архива**, не `multipart/form-data`. Метаданные передаются заголовками, а не полями формы и не query-параметрами.

| Заголовок | Обязательный | Описание |
|-----------|--------------|----------|
| `Content-Type` | да | Формат архива из списка выше. Другое значение → `400 INVALID_CONTENT_TYPE` |
| `Content-Length` | да | Размер тела в байтах. Без него (`Transfer-Encoding: chunked`) → `411 MISSING_CONTENT_LENGTH` |
| `X-Filename` | нет | Имя файла для отображения. Если не указан — имя выводится из `Content-Type`. Символы вне набора `a-zA-Z0-9._-` → `400 INVALID_FILENAME` |
| `X-Tags` | нет | Теги через запятую. Распознаются `manual` и `published` — они защищают версию от автоматической очистки |
| `X-Note` | нет | Комментарий, который сохраняется в записи о версии |
| `X-AI-Session-Id` | нет | Идентификатор AI-сессии, группирует снапшоты в манифесте |

```bash
curl -X POST https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Content-Type: application/gzip" \
  -H "X-Tags: manual" \
  -H "X-Note: Добавил OAuth-флоу" \
  --data-binary @app-sources.tar.gz
```

**Источник кода при развёртывании** — поле `source` в `POST /v1/infra/servers/:id/deploy` принимает три взаимоисключающие формы:

| Форма | Что это |
|-------|---------|
| `source.content` | Встроенный архив в base64 — работает всегда, в том числе на galaxy-приложении |
| `source.url` | Подписанная ссылка из хранилища Вайбкод. На galaxy-приложении — за отдельным включением |
| `source.versionId` | Уже сохранённая версия вида `vN`. На galaxy-приложении — за отдельным включением |

Полный разбор сохранения — [Сохранить снапшот](/docs/source-storage/save), автосохранение и деплой из версии — [Автоматическое сохранение при деплое](/docs/source-storage/auto-save).

## Быстрый старт

Передать проект другому разработчику или новой AI-сессии — три вызова:

```bash
# 1. Что вообще сохранено под этим приложением
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources

# 2. Ссылка на архив нужной версии (действует 30 минут)
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/v1/download

# 3. Скачать архив по полученной ссылке — без дополнительных заголовков
curl -o source-v1.tar.gz "<url из ответа выше>"
```

## Коды ошибок

Отказы, специфичные для хранилища исходников:

| HTTP | Код | Когда возвращается |
|------|-----|---------------------|
| 400 | `INVALID_CONTENT_TYPE` | `Content-Type` не входит в список допустимых форматов архива |
| 400 | `INVALID_SHA256` | Параметр `sha256` не равен 64 шестнадцатеричным символам |
| 400 | `INVALID_VERSION_ID` | Формат `versionId` не соответствует `v<целое неотрицательное число>` |
| 400 | `INVALID_KEEP_LATEST` | Значение `keepLatest` не является целым неотрицательным числом |
| 400 | `SOURCE_VERSION_REQUIRES_APP` | Деплой по `versionId` ключом, которому сервер не принадлежит, а владелец сервера не привязан к приложению |
| 403 | `NOT_AUTHORIZED` | Ключ не является ключом приложения, личным ключом автора или ключом администратора портала |
| 403 | `PORTAL_KEY_REQUIRED` | Ключ не привязан к порталу — сводный реестр такому ключу недоступен |
| 403 | `SOURCE_APP_ID_MISMATCH` | Ключ авторизации `vibe_app_…` обращается к снапшотам другого приложения |
| 403 | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | Сохранение, правка метаданных или удаление вызваны ключом Cowork/Code — [Проектный ключ для деплоя](/docs/cowork/deploy-key) |
| 404 | `APP_NOT_FOUND` | Приложение не существует, удалено или принадлежит другому порталу |
| 404 | `VERSION_NOT_FOUND` | Версии с таким `versionId` нет или она удалена |
| 404 | `SOURCE_VERSION_NOT_FOUND` | Версия не найдена ни в контексте сервера, ни в контексте приложения |
| 409 | `SNAPSHOT_REQUIRED` | Публикация без сохранённого снапшота либо деплой с внешним URL |
| 409 | `PROTECTED_BY_TAG` | Версия защищена тегом `manual` или `published` |
| 410 | `SOURCE_VERSION_BYTES_PURGED` | Запись о версии жива, но байты уже вычищены из хранилища |
| 411 | `MISSING_CONTENT_LENGTH` | Запрос на сохранение пришёл без `Content-Length` |
| 415 | `UNSUPPORTED_ARCHIVE_FORMAT` | Первые байты архива противоречат заявленному `Content-Type` |
| 502 | `SOURCE_DOWNLOAD_URL_FAILED` | Хранилище временно недоступно — повторите запрос |

Полный справочник кодов API — [Коды ошибок](/docs/errors).

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

- [Ключи и авторизация](/docs/keys-auth)
- [Коды ошибок](/docs/errors)
- [MCP для AI](/docs/mcp)
- [Деплой приложения](/docs/infra/deploy)
- [Хранилище](/docs/storage)
- [Удалить сервер](/docs/infra/servers/delete)
