{
  "nodes": [
    {
      "id": "6030c13d-17ff-4f71-9ce2-0edb90eefe70",
      "name": "Sticky_Quarantine",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        2000
      ],
      "parameters": {
        "color": 7,
        "width": 578,
        "height": 412,
        "content": "## \u26a0\ufe0f ERROR HANDLING\nQuarantine zone for failed decryptions, invalid keys, and corrupted files. All failures logged for manual review."
      },
      "typeVersion": 1
    },
    {
      "id": "21d5bd3f-de38-42a3-935b-9f0a8851db27",
      "name": "IF: File Validator",
      "type": "n8n-nodes-base.if",
      "position": [
        -64,
        1632
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.mimeType }}",
              "rightValue": "application/pdf"
            },
            {
              "operator": {
                "type": "number",
                "operation": "smaller"
              },
              "leftValue": "={{ $json.fileSize }}",
              "rightValue": "104857600"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "7adf83f8-48ab-421e-aac3-1f2fe3c42c2c",
      "name": "IF: Key Found",
      "type": "n8n-nodes-base.if",
      "position": [
        416,
        1632
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.password }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "326cdef0-edee-44b2-a7ef-19e77d116c4c",
      "name": "Postgres: Audit Logger",
      "type": "n8n-nodes-base.postgres",
      "position": [
        976,
        1584
      ],
      "parameters": {
        "query": "INSERT INTO audit_log \n(custody_id, file_name, original_hash, unlocked_hash, file_size, \n intake_timestamp, unlock_timestamp, processing_time_ms, \n integrity_status, processing_status, key_id, encryption_type)\nVALUES \n('{{ $json.custodyID }}', '{{ $json.fileName }}', '{{ $json.originalHash }}', \n '{{ $json.unlockedHash }}', {{ $json.fileSize }}, \n '{{ $json.intakeTimestamp }}', '{{ $json.unlockTimestamp }}', \n {{ $json.processingTimeMs }}, '{{ $json.integrityStatus }}', \n '{{ $json.processingStatus }}', '{{ $json.key_id }}', '{{ $json.encryption_type }}')\nRETURNING audit_id;",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.4
    },
    {
      "id": "4ae38931-c4f9-43eb-872f-5c8e4bff6704",
      "name": "Postgres: Quarantine Log",
      "type": "n8n-nodes-base.postgres",
      "position": [
        592,
        2128
      ],
      "parameters": {
        "query": "INSERT INTO quarantine_log \n(custody_id, file_name, failure_reason, failure_timestamp, original_hash, quarantine_status)\nVALUES \n('{{ $json.custodyID }}', '{{ $json.fileName }}', \n '{{ $json.failureReason || \"Key not found in vault\" }}', \n '{{ $now.toISO() }}', '{{ $json.originalHash }}', 'PENDING_REVIEW')\nRETURNING quarantine_id;",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.4
    },
    {
      "id": "4e043139-b7eb-4084-90d6-f18e1b9f395b",
      "name": "Slack: Quarantine Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        752,
        2192
      ],
      "parameters": {
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "93291786-5874-46e1-98bf-d604ed8ed951",
      "name": "Google Drive: Quarantine Vault",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        944,
        2128
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": "QUARANTINE_VAULT"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "d884a84e-3c81-434f-9d34-e49a1b3d511e",
      "name": "Postgres: Validation Failure",
      "type": "n8n-nodes-base.postgres",
      "position": [
        48,
        1776
      ],
      "parameters": {
        "query": "INSERT INTO file_validation_failures \n(custody_id, file_name, mime_type, file_size, failure_reason, timestamp)\nVALUES \n('{{ $json.custodyID }}', '{{ $json.fileName }}', '{{ $json.mimeType }}', \n {{ $json.fileSize }}, 'Invalid file type or size exceeds limit', '{{ $now.toISO() }}')",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.4
    },
    {
      "id": "861fe3de-d59a-40e3-8815-19e1510b49ef",
      "name": "Sticky_Intake1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -288,
        1312
      ],
      "parameters": {
        "color": 7,
        "width": 450,
        "height": 650,
        "content": "## \ud83d\udee1\ufe0f PHASE 1: Intake & Custody\nFetches encrypted files. Generates an initial SHA-256 hash to track the original state of the legacy data before any modification. Validates file types and sizes."
      },
      "typeVersion": 1
    },
    {
      "id": "35459a7b-b829-429e-bf79-0fbc5b36aab8",
      "name": "Sticky_Unlock1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        1312
      ],
      "parameters": {
        "color": 7,
        "width": 600,
        "height": 650,
        "content": "## \ud83d\udd10 PHASE 2: Key Vault & Unlock\nMatches file metadata with the SQL Key Vault. **Unlock Node** strips protection. Parallel branch handles 'Key Failure' quarantine logic with retry mechanism."
      },
      "typeVersion": 1
    },
    {
      "id": "b23463f3-f25a-491b-98f7-ae4ce6824d12",
      "name": "Sticky_Audit1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        1312
      ],
      "parameters": {
        "color": 7,
        "width": 646,
        "height": 650,
        "content": "## \u2696\ufe0f PHASE 3: Audit & Archival\nLogs forensic metadata to Postgres. Moves decrypted assets to the Secure Audit Vault. Notifies Legal of the processed batch with comprehensive reports."
      },
      "typeVersion": 1
    },
    {
      "id": "2f5a4d50-dcf1-42aa-99c1-9d9dfcc145b9",
      "name": "Code: Forensic Intake1",
      "type": "n8n-nodes-base.code",
      "position": [
        -224,
        1632
      ],
      "parameters": {
        "jsCode": "// Code Node: SHA-256 Fingerprinting & Metadata Extraction\nconst crypto = require('crypto');\nconst items = $input.all();\n\nreturn items.map(item => {\n    const binary = item.binary.data;\n    const buffer = Buffer.from(binary.data, 'base64');\n    \n    // Generate forensic hash\n    item.json.originalHash = crypto.createHash('sha256').update(buffer).digest('hex');\n    \n    // Create custody ID with timestamp\n    const timestamp = new Date().toISOString().replace(/[-:]/g, '').split('.')[0];\n    item.json.custodyID = `DISCOVERY-${timestamp}-${Math.random().toString(36).substring(2, 8).toUpperCase()}`;\n    \n    // Extract metadata\n    item.json.fileSize = buffer.length;\n    item.json.intakeTimestamp = new Date().toISOString();\n    item.json.mimeType = binary.mimeType || 'application/pdf';\n    item.json.fileName = item.json.name || 'unknown.pdf';\n    item.json.processingStatus = 'INTAKE_COMPLETE';\n    \n    return item;\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "c51e84c6-2485-4439-9246-60179d39b7aa",
      "name": "Postgres: Key Vault1",
      "type": "n8n-nodes-base.postgres",
      "position": [
        256,
        1632
      ],
      "parameters": {
        "query": "SELECT password, key_id, encryption_type, created_date \nFROM legacy_keys \nWHERE filename = '{{ $json.fileName }}' \nAND active = true \nORDER BY created_date DESC \nLIMIT 1",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.4
    },
    {
      "id": "7592e1f2-15c6-4bb0-a498-37e72068d58d",
      "name": "HTML to PDF: Unlock Engine1",
      "type": "n8n-nodes-htmlcsstopdf.htmlcsstopdf",
      "position": [
        608,
        1520
      ],
      "parameters": {
        "resource": "pdfManipulation",
        "operation": "unlockPdf"
      },
      "credentials": {
        "htmlcsstopdfApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "867b0eda-793b-4c74-9876-048eec7dbf78",
      "name": "Code: Integrity Guard1",
      "type": "n8n-nodes-base.code",
      "position": [
        816,
        1552
      ],
      "parameters": {
        "jsCode": "// Code Node: Post-Unlock Integrity Validation\nconst item = $input.first();\nconst crypto = require('crypto');\n\ntry {\n    const buffer = Buffer.from(item.binary.data.data, 'base64');\n    \n    // Generate hash of unlocked file\n    item.json.unlockedHash = crypto.createHash('sha256').update(buffer).digest('hex');\n    item.json.unlockedSize = buffer.length;\n    item.json.unlockTimestamp = new Date().toISOString();\n    \n    // Verify unlock was successful (hashes should differ)\n    if (item.json.originalHash === item.json.unlockedHash) {\n        item.json.integrityStatus = 'WARNING: Hashes identical - possible unlock failure';\n        item.json.processingStatus = 'UNLOCK_SUSPICIOUS';\n    } else {\n        item.json.integrityStatus = 'VERIFIED: File successfully decrypted';\n        item.json.processingStatus = 'UNLOCK_SUCCESS';\n    }\n    \n    // Calculate processing time\n    const intakeTime = new Date(item.json.intakeTimestamp);\n    const unlockTime = new Date(item.json.unlockTimestamp);\n    item.json.processingTimeMs = unlockTime - intakeTime;\n    \n} catch (error) {\n    item.json.integrityStatus = `ERROR: ${error.message}`;\n    item.json.processingStatus = 'UNLOCK_FAILED';\n}\n\nreturn item;"
      },
      "typeVersion": 2
    },
    {
      "id": "db664b16-1a47-45fc-bacd-c790c2ecea41",
      "name": "Google Drive: Audit Vault1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1136,
        1520
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": "={{ 'AUDIT_VAULT_' + $json.custodyID.split('-')[1] }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "4e4d3ab8-ee2c-470b-92ce-fd51f8f5f8b2",
      "name": "Slack: Compliance Log1",
      "type": "n8n-nodes-base.slack",
      "position": [
        1312,
        1456
      ],
      "parameters": {
        "operation": "create",
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "518a0b1d-c397-4332-b694-c33b3a0310d2",
      "name": "Gmail: Legal Summary1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1312,
        1648
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=**Legacy Document Decryption Report**\n\n**Custody ID:** {{ $json.custodyID }}\n**File Name:** {{ $json.fileName }}\n**Original Hash:** {{ $json.originalHash }}\n**Unlocked Hash:** {{ $json.unlockedHash }}\n**File Size:** {{ ($json.fileSize / 1024 / 1024).toFixed(2) }} MB\n\n**Processing Details:**\n- Intake: {{ $json.intakeTimestamp }}\n- Unlock: {{ $json.unlockTimestamp }}\n- Duration: {{ $json.processingTimeMs }}ms\n\n**Status:** {{ $json.processingStatus }}\n**Integrity:** {{ $json.integrityStatus }}\n\n**Audit Trail:** Logged in database as Audit ID {{ $json.audit_id }}\n**Vault Location:** Google Drive folder AUDIT_VAULT_{{ $json.custodyID.split('-')[1] }}\n\nThis file is now available for legal discovery search indexing.\n\n---\nAutomated Legal Compliance System",
        "options": {},
        "subject": "=\u2705 Decryption Complete: {{ $json.custodyID }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "4c0674f1-b0cb-4aef-bf43-401b686e66bd",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        656
      ],
      "parameters": {
        "width": 464,
        "height": 624,
        "content": "## \u2696\ufe0f Sovereign Decryption & Compliance Gateway v10.0\n\nIndustrial-grade pipeline for the bulk unlocking, indexing, and forensic archival of legacy protected assets.\n\n### \u2699\ufe0f Core Sovereign Logic\n* **PHASE 1: Forensic Intake:** Validates PDF integrity and generates SHA-256 fingerprints to maintain document \"Chain of Custody.\"\n* **PHASE 2: Key Vault Orchestration:** Queries PostgreSQL to match legacy filenames with historical encryption passwords.\n* **PHASE 3: Atomic Unlock:** Compulsory use of **HTML to PDF (Unlock)** to strip passwords and restore full searchability.\n* **PHASE 4: Integrity Guard:** Validates decryption success via binary comparison and logs processing metrics.\n* **PHASE 5: Compliance Archival:** Vaults files in Google Drive and triggers multi-channel alerts (Slack/Gmail).\n\n### \ud83d\udccb Setup & Prerequisites\n1. **Compulsory Node:** **HTML to PDF (Unlock)** for core decryption.\n2. **Databases:** PostgreSQL tables for `legacy_keys`, `audit_log`, and `quarantine_log`.\n3. **Folders:** Define Drive IDs for the Audit Vault and Quarantine Zone.\n\n**Metrics:** `Unlock_Success_Rate`, `Processing_Latency`, `Compliance_Audit_Hash`."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "IF: Key Found": {
      "main": [
        [
          {
            "node": "HTML to PDF: Unlock Engine1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Postgres: Quarantine Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: File Validator": {
      "main": [
        [
          {
            "node": "Postgres: Key Vault1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Postgres: Validation Failure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres: Key Vault1": {
      "main": [
        [
          {
            "node": "IF: Key Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Forensic Intake1": {
      "main": [
        [
          {
            "node": "IF: File Validator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Integrity Guard1": {
      "main": [
        [
          {
            "node": "Postgres: Audit Logger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres: Audit Logger": {
      "main": [
        [
          {
            "node": "Google Drive: Audit Vault1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Quarantine Alert": {
      "main": [
        [
          {
            "node": "Google Drive: Quarantine Vault",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres: Quarantine Log": {
      "main": [
        [
          {
            "node": "Slack: Quarantine Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive: Audit Vault1": {
      "main": [
        [
          {
            "node": "Slack: Compliance Log1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Gmail: Legal Summary1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTML to PDF: Unlock Engine1": {
      "main": [
        [
          {
            "node": "Code: Integrity Guard1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}