> ## 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.

# Установочные хуки

> Выполняйте логику во время жизненного цикла установки, обновления или удаления — выполняйте начальное заполнение данными, создавайте резервные копии записей, проверяйте корректность обновления, очищайте внешние ресурсы.

Установочные хуки — это специальные логические функции, которые выполняются во время жизненного цикла установки, обновления или удаления. Они используют то же окружение выполнения обработчика, что и обычные [logic functions](/l/ru/developers/extend/apps/logic/logic-functions), но объявляются с помощью собственных функций определения и существуют вне обычной модели триггеров (HTTP, cron, события базы данных). Установочные хуки получают `InstallPayload` (`{ previousVersion?: string; newVersion: string }` — `previousVersion` имеет значение `undefined` при новой установке); хук удаления получает `UninstallPayload` (`{ version?: string }` — версия, которая удаляется).

Каждое приложение может определить **не более одного** хука каждого типа (предустановочный, постустановочный, хук удаления). Сборка манифеста завершится ошибкой, если будет обнаружено более одного хука любого типа.

```
┌─────────────────────────────────────────────────────────────┐
│ install flow                                                │
│                                                             │
│   upload package → [pre-install] → metadata migration →     │
│   generate SDK → [post-install]                             │
│                                                             │
│                  old schema visible    new schema visible   │
└─────────────────────────────────────────────────────────────┘
```

## Краткий обзор

|                        | `definePreInstallLogicFunction`                                                                                                            | `definePostInstallLogicFunction`                                                                                                                    |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Запуски                | До миграции метаданных — **предыдущая** схема и данные остаются нетронутыми                                                                | После миграции и генерации SDK — **новая** схема уже применяется                                                                                    |
| Выполнение             | Всегда синхронное; блокирует установку                                                                                                     | Асинхронно по умолчанию (постановка в очередь, 3 повторные попытки); синхронный режим по желанию через `shouldRunSynchronously: true`               |
| При ошибке             | Установка **прерывается** до любых изменений схемы                                                                                         | Асинхронный режим: до 3 повторных попыток. Синхронный режим: вызывающая сторона получает `POST_INSTALL_ERROR` (изменения схемы **не** откатываются) |
| Типичное использование | Создать резервную копию или исправить данные, которые были бы потеряны при миграции; отклонить рискованное обновление, выбросив исключение | Наполнить данными по умолчанию, настроить рабочее пространство, зарегистрировать внешние ресурсы                                                    |

**Общее практическое правило:** по умолчанию используйте post-install. Обращайтесь к pre-install только тогда, когда сама миграция разрушительна и вам нужно перехватить предыдущее состояние, прежде чем оно исчезнет.

| Вы хотите...                                                                                 | Использовать                                                                    |
| -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Инициализировать данные, настроить рабочее пространство, зарегистрировать внешние ресурсы    | `post-install`                                                                  |
| Длительные операции, которые не должны блокировать ответ установки                           | `post-install` (асинхронный режим по умолчанию, с повторными попытками воркера) |
| Быстрая настройка, на которую вызывающая сторона полагается сразу после завершения установки | `post-install` с `shouldRunSynchronously: true`                                 |
| Прочитать или сохранить данные, которые предстоящая миграция может потерять                  | `pre-install`                                                                   |
| Отклонить обновление, которое повредит существующие данные                                   | `pre-install` (бросьте исключение из обработчика)                               |
| Согласование при каждом обновлении                                                           | Любой хук с `shouldRunOnVersionUpgrade: true`                                   |

## Общее поведение для обоих хуков

* Конфиг — это конфиг `defineLogicFunction` без настроек триггера, но с `shouldRunOnVersionUpgrade`.
* **Когда запускается**: по умолчанию только при чистой установке. Установите `shouldRunOnVersionUpgrade: true`, чтобы также запускать его при обновлениях. Используйте `previousVersion` / `newVersion`, чтобы разветвлять логику в зависимости от пути обновления.
* **Идемпотентность имеет значение**: асинхронный post-install может быть повторно выполнен, и любой хук будет запускаться повторно при обновлениях, если включён `shouldRunOnVersionUpgrade`.
* Обычное окружение logic-функций (`APPLICATION_ID`, `APP_ACCESS_TOKEN`, `API_URL`) инъецируется, поэтому вы можете вызывать Twenty API с токеном своего приложения.
* Хук автоматически прикрепляется к манифесту приложения на этапе сборки (`preInstallLogicFunction` / `postInstallLogicFunction`) — ничего не нужно указывать в [`defineApplication()`](/l/ru/developers/extend/apps/config/application).
* Значение `timeoutSeconds` по умолчанию — 300, чтобы позволить выполнять более длительные задачи настройки, такие как инициализация данных.
* **Не выполняется в dev-режиме**: `yarn twenty dev` пропускает процесс установки и синхронизирует файлы напрямую, поэтому хуки там никогда не запускаются. Вместо этого запускайте их вручную:

```bash filename="Terminal" theme={null}
yarn twenty dev:function:exec --postInstall
yarn twenty dev:function:exec --preInstall
```

