Passa al contenuto principale

Chi può vedere cosa

Una dashboard che chiunque abbia l'URL può leggere è uno screenshot con passaggi in più. La ragione per mantenere le dashboard in una piattaforma gestita invece che in una cartella di HTML esportato è che la piattaforma ricorda chi è autorizzato ad aprirle — e continua a ricordarlo anche dopo che la persona che le ha costruite se n'è andata.

Questa pagina è la mappa onesta di quel modello: cosa applica oggi, dove si ferma, e quali parti puoi raggiungere da codice.

I tre ruoli​

Ogni appartenenza a un account porta esattamente un ruolo:

RuoloValoreCosa significa
AdminadminBypassa ogni controllo dei diritti di accesso. Gestisce membri, gruppi e grant.
CreatorcreatorPuò creare e modificare. Soggetto ai diritti di accesso.
ViewerviewerSola lettura. Rifiutato su qualsiasi route che modifica.

Ci sono tre cose da sapere su questo prima di progettarci attorno.

Il ruolo vive nella riga di appartenenza, non nel token. Il JWT non porta alcuna claim di ruolo, quindi ogni decisione sul ruolo è una lettura dal database sulla coppia account/utente. È un po' più lento e molto più difficile da falsificare.

Fallisce in chiuso. Un'appartenenza il cui ruolo salvato non è riconosciuto — un valore legacy, un errore di battitura — si risolve in viewer, non in admin.

Admin è un override, non un rango superiore. Un admin non è "un creator con più grant": il controllo dei permessi va direttamente ad allow prima che venga consultato qualsiasi grant. Non puoi negare l'accesso a un admin da una cartella.

Una chiave API agisce come la persona che l'ha creata

Una chiave API si risolve nell'utente che l'ha creata, con il ruolo di quell'utente. Una chiave generata da un admin è una chiave admin, e tutto ciò che segue si applica ad essa esattamente come si applica a quella persona nel browser. Non esiste un ambito di permessi separato e più ristretto per le chiavi, e una chiave non scade quando il ruolo di chi l'ha creata viene declassato — revoca la chiave.

Ventiquattro route sono deliberatamente chiuse alle chiavi e richiedono una vera sessione browser: fatturazione e pagamenti (16 di esse), la gestione delle chiavi API stessa, la lettura del tuo abbonamento, l'eliminazione dell'account, il cambio password, la telemetria e la firma dei token di embed. Tutto il resto accetta una chiave — incluse tutte le route di diritti di accesso, gruppi, cartelle, dashboard e dataset.

Un'eccezione deliberata. Rendere una dashboard public è vincolato da un interruttore a livello di account, apiKeysMayPublish, che ha valore predefinito false e può essere attivato solo da un admin in un browser. Quindi una chiave — e di conseguenza un agente che la possiede — può costruire, pubblicare e condividere dentro il tuo account, ma per impostazione predefinita non può essere ciò che rende qualcosa leggibile da chiunque al mondo. Vedi Pubblica e condividi.

Gruppi​

Un gruppo è un insieme nominato di utenti dentro un account. Concedi al gruppo; l'appartenenza cambia senza toccare il grant.

Due limiti, entrambi deliberati:

  • I gruppi contengono utenti, non altri gruppi. Non c'è annidamento, quindi non c'è una gerarchia di gruppi di cui tenere conto.
  • Le letture sono aperte a ogni membro dell'account; le scritture sono solo per gli admin. Qualsiasi membro può elencare i gruppi e vedere chi ne fa parte. Solo un admin può creare, rinominare, eliminare o modificare l'appartenenza.

I gruppi sono presenti nell'SDK:

from vibedasher.models import GroupCreate, GroupUpdate

created = client.groups.create(GroupCreate(name="analytics", description="Read-only analysts"))
client.groups.update(created.group.id, GroupUpdate(user_ids_to_add=["<user-id>"]))

for g in client.groups.list().groups:
print(g.name, g.user_count)
const created = await client.groups.create({ name: 'analytics', description: 'Read-only analysts' });
await client.groups.update(created.group.id, { userIdsToAdd: ['<user-id>'] });

const { groups } = await client.groups.list();

