Cloud Run पर Node.js में, Google Workspace Studio के लिए कस्टम चरण बनाना

1. परिचय

Google Workspace Studio की मदद से, Gmail, Google Chat, Google Drive, और Google Sheets जैसे Google Workspace ऐप्लिकेशन में कारोबार से जुड़ी प्रोसेस को ऑटोमेट किया जा सकता है. जब आपके वर्कफ़्लो को किसी बाहरी वेब ऐप्लिकेशन से शुरू करने या अपने क्लाउड एनवायरमेंट में कस्टम लॉजिक चलाने की ज़रूरत हो, तब Cloud Run पर Node.js में, एचटीटीपी Google Workspace ऐड-ऑन की मदद से Google Workspace Studio को बढ़ाया जा सकता है:

  1. कस्टम स्टार्टर चरण (workflowTrigger): यह Google Workspace Studio triggers.fire REST API को कॉल करके, बाहरी इवेंट होने पर Google Workspace Studio फ़्लो शुरू करता है. जैसे, ग्राहक के किसी इंटरनल वेब पोर्टल में टिकट सबमिट करने पर.
  2. कस्टम ऐक्शन स्टेप (workflowAction): यह फ़्लो में पहले के चरणों से वैरिएबल लेता है, आपकी Node.js सेवा में कस्टम लॉजिक या एआई इन्फ़रेंस चलाता है, और आउटपुट वैरिएबल को Google Workspace Studio पर वापस भेजता है.

इस कोडलैब में, Google Workspace Studio के लिए एक पूरा Node.js एचटीटीपी एक्सटेंशन बनाया और उसे Cloud Run पर डिप्लॉय किया जाता है. साथ ही, Cloud Firestore का इस्तेमाल करके, कंटेनर के अलग-अलग वर्शन में चालू फ़्लो ट्रिगर करने वाली सदस्यताओं और सबमिट किए गए टिकट को सेव किया जाता है. इसके अलावा, Gemini Enterprise Agent Platform पर Gemini 3.8 Flash (gemini-3.8-flash) का इस्तेमाल करके, कस्टम ऐक्शन स्टेप में टिकट की प्राथमिकता तय की जाती है. इसमें कीवर्ड मैचिंग फ़ॉलबैक की सुविधा भी मिलती है.

आपको क्या बनाना है

  • Cloud Run पर Node.js, Express, और Firestore की मदद से बनाया गया Support Quick Portal वेब ऐप्लिकेशन और HTTP Google Workspace ऐड-ऑन.
  • नया सहायता टिकट कस्टम स्टार्टर चरण (supportTicketTrigger), जो studio_triggers Firestore कलेक्शन में चालू फ़्लो की सदस्यताएं बनाए रखता है, सबमिट किए गए टिकटों को support_tickets Firestore कलेक्शन में लॉग करता है, और वेब पोर्टल में टिकट सबमिट किए जाने पर ट्रिगर होता है. यह ticketTitle और ticketDescription को Google Workspace Studio फ़्लो में पास करता है.
  • Gemini Enterprise के एजेंट प्लैटफ़ॉर्म (aiplatform.googleapis.com) पर, Gemini 3.8 Flash (gemini-3.8-flash) का इस्तेमाल करके टिकट की प्राथमिकता का पता लगाने वाला प्राथमिकता का पता लगाएं कस्टम ऐक्शन स्टेप (urgencyDetectorStep). इसमें कीवर्ड मैचिंग (urgent, blocker, critical) पर अपने-आप फ़ॉलबैक होने की सुविधा भी है.

आपको क्या सीखने को मिलेगा

  • workflowTrigger और workflowAction एलिमेंट के साथ, एचटीटीपी Google Workspace ऐड-ऑन डिप्लॉयमेंट मेनिफ़ेस्ट (deployment.json) को कॉन्फ़िगर करने का तरीका.
  • studio_triggers Firestore कलेक्शन में, Google Workspace Studio ट्रिगर की सदस्यताओं (triggerId, notifyUri, और userOAuthToken) को कैसे बनाए रखें और triggers.fire REST API का इस्तेमाल करके फ़्लो कैसे ट्रिगर करें.
  • कीवर्ड फ़ॉलबैक के साथ, Gemini Enterprise Agent Platform पर Gemini 3.8 Flash (gemini-3.8-flash) के स्ट्रक्चर्ड आउटपुट का इस्तेमाल करके, Node.js में workflowAction कस्टम स्टेप बनाने का तरीका.

