Documentazione

Multi-tenancy rigorosa

Come betool isola i tuoi dati, segreti ed esecuzioni dalle altre organizzazioni.

Multi-tenancy rigorosa

L'isolamento tra organizzazioni è l'invariante fondante di betool. Ecco come viene garantito, strato per strato.

A livello di database

Ogni tabella di business contiene una colonna org_id (UUID), indicizzata e vincolata da una foreign key a organisation(id).

Tutte le query lato server passano attraverso metodi store che filtrano sistematicamente in base all'org_id della sessione corrente. Nessun percorso di codice espone una query arbitraria; nessun client può forzare un org_id diverso.

Per il ristretto numero di risorse che possono essere condivise tra organizzazioni (tipicamente gli account LLM condivisi a livello di piattaforma), una colonna is_shared BOOLEAN NOT NULL DEFAULT FALSE abilita un opt-in esplicito. Regole:

  • Qualsiasi lettura è autorizzata con WHERE org_id = %s OR is_shared = TRUE.
  • Qualsiasi mutazione di una riga is_shared = TRUE richiede il ruolo hyperadmin (operatore di piattaforma).
  • Qualsiasi mutazione invalida la cache globalmente — nessuna divergenza per singola org.

A livello di filesystem

Ogni org ha la propria radice di storage:

<data_root>/
└── orgs/
    └── <org_id>/
        ├── fixtures/
        ├── uploads/
        ├── knowledge/
        └── exchanges/

Gli helper del server (org_*_dir(org_id)) risolvono questi percorsi. Nessun codice di business può scrivere al di fuori della radice di un'organizzazione.

A livello di cache

Tutte le cache applicative (risoluzione del provider LLM, contesti correnti, file analizzati) sono per singola org. Quando una risorsa is_shared = TRUE viene mutata, la cache è invalidata globalmente — non esiste una finestra durante la quale un'org potrebbe vedere un valore obsoleto.

A livello di segreti

Le credenziali (chiavi LLM, token di autenticazione degli operatori, segreti dei webhook) sono archiviate nel vault di ciascuna org. Non vengono mai restituite in chiaro dall'API: le route GET restituiscono soltanto has_api_key: bool.

Nel piano Enterprise, il vault può essere collegato a HashiCorp Vault, AWS Secrets Manager o Azure Key Vault.

A livello di esecuzione

Quando una pipeline viene eseguita:

  • Gli operatori hanno accesso soltanto agli account esterni dichiarati all'interno della loro org.
  • I modelli LLM sono risolti nell'ordine own > shared (fallback automatico) — sempre.
  • I file allegati sono leggibili soltanto sotto la radice dell'org corrente.

Se un operatore tenta di accedere a una risorsa al di fuori del proprio ambito, l'errore è esplicito (OrgScopeViolation) — non un timeout silenzioso.

Checklist pratica

Ogni volta che viene aggiunta una nuova risorsa condivisibile, il team risponde a queste 4 domande:

  1. Se compare una seconda org di backoffice, il mio codice si comporta correttamente?
  2. Se muto una riga condivisa, tutte le cache per singola org vengono invalidate?
  3. I miei segreti restano rigorosamente lato server?
  4. La mia GET consente ai picker di altre org di elencare la risorsa senza esporre il segreto?

Se una qualsiasi risposta è no, la risorsa non viene rilasciata.