Diritti di accesso — il grant è sulla cartella​

Questa è la frase più importante di questa pagina, e quella che più probabilmente ti sorprenderà:

Un grant nomina una cartella, mai una singola dashboard o un singolo dataset.

Un diritto di accesso è una riga della forma:

(account, folder, resource type, permission, principal) → allow | deny
  • tipo di risorsa — dataset o viz. Sono i due che un grant può nominare; vedi Cosa può nominare un grant per cosa governa tutto il resto.
  • permesso — view, edit, delete, create.
  • principal — un utente o un gruppo.
  • allow / deny — i due tipi di accesso.

Una dashboard è coperta da un grant perché si trova nella cartella a cui è stato concesso. Spostala in un'altra cartella e sarà invece governata dai grant di quella cartella. Non c'è alcun grant per singola dashboard di cui perdere traccia, il che è la metà positiva di questo design; l'altra metà è che la cartella è la più piccola unità che puoi concedere, quindi una cartella che condividi è una cartella che condividi interamente.

Questo non è un tetto a quanto stretta può essere una condivisione​

La frase sopra riguarda la concessione, non la condivisione. Una cartella è la cosa più piccola che puoi nominare in una concessione — e sei tu a decidere cosa c'è in una cartella. Per condividere esattamente una dashboard, dalle una cartella tutta sua: sono tre chiamate che il tuo agente ha già:

create_folder(name="Q3 board pack")
move_to_folder(resource_type="viz", resource_id=<vizId>, folder_id=<newFolderId>)
grant_access(folder_id=<newFolderId>, resource_type="viz",
principal_id=<userId>, principal_type="user", permissions=["view"])

resource_type è dataset o viz nello spostamento, principal_type è user o group, e access_type vale allow per default — deny è l'altro valore, e batte ogni allow.

Queste tre sono strumenti MCP, e l'MCP è la via supportata per farlo. Le rotte di access-rights sono deliberatamente fuori dall'SDK pubblicato e dal riferimento API — sono impiantistica di controllo accessi di cui non abbiamo fissato la forma, quindi non esiste un metodo di client generato per esse e non va usato nessuno. create_folder è quella delle tre con un gemello SDK, client.folders.create.

Spostare una dashboard cambia quali concessioni la governano e nient'altro — la dashboard mantiene il suo id, e il suo link non è toccato. Quindi «condividere per singola dashboard è impossibile» è la conclusione sbagliata da trarre dalla regola della cartella: sono tre chiamate, e la cartella è il modo di esprimerla.

Le due metà di una concessione su dashboard​

Una dashboard e i dati sottostanti sono governati da tipi di risorsa distinti, quindi una condivisione che ne nomina solo uno è fatta a metà. viz:view permette a qualcuno di aprire la dashboard; dataset:view è ciò che permette alle sue tile di restituire numeri. La sezione seguente spiega perché questo non è un dettaglio rinviabile.

Come viene effettivamente presa una decisione​

In ordine. La prima regola che corrisponde vince:

  1. Admin → allow. Incondizionatamente, prima che venga letto qualsiasi grant.
  2. Il principal interno system → allow. Questa è l'identità worker della piattaforma stessa (job di aggiornamento, esecuzioni pianificate); non è un account in cui puoi accedere.
  3. Proprietà → allow. L'utente proprietario della riga può sempre leggerla e modificarla.
  4. Altrimenti, decidono i grant della cartella, e un singolo deny batte ogni allow.

Vale la pena precisare deny-wins, perché è più ristretto di quanto sembri. Un deny rimuove una cartella dall'insieme che ti era stato concesso — non sottrae dalle regole 1–3. Non puoi negare l'accesso a un admin, e non puoi negare a qualcuno una riga di cui è proprietario. Se il tuo modello mentale è "deny è l'arresto di emergenza", non lo è: è una sottrazione solo all'interno dello strato dei grant.

Due comportamenti che ti morderanno​

I grant non si propagano nelle sottocartelle. Il controllo è un test piatto di appartenenza a un insieme sul folder_id proprio della risorsa. Le cartelle hanno effettivamente una relazione genitore/figlio, e l'interfaccia la disegna come un albero — ma nessun codice di autorizzazione la percorre. Un grant su Marketing non raggiunge Marketing / Q3. Concedi ogni cartella che intendi concedere.

