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

# Hook di installazione

> Esegui la logica durante il ciclo di vita di installazione, aggiornamento o disinstallazione — inserisci dati iniziali, esegui il backup dei record, valida l'aggiornamento, pulisci le risorse esterne.

Gli hook di installazione sono funzioni logiche speciali che vengono eseguite durante il ciclo di vita di installazione, aggiornamento o disinstallazione. Condividono lo stesso runtime del gestore delle [logic functions](/l/it/developers/extend/apps/logic/logic-functions) normali, ma sono dichiarati con le proprie funzioni di definizione e vivono al di fuori del normale modello di trigger (HTTP, cron, eventi del database). Gli hook di installazione ricevono un `InstallPayload` (`{ previousVersion?: string; newVersion: string }` — `previousVersion` è `undefined` in caso di nuova installazione); l'hook di disinstallazione riceve un `UninstallPayload` (`{ version?: string }` — la versione che viene rimossa).

Ogni app può definire **al massimo uno** per ciascun hook (pre-install, post-install, uninstall). La build del manifesto genera un errore se viene rilevato più di un hook per qualsiasi tipo.

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

## A colpo d'occhio

|                       | `definePreInstallLogicFunction`                                                                                                 | `definePostInstallLogicFunction`                                                                                                     |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Quando viene eseguito | Prima della migrazione dei metadati — lo schema e i dati **precedenti** sono ancora intatti                                     | Dopo la migrazione e la generazione dell'SDK — il **nuovo** schema è in vigore                                                       |
| Esecuzione            | Sempre sincrona; blocca l'installazione                                                                                         | Async per impostazione predefinita (in coda, 3 tentativi); modalità sync tramite opt-in con `shouldRunSynchronously: true`           |
| In caso di errore     | L'installazione viene **annullata** prima di qualsiasi modifica allo schema                                                     | Async: ritentato fino a 3 volte. Sync: il chiamante riceve `POST_INSTALL_ERROR` (le modifiche allo schema **non** vengono annullate) |
| Uso tipico            | Eseguire il backup o correggere dati che una migrazione perderebbe; rifiutare un aggiornamento rischioso lanciando un'eccezione | Popolare dati predefiniti, configurare il workspace, registrare risorse esterne                                                      |

**Regola generale:** usa post-install come impostazione predefinita. Ricorri al pre-install solo quando la migrazione stessa è distruttiva e devi intercettare lo stato precedente prima che vada perso.

| Vuoi...                                                                                                      | Usa                                                               |
| ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| Popolare i dati, configurare il workspace, registrare risorse esterne                                        | `post-install`                                                    |
| Lavoro di lunga durata che non dovrebbe bloccare la risposta dell'installazione                              | `post-install` (modalità async predefinita, con retry del worker) |
| Eseguire un setup rapido da cui il chiamante dipende immediatamente dopo il completamento dell'installazione | `post-install` con `shouldRunSynchronously: true`                 |
| Leggere o eseguire il backup dei dati che la prossima migrazione perderebbe                                  | `pre-install`                                                     |
| Rifiutare un aggiornamento che corromperebbe i dati esistenti                                                | `pre-install` (genera un'eccezione dall'handler)                  |
| Riconciliazione a ogni aggiornamento                                                                         | Uno qualsiasi dei due hook con `shouldRunOnVersionUpgrade: true`  |

## Comportamento condiviso da entrambi gli hook

* La config è una config di `defineLogicFunction` meno le impostazioni di trigger, più `shouldRunOnVersionUpgrade`.
* **Quando viene eseguito**: solo sulle nuove installazioni, per impostazione predefinita. Imposta `shouldRunOnVersionUpgrade: true` per eseguirlo anche sugli upgrade. Usa `previousVersion` / `newVersion` per ramificare in base al percorso di upgrade.
* **L'idempotenza è importante**: il post-install async può essere ritentato e qualsiasi hook viene rieseguito sugli upgrade quando `shouldRunOnVersionUpgrade` è attivo.
* Il consueto ambiente delle logic-function (`APPLICATION_ID`, `APP_ACCESS_TOKEN`, `API_URL`) viene iniettato, così puoi chiamare le API di Twenty con il token della tua app.
* L'hook viene collegato automaticamente al manifesto dell'applicazione in fase di build (`preInstallLogicFunction` / `postInstallLogicFunction`) — non c'è nulla da referenziare in [`defineApplication()`](/l/it/developers/extend/apps/config/application).
* Il `timeoutSeconds` predefinito è 300 per consentire attività di setup più lunghe, come il seeding dei dati.
* **Non eseguito in modalità dev**: `yarn twenty dev` salta il flusso di installazione e sincronizza direttamente i file, quindi gli hook non vengono mai eseguiti in quell'ambiente. Attivali invece manualmente:

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

