SnappSnapp
  • Per iniziare
  • Installazione
  • Configurazione
  • Styling
  • Introduzione
  • URL Personalizzati
  • Autenticazione
  • Architettura Multi-Dominio
  • Gestione dei Team
  • Integrazioni di Terze Parti
  • Metriche e Analytics
  • Riferimento API
  • English
  • Italiano
  • Per iniziare
  • Installazione
  • Configurazione
  • Styling
  • Introduzione
  • URL Personalizzati
  • Autenticazione
  • Architettura Multi-Dominio
  • Gestione dei Team
  • Integrazioni di Terze Parti
  • Metriche e Analytics
  • Riferimento API
  • English
  • Italiano
  • Feature

    • Introduzione
    • URL Personalizzati
    • Autenticazione
    • Architettura Multi-Dominio
    • Gestione dei Team
    • Integrazioni di Terze Parti
    • Metriche e Analytics
    • Riferimento API

Panoramica

I team sono l’unità che Snapp utilizza per delimitare l’accesso all’interno di un’organizzazione.

Un team viene creato sotto un’organizzazione e poi referenziato da:

  • membership (chi fa parte del team)
  • policy (cosa ogni ruolo può fare nel contesto di quel team)
  • binding alle risorse (quali URL sono condivisi con il team)

Snapp utilizza le organizzazioni di Better-Auth insieme a statement di access control per applicare tutto questo.


Concetti

Organizzazione

Un’organizzazione è il confine per identità e permessi. In Snapp, le organizzazioni vengono create e selezionate per dominio host.

I team esistono solo all’interno di un’organizzazione.


Team

Un team è un contenitore che può essere usato come contesto di permessi.

Nel modello di policy, la chiave di contesto è l’id del team:

permissions: {
  [teamId]: ['create', 'read', 'update', 'delete']
}

Questo consente regole per-team senza hardcodare i nomi dei team nel codice.


Ruoli

Snapp utilizza ruoli a livello di organizzazione:

  • owner
  • admin
  • member

Il ruolo definisce le capacità di default a livello organizzativo ed è anche l’asse su cui si basano le policy dei team.


Modello dei permessi

Statement

Snapp definisce un set ridotto di azioni:

  • create
  • read
  • update
  • delete
  • cancel

Una policy è rappresentata come:

type TPermissions = Record<string, ('create' | 'read' | 'update' | 'delete' | 'cancel')[]>

La struttura persistita è una mappa ruolo → teamId → azioni:

Record<Role, Record<TeamId, Action[]>>

Questa struttura è memorizzata nel database nel campo organizationRole.permission.


Dove vivono le policy

Le policy sono memorizzate per organizzazione nella tabella organizationRole:

  • organizationId (l’organizzazione)
  • role (owner | admin | member)
  • permission (blob JSON)

A runtime, Snapp carica le policy dell’organizzazione corrente e costruisce il grafo effettivo dei ruoli.


Creazione dei team

Flusso UI

I team vengono creati dal pannello dell’organizzazione.

Il form di creazione raccoglie:

  • nome del team
  • permessi iniziali per ruolo (editor a matrice)

Il payload inviato include:

  • organizationId
  • name
  • permissions (stringa JSON)

Flusso server

La creazione di un team esegue tre operazioni:

  1. Controllo di autorizzazione Il chiamante deve avere il permesso di creare team:

    permissions: { team: ['create'] }
    
  2. Creazione del team in Better-Auth.

  3. Materializzazione della policy Per ogni ruolo presente in organizationRole, Snapp aggiorna il JSON dei permessi aggiungendo:

    permission[team.id] = permissions[roleName]
    

Dopo la creazione, le cache vengono invalidate:

  • cache del client di autenticazione (per host)
  • cache dei ruoli (per organizzazione)

Questo garantisce che ogni richiesta successiva veda il grafo di policy aggiornato.


Modifica delle policy di un team

Editor delle policy

