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

# Configurazione di Vault per il Self-Hosting

> Come configurare Supabase Vault per i deployment self-hosted di Switchbord — coprendo i requisiti multi-tenant, le variabili d'ambiente del worker e la risoluzione dei problemi del vault.

# Configurazione di Vault per il Self-Hosting

Switchbord memorizza i segreti per singolo workspace in [Supabase Vault](https://supabase.com/docs/guides/database/vault) — un'estensione Postgres che cifra i segreti a livello di database. Questa pagina copre ciò che chi effettua il self-hosting deve sapere per far funzionare correttamente il vault, specialmente quando si gestiscono più workspace.

***

## Panoramica: Due Modalità di Risoluzione dei Segreti

Switchbord supporta due approcci per fornire segreti a runtime come il token di accesso Meta:

**Modalità Vault (predefinita, consigliata)**
I segreti sono memorizzati per singolo workspace in `vault.secrets`, collegati a ciascun workspace tramite `app_private.workspace_secret_bindings`. Il worker li legge a runtime usando funzioni RPC di Supabase. Questo è l'approccio corretto per qualsiasi deployment con più di un workspace.

**Fallback su variabile d'ambiente (solo workspace singolo)**
Se `SELF_HOSTED=true` è impostato e una lettura del vault fallisce, il worker ricorre a `WHATSAPP_META_ACCESS_TOKEN` dall'ambiente. Questa è una comodità per gli operatori che gestiscono un singolo workspace e vogliono saltare del tutto la configurazione del vault.

<Warning>
  `SELF_HOSTED=true` bypassa le ricerche nel vault e fornisce una credenziale condivisa a tutti i workspace. Se il tuo deployment ha più di un workspace, questo causerà l'invio dei messaggi del workspace A usando il token del workspace B. Non usare il fallback su variabile d'ambiente in deployment multi-workspace.
</Warning>

***

## Perché i Deployment Multi-Tenant Devono Usare Vault

Quando il worker elabora un messaggio in uscita, risolve il token di accesso Meta cercando il workspace che possiede la conversazione. In modalità vault, chiama `sb_read_workspace_secret(workspace_id, 'meta-access-token')` — una ricerca delimitata che restituisce solo il segreto appartenente a quel workspace.

Con `SELF_HOSTED=true`, la ricerca viene saltata del tutto e il valore della variabile d'ambiente viene restituito indipendentemente da quale workspace stia effettuando la richiesta. Non c'è alcun isolamento per singolo workspace. Un secondo workspace aggiunto successivamente utilizzerà silenziosamente il token del primo workspace, il che fallirà oppure — peggio — avrà successo con l'account sbagliato.

<Info>
  Se hai inizialmente effettuato il deployment con `SELF_HOSTED=true` per un singolo workspace e ora stai aggiungendo un secondo workspace, devi rimuovere quel flag, configurare i segreti del vault per entrambi i workspace e riavviare il worker prima che il secondo workspace funzioni correttamente.
</Info>

***

## Come i Segreti Fluiscono Attraverso il Sistema

<Steps>
  <Step title="L'operatore salva una credenziale in Settings">
    L'operatore apre Settings → Provider e inserisce un token di accesso Meta (o una API key per un provider AI). L'app web Switchbord lo invia a `/api/settings/secrets`.
  </Step>

  <Step title="L'API memorizza il segreto in Supabase Vault">
    La route API chiama `storeWorkspaceSecret(workspaceId, secretKind, value)`, che chiama `vault.create_secret()` e inserisce una riga in `app_private.workspace_secret_bindings` che mappa l'ID workspace e il tipo di segreto all'ID del segreto nel vault.
  </Step>

  <Step title="Il worker legge il segreto al momento dell'invio">
    Quando il worker è sul punto di inviare un messaggio, chiama la funzione RPC di Supabase `sb_read_workspace_secret` con l'ID workspace e il tipo di segreto. La funzione viene eseguita con privilegi `SECURITY DEFINER`, legge da `vault.secrets` e restituisce il valore decifrato. Non è richiesta alcuna connessione diretta al database dal worker.
  </Step>
</Steps>

Il worker non memorizza mai in cache i segreti tra le richieste. Ogni operazione di invio innesca una nuova lettura del vault, quindi la rotazione di un segreto in Settings ha effetto immediato.

***

## Requisiti di Configurazione Supabase

### Estensione Vault

Supabase Vault è abilitata per impostazione predefinita su tutti i progetti Supabase Cloud. Se stai eseguendo un'istanza Supabase self-hosted, conferma che l'estensione sia abilitata:

```sql theme={null}
-- Run in your Supabase SQL editor
SELECT * FROM pg_extension WHERE extname = 'supabase_vault';
```

Se la query non restituisce righe, abilitala:

```sql theme={null}
CREATE EXTENSION IF NOT EXISTS supabase_vault SCHEMA vault;
```

<Info>
  Le migrazioni di Switchbord creano automaticamente anche lo schema `app_private` e la tabella `workspace_secret_bindings` quando esegui `supabase db push` o applichi le migrazioni. Non è necessario crearle manualmente.
</Info>

### Funzioni RPC

Il worker usa due funzioni wrapper RPC pubbliche che devono essere presenti nel tuo database:

* `sb_read_workspace_secret(p_workspace_id uuid, p_kind text)` — restituisce il valore decifrato del segreto per un workspace e un tipo di segreto
* `sb_resolve_workspace_by_verify_token(p_verify_token text)` — restituisce l'ID workspace corrispondente a un dato verify token Meta

Queste funzioni sono create dalle migrazioni di Switchbord. Se incontri errori `function does not exist`, ri-esegui le tue migrazioni sul database target:

```bash theme={null}
supabase db push --db-url "$SUPABASE_DB_URL"
```

***

## Memorizzazione dei Segreti

Ci sono due modi per popolare i segreti del vault per un workspace:

**Interfaccia Settings (consigliata)**
Apri Settings → Provider nell'app web Switchbord e inserisci le credenziali direttamente. L'interfaccia chiama automaticamente l'API di scrittura del vault. Non è richiesto alcun accesso diretto al database.

**Editor SQL della Dashboard Supabase**
Per la configurazione iniziale o il caricamento massivo, puoi inserire i segreti direttamente:

```sql theme={null}
-- Insert a secret and get back its vault ID
SELECT vault.create_secret(
  'your-token-value-here',
  'meta-access-token for workspace abc123',
  null
) AS vault_secret_id;

-- Then bind it to a workspace
INSERT INTO app_private.workspace_secret_bindings
  (workspace_id, secret_kind, vault_secret_id)
VALUES
  ('your-workspace-uuid', 'meta-access-token', 'the-vault-secret-id-from-above');
```

<Warning>
  Non inserire segreti in chiaro in nessuna tabella di schema pubblico. Usa sempre `vault.create_secret()` così il valore viene cifrato prima della memorizzazione.
</Warning>

***

## Variabili d'Ambiente del Worker

Il worker necessita solo di una chiave service role di Supabase per leggere dal vault. Non è richiesta alcuna connessione diretta al database per le letture.

**Obbligatorie:**

| Variabile                              | Descrizione                                                                  |
| -------------------------------------- | ---------------------------------------------------------------------------- |
| `NEXT_PUBLIC_SUPABASE_URL`             | L'URL del tuo progetto Supabase, es. `https://xxxx.supabase.co`              |
| `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` | Chiave anon di Supabase                                                      |
| `SUPABASE_SECRET_KEY`                  | Chiave service role di Supabase — usata per le letture del vault tramite RPC |
| `WHATSAPP_PLATFORM_DATA_MODE`          | Impostare su `supabase`                                                      |
| `WORKER_POLL_INTERVAL_MS`              | Intervallo di polling in millisecondi, es. `5000`                            |

**Opzionali:**

| Variabile                    | Descrizione                                                                                                                                                         |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SUPABASE_DB_URL`            | Stringa di connessione Postgres diretta. Necessaria solo se stai usando scritture del vault direttamente dal worker (non tipico — l'app web gestisce le scritture). |
| `SELF_HOSTED=true`           | Abilita il fallback su variabile d'ambiente per deployment a workspace singolo. Non impostare questa variabile se hai più di un workspace.                          |
| `WHATSAPP_META_ACCESS_TOKEN` | Richiesta solo quando `SELF_HOSTED=true` è impostato. Il token di accesso Meta di fallback.                                                                         |

<Tip>
  Se effettui il deployment su Railway, imposta queste come variabili di servizio nel pannello dell'ambiente del tuo servizio worker. Il worker le recepirà al prossimo deploy senza alcuna modifica al codice.
</Tip>

***

## Riferimento dei Tipi di Segreto

| Tipo di Segreto          | Scopo                                                                         |
| ------------------------ | ----------------------------------------------------------------------------- |
| `meta-access-token`      | Token di accesso Meta (WhatsApp Business API) per l'invio dei messaggi        |
| `webhook-signing-secret` | Segreto di firma del payload dei webhook Meta per la verifica delle richieste |
| `meta-verify-token`      | Token di verifica del webhook Meta                                            |
| `openai-api-key`         | API key OpenAI per la generazione di bozze AI                                 |
| `anthropic-api-key`      | API key Anthropic per la generazione AI basata su Claude                      |
| `openrouter-api-key`     | API key OpenRouter per il routing AI multi-modello                            |

***

## Risoluzione dei Problemi

### `vault_unavailable`

L'estensione vault non è abilitata oppure lo schema `app_private` è assente.

* Conferma che l'estensione vault esista (vedi il controllo SQL sopra)
* Ri-esegui le migrazioni di Switchbord: `supabase db push`
* Conferma che `SUPABASE_SECRET_KEY` del worker sia una chiave service role valida, non la chiave anon

### `vault_read_error`

La funzione RPC esiste ma ha restituito un errore durante il tentativo di leggere un segreto.

* Controlla che `sb_read_workspace_secret` sia stata creata con successo dalle tue migrazioni
* Conferma che `SUPABASE_SECRET_KEY` abbia i permessi service role (la chiave anon non può chiamare funzioni `SECURITY DEFINER` che verificano `service_role`)
* Nell'editor SQL di Supabase, verifica che la funzione esista: `\df sb_read_workspace_secret`

### `vault_secret_missing`

La funzione è stata eseguita con successo ma non ha trovato alcun binding per il workspace e il tipo di segreto richiesti. Il segreto non è mai stato memorizzato.

* Apri Settings → Provider per il workspace interessato e salva la credenziale mancante
* Oppure inserisci il binding manualmente usando l'SQL sopra
* Verifica che l'ID workspace in `app_private.workspace_secret_bindings` corrisponda al workspace che effettua la richiesta

### Il worker invia messaggi con l'account sbagliato

Questo è un sintomo di `SELF_HOSTED=true` impostato in un deployment multi-workspace. Viene usata la credenziale di fallback della variabile d'ambiente invece dei segreti del vault per singolo workspace. Rimuovi `SELF_HOSTED=true` dall'ambiente del worker e assicurati che tutti i workspace abbiano i propri segreti configurati nel vault.

***

## Guide Correlate

* [Vault Architecture](/it/security/vault-architecture) — dettagli interni, design dello schema e specifiche di cifratura
* [Secrets and Encryption](/it/security/secrets-and-encryption) — policy di sicurezza e controlli di accesso
* [Meta Credential Setup](/it/operations/meta-credential-setup) — come ottenere le credenziali che memorizzerai nel vault
* [Webhooks](/it/operations/webhooks) — configurazione del token di verifica del webhook Meta