Un deny su create prima non faceva nulla — corretto il 2026-09-08. Il controllo del permesso di creazione leggeva solo le righe allow; il diritto di bootstrap di un Creator a creare nella radice dell'account o in una cartella di cui è proprietario, e una riga allow esplicita altrove, bypassavano entrambi completamente qualsiasi deny. Una riga create / deny esplicita di un admin ora sovrasta entrambi — la stessa regola "un singolo deny batte ogni allow" che il resto di questa pagina descrive per view/edit/delete. Gli admin restano non negabili, coerentemente con ogni altro permesso qui.

Chi può modificare un grant​

Un admin dell'account, o il proprietario della cartella su cui si trova il grant. La lettura dei grant è aperta a qualsiasi membro dell'account: lo stato di condivisione viene visualizzato nell'app su pagine che qualsiasi membro può aprire, quindi la lettura è deliberatamente non vincolata. Considera l'elenco dei grant stesso come informazione visibile a tutto l'account.

Cosa può nominare un grant​

Due tipi di risorsa sono assegnabili: viz (dashboard) e dataset. Costruisci il tuo modello di governance con questi due, tenuti in cartelle: è la forma che il modello applica ed è la sola che la finestra di dialogo offre. POST /v1/access-rights rifiuta qualunque altro tipo di risorsa con un 400, nel momento in cui lo scrivi anziché nel momento in cui qualcuno ci conta.

Tre cose sono governate da qualcosa che non è un grant, e sapere quale da cosa è tutto il senso di questa sezione:

RisorsaCosa la governa
CartellaL'appartenenza all'account per le letture; il ruolo per le mutazioni. Una cartella è il contenitore che un grant nomina, non una cosa contro cui un grant si scrive.
Pianificazione di aggiornamentoLa proprietà, più il confine dell'account.
DomandaSolo il proprietario. Una domanda non può essere condivisa con nessun meccanismo.
AttivitàL'ACL della dashboard a cui appartiene.
ConnessioneIl suo proprietario e gli amministratori dell'account. Qualunque Creator può crearne una.

Un elenco vuoto ti dice di quale genere di vuoto si tratta. GET /v1/access-rights/{folder}/{type} porta un flag enforced, quindi total: 0 per un tipo non assegnabile significa nessun diritto di questo tipo può esistere in alcun luogo, mentre total: 0 per viz significa nessuno ne possiede uno. Le righe scritte prima del rifiuto restano elencate, e restano rimovibili, con enforced: false accanto.

Condividere una dashboard senza condividerne i dati non funziona​

È la domanda a cui il modello non risponde come la maggior parte si aspetta, quindi merita una frase netta: viz:view da solo non dà a nessuno una dashboard funzionante.

I riquadri di una dashboard prendono i loro numeri con POST /v1/query, e quella rotta autorizza ogni dataset coinvolto tramite l'ACL dei dataset, in modalità nega-anziché-scartare: un solo dataset che il lettore non può leggere respinge l'intera query con 403 query_dataset_forbidden. Non viene mai eseguita sul sottoinsieme che è invece consentito. Quindi «fai vedere allo stagista questa dashboard ma non i dati dietro» produce una dashboard i cui riquadri falliscono, non una dashboard con i numeri nascosti.

Concedi anche dataset:view sulla cartella che contiene i dataset — viz:view e dataset:view vanno in coppia, e una concessione che porta solo la prima produce una dashboard in cui ogni tile restituisce 403. Se i dataset non devono essere condivisi in blocco, dagli una cartella loro come fa la ricetta sopra. Oppure, se l'obiettivo è davvero mostrare un risultato senza consegnare i dati sottostanti, pubblica la dashboard o incorporala. Entrambe queste corsie girano sotto l'identità di servizio della piattaforma e non consultano mai questa ACL: è esattamente per questo che possono mostrare un numero a qualcuno che non può interrogarlo.

Verificare il proprio lavoro​

