{
  "name": "Post-Discharge Follow-Up with Red-Flag Escalation",
  "nodes": [
    {
      "parameters": { "httpMethod": "POST", "path": "patient-discharged", "options": {} },
      "id": "d4000000-0000-4000-8000-000000000001",
      "name": "Patient discharged",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [-700, 0],
      "webhookId": "d4000000-0000-4000-8000-000000000001",
      "notesInFlow": true,
      "notes": "Fire this from your EHR discharge event. Expected: patientRef, firstName, phone, dischargeDate, primaryDiagnosis, followUpBooked (bool), language."
    },
    {
      "parameters": { "amount": 48, "unit": "hours" },
      "id": "d4000000-0000-4000-8000-000000000002",
      "name": "Wait 48 hours",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [-480, 0],
      "webhookId": "d4000000-0000-4000-8000-000000000002",
      "notesInFlow": true,
      "notes": "48 hours is the window where most avoidable readmissions are still preventable."
    },
    {
      "parameters": {
        "resource": "sms",
        "operation": "send",
        "from": "={{ $env.CLINIC_SMS_NUMBER }}",
        "to": "={{ $json.phone }}",
        "message": "=Hi {{ $json.firstName }}, this is {{ $env.CLINIC_NAME }} checking in after your discharge. How are you feeling — better, the same, or worse? Also, have you been able to collect and start your medicines? Reply here and a nurse will see it. If you have severe symptoms, call 911.",
        "options": {}
      },
      "id": "d4000000-0000-4000-8000-000000000003",
      "name": "Send check-in",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [-260, 0]
    },
    {
      "parameters": { "httpMethod": "POST", "path": "discharge-reply", "options": {} },
      "id": "d4000000-0000-4000-8000-000000000004",
      "name": "Patient responds",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [-700, 260],
      "webhookId": "d4000000-0000-4000-8000-000000000004"
    },
    {
      "parameters": {
        "jsCode": "// SAFETY-CRITICAL NODE.\n// Red flags are matched with deterministic rules, never by a model.\n// A model may widen escalation later in the flow; it must never narrow it.\n\nconst reply = String($input.first().json.Body || $input.first().json.body || '');\nconst text = reply.toLowerCase();\nconst from = $input.first().json.From || $input.first().json.from;\n\nconst RED_FLAGS = [\n  'chest pain', 'crushing chest', 'can\\'t breathe', 'cannot breathe', 'short of breath',\n  'trouble breathing', 'struggling to breathe',\n  'face drooping', 'slurred', 'weakness on one side', 'numb on one side',\n  'worst headache', 'sudden headache',\n  'bleeding heavily', 'heavy bleeding', 'won\\'t stop bleeding', 'vomiting blood',\n  'blood in stool', 'black stool',\n  'suicidal', 'kill myself', 'end my life', 'hurt myself',\n  'passed out', 'fainted', 'unconscious', 'seizure', 'convulsion',\n  'confused', 'disoriented',\n  'fever', 'temperature of', 'shivering uncontrollably',\n  'wound is red', 'wound smells', 'pus', 'incision opened',\n  'swollen leg', 'calf pain',\n];\n\nconst matched = RED_FLAGS.filter(flag => text.includes(flag));\n\n// Medication non-adherence: urgent but not an emergency.\nconst MED_ISSUES = ['haven\\'t started', 'have not started', 'could not get', 'couldn\\'t get',\n  'too expensive', 'pharmacy', 'ran out', 'no refill', 'stopped taking'];\nconst medIssue = MED_ISSUES.some(p => text.includes(p));\n\nconst worse = /\\bworse\\b|\\bworsening\\b|\\bnot good\\b|\\bbad\\b/.test(text);\n\nlet severity = 'routine';\nif (matched.length > 0) severity = 'emergency';\nelse if (worse || medIssue) severity = 'urgent';\n\nreturn [{ json: { from, reply, severity, matched, medIssue } }];"
      },
      "id": "d4000000-0000-4000-8000-000000000005",
      "name": "Red-flag check (rules only)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [-480, 260]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 },
                "conditions": [
                  {
                    "leftValue": "={{ $json.severity }}",
                    "rightValue": "emergency",
                    "operator": { "type": "string", "operation": "equals" }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Emergency"
            },
            {
              "conditions": {
                "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 },
                "conditions": [
                  {
                    "leftValue": "={{ $json.severity }}",
                    "rightValue": "urgent",
                    "operator": { "type": "string", "operation": "equals" }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Urgent"
            }
          ]
        },
        "options": { "fallbackOutput": "extra", "renameFallbackOutput": "Routine" }
      },
      "id": "d4000000-0000-4000-8000-000000000006",
      "name": "Route by severity",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [-260, 260]
    },
    {
      "parameters": {
        "resource": "sms",
        "operation": "send",
        "from": "={{ $env.CLINIC_SMS_NUMBER }}",
        "to": "={{ $json.from }}",
        "message": "Based on what you have described, please call 911 or go to your nearest emergency department now. We are alerting the on-call clinician as well.",
        "options": {}
      },
      "id": "d4000000-0000-4000-8000-000000000007",
      "name": "Tell patient to seek emergency care",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [0, 120]
    },
    {
      "parameters": {
        "resource": "sms",
        "operation": "send",
        "from": "={{ $env.CLINIC_SMS_NUMBER }}",
        "to": "={{ $env.ON_CALL_NUMBER }}",
        "message": "=RED FLAG — post-discharge check-in.\nPatient: {{ $json.from }}\nTriggers: {{ $json.matched.join(', ') }}\nTheir words: \"{{ $json.reply }}\"\nPatient has been told to call 911. Please follow up now.",
        "options": {}
      },
      "id": "d4000000-0000-4000-8000-000000000008",
      "name": "Page the on-call clinician",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [240, 120],
      "notesInFlow": true,
      "notes": "Both happen: the patient is told to seek care AND a human is paged. Never one or the other."
    },
    {
      "parameters": {
        "resource": "sms",
        "operation": "send",
        "from": "={{ $env.CLINIC_SMS_NUMBER }}",
        "to": "={{ $env.NURSE_LINE_NUMBER }}",
        "message": "=Post-discharge follow-up needs a nurse call today.\nPatient: {{ $json.from }}\n{{ $json.medIssue ? 'Medication access problem reported.' : 'Reports feeling worse.' }}\nTheir words: \"{{ $json.reply }}\"",
        "options": {}
      },
      "id": "d4000000-0000-4000-8000-000000000009",
      "name": "Queue a nurse call",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [0, 300]
    },
    {
      "parameters": {
        "resource": "sms",
        "operation": "send",
        "from": "={{ $env.CLINIC_SMS_NUMBER }}",
        "to": "={{ $json.from }}",
        "message": "Thanks for letting us know — glad you are doing okay. Your reply has been added to your record. If anything changes, message us any time, and call 911 for anything severe.",
        "options": {}
      },
      "id": "d4000000-0000-4000-8000-000000000010",
      "name": "Acknowledge and record",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [0, 460]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": { "__rl": true, "value": "={{ $env.FOLLOWUP_SHEET_ID }}", "mode": "id" },
        "sheetName": { "__rl": true, "value": "Discharge follow-ups", "mode": "name" },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Time": "={{ $now.toISO() }}",
            "Patient": "={{ $json.from }}",
            "Severity": "={{ $json.severity }}",
            "Triggers": "={{ ($json.matched || []).join(', ') }}",
            "Reply": "={{ $json.reply }}"
          }
        },
        "options": {}
      },
      "id": "d4000000-0000-4000-8000-000000000011",
      "name": "Log every response",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [240, 460],
      "notesInFlow": true,
      "notes": "Every interaction is logged, including the routine ones. You need the full trail, not just the escalations."
    }
  ],
  "connections": {
    "Patient discharged": { "main": [[{ "node": "Wait 48 hours", "type": "main", "index": 0 }]] },
    "Wait 48 hours": { "main": [[{ "node": "Send check-in", "type": "main", "index": 0 }]] },
    "Patient responds": {
      "main": [[{ "node": "Red-flag check (rules only)", "type": "main", "index": 0 }]]
    },
    "Red-flag check (rules only)": {
      "main": [
        [
          { "node": "Route by severity", "type": "main", "index": 0 },
          { "node": "Log every response", "type": "main", "index": 0 }
        ]
      ]
    },
    "Route by severity": {
      "main": [
        [
          { "node": "Tell patient to seek emergency care", "type": "main", "index": 0 },
          { "node": "Page the on-call clinician", "type": "main", "index": 0 }
        ],
        [{ "node": "Queue a nurse call", "type": "main", "index": 0 }],
        [{ "node": "Acknowledge and record", "type": "main", "index": 0 }]
      ]
    }
  },
  "pinData": {},
  "settings": { "executionOrder": "v1" },
  "tags": [{ "name": "healthcare" }, { "name": "patient safety" }]
}
