MICHELEPISANI.IT
 

Progettare Flussi Conversazionali Sicuri con Apps Script

Da AppSheet agli Agenti AI

September 02
07:392026

L'evoluzione dello sviluppo su Google Workspace si sta muovendo rapidamente dalle tradizionali interfacce "punta e clicca" verso paradigmi conversazionali intelligenti. Chi sviluppa su AppSheet dispone già di modelli dati robusti, regole di validazione e logiche di business strutturate. Tuttavia, esporre queste risorse a modelli linguistici (LLM) come quelli di Gemini Enterprise richiede di superare due ostacoli critici: la sicurezza contestuale dell'utente e la resa visiva dei dati (UI).

Protocolli emergenti come A2A (Agent-to-Agent) e A2UI (Agent-to-User-Interface) mostrano come trasformare un'applicazione aziendale in un agente interattivo. Sulla stessa direzione si muove anche l'Antigravity SDK di Google, il framework generico per costruire agenti autonomi con Gemini: non è integrato in modo specifico con AppSheet o Apps Script, ma è un segnale utile di dove sta andando l'intero ecosistema Google sul fronte agentico. Vediamo come questi principi si traducono nell'ecosistema Google Workspace e come Google Apps Script può fungere da ponte sicuro.

1. Sicurezza e Identità: Oltre i Service Account

Uno degli errori più comuni nell'integrazione tra LLM e database aziendali è l'uso di un singolo account di servizio (Service Account) condiviso. Questo approccio distrugge la Row-Level Security (RLS) configurata su AppSheet.

Per mantenere l'integrità del sistema, l'agente deve sfruttare la delega dell'identità:

  • RunAsUserEmail: ogni chiamata all'API di AppSheet deve inoltrare l'indirizzo email dell'utente attualmente autenticato nella sessione di chat. Senza questo parametro, l'azione viene eseguita di default con l'identità del proprietario dell'app, non dell'utente corrente: è proprio questo comportamento predefinito a rendere il parametro indispensabile.
  • Autorizzazione OAuth granulare: l'agente non legge dati a cui l'utente non ha accesso nativo.

Nota tecnica importante: il valore da passare a RunAsUserEmail va recuperato in modo affidabile, e qui serve attenzione. Session.getActiveUser().getEmail() non restituisce sempre l'email dell'utente corrente in ogni contesto di esecuzione: torna una stringa vuota, ad esempio, quando lo script gira tramite un trigger installabile non legato a un'azione utente diretta, o quando una Web App è distribuita con impostazione "Esegui come: me" invece di "Esegui come: utente che accede". Funziona in modo affidabile soprattutto per script vincolati o Web App distribuite con "Esegui come: utente che accede", su domini Workspace dove la condivisione dell'identità è abilitata. Prima di usare questo pattern in produzione, verifica il tipo di deployment della tua Web App: un'email vuota o mancante in questo flusso significa che la RLS di AppSheet non verrà applicata come previsto.

2. Dai dump testuali alle interfacce A2UI

Un agente enterprise non può limitarsi a restituire blocchi di testo o Markdown grezzo. Il concetto di A2UI definisce la capacità dell'agente di interpretare la definizione delle tabelle (OpenAPI/AppSheet schema) per generare dinamicamente componenti visivi:

  • Riorganizzazione automatica dei campi prioritari.
  • Form interattivi con date-picker, menu a tendina e checklist nativi.
  • Azioni contestuali (pulsanti di approvazione/modifica) direttamente nel thread di conversazione.

Implementazione: Gateway Apps Script per AppSheet API

Google Apps Script rappresenta lo strumento ideale per orchestrare queste interazioni, agendo da middleware tra le chiamate di un agente (o un Webhook) e l'API REST di AppSheet, garantendo la delega dell'identità dell'utente corrente.

Ecco un esempio completo per interrogare AppSheet preservando l'identità dell'utente:

