{
  "id": "3oSRSvRBcVydac9J",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Clinical Trial Participant Consent Management with Digital Audit Trail and Claude AI",
  "tags": [],
  "nodes": [
    {
      "id": "e88cf9f1-ba27-4451-b167-6b0418d5609a",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1408,
        352
      ],
      "parameters": {
        "width": 780,
        "height": 1208,
        "content": "## Clinical Trial Consent Management with Digital Audit Trail & Claude AI\n\nThis workflow automates end-to-end e-consent management for clinical trials. It captures, validates, timestamps, and stores consent submissions with a full regulatory-compliant audit trail, notifies investigators and participants, and runs daily compliance checks for missing or expiring consents.\n\n### How it works\n\n1. **Capture E-Consent** - Webhook receives signed consent submission from participant portal\n2. **Validate & Timestamp** - Verifies all required fields, applies cryptographic timestamp for legal validity\n3. **Claude AI Compliance Check** - Reviews consent form completeness against ICH E6 GCP guidelines\n4. **Store with Audit Trail** - Writes immutable record to Google Sheets with full chain of custody\n5. **Notify PI & Participant** - Sends confirmation emails to principal investigator and participant\n6. **Daily Expiry Sweep** - Scheduled job checks for expiring or missing consents\n7. **Generate Compliance Report** - Produces daily audit summary for regulatory submission\n\n### Setup Steps\n\n1. Import workflow into n8n\n2. Configure credentials:\n   - **Anthropic API** - Claude AI for compliance review\n   - **Google Sheets** - Consent records and audit log\n   - **SMTP / Gmail** - Email notifications to PI and participants\n   - **DocuSign API** (optional) - For e-signature verification\n3. Set your trial ID, IRB number, and PI email in the `Build Consent Record` node\n4. Update expiry thresholds in the `Daily Expiry Sweep` node\n5. Activate both the webhook and scheduled workflows\n\n### Sample Consent Payload\n```json\n{\n  \"trialId\": \"TRIAL-2025-001\",\n  \"participantId\": \"P-10042\",\n  \"participantEmail\": \"participant@email.com\",\n  \"participantName\": \"Jane Doe\",\n  \"consentFormVersion\": \"v3.2\",\n  \"consentDate\": \"2025-02-22T10:00:00Z\",\n  \"signatureData\": \"base64_signature_string\",\n  \"witnessName\": \"Dr. Smith\",\n  \"capacityConfirmed\": true,\n  \"rightToWithdrawExplained\": true,\n  \"risksExplained\": true,\n  \"questionsAnswered\": true\n}\n```\n\n### Features\n- **ICH E6 GCP compliant** validation with Claude AI review\n- **Immutable audit trail** with hash-based record integrity\n- **Automated expiry alerts** for re-consent workflows\n- **Daily compliance report** ready for IRB/regulatory submission\n- **Full chain of custody** \u2014 who captured, reviewed, and stored every record"
      },
      "typeVersion": 1
    },
    {
      "id": "96e0990d-4474-4654-b0f2-6556b9cbe879",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2416,
        512
      ],
      "parameters": {
        "color": 3,
        "width": 440,
        "height": 328,
        "content": "## 1. Consent Capture & Validation"
      },
      "typeVersion": 1
    },
    {
      "id": "caec55ae-0a7e-41f9-ab11-9fa69b523a5d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2912,
        368
      ],
      "parameters": {
        "color": 3,
        "width": 812,
        "height": 668,
        "content": "## 2. AI Compliance Review & Audit Record"
      },
      "typeVersion": 1
    },
    {
      "id": "bca0a4dc-304f-4b13-ac60-d354b5fd010f",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3760,
        352
      ],
      "parameters": {
        "color": 3,
        "width": 1104,
        "height": 700,
        "content": "## 3. Store, Notify & Confirm"
      },
      "typeVersion": 1
    },
    {
      "id": "e149384d-b0a1-4da8-b6d9-ec51905bc962",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2480,
        1200
      ],
      "parameters": {
        "color": 3,
        "width": 1380,
        "height": 364,
        "content": "## 4. Daily Compliance Sweep & Reporting"
      },
      "typeVersion": 1
    },
    {
      "id": "da0e9618-4357-4f8a-937d-8df15dea93ce",
      "name": "Receive E-Consent Submission",
      "type": "n8n-nodes-base.webhook",
      "position": [
        2496,
        672
      ],
      "parameters": {
        "path": "clinical-consent",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "ab1e8bff-aadd-4e2c-8224-2aec49e033f0",
      "name": "Validate and Timestamp Consent",
      "type": "n8n-nodes-base.code",
      "position": [
        2720,
        672
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Extract consent submission from request body\nconst body = $input.item.json.body || $input.item.json;\n\n// --- Required field validation (ICH E6 GCP mandatory elements) ---\nconst requiredFields = [\n  'trialId', 'participantId', 'participantEmail', 'participantName',\n  'consentFormVersion', 'consentDate', 'signatureData'\n];\nconst missing = requiredFields.filter(f => !body[f]);\nif (missing.length > 0) {\n  throw new Error(`GCP Compliance Failure - Missing required consent fields: ${missing.join(', ')}`);\n}\n\n// --- Validate email format ---\nconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nif (!emailRegex.test(body.participantEmail)) {\n  throw new Error(`Invalid participant email format: ${body.participantEmail}`);\n}\n\n// --- Validate consent date is not in the future ---\nconst consentDate = new Date(body.consentDate);\nif (isNaN(consentDate.getTime())) {\n  throw new Error(`Invalid consent date format: ${body.consentDate}`);\n}\nif (consentDate > new Date()) {\n  throw new Error('Consent date cannot be in the future');\n}\n\n// --- Parse GCP checklist flags ---\nconst gcpChecklist = {\n  capacityConfirmed: Boolean(body.capacityConfirmed),\n  rightToWithdrawExplained: Boolean(body.rightToWithdrawExplained),\n  risksExplained: Boolean(body.risksExplained),\n  benefitsExplained: Boolean(body.benefitsExplained),\n  alternativesExplained: Boolean(body.alternativesExplained),\n  confidentialityExplained: Boolean(body.confidentialityExplained),\n  questionsAnswered: Boolean(body.questionsAnswered),\n  voluntaryParticipation: Boolean(body.voluntaryParticipation !== false),\n  witnessPresent: Boolean(body.witnessName)\n};\n\n// Calculate GCP completeness score\nconst checklistKeys = Object.keys(gcpChecklist);\nconst passedChecks = checklistKeys.filter(k => gcpChecklist[k]).length;\nconst gcpCompletenessScore = Math.round((passedChecks / checklistKeys.length) * 100);\n\n// --- Generate cryptographic-style record hash (deterministic) ---\nconst hashInput = `${body.trialId}|${body.participantId}|${body.consentFormVersion}|${body.consentDate}|${body.signatureData?.substring(0, 32)}`;\nlet hashValue = 0;\nfor (let i = 0; i < hashInput.length; i++) {\n  const char = hashInput.charCodeAt(i);\n  hashValue = ((hashValue << 5) - hashValue) + char;\n  hashValue = hashValue & hashValue;\n}\nconst recordHash = `SHA-${Math.abs(hashValue).toString(16).toUpperCase().padStart(8, '0')}`;\n\n// --- Calculate consent expiry (default: 12 months from consent date) ---\nconst consentExpiryMonths = body.consentExpiryMonths || 12;\nconst expiryDate = new Date(consentDate);\nexpiryDate.setMonth(expiryDate.getMonth() + consentExpiryMonths);\n\n// --- Build normalized consent record ---\nconst consentRecord = {\n  // Identifiers\n  consentRecordId: `CONS-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`,\n  trialId: body.trialId.trim().toUpperCase(),\n  participantId: body.participantId.trim(),\n  irbNumber: body.irbNumber || 'IRB-NOT-PROVIDED',\n  sponsorId: body.sponsorId || null,\n  siteId: body.siteId || null,\n\n  // Participant details\n  participantName: body.participantName.trim(),\n  participantEmail: body.participantEmail.trim().toLowerCase(),\n  participantDob: body.participantDob || null,\n  participantLanguage: body.participantLanguage || 'en',\n\n  // Consent details\n  consentFormVersion: body.consentFormVersion.trim(),\n  consentDate: consentDate.toISOString(),\n  consentExpiryDate: expiryDate.toISOString(),\n  consentType: body.consentType || 'INITIAL',\n  signatureData: body.signatureData,\n  signatureMethod: body.signatureMethod || 'ELECTRONIC',\n\n  // Witness\n  witnessName: body.witnessName || null,\n  witnessEmail: body.witnessEmail || null,\n  piName: body.piName || 'PRINCIPAL_INVESTIGATOR',\n  piEmail: body.piEmail || 'user@example.com',\n\n  // GCP Checklist\n  gcpChecklist,\n  gcpCompletenessScore,\n\n  // Audit metadata\n  recordHash,\n  submittedAt: new Date().toISOString(),\n  ipAddress: body.ipAddress || 'NOT_CAPTURED',\n  userAgent: body.userAgent || 'NOT_CAPTURED',\n  portalVersion: body.portalVersion || '1.0',\n  status: 'PENDING_REVIEW'\n};\n\nreturn { json: { consentRecord } };"
      },
      "typeVersion": 2
    },
    {
      "id": "6b0c850c-0e87-451b-9c10-e8b9281bfaf5",
      "name": "Verify E-Signature via DocuSign",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3024,
        496
      ],
      "parameters": {
        "url": "https://na3.docusign.net/restapi/v2.1/accounts/YOUR_DOCUSIGN_ACCOUNT_ID/envelopes",
        "options": {
          "timeout": 10000
        },
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "custom_field",
              "value": "={{ $json.consentRecord.participantId }}"
            },
            {
              "name": "status",
              "value": "completed"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "4b31dd58-83b6-446d-8b76-27a9d427a184",
      "name": "Check for Duplicate Consent Record",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3024,
        688
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "="
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "a9e844d2-2e3d-426f-8d6d-558bff604a6b",
      "name": "Flag Duplicate or Proceed",
      "type": "n8n-nodes-base.if",
      "position": [
        3248,
        656
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.length || 0 }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "050aead2-e829-4259-ad1b-bc23afd0d81f",
      "name": "Claude AI GCP Compliance Review",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        3472,
        656
      ],
      "parameters": {
        "text": "=You are an expert clinical research regulatory compliance officer with deep knowledge of ICH E6(R2) Good Clinical Practice (GCP), FDA 21 CFR Part 50 (Informed Consent), and EU Clinical Trials Regulation No 536/2014.\n\nReview this e-consent submission for regulatory compliance and completeness.\n\n**Trial Information:**\n- Trial ID: {{ $json.consentRecord.trialId }}\n- IRB Number: {{ $json.consentRecord.irbNumber }}\n- Consent Form Version: {{ $json.consentRecord.consentFormVersion }}\n- Consent Type: {{ $json.consentRecord.consentType }}\n\n**Participant Information:**\n- Participant ID: {{ $json.consentRecord.participantId }}\n- Consent Date: {{ $json.consentRecord.consentDate }}\n- Consent Expiry: {{ $json.consentRecord.consentExpiryDate }}\n- Signature Method: {{ $json.consentRecord.signatureMethod }}\n- Participant Language: {{ $json.consentRecord.participantLanguage }}\n\n**GCP Checklist Results ({{ $json.consentRecord.gcpCompletenessScore }}% complete):**\n- Participant capacity confirmed: {{ $json.consentRecord.gcpChecklist.capacityConfirmed }}\n- Right to withdraw explained: {{ $json.consentRecord.gcpChecklist.rightToWithdrawExplained }}\n- Risks explained: {{ $json.consentRecord.gcpChecklist.risksExplained }}\n- Benefits explained: {{ $json.consentRecord.gcpChecklist.benefitsExplained }}\n- Alternatives explained: {{ $json.consentRecord.gcpChecklist.alternativesExplained }}\n- Confidentiality explained: {{ $json.consentRecord.gcpChecklist.confidentialityExplained }}\n- Questions answered: {{ $json.consentRecord.gcpChecklist.questionsAnswered }}\n- Voluntary participation confirmed: {{ $json.consentRecord.gcpChecklist.voluntaryParticipation }}\n- Witness present: {{ $json.consentRecord.gcpChecklist.witnessPresent }}\n\n**Witness / PI:**\n- Witness Name: {{ $json.consentRecord.witnessName || 'None' }}\n- PI Name: {{ $json.consentRecord.piName }}\n\n**Assessment Task:**\n1. Review all GCP checklist items against ICH E6(R2) Section 4.8 requirements\n2. Identify any regulatory gaps or missing elements\n3. Classify the consent record compliance level\n4. Provide specific remediation steps for any gaps\n5. Assess risk level for IRB/audit purposes\n\n**Response Format (JSON only, no markdown):**\n{\n  \"complianceStatus\": \"COMPLIANT | CONDITIONALLY_COMPLIANT | NON_COMPLIANT\",\n  \"complianceScore\": 95,\n  \"riskLevel\": \"LOW | MEDIUM | HIGH | CRITICAL\",\n  \"gcpFramework\": \"ICH E6(R2)\",\n  \"regulatoryGaps\": [\"list of specific missing or incomplete elements\"],\n  \"remediationRequired\": true,\n  \"remediationSteps\": [\"specific corrective actions required before activation\"],\n  \"auditReadiness\": \"READY | NEEDS_REVIEW | NOT_READY\",\n  \"approvalRecommendation\": \"APPROVE | CONDITIONAL_APPROVE | REJECT\",\n  \"approvalNotes\": \"Brief explanation for PI\",\n  \"witnessRequirementMet\": true,\n  \"electronicSignatureValid\": true,\n  \"reConsentRequired\": false,\n  \"reConsentReason\": null,\n  \"irbFlags\": [\"any items that must be flagged to the IRB\"],\n  \"estimatedRegulatoryRisk\": \"brief 1-sentence risk statement for the audit file\"\n}",
        "options": {
          "systemMessage": "You are a clinical research regulatory compliance expert. Respond with valid JSON only \u2014 no markdown, no code blocks, no preamble. Your reviews must align strictly with ICH E6(R2) GCP, FDA 21 CFR Part 50, and EU CTR 536/2014."
        },
        "promptType": "define"
      },
      "typeVersion": 1.6
    },
    {
      "id": "fe175773-5a1a-49c2-95ff-5f98fe0d8d8f",
      "name": "Claude AI Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        3552,
        880
      ],
      "parameters": {
        "model": "=claude-sonnet-4-20250514",
        "options": {
          "temperature": 0.1
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3c8cb26f-48a0-41c7-a8e8-00ffb5574e3a",
      "name": "Parse Compliance Review",
      "type": "n8n-nodes-base.code",
      "position": [
        3824,
        656
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const aiResponse = $input.item.json;\nlet aiText = aiResponse.response || aiResponse.output || aiResponse.text || '';\n\n// Handle Anthropic content array format\nif (aiResponse.content && Array.isArray(aiResponse.content)) {\n  aiText = aiResponse.content[0]?.text || '';\n}\n\n// Strip any markdown code blocks\nconst cleanText = aiText\n  .replace(/```json\\s*/g, '')\n  .replace(/```\\s*/g, '')\n  .trim();\n\nlet complianceReview;\ntry {\n  complianceReview = JSON.parse(cleanText);\n} catch (error) {\n  throw new Error(`Failed to parse Claude compliance response: ${error.message}. Raw: ${cleanText.substring(0, 200)}`);\n}\n\n// Pull consent record from upstream\nconst consentRecord = $('Validate and Timestamp Consent').item.json.consentRecord;\n\n// Determine final status\nconst finalStatus = complianceReview.approvalRecommendation === 'APPROVE'\n  ? 'APPROVED'\n  : complianceReview.approvalRecommendation === 'CONDITIONAL_APPROVE'\n  ? 'CONDITIONALLY_APPROVED'\n  : 'REJECTED';\n\n// Update consent record status\nconsentRecord.status = finalStatus;\nconsentRecord.complianceReviewedAt = new Date().toISOString();\nconsentRecord.complianceReviewedBy = 'Claude AI GCP Compliance Engine v1';\n\nreturn {\n  json: {\n    consentRecord,\n    complianceReview,\n    finalStatus,\n    requiresRemediaton: complianceReview.remediationRequired || false,\n    requiresEscalation: complianceReview.riskLevel === 'HIGH' || complianceReview.riskLevel === 'CRITICAL',\n    irbFlags: complianceReview.irbFlags || []\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "f1c2f9dc-e0c7-4cfe-b68a-c5e247c9910c",
      "name": "Store Consent Record with Audit Trail",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4048,
        464
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "="
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "173d56ab-1b79-4b9c-9b33-9972486d405e",
      "name": "Notify Principal Investigator",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        4048,
        656
      ],
      "parameters": {
        "options": {
          "allowUnauthorizedCerts": false
        },
        "subject": "=[{{ $json.finalStatus }}] Consent Submission - {{ $json.consentRecord.participantId }} | Trial {{ $json.consentRecord.trialId }}",
        "toEmail": "=",
        "fromEmail": "="
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1,
      "continueOnFail": true
    },
    {
      "id": "783a0604-20f4-4e91-b522-b761a0432fd0",
      "name": "Send Confirmation to Participant",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        4048,
        848
      ],
      "parameters": {
        "options": {},
        "subject": "=Your Informed Consent Confirmation - {{ $json.consentRecord.trialId }}",
        "toEmail": "=",
        "fromEmail": "="
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1,
      "continueOnFail": true
    },
    {
      "id": "4a0486bc-3b33-428c-a2f0-3f53d6d20e25",
      "name": "Build Consent Response",
      "type": "n8n-nodes-base.code",
      "position": [
        4272,
        688
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const data = $('Parse Compliance Review').item.json;\n\nreturn {\n  json: {\n    success: true,\n    consentRecordId: data.consentRecord.consentRecordId,\n    participantId: data.consentRecord.participantId,\n    trialId: data.consentRecord.trialId,\n    finalStatus: data.finalStatus,\n    complianceStatus: data.complianceReview.complianceStatus,\n    complianceScore: data.complianceReview.complianceScore,\n    riskLevel: data.complianceReview.riskLevel,\n    approvalRecommendation: data.complianceReview.approvalRecommendation,\n    approvalNotes: data.complianceReview.approvalNotes,\n    consentExpiryDate: data.consentRecord.consentExpiryDate,\n    recordHash: data.consentRecord.recordHash,\n    remediationRequired: data.requiresRemediaton,\n    remediationSteps: data.complianceReview.remediationSteps || [],\n    regulatoryGaps: data.complianceReview.regulatoryGaps || [],\n    irbFlags: data.irbFlags || [],\n    auditReadiness: data.complianceReview.auditReadiness,\n    processedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "497ab26c-e10e-45cb-a84e-94df987cac8d",
      "name": "Send Consent Confirmation Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        4672,
        688
      ],
      "parameters": {
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        },
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json, null, 2) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "8976b60f-de32-4c40-b808-ef3fcf511e9b",
      "name": "Daily Compliance Sweep Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        2528,
        1360
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 6 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "330cab51-d88a-4ce7-bd00-07bc1415e221",
      "name": "Fetch All Active Consent Records",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2752,
        1360
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "="
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "f5b79833-231e-4179-8bcb-161e7cb8ff38",
      "name": "Analyse Expiring and Missing Consents",
      "type": "n8n-nodes-base.code",
      "position": [
        3024,
        1360
      ],
      "parameters": {
        "jsCode": "const allConsents = $input.all().map(i => i.json);\nconst today = new Date();\n\n// Thresholds\nconst EXPIRY_WARNING_DAYS = 30;\nconst EXPIRY_CRITICAL_DAYS = 7;\n\nconst expiringSoon = [];\nconst expiredAlready = [];\nconst expiringCritical = [];\nconst conditionalNotRemediated = [];\n\nfor (const consent of allConsents) {\n  if (!consent.consentExpiryDate) continue;\n\n  const expiryDate = new Date(consent.consentExpiryDate);\n  const daysUntilExpiry = Math.floor((expiryDate - today) / (1000 * 60 * 60 * 24));\n\n  if (daysUntilExpiry < 0) {\n    expiredAlready.push({ ...consent, daysOverdue: Math.abs(daysUntilExpiry) });\n  } else if (daysUntilExpiry <= EXPIRY_CRITICAL_DAYS) {\n    expiringCritical.push({ ...consent, daysUntilExpiry });\n  } else if (daysUntilExpiry <= EXPIRY_WARNING_DAYS) {\n    expiringSoon.push({ ...consent, daysUntilExpiry });\n  }\n\n  if (consent.finalStatus === 'CONDITIONALLY_APPROVED' && consent.remediationRequired === 'true') {\n    const reviewedAt = new Date(consent.complianceReviewedAt);\n    const daysSinceReview = Math.floor((today - reviewedAt) / (1000 * 60 * 60 * 24));\n    if (daysSinceReview > 7) {\n      conditionalNotRemediated.push({ ...consent, daysSinceReview });\n    }\n  }\n}\n\nconst report = {\n  sweepDate: today.toISOString(),\n  totalActiveConsents: allConsents.length,\n  summary: {\n    expired: expiredAlready.length,\n    expiringCritical: expiringCritical.length,\n    expiringSoon: expiringSoon.length,\n    remediationOverdue: conditionalNotRemediated.length\n  },\n  expiredAlready,\n  expiringCritical,\n  expiringSoon,\n  conditionalNotRemediated,\n  requiresImmediateAction: expiredAlready.length + expiringCritical.length + conditionalNotRemediated.length\n};\n\nreturn [{ json: report }];"
      },
      "typeVersion": 2
    },
    {
      "id": "ffd2c899-417c-47b4-8fc3-5e5374c8d563",
      "name": "Send Daily Compliance Report to PI",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        3280,
        1360
      ],
      "parameters": {
        "options": {},
        "subject": "=[Daily Compliance Report] Consent Sweep {{ new Date().toDateString() }} \u2014 {{ $json.requiresImmediateAction }} Action Items",
        "toEmail": "=",
        "fromEmail": "="
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1,
      "continueOnFail": true
    },
    {
      "id": "10116069-9175-47c3-a5a9-eb13fbf9afb5",
      "name": "Log Sweep Results to Audit Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3584,
        1360
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "="
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "657fb697-1b0d-433b-9ff1-e05e6ae8ff4e",
      "name": "Wait For Load",
      "type": "n8n-nodes-base.wait",
      "position": [
        4480,
        688
      ],
      "parameters": {},
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c29c3a56-102f-48d5-921d-d50a46e8edd0",
  "connections": {
    "Wait For Load": {
      "main": [
        [
          {
            "node": "Send Consent Confirmation Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude AI Model": {
      "ai_languageModel": [
        [
          {
            "node": "Claude AI GCP Compliance Review",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Build Consent Response": {
      "main": [
        [
          {
            "node": "Wait For Load",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Compliance Review": {
      "main": [
        [
          {
            "node": "Store Consent Record with Audit Trail",
            "type": "main",
            "index": 0
          },
          {
            "node": "Notify Principal Investigator",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Confirmation to Participant",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Flag Duplicate or Proceed": {
      "main": [
        [
          {
            "node": "Claude AI GCP Compliance Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive E-Consent Submission": {
      "main": [
        [
          {
            "node": "Validate and Timestamp Consent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Principal Investigator": {
      "main": [
        [
          {
            "node": "Build Consent Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Compliance Sweep Trigger": {
      "main": [
        [
          {
            "node": "Fetch All Active Consent Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate and Timestamp Consent": {
      "main": [
        [
          {
            "node": "Verify E-Signature via DocuSign",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check for Duplicate Consent Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude AI GCP Compliance Review": {
      "main": [
        [
          {
            "node": "Parse Compliance Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify E-Signature via DocuSign": {
      "main": [
        [
          {
            "node": "Flag Duplicate or Proceed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch All Active Consent Records": {
      "main": [
        [
          {
            "node": "Analyse Expiring and Missing Consents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Confirmation to Participant": {
      "main": [
        [
          {
            "node": "Build Consent Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for Duplicate Consent Record": {
      "main": [
        [
          {
            "node": "Flag Duplicate or Proceed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Daily Compliance Report to PI": {
      "main": [
        [
          {
            "node": "Log Sweep Results to Audit Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyse Expiring and Missing Consents": {
      "main": [
        [
          {
            "node": "Send Daily Compliance Report to PI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Consent Record with Audit Trail": {
      "main": [
        [
          {
            "node": "Build Consent Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}