ज़रूरी शर्तें

  • Google Workspace खाता, जिसमें Google Workspace Studio का ऐक्सेस हो.
  • बिलिंग की सुविधा वाला Google Cloud प्रोजेक्ट. इसे आपके उपयोगकर्ता खाते के साथ-साथ, उसी Google Workspace संगठन में बनाया गया हो. इससे आपको टेस्टिंग के लिए, पब्लिश नहीं किए गए ऐड-ऑन डिप्लॉयमेंट इंस्टॉल करने में मदद मिलेगी.

2. Google Cloud प्रोजेक्ट और Firestore सेट अप करना

इस चरण में, आपको अपने प्रोजेक्ट के लिए OAuth के लिए सहमति देने की स्क्रीन को कॉन्फ़िगर करना होगा. साथ ही, Cloud Shell में ज़रूरी Google Cloud और Google Workspace API चालू करने होंगे. इसके अलावा, आपको (default) Firestore डेटाबेस को उपलब्ध कराना होगा और ऐड-ऑन के लिए अनुमति देने वाले सेवा खाते को शुरू करना होगा.

  1. Google Cloud Console खोलें. इसके बाद, अपना Google Cloud प्रोजेक्ट चुनें और सबसे ऊपर मौजूद नेविगेशन बार में, Cloud Shell चालू करें आइकॉन पर क्लिक करें.
  2. OAuth के लिए सहमति की स्क्रीन को कॉन्फ़िगर करें, ताकि Google Workspace आपके ऐड-ऑन के लिए OAuth क्लाइंट उपलब्ध करा सके:
    1. Google Auth Platform Branding पेज खोलें.
    2. अगर कहा जाए, तो शुरू करें पर क्लिक करें. (अगर आपकी सहमति स्क्रीन पहले से कॉन्फ़िगर है, तो तीसरे चरण पर जाएं.)
    3. ऐप्लिकेशन की जानकारी में जाकर, ऐप्लिकेशन के नाम के लिए Support Extension डालें. इसके बाद, उपयोगकर्ता सहायता के लिए ईमेल पता चुनें और आगे बढ़ें पर क्लिक करें.
    4. दर्शक में जाकर, इंटरनल को चुनें. इसके बाद, आगे बढ़ें पर क्लिक करें.
    5. संपर्क जानकारी में जाकर, अपना ईमेल पता डालें और आगे बढ़ें पर क्लिक करें.
    6. पूरा करें में जाकर, Google API सेवाओं के उपयोगकर्ता के डेटा से जुड़ी नीति से सहमत हों. इसके बाद, जारी रखें पर क्लिक करें और फिर बनाएं पर क्लिक करें.
  3. Cloud Shell में, अपना ऐक्टिव प्रोजेक्ट सेट करें. इसके लिए, YOUR_PROJECT_ID को अपने Google Cloud प्रोजेक्ट आईडी से बदलें. इसके बाद, ज़रूरी एपीआई चालू करें:
    gcloud config set project YOUR_PROJECT_ID
    gcloud services enable \
      aiplatform.googleapis.com \
      firestore.googleapis.com \
      run.googleapis.com \
      cloudbuild.googleapis.com \
      artifactregistry.googleapis.com \
      appsmarket-component.googleapis.com \
      gsuiteaddons.googleapis.com \
      workspacestudio.googleapis.com
    
  4. us-central1 में अपना (default) Firestore डेटाबेस उपलब्ध कराएं. अगर यह पहले से मौजूद नहीं है, तो Google Workspace ऐड-ऑन सेवा खाते को शुरू करें:
    gcloud firestore databases describe --database="(default)" >/dev/null 2>&1 || \
      gcloud firestore databases create \
        --database="(default)" \
        --location=us-central1 \
        --type=firestore-native \
        --quiet
    gcloud workspace-add-ons get-authorization
    

3. Firestore और Gemini 3.8 Flash की मदद से Node.js ऐप्लिकेशन बनाना

इस चरण में, ~/studio-support-addon में Node.js ऐप्लिकेशन बनाया जाता है. कोड को मॉड्यूलर और पढ़ने में आसान बनाने के लिए, प्रोजेक्ट को पांच फ़ोकस की गई फ़ाइलों में व्यवस्थित किया जाता है:

  • firestore.js: यह Cloud Firestore क्लाइंट (studio_triggers और support_tickets कलेक्शन) को शुरू करता है. साथ ही, कैश किए गए OAuth टोकन को रीफ़्रेश करता है.
  • starter.js: यह नया सहायता टिकट कस्टम स्टार्टर स्टेप वेबहुक (/onConfigTrigger और /onManageTrigger) लागू करता है.
  • action.js: यह Gemini 3.8 Flash (gemini-3.8-flash) का इस्तेमाल करके, Detect Urgency कस्टम ऐक्शन स्टेप वेबहुक (/onConfigUrgency और /onExecuteUrgency) लागू करता है. इसमें कीवर्ड मैचिंग फ़ॉलबैक का इस्तेमाल किया जाता है.
  • portal.js: यह Support Quick Portal के वेब यूज़र इंटरफ़ेस (GET /) को दिखाता है और Google Workspace Studio के चालू ट्रिगर (POST /api/submit-ticket) को ट्रिगर करता है.
  • index.js: यह सभी Express रास्तों को एक साथ जोड़ता है और एचटीटीपी सर्वर शुरू करता है.

