{
  "meta": {
    "instanceId": "workflow-5ce3a406",
    "versionId": "1.0.0",
    "createdAt": "2025-09-29T07:07:42.946189",
    "updatedAt": "2025-09-29T07:07:42.946198",
    "owner": "n8n-user",
    "license": "MIT",
    "category": "automation",
    "status": "active",
    "priority": "high",
    "environment": "production"
  },
  "nodes": [
    {
      "id": "c4dca8f0-98fa-4b06-a806-1ab271f024a2",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        120,
        460
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a916dcbd-d681-4e09-9ce9-0f50a1b4290b",
              "name": "keep",
              "type": "string",
              "value": "=last"
            },
            {
              "id": "949a2f76-5981-4fd2-9665-b10db26e2f48",
              "name": "action",
              "type": "string",
              "value": "=flag"
            },
            {
              "id": "7f4502b4-c330-4c9c-ab89-ba53874aafbb",
              "name": "owner",
              "type": "string",
              "value": "={{ $json.owner || $json.owners[0].emailAddress }}"
            },
            {
              "id": "592eb79e-28db-4470-8347-36b2a661cb03",
              "name": "folder",
              "type": "string",
              "value": "={{ $json.folder || $json.parents[0]}}"
            }
          ]
        }
      },
      "typeVersion": 3.4,
      "notes": "This set node performs automated tasks as part of the workflow."
    },
    {
      "id": "2562ed4a-8ecd-4a32-ae51-bc85daa9817b",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        1800,
        440
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1d28f976-2467-4d18-8698-556d29a5f8c0",
              "name": "isDuplicate",
              "type": "boolean",
              "value": "={{ $json.isDuplicate }}"
            },
            {
              "id": "e9d8eb20-7668-4287-bfb4-d4f66c019f73",
              "name": "id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "587e5f8e-bd94-4ec5-80f2-066c99922135",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4,
      "notes": "This set node performs automated tasks as part of the workflow."
    },
    {
      "id": "e7f0482c-77c7-46a0-8a36-e61bb624c422",
      "name": "Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        2020,
        440
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "bd33247c-4c88-4c0b-bdfe-6f9dca0205e3",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isDuplicate }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "notes": "This filter node performs automated tasks as part of the workflow."
    },
    {
      "id": "28768732-29a4-4446-8b12-dda187976bf9",
      "name": "Deduplicate Keep First",
      "type": "n8n-nodes-base.code",
      "position": [
        1580,
        560
      ],
      "parameters": {
        "jsCode": "// Sort files by creation time (oldest first)\nconst sorted = items.sort((a, b) => \n  new Date(a.json.createdTime) - new Date(b.json.createdTime));\n\nconst seen = {};\nfor (const item of sorted) {\n  const md5 = item.json.md5Checksum;\n\n  // Failsafe: Skip if md5Checksum is missing or empty\n  if (!md5) {\n    item.json.isDuplicate = false; // Mark as not duplicate to avoid issues\n    continue; // Skip to the next item\n  }\n\n  item.json.isDuplicate = md5 in seen;\n  if (!item.json.isDuplicate) seen[md5] = true;\n}\nreturn items;"
      },
      "executeOnce": false,
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "1f6f9529-2283-4806-ad5a-b0425f9f68e2",
      "name": "Deduplicate Keep Last",
      "type": "n8n-nodes-base.code",
      "position": [
        1580,
        360
      ],
      "parameters": {
        "jsCode": "// Sort files by creation time (latest first)\nconst sorted = items.sort((a, b) => \n  new Date(b.json.createdTime) - new Date(a.json.createdTime));\n\nconst seen = {};\nfor (const item of sorted) {\n  const md5 = item.json.md5Checksum;\n\n  // Failsafe: Skip if md5Checksum is missing or empty\n  if (!md5) {\n    item.json.isDuplicate = false; // Mark as not duplicate to avoid issues\n    continue; // Skip to the next item\n  }\n\n  if (md5 in seen) {\n    item.json.isDuplicate = true;\n  } else {\n    item.json.isDuplicate = false;\n    seen[md5] = true;\n  }\n}\nreturn items;"
      },
      "executeOnce": false,
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "c5250dd1-6eeb-4b89-b2e7-e44a8d88212c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        -120
      ],
      "parameters": {
        "color": 5,
        "width": 440,
        "height": 800,
        "content": "# 2. Configuration\nChoose the **keep** and **action** behavior of the workflow\n\n1. The **keep** parameter let's you decide whether to keep the first or last received file when duplicates are detected. (possible values: `first`, `last`. Default: `last`)\n2. The **action** parameter let's you decide what to do with the detected duplicates. Send them to the trash or flag them by renaming them with prefix DUPLICATE- (possible values: `trash`, `flag`. Default: `flag`) flag already prexied by DUPLICATE- are not flagged again.\n\n\nThe parameters `owner` and `folder` are taken from the trigger and will probably never need to be changed:\n- The **folder** points to the folder to work with. By default it is taken from the trigger.\n- The **owner** parameter needs to match the owner of the files. The workflow only works with files owned by this user. It is specified with the user email and is taken from the first file owner of the trigger."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "67c4d02f-b170-4504-9bae-7bf14db7abd3",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        460,
        180
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 500,
        "content": "## Working Folder\nThe \"Working Folder\" node let's you choose Files to deduplicate.\n\nThis workflow includes a filter to work on just 1 folder at depth level 1. It doesn't work with files in nested folders\n\nYou can remove the Folder filter to work on the entire drive instead or add different filters."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "9ed26ef0-da89-43c5-9e12-2ec97b2e51f6",
      "name": "Send Duplicates to Trash",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2760,
        320
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "deleteFile"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "VypmUgEf64twpmiZ",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3,
      "notes": "This googleDrive node performs automated tasks as part of the workflow."
    },
    {
      "id": "fcfd08fa-7a19-4974-b3bb-6ed27a2030cf",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2800,
        600
      ],
      "parameters": {},
      "typeVersion": 1,
      "notes": "This noOp node performs automated tasks as part of the workflow."
    },
    {
      "id": "de7967e7-eb3b-456c-b12e-6de3165ad29a",
      "name": "Is Flagged",
      "type": "n8n-nodes-base.if",
      "position": [
        2540,
        620
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c8d8eac5-e03a-4673-bcf9-a8acaa95cb8e",
              "operator": {
                "type": "string",
                "operation": "startsWith"
              },
              "leftValue": "={{ $('Trash/Flag Duplicates').item.json.name }}",
              "rightValue": "DUPLICATE-"
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "notes": "This if node performs automated tasks as part of the workflow."
    },
    {
      "id": "d227d6ee-97e7-4b4d-b1a2-4cd402be99d5",
      "name": "Google Drive Trigger",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        -360,
        460
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyX",
              "unit": "minutes",
              "value": 15
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "1-tjf96Ooj0SL8qaE04BGIeCGnd-O1R8c",
          "cachedResultUrl": "{{ $env.WEBHOOK_URL }}",
          "cachedResultName": "2025/04\n"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "VypmUgEf64twpmiZ",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 1,
      "notes": "This googleDriveTrigger node performs automated tasks as part of the workflow."
    },
    {
      "id": "22e1638e-5c2e-41bc-b66e-fcee6af05762",
      "name": "Drop Google Apps files",
      "type": "n8n-nodes-base.filter",
      "position": [
        940,
        460
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1e7d9666-fba0-4fe7-b03a-1a4e5c07b389",
              "operator": {
                "type": "string",
                "operation": "notStartsWith"
              },
              "leftValue": "={{ $json.mimeType }}",
              "rightValue": "application/vnd.google-apps"
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "notes": "This filter node performs automated tasks as part of the workflow."
    },
    {
      "id": "ec80f4de-5dff-4693-bff4-2509fd581d70",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        840,
        180
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 500,
        "content": "# Discard found Google Apps documents\nDocs, Sheets, Forms, Slides, Drawins etc. are discarded because they are not actual binary files and their content can't be directly checked."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "66ee766a-3dea-449f-827c-1922c6e053f3",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -520,
        -120
      ],
      "parameters": {
        "color": 5,
        "width": 440,
        "height": 800,
        "content": "# 1. Trigger Settings and Working Folder\n\nWhen using Google Drive Trigger configure the **Poll times** and the **Folder** to work with.\n\nBy Default the trigger is configured to check for *file uploads* every 15 minutes.\n\nWhen configured with a specific folder in the drive the workflow works only with files directly in the folder (It will not check/modify files in sub-folders).\n\nWhen configured with the root (/) folder of the drive it will check all files in all folders and sub-folders so **USE THIS WITH CAUTION** since it might lead to trashing/renaming of important files. "
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "6f8a7855-2ee3-426d-879f-afb303d5aa20",
      "name": "Working Folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        560,
        460
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "id",
            "value": "={{ $('Config').item.json.folder }}"
          },
          "whatToSearch": "files"
        },
        "options": {
          "fields": [
            "*"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "='{{$('Config').item.json.owner}}' in owners",
        "searchMethod": "query"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "VypmUgEf64twpmiZ",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3,
      "notes": "This googleDrive node performs automated tasks as part of the workflow."
    },
    {
      "id": "6f69e6d3-96ca-4411-9a48-160ebdb2a273",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2500,
        540
      ],
      "parameters": {
        "color": 7,
        "width": 540,
        "height": 220,
        "content": "### Files that already start with *DUPLICATE-* are not flagged again."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "65b4ba42-89ce-437c-a3e8-bf3f9b01cc21",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2500,
        780
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 240,
        "content": "### In Google Drive Trashed files are kept for 30 days before being permanently deleted. \nThey can be reviewed and restored during that 30 day interval."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "99374aa8-e597-4919-8b64-c376b246621a",
      "name": "Google Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2880,
        800
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "update",
        "newUpdatedFileName": "=DUPLICATE-{{ $json.name }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "VypmUgEf64twpmiZ",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3,
      "notes": "This googleDrive node performs automated tasks as part of the workflow."
    },
    {
      "id": "6ae62c31-4cf0-48e7-aa42-19fc259c5981",
      "name": "Keep First/Last",
      "type": "n8n-nodes-base.switch",
      "position": [
        1300,
        460
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "YOUR_CREDENTIAL_HERE",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "7f5ba21d-8f3d-4736-9c34-ac7ebd6a9699",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Config').item.json.keep }}",
                    "rightValue": "last"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "YOUR_CREDENTIAL_HERE",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "93a013f6-6c59-47ad-bce3-8b34cc8f026c",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Config').item.json.keep }}",
                    "rightValue": "first"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2,
      "notes": "This switch node performs automated tasks as part of the workflow."
    },
    {
      "id": "9cb84da7-3cd9-4a53-af09-8b63f1cf8a34",
      "name": "Trash/Flag Duplicates",
      "type": "n8n-nodes-base.switch",
      "position": [
        2240,
        440
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "YOUR_CREDENTIAL_HERE",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "0314ac48-e7b7-406b-abcd-8cd1ab872c79",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Config').item.json.action }}",
                    "rightValue": "trash"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "YOUR_CREDENTIAL_HERE",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "70d8e5f1-16a6-4921-ad9c-ab00049e507d",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Config').item.json.action }}",
                    "rightValue": "flag"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2,
      "notes": "This switch node performs automated tasks as part of the workflow."
    },
    {
      "id": "error-91f1820f",
      "name": "Error Handler",
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        1000,
        400
      ],
      "parameters": {
        "message": "Workflow execution error",
        "options": {}
      }
    }
  ],
  "pinData": {},
  "connections": {
    "9ed26ef0-da89-43c5-9e12-2ec97b2e51f6": {
      "main": [
        [
          {
            "node": "error-handler-9ed26ef0-da89-43c5-9e12-2ec97b2e51f6-5cbd3271",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d227d6ee-97e7-4b4d-b1a2-4cd402be99d5": {
      "main": [
        [
          {
            "node": "error-handler-d227d6ee-97e7-4b4d-b1a2-4cd402be99d5-e147cf13",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6f8a7855-2ee3-426d-879f-afb303d5aa20": {
      "main": [
        [
          {
            "node": "error-handler-6f8a7855-2ee3-426d-879f-afb303d5aa20-17cf1d9d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "99374aa8-e597-4919-8b64-c376b246621a": {
      "main": [
        [
          {
            "node": "error-handler-99374aa8-e597-4919-8b64-c376b246621a-63f9953a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "name": "Set Workflow",
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": null,
    "timezone": "UTC",
    "executionTimeout": 3600,
    "maxExecutions": 1000,
    "retryOnFail": true,
    "retryCount": 3,
    "retryDelay": 1000
  },
  "description": "Automated workflow: Set Workflow. This workflow integrates 10 different services: filter, stickyNote, googleDriveTrigger, code, googleDrive. It contains 24 nodes and follows best practices for error handling and security.",
  "tags": [
    "automation",
    "n8n",
    "production-ready",
    "excellent",
    "optimized"
  ],
  "notes": "Excellent quality workflow: Set Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."
}