<AccordionGroup>
  <Accordion title="definePostInstallLogicFunction" description="Выполняется после применения миграции метаданных рабочего пространства">
    Запускается после завершения установки приложения: метаданные синхронизированы, SDK-клиент сгенерирован, новая схема доступна для запросов. Пример — инициализировать запись по умолчанию при новой установке:

    ```ts src/logic-functions/post-install.ts theme={null}
    import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
    import { CoreApiClient } from 'twenty-client-sdk/core';

    const handler = async ({ previousVersion }: InstallPayload): Promise<void> => {
      if (previousVersion) return; // fresh installs only

      const client = new CoreApiClient();
      await client.mutation({
        createPostCard: {
          __args: { data: { name: 'Welcome to Postcard', content: 'Your first card!' } },
          id: true,
        },
      });
    };

    export default definePostInstallLogicFunction({
      universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
      name: 'post-install',
      description: 'Seeds a welcome post card after install.',
      timeoutSeconds: 300,
      shouldRunOnVersionUpgrade: false,
      shouldRunSynchronously: false,
      handler,
    });
    ```

    Флаг `shouldRunSynchronously` управляет моделью выполнения:

    * `false` *(по умолчанию)* — ставится в очередь сообщений (`retryLimit: 3`) и выполняется воркером. Ответ установки возвращается, как только задача поставлена в очередь. **Используйте для длительных операций** — инициализация больших наборов данных, медленные сторонние API.
    * `true` — выполняется непосредственно в процессе установки. Запрос на установку блокируется до завершения обработчика; выброшенная ошибка возвращается вызывающей стороне как `POST_INSTALL_ERROR` (без повторных попыток). **Используйте для быстрых операций, которые обязательно должны завершиться до ответа.** На этом этапе миграция уже применена, поэтому сбой не откатывает изменения схемы — он только сообщает об ошибке.
  </Accordion>

  <Accordion title="definePreInstallLogicFunction" description="Выполняется до применения миграции метаданных рабочего пространства">
    Запускается до миграции метаданных, в контексте **предыдущей** схемы — подходящее место, чтобы создать резервную копию данных, которые были бы потеряны при миграции, или отклонить рискованное обновление. Перед выполнением сервер запускает чисто добавочную «урезанную синхронизацию», которая регистрирует только pre-install функцию новой версии; всё остальное — объекты, поля и данные предыдущей версии — остаётся нетронутым во время выполнения вашего обработчика.

    Pre-install всегда **синхронный** и блокирует установку. Если обработчик генерирует исключение, установка прерывается до применения каких-либо изменений схемы — рабочее пространство остаётся на предыдущей версии в согласованном состоянии. Это сделано намеренно: pre-install — ваш последний шанс отказать в рискованном обновлении.

    Пример — скопировать значения устаревшего поля перед тем, как миграция его удалит:

    ```ts src/logic-functions/pre-install.ts theme={null}
    import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
    import { CoreApiClient } from 'twenty-client-sdk/core';

    const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise<void> => {
      // Only the 1.x → 2.x upgrade drops the legacy `notes` field.
      if (!previousVersion?.startsWith('1.') || !newVersion.startsWith('2.')) {
        return;
      }

      const client = new CoreApiClient();
      const { postCards } = await client.query({
        postCards: {
          __args: { filter: { notes: { isNot: null } } },
          edges: { node: { id: true, notes: true } },
        },
      });

      // Copy legacy `notes` into `description` before the migration drops the
      // column. If this fails, the upgrade aborts and the workspace stays on v1.
      for (const { node } of postCards.edges) {
        await client.mutation({
          updatePostCard: {
            __args: { id: node.id, data: { description: node.notes } },
            id: true,
          },
        });
      }
    };

    export default definePreInstallLogicFunction({
      universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
      name: 'pre-install',
      description: 'Backs up legacy notes into description before the v2 migration.',
      timeoutSeconds: 300,
      shouldRunOnVersionUpgrade: true,
      handler,
    });
    ```
  </Accordion>
</AccordionGroup>

## Хук удаления

`defineUninstallLogicFunction` объявляет хук, который выполняется, когда пользователь удаляет ваше приложение. Он выполняется **до того**, как метаданные, данные и код приложения будут удалены — после запуска миграции удаления уже нечему будет выполняться — поэтому ваш обработчик все еще может запрашивать объекты и записи приложения. Используйте его для очистки внешних ресурсов: отмены выделения ресурсов API, удаления оставшихся ботов, отзыва вебхуков.

Заметки:

* Хук работает по принципу «по возможности»: он выполняется синхронно, но сбой только логируется и **никогда не блокирует удаление** — очистка не должна делать удаление приложения невозможным.
* Он получает `UninstallPayload` (`{ version?: string }` — версия, которая удаляется).
* Он **не** выполняется при откате неуспешной новой установки — приложение так и не было полностью установлено.
* Хук не может выполниться после того, как приложение удалено, поэтому внешняя очистка, которая зависит от данных приложения (например, ID ботов, сохраненные в записях), должна выполняться здесь, а не во внешнем запланированном задании.
* Как и установочные хуки, он **не выполняется в режиме разработки** — вместо этого запустите его вручную:

```bash filename="Terminal" theme={null}
yarn twenty dev:function:exec --uninstall
```

```ts src/logic-functions/uninstall.ts theme={null}
import { defineUninstallLogicFunction, type UninstallPayload } from 'twenty-sdk/define';
import { CoreApiClient } from 'twenty-client-sdk/core';

const handler = async (_payload: UninstallPayload): Promise<void> => {
  const client = new CoreApiClient();
  const { meetingBots } = await client.query({
    meetingBots: { edges: { node: { id: true, externalBotId: true } } },
  });

  // Delete the provider-side bots so nothing keeps recording after uninstall.
  for (const { node } of meetingBots.edges) {
    await fetch(`https://api.recorder.example/bots/${node.externalBotId}`, {
      method: 'DELETE',
      headers: { Authorization: `Bearer ${process.env.RECORDER_API_KEY}` },
    });
  }
};

export default defineUninstallLogicFunction({
  universalIdentifier: 'b2c3d4e5-6789-01bc-def0-234567890abc',
  name: 'uninstall',
  description: 'Deletes remaining recorder bots when the app is uninstalled.',
  timeoutSeconds: 300,
  handler,
});
```