प्रोजेक्ट शुरू करें और package.json

  1. प्रोजेक्ट डायरेक्ट्री बनाएं और उसमें जाएं:
    mkdir -p ~/studio-support-addon && cd ~/studio-support-addon
    
  2. express, @google-cloud/firestore, और @google/genai की मदद से package.json बनाएँ:
    cat << 'EOF' > package.json
    {
      "name": "studio-support-addon",
      "version": "1.0.0",
      "type": "module",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "dependencies": {
        "@google-cloud/firestore": "^7.11.0",
        "@google/genai": "^1.0.0",
        "express": "^4.21.2"
      }
    }
    EOF
    

firestore.js — शेयर की गई Firestore स्थिति और OAuth टोकन रीफ़्रेश

अपनी दो Firestore कलेक्शन को मैनेज करने और उपयोगकर्ता के OAuth टोकन को कैश मेमोरी में सेव करके रखने के लिए, firestore.js बनाएं:

  • studio_triggers: यह कुकी, Google Workspace Studio की चालू फ़्लो सदस्यताएं (triggerId, notifyUri, और userOAuthToken) सेव करती है, ताकि Cloud Run कंटेनर के रीस्टार्ट होने और स्केल-टू-ज़ीरो इवेंट के बाद भी ये सदस्यताएं बनी रहें.
  • support_tickets: यह कुकी, पोर्टल के ज़रिए सबमिट किए गए हर सहायता टिकट का रिकॉर्ड सेव करती है.
  • refreshTokenInFirestore(req): जब भी Google Workspace Studio आपके किसी वेबहुक एंडपॉइंट को कॉल करता है, तो इसमें कुछ समय के लिए मान्य रहने वाला authorizationEventObject.userOAuthToken शामिल होता है. यह हेल्पर, चालू ट्रिगर दस्तावेज़ों को नए टोकन के साथ अपडेट करता है, ताकि बैकग्राउंड में triggers.fire कॉल को अनुमति मिलती रहे.
cat << 'EOF' > firestore.js
import { Firestore } from '@google-cloud/firestore';

export const db = new Firestore({
  projectId: process.env.GOOGLE_CLOUD_PROJECT || undefined,
  databaseId: '(default)',
  ignoreUndefinedProperties: true,
});

export const triggersCollection = db.collection(
  process.env.FIRESTORE_TRIGGERS_COLLECTION || 'studio_triggers'
);

export const ticketsCollection = db.collection(
  process.env.FIRESTORE_TICKETS_COLLECTION || 'support_tickets'
);

// Keep cached userOAuthToken fresh across active trigger documents
export async function refreshTokenInFirestore(req) {
  const freshToken = req.body?.authorizationEventObject?.userOAuthToken;
  if (!freshToken) return;
  try {
    const snapshot = await triggersCollection.get();
    if (snapshot.empty) return;
    const batch = db.batch();
    snapshot.docs.forEach((doc) => {
      batch.set(
        doc.ref,
        { userOAuthToken: freshToken, updatedAt: new Date().toISOString() },
        { merge: true }
      );
    });
    await batch.commit();
  } catch (err) {
    console.error('Error refreshing OAuth token in Firestore:', err.message);
  }
}
EOF

starter.js — कस्टम स्टार्टर स्टेप (workflowTrigger)

Google Workspace Studio के कस्टम स्टार्टर स्टेप के लिए ज़रूरी दो वेबहुक एंडपॉइंट लागू करने के लिए, starter.js बनाएं:

  • onConfigTrigger (POST /onConfigTrigger): इस इवेंट को तब कॉल किया जाता है, जब कोई उपयोगकर्ता Google Workspace Studio में नया सहायता टिकट को अपने फ़्लो के स्टार्टर के तौर पर चुनता है. यह फ़ंक्शन, स्टार्टर के बारे में बताने वाला pushCard नेविगेशन ऐक्शन दिखाता है.
  • onManageTrigger (POST /onManageTrigger): इस फ़ंक्शन को तब कॉल किया जाता है, जब कोई उपयोगकर्ता किसी फ़्लो को चालू (req.body.workflow.triggerCreation) करता है या उसे बंद करता है / मिटाता है (req.body.workflow.triggerDeletion). यह studio_triggers Firestore कलेक्शन में सदस्यता वाले दस्तावेज़ को सेव करता है या मिटाता है.
