> ## Documentation Index
> Fetch the complete documentation index at: https://twenty-claude-cool-pascal-5ay683.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Публикация

> Распространяйте своё приложение Twenty в маркетплейсе или разверните его для внутреннего использования.

## Обзор

После того как ваше приложение [собрано и протестировано локально](/l/ru/developers/extend/apps/getting-started/concepts), у вас есть два пути для его распространения:

* **Разверните tar-архив** — загрузите своё приложение напрямую на конкретный сервер Twenty для внутреннего или частного использования.
* **Опубликовать в npm** — разместите ваше приложение в маркетплейсе Twenty, чтобы любое рабочее пространство могло его найти и установить.

Оба пути начинаются с одного и того же шага **build**.

## Сборка вашего приложения

Выполните команду сборки, чтобы скомпилировать приложение и сгенерировать готовый к распространению `manifest.json`:

```bash filename="Terminal" theme={null}
yarn twenty dev:build
```

Это компилирует исходные файлы TypeScript, транспилирует функции логики и фронтенд-компоненты и записывает всё в `.twenty/output/`. Добавьте `--tarball`, чтобы также создать пакет `.tgz` для ручного распространения или для команды publish.

## Развертывание на сервер (tarball)

Для приложений, которые вы не хотите делать общедоступными — собственные инструменты, интеграции только для предприятий или экспериментальные сборки — вы можете развернуть tarball напрямую на сервер Twenty.

### Требования

Перед развертыванием вам нужен настроенный remote, указывающий на целевой сервер. Remotes локально хранят URL сервера и учётные данные аутентификации в `~/.twenty/config.json`.

Добавьте remote:

```bash filename="Terminal" theme={null}
yarn twenty remote:add --url https://your-twenty-server.com --as production
```

### Развертывание

Соберите и загрузите ваше приложение на сервер в одном шаге:

```bash filename="Terminal" theme={null}
yarn twenty app:publish --private
# To deploy to a specific remote:
# yarn twenty app:publish --private --remote production
```

### Общий доступ к развернутому приложению

Приложения в формате tarball не отображаются в публичном маркетплейсе, поэтому другие рабочие пространства на том же сервере не найдут их при просмотре. Чтобы поделиться развернутым приложением:

1. Перейдите в **Настройки > Приложения > Регистрации** и откройте ваше приложение
2. На вкладке **Распространение** нажмите **Копировать ссылку для общего доступа**
3. Поделитесь этой ссылкой с пользователями в других рабочих пространствах — она ведёт их прямо на страницу установки приложения

Ссылка общего доступа использует базовый URL сервера (без какого-либо поддомена рабочего пространства), поэтому она работает для любого рабочего пространства на сервере.

### Управление версиями