Ogni campo qui sopra descrive una regola; nessuno ti dice con cosa finisce una persona specifica, e questo non si legge dall'elenco delle concessioni. I diritti si compongono — appartenenze ai gruppi, un deny che batte ogni allow compreso uno ereditato da un gruppo, la separazione per tipo di risorsa e il controllo di ruolo separato sulle mutazioni — in un esito che nessun singolo elenco mostra. Il deny ereditato è il caso che conta: non compare mai nell'elenco degli allow che leggi, quindi «perché questa persona non lo vede» non ha risposta dal solo elenco.

GET /v1/access-rights/{folder}/effective?userId= lo risolve. Per ogni coppia (tipo di risorsa, permesso) restituisce cosa decide l'ACL, quale regola ha deciso, se il ruolo della persona lo consente, se il tipo è applicato, il prodotto di tutto ciò — e la riga di diritto d'accesso che ha prodotto il verdetto, cioè l'id da revocare quando la risposta è un deny. Il tuo agente ha la stessa cosa come describe_effective_access.

Risponde solo alla domanda sull'ACL, e lo dichiara in un elenco caveats presente in ogni risposta: non può vedere le righe che la persona possiede (la proprietà è per riga e batte l'ACL della cartella), non sa nulla delle corsie della dashboard pubblica e dell'embed e — come sopra — una dashboard funzionante ha bisogno anche di diritti sui suoi dataset. Puoi sempre chiedere di te stesso; chiedere di qualcun altro richiede la stessa posizione che serve per cambiare l'ACL: un admin dell'account o il proprietario della cartella.

Raggiungere tutto questo da codice​

SuperficieNegli SDK?
Gruppi (creazione, elenco, modifica, appartenenza)Sì — client.groups.*
Utenti (elenco, modifica, ruolo, appartenenza al gruppo)Sì — client.users.*
AccountSì — client.accounts.*
Diritti di accesso (i grant stessi)No

I diritti di accesso sono esclusi dalla superficie SDK generata, quindi non esiste client.accessRights né una voce per essi nel Riferimento API. Le route esistono e accettano una chiave API — semplicemente non fanno parte del contratto client pubblicato e versionato, e preferiamo dirtelo piuttosto che lasciarti costruire su una forma a cui non ci siamo impegnati. Gestisci i grant nell'app, oppure dal tuo agente: il server MCP espone strumenti per grant, revoke e list-access-rights che chiamano le stesse route sotto la tua identità, ed ereditano la stessa regola admin-o-proprietario-della-cartella.

Filtraggio per riga: la corsia dell'embed, e solo quella​

La sicurezza per riga è reale in Vibedasher, ma vive in un solo posto: le dashboard incorporate dietro un token firmato.

Quando il tuo server genera un token di embed, può allegare filtri al payload del token. Su ogni query la piattaforma riscrive ogni riferimento a un dataset in una subquery filtrata, quindi il visualizzatore non può fisicamente leggere righe al di fuori della propria porzione. I filtri provengono esclusivamente dal token verificato — mai dal corpo della richiesta — quindi un visualizzatore non può ampliare il proprio ambito modificando una richiesta. Un filtro che nomina una colonna che non esiste in nessuno schema di dataset viene rifiutato con un 403 invece di essere ignorato silenziosamente, perché un filtro che silenziosamente non fa nulla è una falla.

Tre limiti da tenere in conto:

  • Si applica solo alla corsia dell'embed. La corsia di query dell'SDK non ha alcuna iniezione obbligatoria di filtri: una chiave API è un chiamante lato server fidato, e limitare i propri utenti è compito tuo, non della piattaforma.
  • L'ACL della cartella non è per riga. Decide quali dashboard e dataset esistono per te, non quali righe al loro interno puoi leggere. Sono domande diverse e Vibedasher le risolve con meccanismi diversi.
  • Una dashboard che interroga nel browser non può essere ristretta affatto, ed è una scelta di progettazione. È la decisione da prendere prima di costruire, non dopo. Una dashboard auto-ospitata sulla corsia senza credenziali — l'albero espulso il cui dataLane è wasm, o qualunque cosa tu abbia costruito da solo sopra un estratto Parquet o JSON — scarica i dati ed esegue ogni query nel browser del visitatore. L'estratto è indirizzato per dataset e istantanea, non per query, quindi contiene tutte le righe di quel dataset, e ogni visitatore riceve lo stesso file. Non resta alcun server lungo il percorso per restringerlo: un filtro scritto nella pagina cambia ciò che viene disegnato, mai ciò che è stato consegnato.