cat << 'EOF' > starter.js
import { triggersCollection, refreshTokenInFirestore } from './firestore.js';

// Custom Starter Configuration Card
export async function onConfigTrigger(req, res) {
  await refreshTokenInFirestore(req);
  res.status(200).json({
    action: {
      navigations: [
        {
          pushCard: {
            sections: [
              {
                header: 'Support Ticket Listener',
                widgets: [
                  {
                    textParagraph: {
                      text: 'This starter listens for new tickets submitted through the Support Quick Portal and stores subscriptions in Firestore.',
                    },
                  },
                ],
              },
            ],
          },
        },
      ],
    },
  });
}

// Custom Starter Subscription Lifecycle (Firestore studio_triggers collection)
export async function onManageTrigger(req, res) {
  try {
    const triggerCreation = req.body?.workflow?.triggerCreation;
    const triggerDeletion = req.body?.workflow?.triggerDeletion;
    const userOAuthToken =
      req.body?.authorizationEventObject?.userOAuthToken || null;

    if (triggerCreation?.triggerId) {
      const triggerId = String(triggerCreation.triggerId);
      const docId = encodeURIComponent(triggerId);
      await triggersCollection.doc(docId).set(
        {
          triggerId,
          notifyUri: triggerCreation.notifyUri || null,
          ...(userOAuthToken ? { userOAuthToken } : {}),
          updatedAt: new Date().toISOString(),
        },
        { merge: true }
      );
    }

    if (triggerDeletion?.triggerId) {
      const triggerId = String(triggerDeletion.triggerId);
      const docId = encodeURIComponent(triggerId);
      await triggersCollection.doc(docId).delete();
    }

    if (!triggerCreation && !triggerDeletion && userOAuthToken) {
      await refreshTokenInFirestore(req);
    }
  } catch (err) {
    console.error('Error in /onManageTrigger:', err.message);
  }
  res.status(200).json({});
}
EOF

action.js — Gemini 3.8 Flash की मदद से कस्टम ऐक्शन स्टेप (workflowAction)

Google Workspace Studio की कस्टम ऐक्शन सुविधा के लिए ज़रूरी दो वेबहुक एंडपॉइंट लागू करने के लिए, action.js बनाएं:

  • onConfigUrgency (POST /onConfigUrgency): यह textInput विजेट वाला कॉन्फ़िगरेशन कार्ड दिखाता है. यह hostAppDataSource.workflowDataSource.includeVariables: true सेट करता है, ताकि उपयोगकर्ता स्टार्टर चरण से मिले ticketDescription वैरिएबल को चुन सकें.
  • onExecuteUrgency (POST /onExecuteUrgency): यह req.body.workflow.actionInvocation.inputs से मिले ticketDescription इनपुट को पढ़ता है. इसके बाद, Gemini 3.8 Flash (gemini-3.8-flash) का इस्तेमाल करके, Gemini Enterprise Agent Platform पर, कारोबार पर पड़ने वाले असर और ज़रूरी होने के हिसाब से इनपुट को कैटगरी में बांटता है. साथ ही, स्ट्रक्चर्ड आउटपुट (responseSchema enum ["High", "Normal"]) देता है. अगर मॉडल कॉल फ़ेल हो जाता है, तो यह detectKeywordUrgency() (urgent, blocker, critical) पर वापस आ जाता है. इसके बाद, hostAppAction.workflowAction.returnOutputVariablesAction का इस्तेमाल करके, urgencyLevel आउटपुट वैरिएबल दिखाता है.
cat << 'EOF' > action.js
import { GoogleGenAI, Type } from '@google/genai';
import { refreshTokenInFirestore } from './firestore.js';

// Initialize Google GenAI SDK for the Gemini Enterprise Agent Platform
const ai = new GoogleGenAI({
  vertexai: true,
  project: process.env.GOOGLE_CLOUD_PROJECT,
  location: 'global',
});

// Fallback keyword classifier if the Gemini API call is unavailable
export function detectKeywordUrgency(description) {
  const lower = (description || '').toLowerCase();
  return lower.includes('urgent') ||
    lower.includes('blocker') ||
    lower.includes('critical')
    ? 'High'
    : 'Normal';
}

// Custom Action Step Configuration Card
export async function onConfigUrgency(req, res) {
  await refreshTokenInFirestore(req);
  res.status(200).json({
    action: {
      navigations: [
        {
          pushCard: {
            sections: [
              {
                header: 'Urgency Detector Step',
                widgets: [
                  {
                    textInput: {
                      name: 'ticketDescription',
                      label: 'Source Description',
                      hintText:
                        'Select the description variable outputted by the starter',
                      hostAppDataSource: {
                        workflowDataSource: {
                          includeVariables: true,
                        },
                      },
                    },
                  },
                ],
              },
            ],
          },
        },
      ],
    },
  });
}