<AccordionGroup>
  <Accordion title="definePostInstallLogicFunction" description="Viene eseguita dopo che la migrazione dei metadati dello spazio di lavoro è stata applicata">
    Viene eseguito una volta che l'installazione della tua app è terminata: metadati sincronizzati, client SDK generato, nuovo schema interrogabile. Esempio — eseguire il seeding di un record predefinito nelle nuove installazioni:

    ```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,
    });
    ```

    Il flag `shouldRunSynchronously` controlla il modello di esecuzione:

    * `false` *(predefinito)* — messo in coda nella message queue (`retryLimit: 3`) ed eseguito da un worker. La risposta dell'installazione ritorna non appena il job viene messo in coda. **Da usare per lavoro di lunga durata** — seeding di grandi dataset, API di terze parti lente.
    * `true` — eseguito inline durante il flusso di installazione. La richiesta di installazione rimane bloccata finché l'handler non termina; un errore lanciato viene esposto al chiamante come `POST_INSTALL_ERROR` (nessun retry). **Da usare per lavoro rapido che deve completarsi prima della risposta.** La migrazione è già stata applicata a questo punto, quindi un errore non annulla le modifiche allo schema — si limita a esporre l'errore.
  </Accordion>

  <Accordion title="definePreInstallLogicFunction" description="Viene eseguita prima che la migrazione dei metadati dello spazio di lavoro sia applicata">
    Viene eseguito prima della migrazione dei metadati, contro lo schema **precedente** — il posto giusto per eseguire il backup di dati che una migrazione perderebbe o per rifiutare un upgrade rischioso. Prima dell'esecuzione, il server esegue una "sincronizzazione ridotta" puramente additiva che registra solo la funzione di pre-install della versione nuova; tutto il resto — oggetti, campi e dati della versione precedente — rimane intatto quando il tuo handler viene eseguito.

    Il pre-install è sempre **sincrono** e blocca l'installazione. Se l'handler genera un'eccezione, l'installazione viene interrotta prima che venga applicata qualsiasi modifica allo schema — il workspace rimane sulla versione precedente in uno stato coerente. Questo è intenzionale: il pre-install è la tua ultima possibilità per rifiutare un aggiornamento rischioso.

    Esempio — copiare i valori di un campo legacy prima che la migrazione lo elimini:

    ```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>

## Hook di disinstallazione

`defineUninstallLogicFunction` dichiara un hook che viene eseguito quando un utente disinstalla la tua app. Viene eseguito **prima** che i metadati, i dati e il codice dell'app vengano rimossi — una volta eseguita la migrazione di eliminazione non rimane più nulla da eseguire — quindi il tuo gestore può ancora interrogare gli oggetti e i record dell'app. Usalo per la pulizia delle risorse esterne: deprovisioning delle risorse API, eliminazione dei bot rimanenti, revoca dei webhook.

Note:

* L'hook è "best-effort": viene eseguito in modo sincrono, ma un errore viene registrato e **non blocca mai la disinstallazione** — la pulizia non deve rendere impossibile rimuovere un'app.
* Riceve `UninstallPayload` (`{ version?: string }` — la versione che viene rimossa).
* Non viene eseguito quando un tentativo di nuova installazione non riuscito viene annullato — l'app non ha mai terminato l'installazione.
* L'hook non può essere eseguito dopo che l'app è stata rimossa, quindi la pulizia esterna che dipende dai dati dell'app (ad es. ID dei bot memorizzati nei record) deve essere eseguita qui, non in un job pianificato esterno.
* Come gli hook di installazione, **non viene eseguito in modalità dev** — attivalo manualmente invece:

```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,
});
```