La UI mostra una matrice di permessi:

  • righe = ruoli (owner, admin, member)
  • colonne = azioni (create, read, update, delete)
  • target = uno specifico team id

Il toggle di una checkbox aggiorna la mappa locale dei permessi e avvia il salvataggio.

Il ruolo owner è bloccato su accesso completo nella UI.


Operazione di salvataggio

Al salvataggio, Snapp invia un aggiornamento batch:

[{ id: roleRowId, p: permissionsForThatRole }]

Lato server, questo aggiorna organizationRole.permission per ogni riga di ruolo.

Dopo l’update:

  • la cache dei ruoli viene invalidata
  • la cache del client di autenticazione viene invalidata

Il successivo controllo dei permessi utilizza quindi il nuovo grafo di policy.


Come funziona l’enforcement

I controlli dei permessi sono lato server

Snapp non si fida della UI. La UI gestisce solo la comodità; l’enforcement avviene sul server tramite hasPermission.


I controlli usano una chiave di contesto

Quando una risorsa è condivisa con un team, l’id del team diventa il contesto dei permessi.

Esempi dalle operazioni sugli URL:

  • Creare un URL con team associati richiede il permesso create su almeno uno dei team selezionati.
  • Aggiornare o eliminare un URL di proprietà altrui richiede il permesso corrispondente per i team a cui l’URL è assegnato.

Questo è applicato valutando:

hasPermission({
  organizationId,
  context: teamId,
  permissions: ['create' | 'update' | 'delete']
})

Enforcement in creazione URL

Quando un URL viene creato con team:

  • Snapp verifica il chiamante rispetto a ogni team selezionato
  • azione richiesta: create
  • l’operazione è consentita se almeno uno dei controlli ha esito positivo

Se nessuno ha esito positivo, la richiesta viene rifiutata.


Enforcement in aggiornamento URL

Durante l’aggiornamento di un URL:

  • se il chiamante è owner o admin → consentito

  • altrimenti, Snapp calcola l’unione di:

    • team già assegnati all’URL
    • team richiesti nell’aggiornamento

Poi verifica:

  • azione richiesta: update
  • consentito se almeno un controllo sui team ha esito positivo

Questo supporta modifiche incrementali senza permettere di aggirare le policy rimuovendo i team.


Enforcement in eliminazione URL

Durante l’eliminazione degli URL:

  • owner e admin possono eliminare (secondo la logica del ruolo)
  • i non-owner possono eliminare solo se tutti i controlli sui team passano per delete

Questo produce una regola più restrittiva per le operazioni distruttive.


Assegnazione dei team alle risorse

Snapp collega i team agli URL tramite una tabella di join (teamToUrl).

Questo serve a due scopi:

  • condivisione: i membri del team possono operare sugli URL condivisi se la policy lo consente
  • contesto di enforcement: l’id del team diventa la chiave di policy per l’autorizzazione

La tabella di join viene aggiornata durante create/update dell’URL nella stessa transazione DB della mutazione dell’URL.


Comportamento delle cache

Sono coinvolte due cache:

  • cache dell’istanza di autenticazione (authCache.auth) indicizzata per origin host
  • cache dei ruoli (authCache.roles) indicizzata per id organizzazione (slugify(host.origin))

Ogni operazione che modifica team o policy invalida le chiavi di cache rilevanti, mantenendo coerenti i controlli dei permessi.


Riepilogo

  • I team sono contesti di permessi all’interno di un’organizzazione.
  • Le policy sono memorizzate come ruolo → teamId → azioni in organizationRole.permission.
  • La UI modifica le policy, ma l’enforcement avviene lato server tramite hasPermission.
  • Le operazioni sugli URL usano l’assegnazione ai team per determinare quali policy applicare.
  • L’invalidazione delle cache mantiene coerente il grafo effettivo dei permessi tra le richieste.
Prev
Architettura Multi-Dominio
Next
Integrazioni di Terze Parti