// Custom Action Step Execution: Gemini 3.8 Flash with keyword fallback
export async function onExecuteUrgency(req, res) {
  await refreshTokenInFirestore(req);
  const inputs = req.body?.workflow?.actionInvocation?.inputs || {};
  const description = inputs.ticketDescription?.stringValues?.[0] || '';

  let urgencyLevel = detectKeywordUrgency(description);
  try {
    const response = await ai.models.generateContent({
      model: 'gemini-3.8-flash',
      contents: `Evaluate the business impact and time sensitivity of this support ticket description and classify its urgency:\n\n${description}`,
      config: {
        responseMimeType: 'text/x.enum',
        responseSchema: {
          type: Type.STRING,
          enum: ['High', 'Normal'],
        },
      },
    });
    const candidate = (response.text || '').trim();
    if (candidate === 'High' || candidate === 'Normal') {
      urgencyLevel = candidate;
    }
  } catch (err) {
    console.error('Gemini fallback to keyword matching:', err.message);
  }

  res.status(200).json({
    hostAppAction: {
      workflowAction: {
        returnOutputVariablesAction: {
          variables: {
            urgencyLevel: {
              stringValues: [urgencyLevel],
            },
          },
        },
      },
    },
  });
}
EOF

portal.js — Quick Portal के यूज़र इंटरफ़ेस (यूआई) और triggers.fire डिस्पैचर के साथ काम करता है