L'ambito per riga e la corsia senza credenziali si escludono a vicenda

Tutto il fascino di quella corsia sta nel fatto che non c'è alcuna chiave nel bundle, nessun token da generare e nessun backend tuo da far girare — e il prezzo è esattamente la stessa proprietà vista dall'altro lato: nulla può dare a un visualizzatore meno righe che a un altro. Non è una lacuna che verrà colmata; è ciò che significa mettere i dati nel browser.

Se alcuni visualizzatori devono vedere meno righe, tieni la query su un server. Due configurazioni lo fanno, ed entrambe tengono la credenziale fuori dalla pagina: il tuo backend genera un token di embed di breve durata che porta il filtro (la piattaforma aggiunge quel predicato a ogni query che autorizza, prima di qualsiasi join o aggregazione, così la pagina non può allargarlo), oppure codice server fidato interroga con una chiave API e restituisce righe che hai già ristretto. Scegliere prima la corsia veloce e poi "restringerla" con un filtro nella pagina produce una dashboard che sembra giusta, non solleva alcun errore, e consegna tutte le righe.

Vedi Incorporare per come un token viene generato e presentato.

Autenticazione a due fattori​

Email + password è l'unico ingresso in Vibedasher che poggia su un solo segreto. Gli accessi con Google e LinkedIn portano il secondo fattore del loro provider; le chiavi API e il token CLI di vibedasher login non sono affatto accessi. Il secondo fattore è quindi opt-in, per utente, solo sull'accesso con password: un codice TOTP a sei cifre da qualsiasi app di autenticazione (Google Authenticator, 1Password, Authy…), attivato da Impostazioni → Autenticazione a due fattori scansionando un codice QR e confermando un codice. L'attivazione consegna otto codici di recupero monouso, mostrati una sola volta: un telefono perso accede con uno di questi.

Cosa cambia all'accesso: dopo una password corretta il browser non riceve una sessione, riceve una sfida di cinque minuti a scopo unico che solo il passaggio del codice può riscattare. L'API non vede mai quella sfida come una credenziale: porta un'audience che l'API rifiuta in partenza, quindi non può essere riprodotta contro api.*.vibedasher.com né infilata nel cookie di sessione. Cinque codici errati bloccano la sfida per quindici minuti; un codice vale una sola volta.

Tre limiti da conoscere:

  • L'attivazione è personale. Ogni membro la attiva per il proprio account; non è qualcosa che un amministratore accende per tutti.
  • Gli accessi OAuth non ricevono mai la sfida, per scelta: aggiungere il nostro fattore sopra quello del provider è attrito senza sicurezza.
  • Lo sblocco è un'azione da amministratore. Un membro senza telefono e senza codice di recupero si rivolge a un amministratore dell'account, che reimposta il suo secondo fattore dalla pagina del membro (l'azione viene registrata). Un proprietario che è l'unico amministratore, senza codice di recupero, passa dal supporto.

Una configurazione pratica​

Per un team di dieci persone con un paio di dataset sensibili:

  1. Rendi admin una o due persone che amministrano l'account. Ricorda che sono ingovernabili dai grant — è il punto del ruolo, ed è la ragione per mantenere l'elenco breve.
  2. Chiunque costruisca è un creator; chiunque legga soltanto è un viewer. Il ruolo viewer è un rifiuto netto su ogni modifica, quindi è un confine reale, non una convenzione dell'interfaccia.
  3. Metti dashboard e dataset in cartelle che rispecchino come vuoi condividerli — una cartella per pubblico, non per argomento. La cartella è il grant.
  4. Concedi ai gruppi, non alle persone. Il grant sopravvive così a chi entra o esce.
  5. Non creare cartelle annidate aspettandoti che il grant del genitore le raggiunga. Concedi ognuna.
  6. Se una dashboard deve arrivare a persone al di fuori dell'account, pubblicala e incorporala con un token firmato che porti i loro filtri per riga — non dare loro un account.