При обновлении уже развернутого tarball-приложения сервер требует, чтобы значение `version` в `package.json` было **строго выше** (согласно упорядочиванию по [semver](https://semver.org)), чем текущая развернутая версия. Повторное развёртывание той же версии или публикация более низкой версии отклоняются до сохранения tarball — в CLI вы увидите ошибку `VERSION_ALREADY_EXISTS`.

Чтобы выпустить обновление:

1. Увеличьте значение поля `version` в вашем `package.json` (например: `1.2.3` → `1.2.4`, `1.3.0` или `2.0.0`).
2. Выполните `yarn twenty app:publish --private` (или `yarn twenty app:publish --private --remote production`)
3. Рабочие пространства, в которых приложение установлено и для него включено автообновление (на вкладке «Настройки» приложения), обновляются автоматически в фоновом режиме; в остальных рабочих пространствах пользователи увидят доступное обновление в своих настройках

<Note>
  Пререлизные теги работают как ожидается: повышение версии `1.0.0-rc.1` → `1.0.0-rc.2` допускается, а финальный релиз вроде `1.0.0` корректно распознаётся как более высокий, чем `1.0.0-rc.5`. Версия в `package.json` должна сама по себе быть корректной строкой semver.
</Note>

### Совместимость версий сервера

Если ваше приложение использует функцию, появившуюся в конкретной версии сервера Twenty (например, провайдеры OAuth, добавленные в v2.3.0), следует объявить минимальную требуемую версию сервера с помощью поля `engines.twenty` в `package.json`:

```json filename="package.json" theme={null}
{
  "name": "twenty-my-app",
  "version": "1.0.0",
  "engines": {
    "node": "^24.5.0",
    "twenty": ">=2.3.0"
  }
}
```

Значение — это стандартный [диапазон semver](https://github.com/npm/node-semver#ranges). Типовые шаблоны:

| Диапазон          | Значение                                           |
| ----------------- | -------------------------------------------------- |
| `>=2.3.0`         | Любой сервер версии 2.3.0 и новее                  |
| `>=2.3.0 \<3.0.0` | 2.3.0 или новее, но ниже следующей мажорной версии |
| `^2.3.0`          | То же, что и `>=2.3.0 \<3.0.0`                     |

**Что происходит при развёртывании и установке:**

* Если `engines.twenty` задано и версия целевого сервера не удовлетворяет диапазону, развёртывание (загрузка tarball-архива) или установка отклоняются с ошибкой `SERVER_VERSION_INCOMPATIBLE` и сообщением, указывающим как требуемый диапазон, так и фактическую версию сервера.
* Если `engines.twenty` **не задано**, приложение принимается на сервере любой версии (обратная совместимость с существующими приложениями).
* Если на сервере `APP_VERSION` не задано, проверка пропускается.

<Note>
  Сервер выполняет окончательную проверку — он проверяет `engines.twenty` как при загрузке tarball-архива, так и при установке в рабочем пространстве. Если вы развёртываете tarball вне стандартного процесса или устанавливаете из маркетплейса, сервер всё равно принудительно проверяет совместимость.
</Note>

## Автоматизированный CI/CD (рабочие процессы, сгенерированные шаблоном)

Приложения, созданные с помощью `create-twenty-app`, «из коробки» включают три рабочих процесса GitHub Actions в каталоге `.github/workflows/`. CI запускается без какой-либо настройки, для CD требуется один секрет, а публикация в npm требует однократной настройки доверенного издателя npm (trusted-publisher).

### CI — `ci.yml`

Автоматически запускает интеграционные тесты при каждом пуше в `main` и для каждого pull request.

**Что делает:**

1. Извлекает исходный код вашего приложения.
2. Запускает изолированный тестовый экземпляр Twenty с помощью составного действия `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test@main` (эквивалент для CI `yarn twenty docker:start --test`).
3. Включает Corepack, настраивает Node.js на основе вашего `.nvmrc` и устанавливает зависимости с помощью `yarn install --immutable`.
4. Запускает `yarn test`, передавая `TWENTY_API_URL` и `TWENTY_API_KEY` из запущенного экземпляра, чтобы ваши тесты могли взаимодействовать с реальным сервером.

**Параметры конфигурации:**

* `TWENTY_VERSION` (переменная окружения, по умолчанию `latest`) — зафиксируйте версию сервера Twenty, используемую в CI, отредактировав это значение в `ci.yml`.
* Параллельные запуски группируются по `github.ref` и отменяют выполняющиеся прогоны при новых пушах.

Секреты не требуются — тестовый экземпляр эфемерен и существует только на время выполнения задания.

### CD — `cd.yml`

Разворачивает ваше приложение на настроенном сервере Twenty при каждом пуше в `main` и, при необходимости, из pull request при наличии метки `deploy`.

**Что делает:**

1. Извлекает head-коммит PR (для PR с меткой) или запушенный коммит.
2. Запускает `twentyhq/twenty/.github/actions/deploy-twenty-app@main` — эквивалент для CI `yarn twenty app:publish --private`.
3. Запускает `twentyhq/twenty/.github/actions/install-twenty-app@main`, чтобы новая развернутая версия была установлена в целевое рабочее пространство.

**Обязательная конфигурация:**

| Настройка               | Где                                                                   | Назначение                                                                                                              |
| ----------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `TWENTY_DEPLOY_URL`     | `env` в `cd.yml` (по умолчанию `http://localhost:3000`)               | Сервер Twenty, на который выполняется деплой. Перед первым использованием замените это на URL вашего реального сервера. |
| `TWENTY_DEPLOY_API_KEY` | В репозитории GitHub — **Settings → Secrets and variables → Actions** | Ключ API с правом деплоя на целевом сервере.                                                                            |

<Note>
  Значение `TWENTY_DEPLOY_URL` по умолчанию — `http://localhost:3000` — это заглушка: с хостируемого GitHub раннера к ней не будет доступа. Перед включением CD замените его на публичный URL вашего сервера (или используйте self-hosted раннер с сетевым доступом).
</Note>

**Запуск предварительного деплоя из PR:**

Добавьте к pull request метку `deploy`. Условие `if:` в `cd.yml` запустит задачу для этого PR, используя его head-коммит, что позволит проверить изменение на целевом сервере до слияния.

### Публикация — `publish.yml`

Публикует ваше приложение в npm с указанием происхождения (provenance), когда вы отправляете тег версии (например, `v1.0.0`), или когда вы запускаете рабочий процесс вручную на вкладке Actions.

**Что делает:**

1. Клонирует ваше приложение, настраивает Node.js и обновляет npm (для доверенной публикации требуется npm версии 11.5.1 или новее).
2. Запускает `yarn twenty app:publish`, который собирает приложение и публикует `.twenty/output` в npm. В CI он автоматически добавляет `--provenance` и `--access public`, поэтому в рабочем процессе флаги не требуются.

**Первоначальная настройка:**

На npmjs.com откройте свой пакет > **Settings → Trusted Publisher** и зарегистрируйте этот репозиторий, указав рабочий процесс `publish.yml` (см. [документацию по доверенной публикации в npm](https://docs.npmjs.com/trusted-publishers)). Публикация с provenance подтверждает, какой репозиторий GitHub собрал пакет, а также позволяет вам заявить права на ваше приложение в маркетплейсе Twenty.

<Note>
  npm принимает подтверждение происхождения только из **публичных** репозиториев с исходным кодом. Если вы публикуете из приватного репозитория, npm отклоняет пакет подтверждения происхождения OIDC с ошибкой `E422 ... Ошибка `Unsupported GitHub Actions source repository visibility: "private"`. Чтобы публиковать из приватного репозитория, отключите подтверждение происхождения, установив `TWENTY\_APP\_PUBLISH\_DISABLE\_PROVENANCE: 'true'`в`env`шага публикации (закомментированная подсказка включена в сгенерированный`publish.yml\`):

  ```yaml filename=".github/workflows/publish.yml" theme={null}
        - name: Publish to npm
          env:
            TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'
          run: yarn twenty app:publish
  ```
</Note>

### Закрепление версий повторно используемых действий

Рабочие процессы `ci.yml` и `cd.yml` ссылаются на повторно используемые действия с указанием `@main`, поэтому обновления действий в репозитории `twentyhq/twenty` подхватываются автоматически. Если вам нужны детерминированные сборки, замените `@main` на SHA коммита или тег релиза в каждой строке `uses:`.

## Публикация в npm

Публикация в npm делает ваше приложение видимым в маркетплейсе Twenty. Любое рабочее пространство Twenty может просматривать, устанавливать и обновлять приложения из маркетплейса непосредственно из интерфейса.

### Требования

* Учётная запись [npm](https://www.npmjs.com)
* Ключевое слово `twenty-app` в массиве `keywords` вашего `package.json` (добавьте его вручную — по умолчанию оно не включено в шаблон `create-twenty-app`)

```json filename="package.json" theme={null}
{
  "name": "twenty-app-postcard-sender",
  "version": "1.0.0",
  "keywords": ["twenty-app"]
}
```

### Метаданные маркетплейса

Конфигурация `defineApplication()` поддерживает необязательные поля, которые определяют, как ваше приложение отображается в маркетплейсе. Используйте `logo` и `galleryImages`, чтобы ссылаться на изображения из папки `public/`:

```ts src/application-config.ts theme={null}
export default defineApplication({
  universalIdentifier: '...',
  displayName: 'My App',
  description: 'A great app',
  logo: 'public/logo.png',
  galleryImages: [
    'public/screenshot-1.png',
    'public/screenshot-2.png',
  ],
});
```

См. [аккордеон defineApplication](/l/ru/developers/extend/apps/config/application#marketplace-metadata) на странице «Создание приложений» для полного списка полей маркетплейса (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl` и т. д.).

#### Рекомендуемые размеры изображений галереи

Маркетплейс отображает `galleryImages` в контейнере с фиксированным соотношением сторон `8:5` (например, `1600×1000 px`).

<Note>
  Изображения галереи с любым соотношением сторон отображаются полностью и никогда не обрезаются, но всё, что значительно выше или уже, чем `8:5`, будет иметь пустые поля по бокам.
</Note>

#### Ограничение размера изображения

Файл `logo` и каждый файл из `galleryImages` не должны превышать **10 MB**. Более крупные файлы пропускаются при повторном размещении ваших опубликованных ресурсов на маркетплейсе, поэтому они не будут отображаться.

### Публикация

```bash filename="Terminal" theme={null}
yarn twenty app:publish
```

Чтобы опубликовать с определённым dist-tag (например, `beta` или `next`):

```bash filename="Terminal" theme={null}
yarn twenty app:publish --tag beta
```

### Как работает обнаружение приложений в маркетплейсе

Сервер Twenty синхронизирует каталог маркетплейса из реестра npm **каждый час**.

Вы можете запустить синхронизацию немедленно, вместо ожидания:

```bash filename="Terminal" theme={null}
yarn twenty dev:catalog-sync
# To target a specific remote:
# yarn twenty dev:catalog-sync --remote production
```

Метаданные, отображаемые в маркетплейсе, берутся из вашей конфигурации `defineApplication()` — см. раздел [Метаданные маркетплейса](#marketplace-metadata) выше.

<Note>
  Если ваше приложение не определяет `aboutDescription` в `defineApplication()`, маркетплейс автоматически использует `README.md` вашего пакета из npm в качестве содержимого страницы «О приложении». Это означает, что вы можете поддерживать единый README как для npm, так и для маркетплейса Twenty. Если вы хотите другое описание в маркетплейсе, явно задайте `aboutDescription`.
</Note>

### Публикация через CI

Сгенерированный выше рабочий процесс `publish.yml` автоматически публикует в npm по тегам версий, с provenance. Поскольку `yarn twenty app:publish` при запуске в CI добавляет за вас `--provenance` и `--access public`, в рабочем процессе не нужны флаги npm — требуется только однократная настройка доверенного издателя.

Для других систем CI (GitLab CI, CircleCI и т. д.) запустите `yarn install`, затем `yarn twenty app:publish`. Provenance создается, когда среда может выпустить токен OIDC, и в противном случае автоматически пропускается.

<Note>
  **npm provenance** добавляет значок доверия к вашему пакету в npm, позволяя пользователям проверить, что пакет был собран из конкретного коммита в общедоступном конвейере CI. Это также то, что позволяет вам заявить права на ваше приложение в маркетплейсе Twenty. Подробности см. в [документации по npm provenance](https://docs.npmjs.com/generating-provenance-statements).
</Note>

## Установка приложений

После публикации приложения (npm) или его развертывания (tarball) рабочие пространства могут установить его через интерфейс.

Перейдите на страницу **Настройки > Приложения** в Twenty, где можно просматривать и устанавливать как приложения из маркетплейса, так и развернутые через tarball.

Вы также можете устанавливать приложения из командной строки:

```bash filename="Terminal" theme={null}
yarn twenty app:install
```

<Note>
  Сервер при установке применяет версионирование semver, аналогичное правилам при развёртывании:

  * Установка той же версии, которая уже установлена в вашем рабочем пространстве, отклоняется с ошибкой `APP_ALREADY_INSTALLED`.
  * Установка версии ниже текущей отклоняется с ошибкой `CANNOT_DOWNGRADE_APPLICATION`.

  Чтобы установить более новую версию, сначала разверните или опубликуйте её, затем снова выполните `yarn twenty app:install`.
</Note>