वेब पोर्टल पर सेवा देने और Google Workspace Studio को टिकट सबमिट करने के लिए, portal.js बनाएं:

  • renderPortal (GET /): यह studio_triggers Firestore कलेक्शन से क्वेरी करता है, ताकि यह दिखाया जा सके कि Google Workspace Studio के कितने ट्रिगर रजिस्टर किए गए हैं. साथ ही, यह एचटीएमएल टिकट सबमिट करने का फ़ॉर्म दिखाता है.
  • submitTicket (POST /api/submit-ticket): यह studio_triggers में मौजूद सभी चालू ट्रिगर दस्तावेज़ों को दोहराता है. साथ ही, ticketTitle और ticketDescription आउटपुट वैरिएबल और यूनीक requestId के साथ Google Workspace Studio triggers.fire एंडपॉइंट (https://workspacestudio.googleapis.com/v1/triggers/{triggerId}:fire) को शुरू करता है. इसके बाद, टिकट को support_tickets Firestore कलेक्शन में सेव करता है.
cat << 'EOF' > portal.js
import { triggersCollection, ticketsCollection } from './firestore.js';

// Support Quick Portal UI
export async function renderPortal(req, res) {
  let activeCount = 0;
  try {
    const snapshot = await triggersCollection.get();
    activeCount = snapshot.size;
  } catch (err) {
    console.error('Error reading studio_triggers collection:', err.message);
  }

  res.status(200).send(`<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Support Quick Portal</title>
    <style>
      body { font-family: Arial, sans-serif; padding: 24px; max-width: 540px; margin: auto; color: #202124; }
      .badge { background: #e8f0fe; color: #1967d2; padding: 8px 12px; border-radius: 6px; font-size: 14px; margin-bottom: 16px; }
      label { font-weight: bold; display: block; margin-top: 16px; }
      input, textarea { width: 100%; margin-top: 6px; padding: 10px; box-sizing: border-box; border: 1px solid #dadce0; border-radius: 4px; }
      button { background-color: #1a73e8; color: white; border: none; padding: 10px 18px; margin-top: 16px; font-weight: bold; cursor: pointer; border-radius: 4px; }
      button:hover { background-color: #1557b0; }
      #status { margin-top: 16px; font-weight: bold; }
    </style>
  </head>
  <body>
    <h2>Support Quick Portal</h2>
    <div class="badge">
      Active Google Workspace Studio triggers in Firestore (<code>studio_triggers</code>):
      <strong id="trigger-count">${activeCount}</strong>
    </div>
    <p>Submit a support ticket below to fire your Google Workspace Studio flow.</p>

    <label for="title">Ticket Title</label>
    <input type="text" id="title" placeholder="e.g. Database failure">

    <label for="description">Issue Description</label>
    <textarea id="description" rows="4" placeholder="Describe the issue..."></textarea>

    <button onclick="submitTicket()">Submit Ticket</button>
    <div id="status"></div>

    <script>
      async function submitTicket() {
        const title = document.getElementById('title').value.trim();
        const description = document.getElementById('description').value.trim();
        const statusEl = document.getElementById('status');

        if (!title || !description) {
          statusEl.style.color = '#d93025';
          statusEl.textContent = 'Please fill out both fields.';
          return;
        }

        statusEl.style.color = '#188038';
        statusEl.textContent = 'Submitting ticket...';

        try {
          const res = await fetch('/api/submit-ticket', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ title, description }),
          });
          const data = await res.json();
          if (data.ok) {
            statusEl.textContent =
              'Ticket saved to Firestore! Fired ' + data.triggersFired + ' Google Workspace Studio trigger(s).';
          } else {
            statusEl.style.color = '#d93025';
            statusEl.textContent = 'Error: ' + (data.error || 'Unknown error');
          }
        } catch (err) {
          statusEl.style.color = '#d93025';
          statusEl.textContent = 'Request failed: ' + err.message;
        }
      }
    </script>
  </body>
</html>`);
}

// Portal Form Submission -> Fire Active Google Workspace Studio Triggers
export async function submitTicket(req, res) {
  const title = req.body?.title || 'Untitled Ticket';
  const description = req.body?.description || '';
  const results = [];

  try {
    const snapshot = await triggersCollection.get();
    for (const doc of snapshot.docs) {
      const trigger = doc.data();
      if (!trigger.triggerId || !trigger.userOAuthToken) continue;

      const response = await fetch(
        `https://workspacestudio.googleapis.com/v1/triggers/${encodeURIComponent(trigger.triggerId)}:fire`,
        {
          method: 'POST',
          headers: {
            Authorization: `Bearer ${trigger.userOAuthToken}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            name: 'triggers/' + trigger.triggerId,
            outputs: {
              ticketTitle: { stringValues: [title] },
              ticketDescription: { stringValues: [description] },
            },
            requestId:
              'req_' + Date.now() + '_' + Math.floor(Math.random() * 1000),
          }),
        }
      );
      results.push({ triggerId: trigger.triggerId, status: response.status });
    }

    await ticketsCollection.add({
      title,
      description,
      triggersFired: results.length,
      createdAt: new Date().toISOString(),
    });

    res.status(200).json({ ok: true, triggersFired: results.length, results });
  } catch (err) {
    console.error('Error in /api/submit-ticket:', err.message);
    res.status(500).json({ ok: false, error: err.message });
  }
}
EOF

index.js — Express सर्वर का एंट्री पॉइंट

अपने पोर्टल के रास्तों और Google Workspace Studio के वेबहुक एंडपॉइंट को एक साथ जोड़ने के लिए index.js बनाएं. इसके लिए, Express HTTP सर्वर को PORT पर लिसन करें (Cloud Run पर डिफ़ॉल्ट 8080):

cat << 'EOF' > index.js
import express from 'express';
import { onConfigTrigger, onManageTrigger } from './starter.js';
import { onConfigUrgency, onExecuteUrgency } from './action.js';
import { renderPortal, submitTicket } from './portal.js';

const app = express();
app.use(express.json());

// Support Quick Portal routes
app.get('/', renderPortal);
app.post('/api/submit-ticket', submitTicket);

// Google Workspace Studio Custom Starter Step webhooks
app.post('/onConfigTrigger', onConfigTrigger);
app.post('/onManageTrigger', onManageTrigger);

// Google Workspace Studio Custom Action Step webhooks
app.post('/onConfigUrgency', onConfigUrgency);
app.post('/onExecuteUrgency', onExecuteUrgency);

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Support Extension listening on port ${PORT}`);
});
EOF

4. Cloud Run पर डिप्लॉय करना और ऐड-ऑन इंस्टॉल करना

इस चरण में, Node.js सेवा को Cloud Run पर डिप्लॉय किया जाता है. साथ ही, Google Workspace ऐड-ऑन को शुरू करने वाले व्यक्ति और Firestore को IAM अनुमतियां दी जाती हैं. इसके अलावा, एजेंट प्लैटफ़ॉर्म के रनटाइम ऐक्सेस की अनुमति दी जाती है, deployment.json मेनिफ़ेस्ट जनरेट किया जाता है, और ऐड-ऑन डिप्लॉयमेंट इंस्टॉल किया जाता है.

  1. अपने प्रोजेक्ट और Firestore कलेक्शन के एनवायरमेंट वैरिएबल के साथ, support-extension सेवा को Cloud Run पर डिप्लॉय करें:
    gcloud run deploy support-extension \
      --source . \
      --region us-central1 \
      --allow-unauthenticated \
      --set-env-vars="GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project),FIRESTORE_TRIGGERS_COLLECTION=studio_triggers,FIRESTORE_TICKETS_COLLECTION=support_tickets" \
      --quiet
    
  2. Google Workspace Studio को आपके वेबुक एंडपॉइंट कॉल करने की अनुमति देने के लिए, Google Workspace ऐड-ऑन के सेवा खाते को Cloud Run सेवा पर roles/run.invoker दें:
    ADDON_SA=$(gcloud workspace-add-ons get-authorization --format="value(serviceAccountEmail)")
    gcloud run services add-iam-policy-binding support-extension \
      --region=us-central1 \
      --member="serviceAccount:${ADDON_SA}" \
      --role="roles/run.invoker" \
      --quiet
    
  3. Cloud Run रनटाइम सेवा खाते को ये अनुमतियां दें: roles/datastore.user (studio_triggers और support_tickets Firestore कलेक्शन को पढ़ने और लिखने के लिए) और roles/aiplatform.user (Gemini Enterprise Agent Platform पर Gemini को कॉल करने के लिए):
    PROJECT_ID=$(gcloud config get-value project)
    PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")
    RUNTIME_SA=$(gcloud run services describe support-extension --region=us-central1 --format="value(spec.template.spec.serviceAccountName)")
    RUNTIME_SA=${RUNTIME_SA:-"${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"}
    
    gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
      --member="serviceAccount:${RUNTIME_SA}" \
      --role="roles/datastore.user" \
      --condition=None \
      --quiet
    
    gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
      --member="serviceAccount:${RUNTIME_SA}" \
      --role="roles/aiplatform.user" \
      --condition=None \
      --quiet
    
  4. डिप्लॉय किए गए Cloud Run यूआरएल को वापस पाएं और deployment.json मेनिफ़ेस्ट जनरेट करें. इसमें supportTicketTrigger (workflowTrigger) और urgencyDetectorStep (workflowAction) एलिमेंट तय किए गए हों:
    SERVICE_URL=$(gcloud run services describe support-extension --region=us-central1 --format="value(status.url)")
    
    cat << EOF > deployment.json
    {
      "oauthScopes": [
        "https://www.googleapis.com/auth/workspace.studio.trigger",
        "https://www.googleapis.com/auth/userinfo.email"
      ],
      "addOns": {
        "common": {
          "name": "Support Extension",
          "logoUrl": "https://www.gstatic.com/images/branding/productlogos/buganizer/v1/192px.svg"
        },
        "studio": {
          "flows": {
            "workflowElements": [
              {
                "id": "supportTicketTrigger",
                "state": "ACTIVE",
                "name": "New Support Ticket",
                "description": "Fires when someone submits a ticket in the Support Quick Portal.",
                "workflowTrigger": {
                  "inputs": [],
                  "outputs": [
                    {
                      "id": "ticketTitle",
                      "description": "Ticket Title",
                      "cardinality": "SINGLE",
                      "dataType": { "basicType": "STRING" }
                    },
                    {
                      "id": "ticketDescription",
                      "description": "Ticket Description",
                      "cardinality": "SINGLE",
                      "dataType": { "basicType": "STRING" }
                    }
                  ],
                  "onConfigFunction": "${SERVICE_URL}/onConfigTrigger",
                  "onManageFunction": "${SERVICE_URL}/onManageTrigger"
                }
              },
              {
                "id": "urgencyDetectorStep",
                "state": "ACTIVE",
                "name": "Detect Urgency",
                "description": "Evaluates the ticket description to detect High or Normal urgency.",
                "workflowAction": {
                  "inputs": [
                    {
                      "id": "ticketDescription",
                      "description": "Description to scan",
                      "cardinality": "SINGLE",
                      "dataType": { "basicType": "STRING" }
                    }
                  ],
                  "outputs": [
                    {
                      "id": "urgencyLevel",
                      "description": "Detected Urgency (High / Normal)",
                      "cardinality": "SINGLE",
                      "dataType": { "basicType": "STRING" }
                    }
                  ],
                  "onConfigFunction": "${SERVICE_URL}/onConfigUrgency",
                  "onExecuteFunction": "${SERVICE_URL}/onExecuteUrgency"
                }
              }
            ]
          }
        },
        "httpOptions": {
          "authorizationHeader": "SYSTEM_ID_TOKEN"
        }
      }
    }
    EOF
    
  5. अपने खाते के लिए, Google Workspace ऐड-ऑन डिप्लॉयमेंट बनाएं (या बदलें) और उसे इंस्टॉल करें. साथ ही, सहायता पोर्टल के यूआरएल को प्रिंट करें:
    gcloud workspace-add-ons deployments create support-extension --deployment-file=deployment.json || \
      gcloud workspace-add-ons deployments replace support-extension --deployment-file=deployment.json
    gcloud workspace-add-ons deployments install support-extension
    echo "Support Quick Portal URL: ${SERVICE_URL}"
    

5. Google Workspace Studio में, कस्टम चरणों को टेस्ट करना

  1. Google Workspace Studio खोलें. अगर यह पहले से खुला है, तो ब्राउज़र टैब को रीफ़्रेश करें. इसके बाद, नया फ़्लो पर क्लिक करें.
  2. स्टार्टर चुनें > सहायता एक्सटेंशन > नया सहायता टिकट पर क्लिक करें.
  3. चरण जोड़ें (+) > सहायता एक्सटेंशन > जल्द कार्रवाई करने की ज़रूरत का पता लगाएं पर क्लिक करें. सोर्स का ब्यौरा फ़ील्ड में, + वैरिएबल पर क्लिक करें. इसके बाद, टिकट का ब्यौरा चुनें.
  4. चरण जोड़ें (+) पर क्लिक करें. इसके बाद, Chat > मुझे Chat में सूचना दें चरण जोड़ें. इसमें मैसेज में टिकट का टाइटल, ज़रूरत का लेवल, और टिकट का ब्यौरा वैरिएबल शामिल करें.
  5. सबसे ऊपर दाएं कोने में मौजूद, फ़्लो को चालू करें पर टॉगल करें. Google Workspace Studio, Cloud Run पर मौजूद आपके /onManageTrigger एंडपॉइंट को तुरंत कॉल करता है. यह studio_triggers कलेक्शन में, चालू ट्रिगर सदस्यता लिखता है.
  6. नए टैब में, Support Quick Portal का यूआरएल (https://support-extension-...run.app) खोलें. पुष्टि करें कि पोर्टल में 1Firestore में ट्रिगर चालू है दिख रहा हो. इसके बाद, Gemini 3.8 Flash (gemini-3.8-flash) के क्लासिफ़िकेशन की जांच करने के लिए, दो टिकट सबमिट करें:
    • ज़्यादा असर डालने वाली समस्या (टिकट का टाइटल: London office lockout, समस्या का ब्यौरा: All 500 employees in the London office are locked out of their workstations 20 minutes before the board presentation.): urgent या blocker जैसे हार्डकोड किए गए कीवर्ड के बिना भी, gemini-3.8-flash इस टिकट को High के तौर पर क्लासिफ़ाई करता है.
    • रूटीन टिकट (टिकट का टाइटल: Conference room adapters, समस्या का ब्यौरा: Could we order two extra HDMI adapters for the third-floor conference room next month?): gemini-3.8-flash इस टिकट को Normal के तौर पर क्लासिफ़ाई करता है.
  7. Google Chat और Google Workspace Studio के गतिविधि टैब में जाकर पुष्टि करें कि आपका फ़्लो, Urgency Level: High और Urgency Level: Normal वाले दोनों टिकट के लिए चला हो.

6. व्यवस्थित करें

अपने Google Cloud खाते पर लगने वाले शुल्क से बचने के लिए, Cloud Shell में डिप्लॉय किए गए संसाधनों को हटाएं:

gcloud workspace-add-ons deployments uninstall support-extension
gcloud workspace-add-ons deployments delete support-extension --quiet
gcloud run services delete support-extension --region=us-central1 --quiet
gcloud firestore databases delete --database="(default)" --quiet

7. बधाई हो!

आपने Gemini Enterprise Agent Platform पर Firestore, Cloud Run, और Gemini 3.8 Flash का इस्तेमाल करके, Google Workspace Studio के लिए Node.js HTTP एक्सटेंशन बनाया, उसे डिप्लॉय किया, और उसकी जांच की!

हमने क्या-क्या कवर किया है

  • workflowTrigger और workflowAction एलिमेंट के साथ, Google Workspace Studio के एचटीटीपी ऐड-ऑन मेनिफ़ेस्ट (deployment.json) को कॉन्फ़िगर करना.
  • यह कुकी, Google Workspace Studio workflowTrigger की सदस्यताओं को studio_triggers Firestore कलेक्शन में सेव करती है. साथ ही, पोर्टल सबमिशन को support_tickets में लॉग करती है, ताकि Cloud Run की स्केलिंग और फिर से डिप्लॉयमेंट के दौरान ट्रिगर काम करते रहें.
  • Gemini Enterprise Agent Platform पर, Gemini 3.8 Flash (gemini-3.8-flash) की मदद से सहायता टिकटों को कैटगरी में बांटने वाला workflowAction चरण बनाना. इसमें कीवर्ड मैचिंग फ़ॉलबैक की सुविधा भी शामिल है.

अगले चरण