/**
 * Esegue una query sull'API di AppSheet delegando l'identità dell'utente attivo.
 *
 * IMPORTANTE: Session.getActiveUser().getEmail() restituisce un valore
 * affidabile solo in specifici contesti di esecuzione (script vincolati,
 * o Web App distribuite con "Esegui come: utente che accede" su un
 * dominio Workspace con condivisione dell'identità abilitata).
 * Verifica il tipo di deployment prima di usare questo pattern in produzione.
 *
 * @param {string} tableName - Nome della tabella su AppSheet.
 * @param {string} selector - Espressione di filtro (es. "AND([Status] = 'Pending')").
 * @returns {Array<Object>} Dati restituiti dall'applicazione.
 */
function queryAppSheetAsUser(tableName, selector) {
  const APP_ID = PropertiesService.getScriptProperties().getProperty('APPSHEET_APP_ID');
  const APP_KEY = PropertiesService.getScriptProperties().getProperty('APPSHEET_APP_KEY');

  // Recupera l'email dell'utente che invoca lo script (contesto di esecuzione)
  const currentUserEmail = Session.getActiveUser().getEmail();

  if (!currentUserEmail) {
    throw new Error(
      "Impossibile determinare l'identità dell'utente corrente. " +
      "Verifica il tipo di deployment (vedi nota nel commento della funzione)."
    );
  }

  const url = `https://api.appsheet.com/api/v2/apps/${APP_ID}/tables/${encodeURIComponent(tableName)}/Action`;

  const payload = {
    "Action": "Find",
    "Properties": {
      "Locale": "it-IT",
      "Timezone": "W. Europe Standard Time",
      // Parametro chiave: esegue l'operazione con i permessi specifici dell'utente
      "RunAsUserEmail": currentUserEmail
    },
    "Rows": [],
    "Selector": selector || ""
  };

  const options = {
    "method": "post",
    "contentType": "application/json",
    "headers": {
      "ApplicationAccessKey": APP_KEY
    },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": false
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const jsonResponse = JSON.parse(response.getContentText());

    Logger.log(`Recuperati con successo ${jsonResponse.length} record per ${currentUserEmail}`);
    return jsonResponse;
  } catch (error) {
    Logger.log(`Errore durante la chiamata ad AppSheet API: ${error.message}`);
    throw error;
  }
}

/**
 * Funzione di test per verificare la connessione sicura.
 */
function testAppSheetIntegration() {
  const tableName = "Ordini";
  const filter = "[Importo] > 100";

  const risultati = queryAppSheetAsUser(tableName, filter);
  Logger.log(risultati);
}

Conclusioni

Il passaggio dalle app no-code agli agenti AI autonomi non richiede di riscrivere l'architettura aziendale da zero. Sfruttando gli schemi dati esistenti di AppSheet, l'identità contestuale tramite OAuth e protocolli di rendering avanzati come A2UI, gli sviluppatori possono creare interfacce conversazionali avanzate e conformi alle policy aziendali. Apps Script si conferma il collante fondamentale per orchestrare questo flusso in Google Workspace, a patto di verificare sempre, caso per caso, in quale contesto di deployment gira lo script prima di fidarsi dell'identità restituita dalla piattaforma.

Tags
Non ci sono tag per questo elemento

Autore

Michele Pisani

Michele Pisani

Ho uno spiccato orientamento al problem-solving, se è troppo facile non mi diverto :)
Credo nella volontà e nel cambiamento perchè hanno fatto della mia passione il mio pane quotidiano.
Se devo descrivermi con una sola parola direi... "Concretezza", la mia stretta di mano è una garanzia.

0 Commenti

Non ci sono commenti

Nessuno ha ancora commentato questo articolo, fallo tu per primo!

Scrivi un Commento

Scrivi un Commento

Il tuo indirizzo email non sarà pubblicato.
I campi contrassegnati da un * sono obbligatori

Articoli e Argomenti correlati

Il Canale YouTube in ITALIANO

1 VIDEO GRATIS ogni 2 settimane! ISCRIVITI!

Entra a far parte della community su Facebook

Categorie popolari

Iscriviti alla mia newsletter

La tua e-mail con me sarà al sicuro.
Non fornirò mai le tue informazioni a nessuno!

Ultimi commenti

Michele Pisani

Direi la forma "Allow: /". La riga Disallow: (senza alcuna path) indica che non ci sono …

maurizio

Grazie per la spiegazione chiare e le utili informazioni. Mi rimane da capire se è meglio …

olgica

NON MI FUNZIONA,SALUTI.CIAO