{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "AI Personal Admin Inbox Assistant",
  "tags": [],
  "nodes": [
    {
      "id": "ee1059a0-f837-4af6-bd02-b3597d055f03",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -256
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 896,
        "content": "## AI Personal Admin Inbox Assistant\n\n### How it works\n\nThis workflow monitors an admin Gmail inbox, normalizes and redacts incoming messages, checks task memory in Airtable and Google Sheets, and skips duplicates. New items are classified by OpenAI, converted into admin alerts, optionally sent to Slack and Microsoft Teams, and then logged to Sheets and/or Airtable before completion.\n\n### Setup steps\n\n- Connect Gmail credentials for the trigger account and configure the inbox/label or search criteria to monitor.\n- Open the Set Inbox Configuration code node and set memory/logging toggles, Slack and Teams alert preferences, destination IDs, and any redaction or priority rules.\n- Add OpenAI credentials and review the classifier prompt/model settings for the admin item categories you want extracted.\n- Connect Slack credentials and configure the target channel if Slack alerts are enabled.\n- Configure the Microsoft Teams incoming webhook URL used by the HTTP Request node if Teams alerts are enabled.\n- Connect Google Sheets credentials and set the spreadsheet, sheet names, and expected columns for task memory and task logging.\n- Connect Airtable credentials and set the base, table, and field mappings for task memory and task logging.\n- Verify the Sheets and Airtable schemas match the fields produced by the workflow, then test with a sample email before activating the Gmail trigger.\n\n### Customization\n\nYou can adjust which memory sources are used, the duplicate-detection rules, the AI classification categories, Slack/Teams alert conditions, and whether completed admin tasks are logged to Sheets, Airtable, or both."
      },
      "typeVersion": 1
    },
    {
      "id": "6e0ce98d-1404-475b-9e96-7f8a69e6274a",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 240,
        "height": 320,
        "content": "## Receive admin email\n\nStarts the workflow whenever a matching admin email arrives in Gmail."
      },
      "typeVersion": 1
    },
    {
      "id": "085dab67-3889-49b9-a9d0-bf9c852cdbd1",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 320,
        "content": "## Configure and sanitize email\n\nLoads editable admin-inbox settings, then normalizes the message content and redacts sensitive details before downstream processing."
      },
      "typeVersion": 1
    },
    {
      "id": "54aedfa3-24f5-4120-bb3b-a494f4165f38",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 512,
        "content": "## Load Airtable memory\n\nChecks whether Airtable task memory should be used, reads it when enabled, compiles the results, or passes through an empty/bypassed memory state."
      },
      "typeVersion": 1
    },
    {
      "id": "ecf99206-7c0d-4599-abf6-93f8ce516105",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 544,
        "content": "## Load Sheets memory\n\nChecks whether Google Sheets task memory should be used, reads and combines existing task records, or transfers the prior memory state when Sheets memory is disabled."
      },
      "typeVersion": 1
    },
    {
      "id": "91f3a302-ce1e-45f6-87cc-b11b63dba64c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 496,
        "content": "## Detect duplicate items\n\nCompares the incoming admin email against task memory, decides whether it is new, and ends processing early for duplicates."
      },
      "typeVersion": 1
    },
    {
      "id": "06d66977-c776-425d-9aba-240b669b68f1",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3024,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 496,
        "content": "## Classify admin request\n\nUses OpenAI to classify and extract actionable admin details, examines the extraction, and routes invalid or skipped items to an early completion path."
      },
      "typeVersion": 1
    },
    {
      "id": "04d03ef9-9dbd-4db3-9d06-bdf3f2cf3885",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3568,
        -256
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 416,
        "content": "## Prepare Slack alert\n\nFormats the extracted admin item into an alert payload and decides whether a Slack notification is required."
      },
      "typeVersion": 1
    },
    {
      "id": "a178a888-98d0-4ba4-9fb9-95f1cd805933",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4096,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 512,
        "content": "## Send Slack alert\n\nEither sends the formatted alert to Slack and validates delivery, or records that Slack notification was intentionally omitted."
      },
      "typeVersion": 1
    },
    {
      "id": "cc07b086-b60b-417e-8625-4908e6ea2d7e",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4592,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 240,
        "height": 368,
        "content": "## Check Teams routing\n\nDetermines whether the workflow should also notify Microsoft Teams after the Slack step has been handled."
      },
      "typeVersion": 1
    },
    {
      "id": "ff58c5ea-034e-46a8-832e-66b5caa0c200",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4880,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 512,
        "content": "## Send Teams alert\n\nEither posts the admin alert to a Teams webhook and validates the result, or records that Teams notification was skipped."
      },
      "typeVersion": 1
    },
    {
      "id": "1e7b4554-30e7-4750-813f-f3fa4a227906",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5360,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 240,
        "height": 336,
        "content": "## Create task log\n\nBuilds the consolidated admin task log object after alert delivery decisions have been completed."
      },
      "typeVersion": 1
    },
    {
      "id": "2e969d2d-0cd0-4662-b6a5-008a43e57359",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5648,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 496,
        "content": "## Log task to Sheets\n\nChecks whether Google Sheets logging is enabled, writes the task entry when required, verifies the entry, or bypasses Sheets logging."
      },
      "typeVersion": 1
    },
    {
      "id": "bf4b3e17-8167-43bf-bde3-587df8a75db0",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6400,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 496,
        "content": "## Log task to Airtable\n\nChecks whether Airtable logging is enabled, creates the task record when required, verifies the entry, or bypasses Airtable logging."
      },
      "typeVersion": 1
    },
    {
      "id": "6df87a6e-dc91-4708-a3a5-c3228a67d3fb",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7168,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 240,
        "height": 384,
        "content": "## Complete admin processing\n\nFinalizes successful processing after optional alerts and logging have finished."
      },
      "typeVersion": 1
    },
    {
      "id": "99999999-9999-9999-9999-000000000001",
      "name": "Admin Email Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        0,
        320
      ],
      "parameters": {
        "filters": {
          "q": "label:Admin newer_than:7d"
        },
        "options": {
          "downloadAttachments": false
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000002",
      "name": "Set Inbox Configuration",
      "type": "n8n-nodes-base.code",
      "position": [
        288,
        320
      ],
      "parameters": {
        "jsCode": "// ===== EDIT YOUR SETTINGS HERE =====\n// Defaults below match the Gumroad + n8n Creator listings.\n// Change only what you need; leave unused destinations as placeholders.\n\n// Where to log admin tasks:\n//   'sheets'   -> Google Sheets only\n//   'airtable' -> Airtable only\n//   'both'     -> Google Sheets and Airtable\nconst TASK_LOG = 'sheets';\n\nconst GOOGLE_SHEET_ID = 'your-google-sheet-id';\nconst SHEETS_TAB_NAME = 'Admin Tasks';\n\nconst AIRTABLE_BASE_ID = 'appXXXXXXXXXXXXXX';\nconst ADMIN_TASKS_TABLE_NAME = 'Admin Tasks';\n\n// Where to send alerts for urgent, due-soon, or review-needed admin items:\n//   'slack' -> Slack only\n//   'teams' -> Microsoft Teams only\n//   'both'  -> Slack and Teams\n//   'none'  -> no chat alerts\nconst NOTIFY_CHANNELS = 'slack';\nconst SLACK_CHANNEL = '#admin-tasks';\nconst TEAMS_WEBHOOK_URL = 'https://outlook.office.com/webhook/your-teams-incoming-webhook';\n\nconst URGENT_DUE_DAYS = 3;\nconst DUPLICATE_WINDOW_DAYS = 30;\nconst ALERT_REVIEW_ITEMS = true;\nconst REDACT_BEFORE_AI = true;\nconst DEFAULT_SOURCE = 'gmail_admin';\n\nconst payload = $input.first().json;\nconst taskLog = String(TASK_LOG || 'sheets').toLowerCase().trim();\nconst notifyChannels = String(NOTIFY_CHANNELS || 'slack').toLowerCase().trim();\n\nreturn [\n  {\n    json: {\n      taskLog,\n      useSheetsLog: taskLog === 'sheets' || taskLog === 'both',\n      useAirtableLog: taskLog === 'airtable' || taskLog === 'both',\n      googleSheetId: GOOGLE_SHEET_ID,\n      sheetsTabName: SHEETS_TAB_NAME,\n      airtableBaseId: AIRTABLE_BASE_ID,\n      adminTasksTableName: ADMIN_TASKS_TABLE_NAME,\n      notifyChannels,\n      useSlack: notifyChannels === 'slack' || notifyChannels === 'both',\n      useTeams: notifyChannels === 'teams' || notifyChannels === 'both',\n      slackChannel: SLACK_CHANNEL,\n      teamsWebhookUrl: TEAMS_WEBHOOK_URL,\n      urgentDueDays: URGENT_DUE_DAYS,\n      duplicateWindowDays: DUPLICATE_WINDOW_DAYS,\n      alertReviewItems: ALERT_REVIEW_ITEMS,\n      redactBeforeAi: REDACT_BEFORE_AI,\n      defaultSource: DEFAULT_SOURCE,\n      payload,\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000003",
      "name": "Redact Email Content",
      "type": "n8n-nodes-base.code",
      "position": [
        560,
        320
      ],
      "parameters": {
        "jsCode": "const settings = $input.first().json;\nconst raw = settings.payload || {};\n\nconst htmlToText = (value) => String(value || '')\n  .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n  .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n  .replace(/<br\\s*\\/?>/gi, '\\n')\n  .replace(/<\\/p>/gi, '\\n')\n  .replace(/<[^>]+>/g, ' ')\n  .replace(/&nbsp;/g, ' ')\n  .replace(/&amp;/g, '&')\n  .replace(/&lt;/g, '<')\n  .replace(/&gt;/g, '>')\n  .replace(/\\s+\\n/g, '\\n')\n  .replace(/[ \\t]+/g, ' ')\n  .trim();\n\nconst redact = (value) => {\n  let text = String(value || '');\n  text = text.replace(/\\b\\d{3}-\\d{2}-\\d{4}\\b/g, '[REDACTED_SSN]');\n  text = text.replace(/\\b(?:\\d[ -]*?){13,19}\\b/g, (match) => {\n    const digits = match.replace(/\\D/g, '');\n    return digits.length >= 13 ? `[REDACTED_NUMBER_ENDING_${digits.slice(-4)}]` : match;\n  });\n  text = text.replace(/\\b(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\\b/g, '[REDACTED_PHONE]');\n  text = text.replace(/\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/gi, '[REDACTED_EMAIL]');\n  text = text.replace(/\\b\\d{1,6}\\s+[A-Za-z0-9.'-]+\\s+(?:Street|St|Avenue|Ave|Road|Rd|Drive|Dr|Lane|Ln|Boulevard|Blvd|Court|Ct|Way|Place|Pl)\\b/gi, '[REDACTED_ADDRESS]');\n  text = text.replace(/\\b(?:account|acct|policy|member|case|claim|confirmation|reservation|invoice)\\s*(?:number|#|id)?\\s*[:#]?\\s*[A-Z0-9-]{4,}\\b/gi, (match) => {\n    const id = match.match(/[A-Z0-9-]{4,}$/i)?.[0] || '';\n    return `${match.split(':')[0].split('#')[0].trim()} [REDACTED_ID_ENDING_${id.slice(-4)}]`;\n  });\n  return text;\n};\n\nconst headers = raw.headers || raw.payload?.headers || {};\nconst subject = raw.subject || raw.Subject || headers.subject || raw.payload?.subject || '';\nconst fromEmail = raw.from || raw.From || headers.from || raw.payload?.from || '';\nconst messageId = raw.id || raw.messageId || raw.message_id || raw.payload?.id || `admin-${Date.now()}`;\nconst receivedAt = raw.date || raw.internalDate || raw.receivedAt || new Date().toISOString();\nconst textBody = raw.textPlain || raw.text || raw.snippet || raw.body?.text || '';\nconst htmlBody = raw.textHtml || raw.html || raw.body?.html || '';\nconst rawText = htmlToText(textBody || htmlBody || raw.snippet || JSON.stringify(raw).slice(0, 6000));\nconst redactedText = settings.redactBeforeAi ? redact(rawText) : rawText;\nconst compact = rawText.toLowerCase().replace(/\\s+/g, ' ').replace(/'/g, '').slice(0, 1000);\nconst adminHash = `${fromEmail}|${subject}|${compact}`.toLowerCase();\n\nreturn [\n  {\n    json: {\n      ...settings,\n      messageId: String(messageId),\n      receivedAt,\n      source: raw.source || settings.defaultSource || 'gmail_admin',\n      originalSubject: String(subject),\n      fromEmail: String(fromEmail),\n      rawText: rawText.slice(0, 10000),\n      redactedText: redactedText.slice(0, 10000),\n      rawTextSnippet: rawText.slice(0, 1000),\n      adminHash,\n      redactionApplied: rawText !== redactedText,\n      _mockExistingTasks: Array.isArray(raw._mockExistingTasks) ? raw._mockExistingTasks : [],\n      _testScenario: raw._testScenario || raw.scenario || '',\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000040",
      "name": "Evaluate Airtable Memory Usage",
      "type": "n8n-nodes-base.if",
      "position": [
        780,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.useAirtableLog }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000004",
      "name": "Read Airtable Memory",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1040,
        200
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.airtableBaseId }}"
        },
        "limit": 10,
        "table": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.adminTasksTableName }}"
        },
        "options": {},
        "operation": "search",
        "returnAll": false,
        "filterByFormula": "=OR({Message ID} = '{{ $json.messageId }}', {Admin Hash} = '{{ $json.adminHash }}')"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1,
      "alwaysOutputData": true
    },
    {
      "id": "99999999-9999-9999-9999-000000000041",
      "name": "Compile Airtable Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1300,
        200
      ],
      "parameters": {
        "jsCode": "const admin = $('Redact Email Content').first().json;\nconst rows = $input\n  .all()\n  .map((item) => item.json)\n  .filter((row) => !row._mockEmpty)\n  .map((row) => row.fields || row);\nreturn [{ json: { ...admin, _lookupRows: rows } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000042",
      "name": "Skip Airtable Data Usage",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        420
      ],
      "parameters": {
        "jsCode": "const admin = $('Redact Email Content').first().json;\nreturn [{ json: { ...admin, _lookupRows: [] } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000043",
      "name": "Evaluate Sheets Memory Usage",
      "type": "n8n-nodes-base.if",
      "position": [
        1560,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.useSheetsLog }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000044",
      "name": "Read Sheets Memory",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1820,
        200
      ],
      "parameters": {
        "options": {},
        "resource": "sheet",
        "operation": "read",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.sheetsTabName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "alwaysOutputData": true
    },
    {
      "id": "99999999-9999-9999-9999-000000000045",
      "name": "Combine Sheets Data",
      "type": "n8n-nodes-base.code",
      "position": [
        2080,
        200
      ],
      "parameters": {
        "jsCode": "function fromNode(name) {\n  try {\n    return $(name).first().json;\n  } catch (error) {\n    return null;\n  }\n}\n\nconst prev =\n  fromNode('Compile Airtable Data') ||\n  fromNode('Skip Airtable Data Usage') ||\n  $('Redact Email Content').first().json;\n\nconst sheetRows = $input\n  .all()\n  .map((item) => item.json)\n  .filter((row) => !row._mockEmpty)\n  .map((row) => row.fields || row);\n\nreturn [{ json: { ...prev, _lookupRows: [...(prev._lookupRows || []), ...sheetRows] } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000046",
      "name": "Transfer Memory Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1820,
        420
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: item }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000005",
      "name": "Detect Email Duplication",
      "type": "n8n-nodes-base.code",
      "position": [
        2320,
        320
      ],
      "parameters": {
        "jsCode": "const admin = $input.first().json;\nconst rows = Array.isArray(admin._lookupRows) ? admin._lookupRows : [];\nconst windowDays = admin.duplicateWindowDays ?? 30;\nconst cutoff = Date.now() - windowDays * 24 * 60 * 60 * 1000;\n\nconst isDuplicate = rows.some((row) => {\n  const record = row.fields || row;\n  if (record._mockEmpty) return false;\n  const existingMessageId = String(record['Message ID'] || record.messageId || '').trim();\n  const existingHash = String(record['Admin Hash'] || record.adminHash || '').toLowerCase();\n  const existingAt = Date.parse(record['Received At'] || record.receivedAt || record.createdTime || '');\n\n  if (admin.messageId && existingMessageId && admin.messageId === existingMessageId) {\n    if (!existingAt || existingAt >= cutoff) return true;\n  }\n\n  if (admin.adminHash && existingHash && admin.adminHash === existingHash) {\n    if (!existingAt || existingAt >= cutoff) return true;\n  }\n\n  return false;\n});\n\nreturn [{ json: { ...admin, isDuplicate } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000006",
      "name": "Check Email Item Status",
      "type": "n8n-nodes-base.if",
      "position": [
        2580,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.isDuplicate }}",
              "rightValue": false
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000099",
      "name": "Complete Duplicate Admin Processing",
      "type": "n8n-nodes-base.code",
      "position": [
        2840,
        520
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [\n  {\n    json: {\n      status: 'skipped',\n      reason: item.isDuplicate ? 'duplicate_admin_item' : 'filtered',\n      messageId: item.messageId,\n      adminHash: item.adminHash,\n      testScenario: item._testScenario || '',\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000007",
      "name": "AI Classify Email",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        3072,
        320
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "temperature": 0.1
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You classify personal admin emails and extract task/reminder fields. Return ONLY valid JSON with keys: isAdminItem (boolean), extractionStatus (extracted|not_admin|failed), failureReason, category, priority (low|medium|high|urgent), dueDate, dueTime, organization, actionRequired (boolean), taskTitle, summary, recommendedNextStep, amount, accountLastFour, url, confidence, needsReview, notes. Treat bills, renewals, appointments, travel check-ins, warranties, school/home notices, insurance/admin notices, subscriptions, and deadlines as admin items. Treat newsletters, promotions, social updates, and purely informational email as not_admin. Do not give legal, financial, or medical advice; summarize next admin action only."
            },
            {
              "role": "user",
              "content": "=Admin email after privacy redaction:\nFrom: {{ $('Detect Email Duplication').item.json.fromEmail }}\nSubject: {{ $('Detect Email Duplication').item.json.originalSubject }}\nReceived: {{ $('Detect Email Duplication').item.json.receivedAt }}\nBody:\n{{ $('Detect Email Duplication').item.json.redactedText }}"
            }
          ]
        },
        "resource": "text",
        "operation": "message"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.8,
      "continueOnFail": true
    },
    {
      "id": "99999999-9999-9999-9999-000000000008",
      "name": "Examine Email Extraction",
      "type": "n8n-nodes-base.code",
      "position": [
        3328,
        320
      ],
      "parameters": {
        "jsCode": "const admin = $('Detect Email Duplication').first().json;\nconst aiItem = $input.first().json;\nconst raw =\n  aiItem.message?.content ||\n  aiItem.content ||\n  aiItem.text ||\n  aiItem.output ||\n  aiItem.output_text ||\n  aiItem.choices?.[0]?.message?.content ||\n  '';\n\nlet extraction = {\n  isAdminItem: true,\n  extractionStatus: 'extracted',\n  failureReason: '',\n  category: 'General admin',\n  priority: 'medium',\n  dueDate: '',\n  dueTime: '',\n  organization: '',\n  actionRequired: true,\n  taskTitle: '',\n  summary: '',\n  recommendedNextStep: '',\n  amount: '',\n  accountLastFour: '',\n  url: '',\n  confidence: 50,\n  needsReview: true,\n  notes: '',\n};\n\nlet parsedOk = false;\ntry {\n  const jsonMatch = String(raw).match(/\\{[\\s\\S]*\\}/);\n  if (jsonMatch) {\n    extraction = { ...extraction, ...JSON.parse(jsonMatch[0]) };\n    parsedOk = true;\n  }\n} catch (error) {\n  extraction.extractionStatus = 'failed';\n  extraction.failureReason = 'OpenAI returned text that was not valid admin JSON';\n}\n\nif (!parsedOk && !extraction.failureReason) {\n  extraction.extractionStatus = 'failed';\n  extraction.failureReason = 'OpenAI did not return a JSON object';\n}\n\nconst confidence = Math.max(0, Math.min(100, Number(extraction.confidence) || 50));\nconst priority = String(extraction.priority || 'medium').toLowerCase();\nconst dueDateValue = String(extraction.dueDate || '');\nconst dueTimeValue = String(extraction.dueTime || '');\nconst dueAt = Date.parse(dueDateValue);\nconst dueSoon = Number.isFinite(dueAt)\n  ? dueAt <= Date.now() + (admin.urgentDueDays ?? 3) * 24 * 60 * 60 * 1000\n  : false;\nconst isAdminItem = extraction.isAdminItem !== false && extraction.extractionStatus !== 'not_admin';\nconst needsReview = Boolean(extraction.needsReview || confidence < 70 || (!extraction.taskTitle && !extraction.summary));\nconst extractionFailed = Boolean(aiItem.error || extraction.extractionStatus === 'failed' || !parsedOk);\nconst extractionSucceeded = Boolean(isAdminItem && !extractionFailed);\n\nlet route = 'standard';\nif (!isAdminItem) route = 'not_admin';\nelse if (extractionFailed) route = 'extraction_failed';\nelse if (needsReview) route = 'review';\nelse if (priority === 'urgent' || priority === 'high') route = 'priority';\nelse if (dueSoon) route = 'due_soon';\n\nconst shouldAlert = Boolean(\n  admin.notifyChannels !== 'none' &&\n    extractionSucceeded &&\n    (priority === 'urgent' ||\n      priority === 'high' ||\n      dueSoon ||\n      (admin.alertReviewItems && needsReview))\n);\n\nreturn [\n  {\n    json: {\n      ...admin,\n      category: String(extraction.category || 'General admin'),\n      priority,\n      dueDate: dueDateValue,\n      dueTime: dueTimeValue,\n      dueSoon,\n      organization: String(extraction.organization || ''),\n      actionRequired: Boolean(extraction.actionRequired),\n      taskTitle: String(extraction.taskTitle || extraction.summary || 'Admin item needs review'),\n      summary: String(extraction.summary || ''),\n      recommendedNextStep: String(extraction.recommendedNextStep || ''),\n      amount: String(extraction.amount || ''),\n      accountLastFour: String(extraction.accountLastFour || ''),\n      url: String(extraction.url || ''),\n      isAdminItem,\n      extractionStatus: extractionFailed ? 'failed' : isAdminItem ? 'extracted' : 'not_admin',\n      extractionSucceeded,\n      extractionFailureReason:\n        aiItem.error?.message ||\n        extraction.failureReason ||\n        (!isAdminItem ? 'Email does not appear to be an admin task, reminder, bill, renewal, appointment, travel item, or deadline' : ''),\n      confidence,\n      needsReview,\n      shouldAlert,\n      route,\n      notes: String(extraction.notes || ''),\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000072",
      "name": "Verify Extraction Success",
      "type": "n8n-nodes-base.if",
      "position": [
        3584,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.extractionSucceeded }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000073",
      "name": "Complete Skipped Admin Processing",
      "type": "n8n-nodes-base.code",
      "position": [
        3840,
        528
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nconst reason = item.isAdminItem === false ? 'non_admin_email' : 'extraction_failed';\n\nreturn [\n  {\n    json: {\n      status: 'skipped',\n      reason,\n      message:\n        reason === 'non_admin_email'\n          ? 'Email was processed successfully but does not appear to be an admin task.'\n          : 'Admin task extraction failed. Check the email content or OpenAI node output.',\n      messageId: item.messageId,\n      adminHash: item.adminHash,\n      extractionStatus: item.extractionStatus,\n      extractionFailureReason: item.extractionFailureReason || '',\n      originalSubject: item.originalSubject,\n      fromEmail: item.fromEmail,\n      testScenario: item._testScenario || '',\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000009",
      "name": "Format Alert Message",
      "type": "n8n-nodes-base.code",
      "position": [
        3616,
        0
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nconst reason =\n  item.route === 'review'\n    ? 'Needs review'\n    : item.route === 'priority'\n      ? 'Priority admin item'\n      : item.route === 'due_soon'\n        ? 'Due soon'\n        : 'Admin item logged';\n\nconst details = [\n  `Reason: ${reason}`,\n  `Task: ${item.taskTitle}`,\n  `Category: ${item.category}`,\n  `Priority: ${item.priority}`,\n  item.dueDate ? `Due: ${item.dueDate}${item.dueTime ? ` ${item.dueTime}` : ''}` : '',\n  item.organization ? `Organization: ${item.organization}` : '',\n  item.amount ? `Amount: ${item.amount}` : '',\n  `Confidence: ${item.confidence}/100`,\n  `Subject: ${item.originalSubject}`,\n].filter(Boolean);\n\nconst slackMessage = [`*${reason}: ${item.taskTitle}*`, '', ...details.map((line) => `- ${line}`)].join('\\n');\nconst teamsMessage = [`**${reason}: ${item.taskTitle}**`, '', ...details.map((line) => `- ${line}`)].join('\\n');\n\nreturn [\n  {\n    json: {\n      ...item,\n      useSlackAlert: Boolean(item.shouldAlert && item.useSlack),\n      useTeamsAlert: Boolean(item.shouldAlert && item.useTeams),\n      slackMessage,\n      teamsMessage,\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000050",
      "name": "Evaluate Slack Alert Need",
      "type": "n8n-nodes-base.if",
      "position": [
        3888,
        -96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.useSlackAlert }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000051",
      "name": "Send Slack Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        4140,
        100
      ],
      "parameters": {
        "text": "={{ $json.slackMessage }}",
        "select": "channel",
        "resource": "message",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.slackChannel }}"
        },
        "operation": "post",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000052",
      "name": "Confirm Slack Alert Sent",
      "type": "n8n-nodes-base.code",
      "position": [
        4400,
        100
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: { ...item, alertSent: 'yes' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000053",
      "name": "Skip Slack Alert",
      "type": "n8n-nodes-base.code",
      "position": [
        4140,
        300
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: { ...item, alertSent: item.alertSent || 'no' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000054",
      "name": "Evaluate Teams Alert Need",
      "type": "n8n-nodes-base.if",
      "position": [
        4640,
        220
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.useTeamsAlert }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000055",
      "name": "Post to Teams Webhook",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4928,
        96
      ],
      "parameters": {
        "url": "={{ $json.teamsWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ text: $json.teamsMessage }) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000056",
      "name": "Confirm Teams Alert Sent",
      "type": "n8n-nodes-base.code",
      "position": [
        5200,
        96
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: { ...item, alertSent: 'yes' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000057",
      "name": "Skip Teams Alert",
      "type": "n8n-nodes-base.code",
      "position": [
        4928,
        304
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: { ...item, alertSent: item.alertSent || 'no' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000010",
      "name": "Create Task Log Entry",
      "type": "n8n-nodes-base.code",
      "position": [
        5400,
        220
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [\n  {\n    json: {\n      taskLog: item.taskLog,\n      useSheetsLog: item.useSheetsLog,\n      useAirtableLog: item.useAirtableLog,\n      googleSheetId: item.googleSheetId,\n      sheetsTabName: item.sheetsTabName,\n      airtableBaseId: item.airtableBaseId,\n      adminTasksTableName: item.adminTasksTableName,\n      'Received At': item.receivedAt,\n      Source: item.source,\n      'Message ID': item.messageId,\n      'Admin Hash': item.adminHash,\n      Category: item.category,\n      Priority: item.priority,\n      'Due Date': item.dueDate,\n      'Due Time': item.dueTime,\n      Organization: item.organization,\n      Sender: item.fromEmail,\n      'Action Required': item.actionRequired ? 'yes' : 'no',\n      'Task Title': item.taskTitle,\n      Summary: item.summary,\n      'Recommended Next Step': item.recommendedNextStep,\n      Amount: item.amount,\n      'Account Last Four': item.accountLastFour,\n      URL: item.url,\n      'Is Admin Item': item.isAdminItem ? 'yes' : 'no',\n      'Extraction Status': item.extractionStatus,\n      'Extraction Failure Reason': item.extractionFailureReason,\n      Confidence: item.confidence,\n      'Needs Review': item.needsReview ? 'yes' : 'no',\n      'Alert Sent': item.alertSent || 'no',\n      Status:\n        item.route === 'review'\n          ? 'Needs Review'\n          : item.route === 'priority'\n            ? 'Priority'\n            : item.route === 'due_soon'\n              ? 'Due Soon'\n              : 'Logged',\n      'Original Subject': item.originalSubject,\n      'From Email': item.fromEmail,\n      'Redaction Applied': item.redactionApplied ? 'yes' : 'no',\n      'Raw Text Snippet': item.rawTextSnippet,\n      Notes: item.notes,\n      _testScenario: item._testScenario || '',\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000060",
      "name": "Evaluate Sheets Log Need",
      "type": "n8n-nodes-base.if",
      "position": [
        5696,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.useSheetsLog }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000061",
      "name": "Append Task Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        5952,
        96
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $json[\"URL\"] }}",
            "Notes": "={{ $json[\"Notes\"] }}",
            "Amount": "={{ $json[\"Amount\"] }}",
            "Sender": "={{ $json[\"Sender\"] }}",
            "Source": "={{ $json[\"Source\"] }}",
            "Status": "={{ $json[\"Status\"] }}",
            "Summary": "={{ $json[\"Summary\"] }}",
            "Category": "={{ $json[\"Category\"] }}",
            "Due Date": "={{ $json[\"Due Date\"] }}",
            "Due Time": "={{ $json[\"Due Time\"] }}",
            "Priority": "={{ $json[\"Priority\"] }}",
            "Admin Hash": "={{ $json[\"Admin Hash\"] }}",
            "Alert Sent": "={{ $json[\"Alert Sent\"] }}",
            "Confidence": "={{ $json[\"Confidence\"] }}",
            "From Email": "={{ $json[\"From Email\"] }}",
            "Message ID": "={{ $json[\"Message ID\"] }}",
            "Task Title": "={{ $json[\"Task Title\"] }}",
            "Received At": "={{ $json[\"Received At\"] }}",
            "Needs Review": "={{ $json[\"Needs Review\"] }}",
            "Organization": "={{ $json[\"Organization\"] }}",
            "Is Admin Item": "={{ $json[\"Is Admin Item\"] }}",
            "Action Required": "={{ $json[\"Action Required\"] }}",
            "Original Subject": "={{ $json[\"Original Subject\"] }}",
            "Raw Text Snippet": "={{ $json[\"Raw Text Snippet\"] }}",
            "Account Last Four": "={{ $json[\"Account Last Four\"] }}",
            "Extraction Status": "={{ $json[\"Extraction Status\"] }}",
            "Redaction Applied": "={{ $json[\"Redaction Applied\"] }}",
            "Recommended Next Step": "={{ $json[\"Recommended Next Step\"] }}",
            "Extraction Failure Reason": "={{ $json[\"Extraction Failure Reason\"] }}"
          },
          "schema": [
            {
              "id": "Received At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Received At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Admin Hash",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Admin Hash",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Priority",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Priority",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Time",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Organization",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Organization",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sender",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Sender",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Action Required",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Action Required",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Task Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Task Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Recommended Next Step",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Recommended Next Step",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Account Last Four",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Account Last Four",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Is Admin Item",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Is Admin Item",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Extraction Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Extraction Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Extraction Failure Reason",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Extraction Failure Reason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Confidence",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Confidence",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Needs Review",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Needs Review",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Alert Sent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Alert Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Original Subject",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Original Subject",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "From Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "From Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Redaction Applied",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Redaction Applied",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Raw Text Snippet",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Raw Text Snippet",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Notes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "resource": "sheet",
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.sheetsTabName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "99999999-9999-9999-9999-000000000062",
      "name": "Confirm Sheets Log Entry",
      "type": "n8n-nodes-base.code",
      "position": [
        6208,
        96
      ],
      "parameters": {
        "jsCode": "const prior = $('Create Task Log Entry').first().json;\nreturn [{ json: { ...prior, sheetsLogged: 'yes' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000063",
      "name": "Skip Sheets Logging",
      "type": "n8n-nodes-base.code",
      "position": [
        5952,
        304
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: { ...item, sheetsLogged: 'no' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000064",
      "name": "Evaluate Airtable Log Need",
      "type": "n8n-nodes-base.if",
      "position": [
        6448,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "+1234567890",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.useAirtableLog }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99999999-9999-9999-9999-000000000065",
      "name": "Add Task Log to Airtable",
      "type": "n8n-nodes-base.airtable",
      "position": [
        6720,
        96
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.airtableBaseId }}"
        },
        "table": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.adminTasksTableName }}"
        },
        "columns": {
          "value": {
            "URL": "={{ $json[\"URL\"] }}",
            "Notes": "={{ $json[\"Notes\"] }}",
            "Amount": "={{ $json[\"Amount\"] }}",
            "Sender": "={{ $json[\"Sender\"] }}",
            "Source": "={{ $json[\"Source\"] }}",
            "Status": "={{ $json[\"Status\"] }}",
            "Summary": "={{ $json[\"Summary\"] }}",
            "Category": "={{ $json[\"Category\"] }}",
            "Due Date": "={{ $json[\"Due Date\"] }}",
            "Due Time": "={{ $json[\"Due Time\"] }}",
            "Priority": "={{ $json[\"Priority\"] }}",
            "Admin Hash": "={{ $json[\"Admin Hash\"] }}",
            "Alert Sent": "={{ $json[\"Alert Sent\"] }}",
            "Confidence": "={{ $json[\"Confidence\"] }}",
            "From Email": "={{ $json[\"From Email\"] }}",
            "Message ID": "={{ $json[\"Message ID\"] }}",
            "Task Title": "={{ $json[\"Task Title\"] }}",
            "Received At": "={{ $json[\"Received At\"] }}",
            "Needs Review": "={{ $json[\"Needs Review\"] }}",
            "Organization": "={{ $json[\"Organization\"] }}",
            "Is Admin Item": "={{ $json[\"Is Admin Item\"] }}",
            "Action Required": "={{ $json[\"Action Required\"] }}",
            "Original Subject": "={{ $json[\"Original Subject\"] }}",
            "Raw Text Snippet": "={{ $json[\"Raw Text Snippet\"] }}",
            "Account Last Four": "={{ $json[\"Account Last Four\"] }}",
            "Extraction Status": "={{ $json[\"Extraction Status\"] }}",
            "Redaction Applied": "={{ $json[\"Redaction Applied\"] }}",
            "Recommended Next Step": "={{ $json[\"Recommended Next Step\"] }}",
            "Extraction Failure Reason": "={{ $json[\"Extraction Failure Reason\"] }}"
          },
          "schema": [
            {
              "id": "Received At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Received At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Admin Hash",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Admin Hash",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Priority",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Priority",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Time",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Organization",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Organization",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sender",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Sender",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Action Required",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Action Required",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Task Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Task Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Recommended Next Step",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Recommended Next Step",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Account Last Four",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Account Last Four",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Is Admin Item",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Is Admin Item",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Extraction Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Extraction Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Extraction Failure Reason",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Extraction Failure Reason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Confidence",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Confidence",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Needs Review",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Needs Review",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Alert Sent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Alert Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Original Subject",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Original Subject",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "From Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "From Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Redaction Applied",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Redaction Applied",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Raw Text Snippet",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Raw Text Snippet",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Notes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "99999999-9999-9999-9999-000000000066",
      "name": "Confirm Airtable Log Entry",
      "type": "n8n-nodes-base.code",
      "position": [
        6976,
        96
      ],
      "parameters": {
        "jsCode": "const prior = $('Evaluate Airtable Log Need').first().json;\nreturn [{ json: { ...prior, airtableLogged: 'yes' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000067",
      "name": "Skip Airtable Logging",
      "type": "n8n-nodes-base.code",
      "position": [
        6720,
        304
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [{ json: { ...item, airtableLogged: 'no' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "99999999-9999-9999-9999-000000000011",
      "name": "Finalize Admin Workflow",
      "type": "n8n-nodes-base.code",
      "position": [
        7216,
        224
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nreturn [\n  {\n    json: {\n      status: 'ok',\n      taskLog: item.taskLog,\n      sheetsLogged: item.sheetsLogged || 'no',\n      airtableLogged: item.airtableLogged || 'no',\n      taskTitle: item['Task Title'],\n      category: item.Category,\n      priority: item.Priority,\n      dueDate: item['Due Date'],\n      needsReview: item['Needs Review'],\n      alertSent: item['Alert Sent'],\n      redactionApplied: item['Redaction Applied'],\n      testScenario: item._testScenario || '',\n    },\n  },\n];"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "ai-personal-admin-inbox-assistant-v1",
  "connections": {
    "Send Slack Alert": {
      "main": [
        [
          {
            "node": "Confirm Slack Alert Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Slack Alert": {
      "main": [
        [
          {
            "node": "Evaluate Teams Alert Need",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Teams Alert": {
      "main": [
        [
          {
            "node": "Create Task Log Entry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Classify Email": {
      "main": [
        [
          {
            "node": "Examine Email Extraction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Sheets Memory": {
      "main": [
        [
          {
            "node": "Combine Sheets Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Admin Email Trigger": {
      "main": [
        [
          {
            "node": "Set Inbox Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Sheets Data": {
      "main": [
        [
          {
            "node": "Detect Email Duplication",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Sheets Logging": {
      "main": [
        [
          {
            "node": "Evaluate Airtable Log Need",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Alert Message": {
      "main": [
        [
          {
            "node": "Evaluate Slack Alert Need",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Airtable Memory": {
      "main": [
        [
          {
            "node": "Compile Airtable Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Redact Email Content": {
      "main": [
        [
          {
            "node": "Evaluate Airtable Memory Usage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transfer Memory Data": {
      "main": [
        [
          {
            "node": "Detect Email Duplication",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compile Airtable Data": {
      "main": [
        [
          {
            "node": "Evaluate Sheets Memory Usage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Task Log Entry": {
      "main": [
        [
          {
            "node": "Evaluate Sheets Log Need",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to Teams Webhook": {
      "main": [
        [
          {
            "node": "Confirm Teams Alert Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Airtable Logging": {
      "main": [
        [
          {
            "node": "Finalize Admin Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Email Item Status": {
      "main": [
        [
          {
            "node": "AI Classify Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Complete Duplicate Admin Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Inbox Configuration": {
      "main": [
        [
          {
            "node": "Redact Email Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Task Log to Airtable": {
      "main": [
        [
          {
            "node": "Confirm Airtable Log Entry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Confirm Sheets Log Entry": {
      "main": [
        [
          {
            "node": "Evaluate Airtable Log Need",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Confirm Slack Alert Sent": {
      "main": [
        [
          {
            "node": "Evaluate Teams Alert Need",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Confirm Teams Alert Sent": {
      "main": [
        [
          {
            "node": "Create Task Log Entry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Email Duplication": {
      "main": [
        [
          {
            "node": "Check Email Item Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Sheets Log Need": {
      "main": [
        [
          {
            "node": "Append Task Log to Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip Sheets Logging",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Examine Email Extraction": {
      "main": [
        [
          {
            "node": "Verify Extraction Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Airtable Data Usage": {
      "main": [
        [
          {
            "node": "Evaluate Sheets Memory Usage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Task Log to Sheets": {
      "main": [
        [
          {
            "node": "Confirm Sheets Log Entry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Slack Alert Need": {
      "main": [
        [
          {
            "node": "Send Slack Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Teams Alert Need": {
      "main": [
        [
          {
            "node": "Post to Teams Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip Teams Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Extraction Success": {
      "main": [
        [
          {
            "node": "Format Alert Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Complete Skipped Admin Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Confirm Airtable Log Entry": {
      "main": [
        [
          {
            "node": "Finalize Admin Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Airtable Log Need": {
      "main": [
        [
          {
            "node": "Add Task Log to Airtable",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip Airtable Logging",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Sheets Memory Usage": {
      "main": [
        [
          {
            "node": "Read Sheets Memory",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Transfer Memory Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Airtable Memory Usage": {
      "main": [
        [
          {
            "node": "Read Airtable Memory",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip Airtable Data Usage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}