{
  "id": "exOYTSuZ3nUTQLmY",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Workflow Operation Report Generator",
  "tags": [
    {
      "id": "HfER5l2FvgTxes63",
      "name": "MONCHO",
      "createdAt": "2025-11-01T19:49:45.970Z",
      "updatedAt": "2025-11-01T19:49:45.970Z"
    }
  ],
  "nodes": [
    {
      "id": "8b465181-5298-405e-b3cc-ffdad3791441",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2240,
        -416
      ],
      "parameters": {
        "width": 1008,
        "height": 1168,
        "content": "# Workflow Operation Report Generator\nThis will probably sound familiar. You design a great workflow, but you don\u2019t add any sticky notes or document it. After some time, you want to modify some of its settings, but you no longer remember exactly what each node was supposed to do.\n\nThe solution to that annoying problem is this workflow. Its purpose is to generate a report, in a Google Docs document, based on a structured analysis of the workflow selected by the user.\n\n## **How it works / What it does**\n1. **Manual trigger**: The workflow starts manually.\n2. **Select and fetch the workflow to document**: Retrieves the structured information of the selected workflow.\n3. **JSON normalization and cleanup**: The selected workflow is cleaned and transformed to keep only the relevant (and safe) information needed to generate the technical documentation.\n4. **Documentation report generation**: A professional HTML report is created using an LLM (OpenAI GPT-4.1).\n5. **Code node analysis**: If the workflow contains Code nodes, they are analyzed and the result is added to the main report.\n6. **Final document creation**: The HTML report is uploaded as a Google Docs document in Google Drive.\n\n## **How to set it up**\n1. **Add the nodes in the following order**:\n   * Manual Trigger\n   * n8n node \u201cSelect Workflow\u201d (choose the desired workflow)\n   * Code node \u201cNormalize Workflow JSON\u201d\n   * OpenAI node (Message a model) \u201cGenerate Report\u201d (add system prompt and user prompt)\n   * Code node \u201cCollect Code Node Info\u201d\n   * If node \u201cAre there Code Nodes?\u201d\n   * OpenAI node (Message a model) \u201cAnalyze Code Nodes\u201d (add system prompt and user prompt)\n   * Edit Fields (Set) node \u201cMerge Report and Code Node Analysis\u201d\n   * HTTP Request node \u201cCreate Google Docs Document\u201d (including Code node analysis)\n   * HTTP Request node \u201cCreate Google Docs Document_1\u201d (without including Code node analysis)\n2. **Configure credentials** for n8n, OpenAI, and Google Drive.\n3. **Run a test execution** to make sure the document is generated and archived.\n\n## **Requirements**\n* **Credentials**:\n  * n8n API key\n  * OpenAI API key\n  * Google Drive (OAuth2) with read/write permissions\n* **Access**:\n  * Write access to the target Google Drive folders\n\n## **How to customize the workflow**\n* **Automate the trigger**: Use a Webhook Trigger to run it on-demand from external apps.\n* **Change the prompts (system and user) in the OpenAI nodes** to generate different types of content.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "76ba8d62-bdbb-460d-b234-fbe0e0cc82f4",
      "name": "Select Workflow",
      "type": "n8n-nodes-base.n8n",
      "position": [
        -1440,
        -864
      ],
      "parameters": {
        "operation": "get",
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "exOYTSuZ3nUTQLmY",
          "cachedResultName": "Documentador de workflows V1_ingl\u00e9s (#exOYTSuZ3nUTQLmY)"
        },
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8f9890e2-71ef-4926-9f46-235c052c8618",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1664,
        -864
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "fc39a272-721c-4729-8f34-c46b988f1b03",
      "name": "Normalize Workflow JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        -1216,
        -864
      ],
      "parameters": {
        "jsCode": "/**\n * ============================================================\n * Node: Normalize Workflow JSON\n * Goal:\n *  - Clean and normalize an n8n workflow for documentation\n *  - Remove noise and sensitive data\n *  - PRESERVE the code of Code nodes (jsCode) intact\n *  - Prepare a structure that is easy for LLMs to consume\n * ============================================================\n */\n\n/**\n * Returns an object with only the specified keys.\n * Used to avoid carrying unnecessary fields.\n */\nfunction pick(obj, keys) {\n  const out = {};\n  for (const k of keys) {\n    if (obj && Object.prototype.hasOwnProperty.call(obj, k)) {\n      out[k] = obj[k];\n    }\n  }\n  return out;\n}\n\n/**\n * Trims long strings to avoid blowing up the LLM context.\n * IMPORTANT: This is NOT applied to jsCode (see below).\n */\nfunction safeString(v, max = 5000) {\n  if (v == null) return v;\n  const s = typeof v === \"string\" ? v : JSON.stringify(v);\n  return s.length > max ? s.slice(0, max) + \"\u2026\" : s;\n}\n\n/**\n * Converts n8n's connections structure (very nested)\n * into a flat list of edges.\n * This makes it easier to reconstruct the real execution flow.\n */\nfunction flattenConnections(connections) {\n  const edges = [];\n  if (!connections || typeof connections !== \"object\") return edges;\n\n  for (const fromNodeName of Object.keys(connections)) {\n    const byType = connections[fromNodeName];\n    if (!byType || typeof byType !== \"object\") continue;\n\n    for (const connType of Object.keys(byType)) {\n      const groups = byType[connType];\n      if (!Array.isArray(groups)) continue;\n\n      for (let fromOutputIndex = 0; fromOutputIndex < groups.length; fromOutputIndex++) {\n        const targets = groups[fromOutputIndex];\n        if (!Array.isArray(targets)) continue;\n\n        for (const t of targets) {\n          if (!t || typeof t !== \"object\") continue;\n          edges.push({\n            from: fromNodeName,\n            to: t.node,\n            connectionType: connType,\n            fromOutputIndex,\n            toInputIndex: typeof t.index === \"number\" ? t.index : null,\n            toType: t.type || null,\n          });\n        }\n      }\n    }\n  }\n  return edges;\n}\n\n/**\n * =========================\n * MAIN\n * =========================\n */\n\n// The workflow usually comes in items[0].json\nconst raw = items?.[0]?.json;\nif (!raw) {\n  return [{ json: { error: \"Workflow not found in items[0].json\" } }];\n}\n\n/**\n * Some n8n nodes return the workflow wrapped in { workflow: {...} }\n * Here we normalize it so we always work with the same structure.\n */\nconst wf =\n  raw.workflow && typeof raw.workflow === \"object\" && raw.workflow.nodes\n    ? raw.workflow\n    : raw;\n\n// Workflow name (fallbacks for safety)\nconst workflowName = wf.name || raw.name || \"Unnamed workflow\";\n\n/**\n * Trimming configuration:\n * - DEFAULT_MAX_STRING: normal strings (URLs, text, etc.)\n * - MAX_JS_CODE: JavaScript code\n *\n * MAX_JS_CODE = null  -> jsCode is never trimmed\n * This is KEY for the two-call LLM strategy.\n */\nconst DEFAULT_MAX_STRING = 8000;\nconst MAX_JS_CODE = null;\n\n/**\n * Node normalization:\n * - Keep only useful fields for documentation\n * - Clean long parameters\n * - Keep jsCode intact\n */\nconst nodes = Array.isArray(wf.nodes) ? wf.nodes : [];\nconst cleanedNodes = nodes.map((n) => {\n  // Basic node metadata\n  const base = pick(n, [\n    \"id\",\n    \"name\",\n    \"type\",\n    \"typeVersion\",\n    \"position\",\n    \"disabled\",\n    \"notes\",\n    \"notesInFlow\",\n    \"retryOnFail\",\n    \"continueOnFail\",\n    \"alwaysOutputData\",\n    \"executeOnce\",\n  ]);\n\n  // Node parameters (the most important part for documentation)\n  const params = n?.parameters ?? {};\n\n  /**\n   * Controlled parameter trimming:\n   * - normal strings -> standard trim\n   * - parameters.jsCode -> DO NOT trim\n   */\n  const paramsTrimmed = JSON.parse(\n    JSON.stringify(params, (key, value) => {\n      if (typeof value !== \"string\") return value;\n\n      if (key === \"jsCode\") {\n        if (MAX_JS_CODE == null) return value; // keep code intact\n        return safeString(value, MAX_JS_CODE);\n      }\n\n      return safeString(value, DEFAULT_MAX_STRING);\n    })\n  );\n\n  base.parameters = paramsTrimmed;\n\n  /**\n   * Quick marker for triggers.\n   * Useful so the LLM can identify flow entry points.\n   */\n  const isTrigger =\n    typeof n?.type === \"string\" && n.type.toLowerCase().includes(\"trigger\");\n  base.isTrigger = isTrigger;\n\n  return base;\n});\n\n/**\n * Explicit extraction of Code nodes.\n * This allows the \"Code-only\" LLM to work with an input\n * that is small and very focused.\n */\nconst codeNodes = cleanedNodes\n  .filter((n) => n.type === \"n8n-nodes-base.code\")\n  .map((n) => {\n    const jsCode = n?.parameters?.jsCode ?? null;\n\n    return {\n      id: n.id,\n      name: n.name,\n      type: n.type,\n      jsCode, // keep code intact\n      lineCount: typeof jsCode === \"string\" ? jsCode.split(\"\\n\").length : 0,\n      charCount: typeof jsCode === \"string\" ? jsCode.length : 0,\n    };\n  });\n\n/**\n * Connection processing:\n * - edges: flat and easy-to-explain version\n * - connections: original structure (in case the LLM needs detail)\n */\nconst connections =\n  wf.connections && typeof wf.connections === \"object\"\n    ? wf.connections\n    : {};\nconst edges = flattenConnections(connections);\n\n/**\n * Minimal workflow settings useful for documentation\n */\nconst settings =\n  wf.settings && typeof wf.settings === \"object\"\n    ? pick(wf.settings, [\n        \"timezone\",\n        \"saveDataErrorExecution\",\n        \"saveDataSuccessExecution\",\n        \"saveManualExecutions\",\n        \"executionTimeout\",\n      ])\n    : {};\n\n/**\n * Final output:\n * - nodes: normalized nodes\n * - codeNodes: direct input for the Code-only LLM\n * - edges: flow reconstruction\n */\nreturn [\n  {\n    json: {\n      workflowName,\n      workflowId: wf.id ?? raw.id ?? null,\n      active:\n        typeof wf.active === \"boolean\"\n          ? wf.active\n          : typeof raw.active === \"boolean\"\n          ? raw.active\n          : null,\n      nodeCount: cleanedNodes.length,\n      edgeCount: edges.length,\n      nodes: cleanedNodes,\n      codeNodes,\n      edges,\n      connections,\n      settings,\n    },\n  },\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6b13daa6-58d1-433c-b277-315bd2a775fe",
      "name": "Generate Report",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "maxTries": 5,
      "position": [
        -992,
        -864
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "GPT-4.1"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "=## Role\nYou are an expert technical and functional documentation writer, specialized in automation with n8n. Your goal is to transform an n8n workflow JSON into a complete, clear, and well-structured documentation document following professional software engineering standards.\n\n### Mission\nBased on the provided JSON:\n1. **Purpose:** Explain the \u201cwhy\u201d of the workflow (business value).\n2. **Architecture:** Describe the logic by following the \u201cconnections\u201d graph.\n3. **Technical Configuration:** Detail parameters, especially translating n8n expressions (those starting with \u201c=\u201d and containing JS code) into clear natural language.\n4. **Governance:** Identify credentials, environment variables, and error-handling settings.\n\n### Technical Analysis Rules (Sources of Truth)\n* **Critical Path:** Do not list nodes alphabetically. Follow the workflow from the trigger through the connection indexes (main[0], etc.).\n* **Expression Interpretation:** If a parameter contains code inside curly braces, analyze the embedded JS. Explain which source nodes it references and what transformation it performs.\n* **Global Settings:** Review the \u201csettings\u201d object in the JSON to identify time zones, error handling, or timeouts applied to the entire workflow.\n* **Flow Control Nodes:** Explain in detail the conditions of IF, Switch, or Filter nodes, indicating which value is evaluated and what success/failure criteria exist.\n\n### What NOT to do\n* Do not invent endpoints or secrets.\n* If a value is sensitive and not hidden, replace it with [CONFIDENTIAL/REDACTED].\n* Do not assume external integrations that are not explicitly present in the node.\n\n### Output Format (Strict HTML)\nDeliver the document exclusively in HTML (using tags h2, h3, p, ul, li, table, strong). Do not use Markdown blocks.\n\n**Title (Centered):** `<h1>n8n Workflow Technical Documentation: {{ $json.workflowName }}</h1>`\n\n**Required Structure:**\n1. **Executive Summary** Problem solved and main data flow.\n2. **Workflow Global Configuration** (Extracted from \u201csettings\u201d) Retries, error handling, and status (active/inactive).\n3. **Workflow Overview** High-level stages.\n4. **Node-by-node (Detailed)**\n   * For each node:\n     * Node name.\n     * Type.\n     * Version.\n     * Function (input/output logic).\n     * Key configuration: Parameters and translation of JS expressions into human-readable language.\n     * Errors/risks (if applicable).\n5. **Routing Logic** Explanation of branches and conditions.\n6. **Credentials Management** Table with Node | Service | Credential Type | Usage.\n7. **Deployment and Operations Requirements**\n   * Variables, dependencies, permissions, environment considerations.\n8. **Risk Analysis and Observations** Based on the JSON (e.g., missing error nodes, dependency on external APIs, lack of retries, improvement proposals).\n\nBetween each section, add a line break.\n\n### Behavior in case of ambiguity\nIf the JSON is partial or connection data is missing, state: \u201cInformation not available in the original JSON\u201d. Do not make creative assumptions.\n"
            },
            {
              "content": "=Variable name = \"contexto_1\"  \nVariable value \"contexto_1\" = {{ JSON.stringify($json) }}\n\nYour task is to analyze exclusively the \"contexto_1\" variable and generate a complete documentation document in Markdown, following exactly the instructions from the system prompt.\n\nSpecific instructions\n\nUse only the information contained in the \"contexto_1\" variable.\n\nReconstruct the real workflow using `connections`.\n\nDescribe each node with its function, relevant configuration, and role within the workflow.\n\nClearly identify the required credentials, which nodes use them, and what access they are used for.\n\nDo not invent information or values.\n\nIf any data cannot be inferred, state it explicitly.\n\nOutput format\n\nReturn only the final document in HTML (no Markdown), with the sections defined in the system prompt, in the specified order and with no additional comments. Use `h1`, `h2`, `h3`, `p`, `ul`, `li`, `pre`, `code`, `strong`.\n"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 2.1,
      "waitBetweenTries": 3000
    },
    {
      "id": "8e81363f-c4a6-4782-b50e-0318a692025a",
      "name": "Collect Code Node Info",
      "type": "n8n-nodes-base.code",
      "position": [
        -640,
        -864
      ],
      "parameters": {
        "jsCode": "/**\n * Extract Code nodes (n8n Code node type) from a previously normalized workflow payload.\n * This produces a compact output focused only on JavaScript code blocks (jsCode),\n * useful for documentation, auditing, or sending to a \"code-only\" LLM step.\n */\n\n// Read the normalized nodes list from the \"Normalize Workflow JSON\" node output.\n// Fallback to an empty array if it's missing.\nconst nodes = $('Normalize Workflow JSON').first().json.nodes ?? [];\n\n/**\n * Build a minimal list of Code nodes:\n * - Keep only nodes with type \"n8n-nodes-base.code\"\n * - Extract basic identifiers plus the embedded JavaScript code (jsCode)\n */\nconst codeNodes = nodes\n  .filter(n => n.type === 'n8n-nodes-base.code')\n  .map(n => ({\n    id: n.id,\n    name: n.name,\n    jsCode: n.parameters?.jsCode ?? null\n  }));\n\n/**\n * Return a summary plus the extracted code nodes:\n * - codeNodeCount: number of Code nodes found\n * - codeNodes: array with { id, name, jsCode }\n */\nreturn [\n  {\n    json: {\n      codeNodeCount: codeNodes.length,\n      codeNodes\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "7fb03fd1-fc0e-4d46-922d-7481f0a8e58e",
      "name": "Are there Code Nodes?",
      "type": "n8n-nodes-base.if",
      "position": [
        -416,
        -864
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d27d4e55-a86c-4039-8721-f5d08f6982fd",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.codeNodeCount }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "f3d08594-41f5-4944-85b2-43c87756660c",
      "name": "Analyze Code Nodes",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "maxTries": 5,
      "position": [
        -192,
        -992
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "GPT-4.1"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "=# Role\nYou are an expert software technical analyst specialized in n8n. Your task is EXCLUSIVELY to interpret n8n \"Code\" node scripts (JavaScript) and perform a forensic analysis of the code to explain its logic, inputs, and outputs.\n\n## Analysis Rules:\n1. **Execution context:** Identify whether the code processes items individually or operates on the full array (`$input.all()`).\n2. **Dependencies:** Identify whether the script references other workflow nodes (`$node`) or global variables (`$vars`).\n3. **JS logic:** Translate the algorithmic logic (loops, mappings, filters) into easy-to-understand logical steps.\n4. **Data handling:** Describe which properties from the input JSON are kept, which are removed, and which are created from scratch.\n5. **No hallucination:** If the code uses a variable that is not defined within the script, flag it as **\"External Dependency Required\"**.\n\n## Mandatory output format (Strict HTML):\nDeliver a document exclusively in HTML (using tags `h2`, `h3`, `p`, `ul`, `li`, `strong`, `code`). Do not use Markdown code blocks (```).\n\nThe only title of the document must be: `<h2>Existing code nodes in the workflow</h2>`\n\n**Structure for each node:**\n\n<section>\n  <h3>Node: [NODE_NAME]</h3>\n  <ul>\n    <li><strong>ID:</strong> [NODE_ID]</li>\n    <li><strong>Summary:</strong> Brief description (1 sentence) of what the script does.</li>\n    <li><strong>Execution mode:</strong> (Individual execution or batch processing).</li>\n    <li><strong>Expected inputs:</strong> Specific fields the script looks for in the input JSON object.</li>\n    <li><strong>Outputs:</strong> Structure of the object returned by the script.</li>\n    <li><strong>Logical steps:</strong>\n      <ul>\n        <li>Step 1...</li>\n        <li>Step 2...</li>\n      </ul>\n    </li>\n    <li><strong>Errors/Risks:</strong> Potential failures (e.g., missing null validation, dependency on non-existing nodes, memory limits with large arrays).</li>\n  </ul>\n</section>\n"
            },
            {
              "content": "=/**\n * Input:\n * - \"code_nodes\": array of n8n Code nodes with: id, name, jsCode, lineCount, charCount\n *\n * Objective:\n * - Analyze exclusively \"code_nodes\"\n * - Explain each script in a verifiable way\n */\n\nVariable \"code_nodes\" =\n{{ JSON.stringify($json.codeNodes) }}\n\nInstructions:\n1) Iterate through \"code_nodes\" in order.\n2) For each node:\n   - \"Summary\": 3 to 6 sentences describing the purpose of the script and its outcome.\n   - \"Inputs\": list of data the script READS (e.g., `items[0].json`, `$json.field`, variables, env if present, etc.). If it cannot be determined, state it.\n   - \"Outputs\": list of data the script RETURNS or EMITS (e.g., `return [{ json: {...}}]`, added properties, expected structure).\n   - \"Steps\": numbered list in plain text (one action per line) describing the internal flow.\n   - \"Risks\": potential failures, fragile assumptions, side effects, or maintenance pain points.\n"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 2.1,
      "waitBetweenTries": 3000
    },
    {
      "id": "db52b906-31b9-4cee-8fdc-6a034e552fe6",
      "name": "Merge Report and Code Node Analysis",
      "type": "n8n-nodes-base.set",
      "position": [
        160,
        -992
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a54ab032-fc83-4340-8050-08a82fb473f5",
              "name": "=complete_text",
              "type": "string",
              "value": "={{ $('Generate Report').item.json.output[0].content[0].text }}\n<br>\n\n{{ $json.output[0].content[0].text }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f40e3040-a542-4e7b-a3ae-be40f58e4508",
      "name": "Create Google Docs Document",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 5,
      "position": [
        384,
        -992
      ],
      "parameters": {
        "url": "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true",
        "body": "=--foo_bar_baz\nContent-Type: application/json; charset=UTF-8\n\n{\n  \"name\": \"{{ $('Normalize Workflow JSON').item.json.workflowName }}_Technical Documentation\",\n  \"mimeType\": \"application/vnd.google-apps.document\",\n  \"parents\": [\"YOUR_FOLDER_ID\"]\n}\n\n--foo_bar_baz\nContent-Type: text/html; charset=UTF-8\n\n{{ $json.complete_text }}\n\n--foo_bar_baz--",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendQuery": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "rawContentType": "multipart/related; boundary=foo_bar_baz",
        "queryParameters": {
          "parameters": [
            {
              "name": "uploadType",
              "value": "multipart"
            },
            {
              "name": "supportsAllDrives",
              "value": "true"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {}
          ]
        },
        "nodeCredentialType": "googleDriveOAuth2Api"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "waitBetweenTries": 3000
    },
    {
      "id": "b1b2949f-e722-4a63-870c-af0a2a20858e",
      "name": "Create Google Docs Document_1",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 5,
      "position": [
        -192,
        -736
      ],
      "parameters": {
        "url": "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true",
        "body": "=--foo_bar_baz\nContent-Type: application/json; charset=UTF-8\n\n{\n  \"name\": \"{{ $('Normalize Workflow JSON').item.json.workflowName }}_Technical documentation\",\n  \"mimeType\": \"application/vnd.google-apps.document\",\n  \"parents\": [\"YOUR_FOLDER_ID\"]\n}\n\n--foo_bar_baz\nContent-Type: text/html; charset=UTF-8\n\n{{ $('Generate Report').item.json.output[0].content[0].text }}\n\n--foo_bar_baz--",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendQuery": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "rawContentType": "multipart/related; boundary=foo_bar_baz",
        "queryParameters": {
          "parameters": [
            {
              "name": "uploadType",
              "value": "multipart"
            },
            {
              "name": "supportsAllDrives",
              "value": "true"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {}
          ]
        },
        "nodeCredentialType": "googleDriveOAuth2Api"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "waitBetweenTries": 3000
    },
    {
      "id": "d3b0c444-8a78-4ec5-8b1b-d27bc9cb44c2",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -816,
        160
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1ultzktRcOF1XNL0C_pAuEEkBOzXiFq2o#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "c4ece376-1f70-4502-83c0-789426846a31",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        160
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1hrx93ZVnAe_7PG_pJDlGjZ9-EuneUVTQ#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "5ce1fb6b-317c-4f96-b3fc-8df1b53d58c6",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        160
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1aBgb7KGZEiGPkTsxTxBTLy3yLVaXvqqj#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "c9aa3930-fa5e-4a0f-b002-96c776298c5f",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        160
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1Tvq74Ul3TfamDU0HxI5ug6xhXHSYAszu#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "3294717d-60bc-45f0-aff9-acae03c831f5",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        160
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1FWfXYYykClqd89shOR8Bi2QoNRA97jXD#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "45f2ec60-9bfa-4701-b933-79fdf6590511",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -816,
        -432
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1MR1REAL3Iotg4DPNKcwee6hnRInLSv1m#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "92a8797d-e0e2-4e63-bedb-e07c4a3fc855",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        -432
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1PPdhDp1TqCM7wP_OIm-Zw39AwC-dwPWz#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "d117c5df-fb89-49e3-aa6e-4bf3b21dc5e8",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -432
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1pWplUg5-VInxFCDSESzCzvmHLqvI1TiR#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "d4199004-d219-4957-9218-5632e9da3da8",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        -432
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1J4b9_sOdIKUqic1GcnDJ5eNtsXEPtcxg#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "10d65d74-680c-4ebd-aa20-c29a493d8c40",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        -432
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 576,
        "content": "![Mi imagen](https://lh3.googleusercontent.com/d/1p46mjrexkHLLfVhT0krU4HPRlPa2sZuy#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "763e8235-e2a4-402d-ae84-cf3a019ccc1e",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        -544
      ],
      "parameters": {
        "color": 6,
        "width": 320,
        "height": 96,
        "content": "\n\n## FINAL REPORT EXAMPLE"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "31dbe834-f542-48e3-a4fe-00edbdade14f",
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Select Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Report": {
      "main": [
        [
          {
            "node": "Collect Code Node Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Workflow": {
      "main": [
        [
          {
            "node": "Normalize Workflow JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Code Nodes": {
      "main": [
        [
          {
            "node": "Merge Report and Code Node Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Are there Code Nodes?": {
      "main": [
        [
          {
            "node": "Analyze Code Nodes",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Google Docs Document_1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect Code Node Info": {
      "main": [
        [
          {
            "node": "Are there Code Nodes?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Workflow JSON": {
      "main": [
        [
          {
            "node": "Generate Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Google Docs Document_1": {
      "main": [
        []
      ]
    },
    "Merge Report and Code Node Analysis": {
      "main": [
        [
          {
            "node": "Create Google Docs Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}