{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "3527dde7-199d-40e0-a68c-f424177655db",
      "name": "\ud83d\udccb Flow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        0
      ],
      "parameters": {
        "width": 640,
        "height": 494,
        "content": "## \ud83d\udc8a WhatsApp Medication Reminder Bot with Dosage Tracking\n\n**How it works:**\n1. Schedule Trigger runs 3x daily (morning, afternoon, night) and sends medication reminders to all active patients\n2. Patient replies *taken*, *skip* or *snooze* to log their response\n3. If no response within 2 hours \u2192 caregiver is auto-alerted\n4. Patient can type *mystats* to see their weekly adherence report\n5. Patient types *mymeds* to see today's medication schedule\n6. Caregiver types *report <phone>* to get a patient's full adherence summary\n\n**Credentials needed:** WATI, Google Sheets OAuth2"
      },
      "typeVersion": 1
    },
    {
      "id": "03b70fab-0e5c-4e8d-b85b-04676595348c",
      "name": "Sticky \u2013 Scheduled Reminders",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2512,
        1312
      ],
      "parameters": {
        "color": 7,
        "width": 1456,
        "height": 338,
        "content": "### 1\ufe0f\u20e3 Scheduled Reminder Dispatch\n**Schedule Trigger** fires 3x daily: 8AM, 1PM, 8PM.\n**Sheets \u2013 Read Medications** fetches all active medication records.\n**Filter by Time Slot Code** keeps only medications due in the current time window (morning / afternoon / night).\n**Build & Send Reminder Loop** sends a personalised reminder per patient with taken/skip/snooze options."
      },
      "typeVersion": 1
    },
    {
      "id": "c532ecf6-0291-44f9-b9b0-a77b205418ff",
      "name": "Sticky \u2013 Inbound Routing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        1184
      ],
      "parameters": {
        "color": 7,
        "width": 880,
        "height": 770,
        "content": "### 2\ufe0f\u20e3 Inbound Reply Routing\n**WATI Trigger** receives patient replies.\n**Route Message Switch** detects keyword:\n- `taken` \u2192 log dose taken \u2705\n- `skip` \u2192 log dose skipped \u26a0\ufe0f\n- `snooze` \u2192 schedule a 30-min follow-up reminder\n- `mystats` \u2192 weekly adherence report\n- `mymeds` \u2192 today's medication schedule\n- `report <phone>` \u2192 caregiver pulls patient report\n- anything else \u2192 help message"
      },
      "typeVersion": 1
    },
    {
      "id": "9cc5de58-5424-440d-bde2-17b4455a3e7e",
      "name": "Sticky \u2013 Taken & Skip",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        592
      ],
      "parameters": {
        "color": 7,
        "width": 1052,
        "height": 456,
        "content": "### 3\ufe0f\u20e3 Dose Logging \u2014 Taken & Skip\n**Taken Flow:** Logs dose as Taken in AdherenceLog sheet with timestamp. Sends positive reinforcement message. Updates streak counter.\n**Skip Flow:** Logs dose as Skipped. Sends empathetic reminder message. Flags for caregiver alert if 2+ consecutive skips detected."
      },
      "typeVersion": 1
    },
    {
      "id": "facc287f-8f74-4864-9773-86a300c827b2",
      "name": "Sticky \u2013 Snooze & Missed Alert",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        1072
      ],
      "parameters": {
        "color": 7,
        "width": 1052,
        "height": 584,
        "content": "### 4\ufe0f\u20e3 Snooze & Missed Dose Alert\n**Snooze Flow:** Logs snooze request with a follow-up timestamp. A second Schedule Trigger (every 30 min) checks for pending snoozes and re-sends reminders.\n**Missed Dose Check:** Runs hourly. If a reminder was sent but no response logged within 2 hours \u2192 sends alert to caregiver WhatsApp with patient name, medication and time."
      },
      "typeVersion": 1
    },
    {
      "id": "bc02854c-cd3c-4ea7-9ed7-6779edc23c8f",
      "name": "Sticky \u2013 Reports",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        1696
      ],
      "parameters": {
        "color": 7,
        "width": 1036,
        "height": 760,
        "content": "### 5\ufe0f\u20e3 Reports & Stats\n**My Stats:** Reads AdherenceLog for this patient's phone, calculates 7-day adherence %, streak, best/worst day and sends a visual report.\n**My Meds:** Shows today's full medication schedule with timings and dosage.\n**Caregiver Report:** Caregiver sends *report <phone>* \u2192 pulls full adherence history for that patient and sends summary."
      },
      "typeVersion": 1
    },
    {
      "id": "a51374ef-5515-4379-9a8a-f295007f8883",
      "name": "Schedule Trigger \u2013 8AM 1PM 8PM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        2592,
        1472
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8,13,20 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "97d52ce9-2530-4477-8830-3f4c3058d990",
      "name": "Google Sheets \u2013 Read Medications",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2832,
        1472
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=0",
          "cachedResultName": "Medications"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "36903a3a-8b63-44a4-9c84-a7c093efb05a",
      "name": "Filter Medications by Time Slot",
      "type": "n8n-nodes-base.code",
      "position": [
        3072,
        1472
      ],
      "parameters": {
        "jsCode": "// Filter Medications by Current Time Slot\n// Determines if it's morning (8AM), afternoon (1PM) or night (8PM)\n// and returns only medications scheduled for this slot\n\nconst allRows = $input.all();\nconst now = new Date();\nconst hour = now.getHours();\n\n// Determine current time slot\nlet currentSlot = '';\nif (hour >= 6 && hour < 12)  currentSlot = 'morning';\nelse if (hour >= 12 && hour < 17) currentSlot = 'afternoon';\nelse currentSlot = 'night';\n\nconst slotLabel = { morning: '\ud83c\udf05 Morning', afternoon: '\u2600\ufe0f Afternoon', night: '\ud83c\udf19 Night' }[currentSlot];\n\n// Filter active medications for this time slot\nconst dueMeds = allRows.filter(r => {\n  const status = (r.json.status || '').toLowerCase();\n  const frequency = (r.json.frequency || '').toLowerCase();\n  const timeSlots = (r.json.timeSlots || '').toLowerCase();\n\n  if (status !== 'active') return false;\n\n  // Check if this medication is due in current slot\n  if (timeSlots.includes(currentSlot)) return true;\n  if (frequency === 'once daily' && currentSlot === 'morning') return true;\n  if (frequency === 'twice daily' && (currentSlot === 'morning' || currentSlot === 'night')) return true;\n  if (frequency === 'thrice daily') return true;\n  return false;\n});\n\nif (dueMeds.length === 0) {\n  return [{ json: { message: `No medications due for ${currentSlot} slot`, count: 0 } }];\n}\n\n// Group by patient phone \u2014 one message per patient with all their meds\nconst byPhone = {};\nfor (const row of dueMeds) {\n  const phone = row.json.phone;\n  if (!byPhone[phone]) {\n    byPhone[phone] = {\n      phone,\n      patientName: row.json.patientName,\n      caregiverPhone: row.json.caregiverPhone,\n      medications: [],\n      currentSlot,\n      slotLabel\n    };\n  }\n  byPhone[phone].medications.push({\n    medName: row.json.medName,\n    dosage: row.json.dosage,\n    instructions: row.json.instructions || '',\n    medId: row.json.medId || row.json.medName\n  });\n}\n\nreturn Object.values(byPhone).map(p => ({ json: p }));"
      },
      "typeVersion": 2
    },
    {
      "id": "06817ea7-55d0-41ba-b619-813eaa12fdc2",
      "name": "Build Medication Reminder",
      "type": "n8n-nodes-base.code",
      "position": [
        3312,
        1472
      ],
      "parameters": {
        "jsCode": "// Build Medication Reminder Message\n// Creates a WhatsApp reminder listing all meds due for this slot\n\nconst data = $json;\nconst { phone, patientName, medications, slotLabel, currentSlot } = data;\nconst now = new Date();\nconst logKey = `${phone}_${now.toISOString().split('T')[0]}_${currentSlot}`;\n\nconst medLines = medications.map((m, i) =>\n  `  ${i + 1}. \ud83d\udc8a *${m.medName}* \u2014 ${m.dosage}${m.instructions ? `\\n     \ud83d\udcdd ${m.instructions}` : ''}`\n).join('\\n');\n\nconst lines = [\n  `${slotLabel} *Medication Reminder* \ud83d\udc8a`,\n  `\ud83d\udc4b Hi *${patientName}!*`,\n  '',\n  `Please take your ${currentSlot} medications:`,\n  '',\n  medLines,\n  '',\n  '\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501',\n  'Reply with:',\n  '\u2705 *taken* \u2013 I have taken my medication',\n  '\ud83d\ude34 *snooze* \u2013 Remind me in 30 minutes',\n  '\u23ed\ufe0f *skip* \u2013 I am skipping this dose',\n];\n\nreturn {\n  json: {\n    phone,\n    patientName,\n    caregiverPhone: data.caregiverPhone,\n    currentSlot,\n    logKey,\n    reminderMessage: lines.join('\\n'),\n    sentAt: now.toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "52c8e202-57b7-459a-9bac-97703e11d89b",
      "name": "Google Sheets \u2013 Log Reminder Sent",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3552,
        1472
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ new Date().toISOString().split('T')[0] }}",
            "slot": "={{ $json.currentSlot }}",
            "phone": "={{ $json.phone }}",
            "logKey": "={{ $json.logKey }}",
            "sentAt": "={{ $json.sentAt }}",
            "status": "Pending",
            "patientName": "={{ $json.patientName }}",
            "caregiverPhone": "={{ $json.caregiverPhone }}"
          },
          "schema": [
            {
              "id": "logKey",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "logKey",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "patientName",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "patientName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "slot",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "slot",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sentAt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sentAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "respondAt",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "respondAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "caregiverPhone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "caregiverPhone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "8efb5ffd-6859-48da-adc0-cef89cfcaf07",
      "name": "Route Message",
      "type": "n8n-nodes-base.switch",
      "position": [
        336,
        1456
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Taken",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "9ce57f31-b5ab-46dd-9f8e-2b4c7392c2b2",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.text.toLowerCase().trim() }}",
                    "rightValue": "taken"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Skip",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "34cea88a-cf1a-4b8d-af85-b07cbc031f67",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.text.toLowerCase().trim() }}",
                    "rightValue": "skip"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Snooze",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "c13d23e0-e6d3-4e0d-bddc-3e9372a76601",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.text.toLowerCase().trim() }}",
                    "rightValue": "snooze"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "My Stats",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "499dc0f0-288f-4b63-bfbe-c1e623cebbf1",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.text.toLowerCase().trim() }}",
                    "rightValue": "mystats"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "My Meds",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "3ffcee4c-5b30-47a1-8ca5-e5b8ae314fd0",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.text.toLowerCase().trim() }}",
                    "rightValue": "mymeds"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Caregiver Report",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "62b48c7a-9d33-466d-aaec-c7c649a71d18",
                    "operator": {
                      "type": "string",
                      "operation": "startsWith"
                    },
                    "leftValue": "={{ $json.text }}",
                    "rightValue": "report "
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "d3513e9b-8943-423f-8e7e-e6acce415e18",
      "name": "Google Sheets \u2013 Read Log (Taken)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1424,
        704
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "159c0619-095a-47df-881c-6225d32b55d2",
      "name": "Process Taken",
      "type": "n8n-nodes-base.code",
      "position": [
        1680,
        704
      ],
      "parameters": {
        "jsCode": "// Process Taken Response\n// Finds the latest Pending log for this patient\n// Calculates streak and builds positive reinforcement message\n\nconst phone = $('Wati Trigger').first().json.waId|| $('WATI Trigger').item.json.from;\nconst patientName =  $('Wati Trigger').first().json.senderName|| 'Patient';\nconst allRows = $input.all();\nconst now = new Date();\nconst today = now.toISOString().split('T')[0];\n\n// Find latest pending log for this phone\nconst myLogs = allRows\n  .filter(r => r.json.phone === phone)\n  .sort((a, b) => new Date(b.json.sentAt) - new Date(a.json.sentAt));\n\nconst pendingLog = myLogs.find(r => r.json.status === 'Pending');\n\n// Calculate current streak (consecutive taken days)\nconst takenDays = new Set(\n  allRows\n    .filter(r => r.json.phone === phone && r.json.status === 'Taken')\n    .map(r => r.json.date)\n);\n\nlet streak = 0;\nconst checkDate = new Date(today);\nwhile (takenDays.has(checkDate.toISOString().split('T')[0])) {\n  streak++;\n  checkDate.setDate(checkDate.getDate() - 1);\n}\n\n// Streak emoji\nlet streakMsg = '';\nif (streak >= 30) streakMsg = `\ud83c\udfc6 Incredible! ${streak}-day streak!`;\nelse if (streak >= 14) streakMsg = `\ud83c\udf1f Amazing! ${streak}-day streak!`;\nelse if (streak >= 7)  streakMsg = `\ud83d\udd25 On fire! ${streak}-day streak!`;\nelse if (streak >= 3)  streakMsg = `\ud83d\udcaa ${streak}-day streak! Keep going!`;\nelse streakMsg = `\u2705 Great job taking your medication!`;\n\nconst lines = [\n  `\u2705 *Dose Logged \u2013 Taken!*`,\n  '',\n  `Well done, *${patientName}!* \ud83c\udf89`,\n  streakMsg,\n  '',\n  `\ud83d\udcc5 *Date:* ${today}`,\n  `\ud83d\udd50 *Time:* ${now.toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit' })}`,\n  '',\n  'Consistency is the key to good health! \ud83d\udc9a',\n  'Reply *mystats* to see your full adherence report.'\n];\n\nreturn [{ json: {\n  phone,\n  patientName,\n  logKey: pendingLog?.json.logKey || `${phone}_${today}_unknown`,\n  takenMessage: lines.join('\\n'),\n  today,\n  respondedAt: now.toISOString()\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ce837757-ed51-43ec-804a-536288661a96",
      "name": "Google Sheets \u2013 Update Taken",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1920,
        704
      ],
      "parameters": {
        "columns": {
          "value": {
            "logKey": "={{ $json.logKey }}",
            "status": "Taken"
          },
          "schema": [
            {
              "id": "logKey",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "logKey",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "patientName",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "patientName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "slot",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "slot",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sentAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "sentAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "respondAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "respondAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "caregiverPhone",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "caregiverPhone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "logKey"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "4196c4a3-032e-41b8-9378-46142d7ea711",
      "name": "Google Sheets \u2013 Read Log (Skip)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1424,
        880
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "2a2bd2d7-421b-4a78-aaa4-380416f9571b",
      "name": "Process Skip",
      "type": "n8n-nodes-base.code",
      "position": [
        1680,
        880
      ],
      "parameters": {
        "jsCode": "// Process Skip Response\n// Logs the skip, checks for consecutive skips\n// If 2+ consecutive skips \u2192 flag for caregiver alert\n\nconst phone = $('Wati Trigger').first().json.waId || $('WATI Trigger').item.json.from;\nconst patientName = $input.first().json.patientName || 'Patient';\nconst allRows = $input.all();\nconst now = new Date();\nconst today = now.toISOString().split('T')[0];\n\nconst myLogs = allRows\n  .filter(r => r.json.phone === phone)\n  .sort((a, b) => new Date(b.json.sentAt) - new Date(a.json.sentAt));\n\nconst pendingLog = myLogs.find(r => r.json.status === 'Pending');\ncaregiverPhone = $input.first().json.caregiverPhone || '';\n\n// Count consecutive recent skips\nconst recentLogs = myLogs.slice(0, 6);\nconst consecutiveSkips = recentLogs.filter(r => r.json.status === 'Skipped').length;\nconst alertCaregiver = consecutiveSkips >= 2;\n\nconst skipLines = [\n  `\u23ed\ufe0f *Dose Logged \u2013 Skipped*`,\n  '',\n  `We've noted your skip, *${patientName}.*`,\n  '',\n  '\u26a0\ufe0f Please consult your doctor before skipping medication regularly.',\n  '\ud83d\udca1 Tip: If you are experiencing side effects, contact your healthcare provider.',\n  '',\n  'Your next reminder will be sent on schedule.',\n  'Reply *mystats* to see your adherence report.'\n];\n\nconst caregiverLines = alertCaregiver ? [\n  `\ud83d\udea8 *Medication Skip Alert*`,\n  '',\n  `\ud83d\udc64 *Patient:* ${patientName}`,\n  `\ud83d\udcde *Phone:* ${phone}`,\n  `\u23ed\ufe0f *Consecutive Skips Detected:* ${consecutiveSkips + 1}`,\n  `\ud83d\udcc5 *Date:* ${today}`,\n  `\ud83d\udd50 *Time:* ${now.toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit' })}`,\n  '',\n  'Please check in with the patient.'\n] : [];\n\nreturn [{ json: {\n  phone,\n  patientName,\n  caregiverPhone,\n  logKey: $input.first().json.logKey || `${phone}_${today}_unknown`,\n  skipMessage: skipLines.join('\\n'),\n  caregiverMessage: caregiverLines.join('\\n'),\n  alertCaregiver,\n  respondedAt: now.toISOString()\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c79c62f4-38be-4cf9-964a-b3cc46d1b0a3",
      "name": "Google Sheets \u2013 Update Skipped",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1920,
        880
      ],
      "parameters": {
        "columns": {
          "value": {
            "logKey": "={{ $json.logKey }}",
            "status": "Skipped"
          },
          "schema": [
            {
              "id": "logKey",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "logKey",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "patientName",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "patientName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "slot",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "slot",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sentAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "sentAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "respondAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "respondAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "caregiverPhone",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "caregiverPhone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "logKey"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "7426d957-e5ad-4f49-8a62-8f8a0d237740",
      "name": "Process Snooze",
      "type": "n8n-nodes-base.code",
      "position": [
        1440,
        1200
      ],
      "parameters": {
        "jsCode": "// Process Snooze Request\n// Logs snooze with a follow-up time 30 minutes from now\n\nconst phone = $json.waId || $json.from || 'unknown';\nconst patientName = $json.senderName || 'Patient';\nconst now = new Date();\nconst followUpTime = new Date(now.getTime() + 30 * 60 * 1000);\n\nconst snoozeLines = [\n  `\ud83d\ude34 *Snooze Set!*`,\n  '',\n  `No problem, *${patientName}!*`,\n  `We'll remind you again at *${followUpTime.toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit' })}*. \u23f0`,\n  '',\n  '\ud83d\udc8a Please don\\'t forget your medication!'\n];\n\nreturn [{ json: {\n  phone,\n  patientName,\n  snoozeMessage: snoozeLines.join('\\n'),\n  followUpAt: followUpTime.toISOString(),\n  snoozedAt: now.toISOString()\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c048e9e0-6e80-4a2d-ac9b-6f21caa484e4",
      "name": "Google Sheets \u2013 Log Snooze",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1824,
        1200
      ],
      "parameters": {
        "columns": {
          "value": {
            "phone": "={{ $json.phone }}",
            "status": "Pending",
            "snoozedAt": "={{ $json.snoozedAt }}",
            "followUpAt": "={{ $json.followUpAt }}"
          },
          "schema": [
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "patientName ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "patientName ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "followUpAt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "followUpAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "snoozedAt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "snoozedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1864808001,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=1864808001",
          "cachedResultName": "SnoozeQueue"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "3980b984-eecf-405b-82a1-04ff9bd4cca0",
      "name": "Schedule Trigger \u2013 Every 30 Min",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1440,
        1328
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f2bbcd28-3930-44b3-a776-b8703ab598a8",
      "name": "Google Sheets \u2013 Read Snooze Queue",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1664,
        1328
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1864808001,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=1864808001",
          "cachedResultName": "SnoozeQueue"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "5bb3d95b-41ff-43e8-ab61-e6a78ce8fcbd",
      "name": "Check Snooze Queue",
      "type": "n8n-nodes-base.code",
      "position": [
        1936,
        1328
      ],
      "parameters": {
        "jsCode": "// Check Snooze Queue & Missed Doses\n// 1. Finds snooze entries where followUpAt <= now \u2192 resend reminder\n// 2. Finds AdherenceLog entries that are still Pending after 2 hours \u2192 missed dose\n\nconst allSnooze = $input.all();\nconst now = new Date();\n\n// Filter snooze entries due for follow-up\nconst dueSnoozes = allSnooze.filter(r => {\n  const followUpAt = new Date(r.json.followUpAt);\n  return r.json.status === 'Pending' && followUpAt <= now;\n});\n\nif (dueSnoozes.length === 0) {\n  return [{ json: { message: 'No snooze follow-ups due', count: 0, items: [] } }];\n}\n\nreturn dueSnoozes.map(r => ({\n  json: {\n    phone: r.json.phone,\n    patientName: r.json.patientName,\n    followUpMessage: `\u23f0 *Snooze Reminder!*\\n\\n\ud83d\udc8a Hi *${r.json.patientName}!* It\\'s time to take your medication now.\\n\\nReply *taken*, *skip* or *snooze* to log your response.`\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "4d942933-3d56-4f07-b32b-fe7a0fd1d8bc",
      "name": "Schedule Trigger \u2013 Every 1 Hour",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1456,
        1488
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "21749e76-c828-4c3c-9c56-4ea5888fee31",
      "name": "Google Sheets \u2013 Read Log (Missed Check)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1696,
        1488
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "20aaac89-0f54-4d6a-a99f-95ea10627376",
      "name": "Detect Missed Doses",
      "type": "n8n-nodes-base.code",
      "position": [
        1936,
        1488
      ],
      "parameters": {
        "jsCode": "// Detect Missed Doses\n// Finds AdherenceLog entries still 'Pending' after 2 hours\n// Groups by caregiver phone and builds alert messages\n\nconst allRows = $input.all();\nconst now = new Date();\nconst twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);\n\nconst missedItems = allRows.filter(r => {\n  const sentAt = new Date(r.json.sentAt || 0);\n  return r.json.status === 'Pending' && sentAt <= twoHoursAgo;\n});\n\nif (missedItems.length === 0) {\n  return [{ json: { message: 'No missed doses detected', count: 0 } }];\n}\n\n// Group by caregiver so one message per caregiver\nconst byCg = {};\nfor (const row of missedItems) {\n  const cg = row.json.caregiverPhone;\n  if (!cg) continue;\n  if (!byCg[cg]) byCg[cg] = [];\n  byCg[cg].push(row.json);\n}\n\nreturn Object.entries(byCg).map(([cgPhone, items]) => {\n  const lines = [\n    `\ud83d\udea8 *Missed Dose Alert*`,\n    '',\n    `The following patient(s) have NOT responded to their medication reminder:`,\n    ''\n  ];\n  for (const item of items) {\n    lines.push(`\ud83d\udc64 *${item.patientName}* (${item.phone})`);\n    lines.push(`   \ud83d\udcc5 Date: ${item.date} | Slot: ${item.slot}`);\n    lines.push(`   \u23f0 Reminder sent at: ${new Date(item.sentAt).toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'})}`);\n    lines.push('');\n  }\n  lines.push('Please follow up with the patient immediately.');\n  return { json: { caregiverPhone: cgPhone, alertMessage: lines.join('\\n') } };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "f64cea68-3edf-46bb-b220-4808627a2286",
      "name": "Google Sheets \u2013 Read Log (Stats)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1488,
        1904
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "59897745-4615-4578-8402-87ccd0b23609",
      "name": "Build My Stats",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        1904
      ],
      "parameters": {
        "jsCode": "// Build My Stats Report\n// 7-day adherence %, streak, best day, visual bar chart\n\nconst phone = $('Wati Trigger').first().json.waId || $('WATI Trigger').item.json.from;\nconst patientName = $('Wati Trigger').first().json.senderName || 'Patient';\nconst allRows = $input.all();\nconst now = new Date();\n\nconst myLogs = allRows.filter(r => r.json.phone === phone);\n\nif (myLogs.length === 0) {\n  return [{ json: { phone, statsMessage: `\ud83d\udcca No medication history found yet, *${patientName}!*\\n\\nStart taking your medications and reply *taken* after each dose.` } }];\n}\n\n// Last 7 days analysis\nconst last7 = [];\nfor (let i = 6; i >= 0; i--) {\n  const d = new Date(now);\n  d.setDate(d.getDate() - i);\n  const dateStr = d.toISOString().split('T')[0];\n  const dayLogs = myLogs.filter(r => r.json.date === dateStr);\n  const taken  = dayLogs.filter(r => r.json.status === 'Taken').length;\n  const total  = dayLogs.filter(r => r.json.status !== 'Pending').length;\n  const pct    = total > 0 ? Math.round((taken / total) * 100) : null;\n  last7.push({ dateStr, taken, total, pct, dayName: d.toLocaleDateString('en-IN', { weekday: 'short' }) });\n}\n\nconst totalTaken   = myLogs.filter(r => r.json.status === 'Taken').length;\nconst totalLogged  = myLogs.filter(r => r.json.status !== 'Pending').length;\nconst overallPct   = totalLogged > 0 ? Math.round((totalTaken / totalLogged) * 100) : 0;\n\n// Current streak\nlet streak = 0;\nconst sortedDates = [...new Set(myLogs.filter(r=>r.json.status==='Taken').map(r=>r.json.date))].sort().reverse();\nconst checkDate = new Date(now);\nfor (const d of sortedDates) {\n  if (d === checkDate.toISOString().split('T')[0]) {\n    streak++;\n    checkDate.setDate(checkDate.getDate() - 1);\n  } else break;\n}\n\n// Bar chart for last 7 days\nconst barLines = last7.map(d => {\n  if (d.pct === null) return `${d.dayName}: \u2500\u2500\u2500 No data`;\n  const filled = Math.round(d.pct / 10);\n  const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(10 - filled);\n  const emoji = d.pct === 100 ? '\u2705' : d.pct >= 50 ? '\u26a0\ufe0f' : '\u274c';\n  return `${d.dayName} ${bar} ${d.pct}% ${emoji}`;\n});\n\n// Overall bar\nconst overallFilled = Math.round(overallPct / 10);\nconst overallBar = '\u2588'.repeat(overallFilled) + '\u2591'.repeat(10 - overallFilled);\n\nconst lines = [\n  `\ud83d\udcca *Medication Adherence Report*`,\n  `\ud83d\udc64 *${patientName}*`,\n  '',\n  `${overallBar} *${overallPct}% Overall*`,\n  `\ud83d\udd25 *Current Streak:* ${streak} day${streak !== 1 ? 's' : ''}`,\n  '',\n  '\u2501\u2501 *Last 7 Days* \u2501\u2501',\n  ...barLines,\n  '',\n  `\u2705 Taken: ${totalTaken} doses`,\n  `\u23ed\ufe0f Skipped: ${myLogs.filter(r=>r.json.status==='Skipped').length} doses`,\n  `\u2753 Missed: ${myLogs.filter(r=>r.json.status==='Pending').length} doses`,\n  '',\n  'Keep it up! Consistency saves lives \ud83d\udc9a'\n];\n\nreturn [{ json: { phone, statsMessage: lines.join('\\n') } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "293849b3-4226-4f7b-9eb4-25f47689209d",
      "name": "Google Sheets \u2013 Read My Meds",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1488,
        2080
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=0",
          "cachedResultName": "Medications"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "6ab026e7-4305-47ad-aa40-6a2afaac2905",
      "name": "Build My Meds Schedule",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        2080
      ],
      "parameters": {
        "jsCode": "// Build My Medications Schedule\n// Shows today's full schedule with timings and dosage\n\nconst phone = $('Wati Trigger').first().json.waId|| $('WATI Trigger').item.json.from;\nconst patientName =$('Wati Trigger').first().json.senderName|| 'Patient';\nconst allRows = $input.all();\n\nconst myMeds = allRows.filter(r =>\n  r.json.phone === phone && (r.json.status || '').toLowerCase() === 'active'\n);\n\nif (myMeds.length === 0) {\n  return [{ json: { phone, myMedsMessage: `\ud83d\udc8a No active medications found, *${patientName}.*\\n\\nPlease contact your healthcare provider.` } }];\n}\n\nconst slotMap = { morning: '\ud83c\udf05 Morning (8:00 AM)', afternoon: '\u2600\ufe0f Afternoon (1:00 PM)', night: '\ud83c\udf19 Night (8:00 PM)' };\nconst grouped = { morning: [], afternoon: [], night: [] };\n\nfor (const row of myMeds) {\n  const slots = (row.json.timeSlots || 'morning').split(',').map(s => s.trim().toLowerCase());\n  for (const slot of slots) {\n    if (grouped[slot]) grouped[slot].push(row.json);\n  }\n}\n\nconst today = new Date().toLocaleDateString('en-IN', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });\n\nconst lines = [\n  `\ud83d\udc8a *Today's Medication Schedule*`,\n  `\ud83d\udc64 *${patientName}*`,\n  `\ud83d\udcc5 ${today}`,\n  ''\n];\n\nfor (const [slot, meds] of Object.entries(grouped)) {\n  if (meds.length === 0) continue;\n  lines.push(slotMap[slot]);\n  for (const m of meds) {\n    lines.push(`  \u2022 *${m.medName}* \u2014 ${m.dosage}`);\n    if (m.instructions) lines.push(`    \ud83d\udcdd ${m.instructions}`);\n  }\n  lines.push('');\n}\n\nlines.push('\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501');\nlines.push('Reply *taken*, *skip* or *snooze* after each dose.');\nlines.push('Reply *mystats* for your adherence report.');\n\nreturn [{ json: { phone, myMedsMessage: lines.join('\\n') } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "eccbd185-7ba8-49df-aeba-ca654e375606",
      "name": "Google Sheets \u2013 Read Log (Caregiver)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1488,
        2240
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 816163013,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit#gid=816163013",
          "cachedResultName": "AdherenceLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IGGQCHH59cFU-4A_ERv5s-SD0o1rrXwEZ9-jQX049g4/edit?usp=drivesdk",
          "cachedResultName": "Untitled spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "52f2e40d-c1c9-4f7b-97af-182b0271d0ee",
      "name": "Build Caregiver Report",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        2240
      ],
      "parameters": {
        "jsCode": "// Build Caregiver Patient Report\n// Caregiver sends: 'report 919876543210'\n// Returns full adherence summary for that patient\n\nconst text = $('Wati Trigger').first().json.text||''.trim();\nconst caregiverPhone =  $input.first().json.caregiverPhone|| $('WATI Trigger').item.json.from;\nconst patientPhone = $('Wati Trigger').first().json.waId;\n\nif (!patientPhone) {\n  return [{ json: { phone: caregiverPhone, reportMessage: '\u26a0\ufe0f Please provide a patient phone number.\\nExample: *report 919876543210*' } }];\n}\n\nconst allRows = $input.all();\nconst patientLogs = allRows.filter(r => r.json.phone === patientPhone);\n\nif (patientLogs.length === 0) {\n  return [{ json: { phone: caregiverPhone, reportMessage: `\u274c No records found for *${patientPhone}*.` } }];\n}\n\nconst patientName = patientLogs[0].json.patientName || 'Patient';\nconst totalTaken   = patientLogs.filter(r => r.json.status === 'Taken').length;\nconst totalSkipped = patientLogs.filter(r => r.json.status === 'Skipped').length;\nconst totalMissed  = patientLogs.filter(r => r.json.status === 'Pending').length;\nconst totalLogged  = totalTaken + totalSkipped + totalMissed;\nconst adherencePct = totalLogged > 0 ? Math.round((totalTaken / totalLogged) * 100) : 0;\n\n// Last 7 days summary\nconst now = new Date();\nconst recentDays = [];\nfor (let i = 6; i >= 0; i--) {\n  const d = new Date(now);\n  d.setDate(d.getDate() - i);\n  const dateStr = d.toISOString().split('T')[0];\n  const dayLogs = patientLogs.filter(r => r.json.date === dateStr);\n  const t = dayLogs.filter(r => r.json.status === 'Taken').length;\n  const tot = dayLogs.filter(r => r.json.status !== 'Pending').length;\n  const pct = tot > 0 ? Math.round((t / tot) * 100) : null;\n  const dayName = d.toLocaleDateString('en-IN', { weekday: 'short', month: 'short', day: 'numeric' });\n  const emoji = pct === null ? '\u2500' : pct === 100 ? '\u2705' : pct >= 50 ? '\u26a0\ufe0f' : '\u274c';\n  recentDays.push(`${dayName}: ${pct !== null ? pct + '%' : 'No data'} ${emoji}`);\n}\n\nconst overallFilled = Math.round(adherencePct / 10);\nconst overallBar = '\u2588'.repeat(overallFilled) + '\u2591'.repeat(10 - overallFilled);\n\nconst lines = [\n  `\ud83d\udccb *Patient Adherence Report*`,\n  `\ud83d\udc64 *Patient:* ${patientName}`,\n  `\ud83d\udcde *Phone:* ${patientPhone}`,\n  '',\n  `${overallBar} *${adherencePct}% Overall*`,\n  '',\n  `\u2705 *Taken:* ${totalTaken} doses`,\n  `\u23ed\ufe0f *Skipped:* ${totalSkipped} doses`,\n  `\u2753 *Missed:* ${totalMissed} doses`,\n  `\ud83d\udce6 *Total Logged:* ${totalLogged} doses`,\n  '',\n  '\u2501\u2501 *Last 7 Days* \u2501\u2501',\n  ...recentDays,\n  '',\n  `Report generated: ${now.toLocaleDateString('en-IN')}`\n];\n\nreturn [{ json: { phone: caregiverPhone, reportMessage: lines.join('\\n') } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f03f68e3-a5b4-4f3e-aa07-408a2df7e6b1",
      "name": "Send a text message",
      "type": "n8n-nodes-wati.wati",
      "position": [
        3776,
        1472
      ],
      "parameters": {
        "target": "=917024935915",
        "messageText": "={{ $('Build Medication Reminder').item.json.reminderMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "509e2d6b-3205-4d08-969c-0b840ddd0eae",
      "name": "Wati Trigger",
      "type": "n8n-nodes-wati.watiTrigger",
      "position": [
        96,
        1536
      ],
      "parameters": {
        "event": "messageReceived"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "fe701382-9087-4e7a-85a5-6d5acf534f1a",
      "name": "Send a text message1",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2160,
        704
      ],
      "parameters": {
        "target": "={{ $('Wati Trigger').item.json.waId }}",
        "messageText": "={{ $('Process Taken').item.json.takenMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "be7b476e-74f8-4de5-80fb-787e126b52ac",
      "name": "Send a text message2",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2160,
        880
      ],
      "parameters": {
        "target": "={{ $('Wati Trigger').item.json.waId }}",
        "messageText": "={{ $('Process Skip').item.json.skipMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "25d4311c-b26d-4dff-b8d9-0d4c781bf224",
      "name": "Send a text message3",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2096,
        1200
      ],
      "parameters": {
        "target": "={{ $('Wati Trigger').item.json.waId }}",
        "messageText": "={{ $('Process Snooze').item.json.snoozeMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8f28a3c3-9446-4fed-a69d-effe23c84a71",
      "name": "Send a text message4",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2000,
        1904
      ],
      "parameters": {
        "target": "={{ $('Wati Trigger').item.json.waId }}",
        "messageText": "={{ $json.statsMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "682c2e3a-49b2-4bc7-a856-c3e8f60f107f",
      "name": "Send a text message5",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2000,
        2080
      ],
      "parameters": {
        "target": "={{ $('Wati Trigger').item.json.waId }}",
        "messageText": "={{ $json.myMedsMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0b95e745-e435-4a5f-883b-7346a20178e5",
      "name": "Send a text message6",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2000,
        2240
      ],
      "parameters": {
        "target": "={{ $('Wati Trigger').item.json.waId }}",
        "messageText": "={{ $json.reportMessage }}"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "34393446-073c-48bb-8b02-9dad32feb24f",
      "name": "Send a text message7",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2240,
        1328
      ],
      "parameters": {
        "target": "917024935915",
        "messageText": "hi"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5fc474db-2fd0-4e8a-8b47-609c2cbea911",
      "name": "Send a text message8",
      "type": "n8n-nodes-wati.wati",
      "position": [
        2144,
        1488
      ],
      "parameters": {
        "target": "917024935915",
        "messageText": "hi"
      },
      "credentials": {
        "watiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Process Skip": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Update Skipped",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wati Trigger": {
      "main": [
        [
          {
            "node": "Route Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Taken": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Update Taken",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Message": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Read Log (Taken)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Sheets \u2013 Read Log (Skip)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Process Snooze",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Sheets \u2013 Read Log (Stats)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Sheets \u2013 Read My Meds",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Sheets \u2013 Read Log (Caregiver)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build My Stats": {
      "main": [
        [
          {
            "node": "Send a text message4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Snooze": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Log Snooze",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Snooze Queue": {
      "main": [
        [
          {
            "node": "Send a text message7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Missed Doses": {
      "main": [
        [
          {
            "node": "Send a text message8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Caregiver Report": {
      "main": [
        [
          {
            "node": "Send a text message6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build My Meds Schedule": {
      "main": [
        [
          {
            "node": "Send a text message5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Medication Reminder": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Log Reminder Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Log Snooze": {
      "main": [
        [
          {
            "node": "Send a text message3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read My Meds": {
      "main": [
        [
          {
            "node": "Build My Meds Schedule",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Update Taken": {
      "main": [
        [
          {
            "node": "Send a text message1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Medications by Time Slot": {
      "main": [
        [
          {
            "node": "Build Medication Reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Update Skipped": {
      "main": [
        [
          {
            "node": "Send a text message2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger \u2013 8AM 1PM 8PM": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Read Medications",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Log (Skip)": {
      "main": [
        [
          {
            "node": "Process Skip",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger \u2013 Every 1 Hour": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Read Log (Missed Check)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger \u2013 Every 30 Min": {
      "main": [
        [
          {
            "node": "Google Sheets \u2013 Read Snooze Queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Log (Stats)": {
      "main": [
        [
          {
            "node": "Build My Stats",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Log (Taken)": {
      "main": [
        [
          {
            "node": "Process Taken",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Medications": {
      "main": [
        [
          {
            "node": "Filter Medications by Time Slot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Log Reminder Sent": {
      "main": [
        [
          {
            "node": "Send a text message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Snooze Queue": {
      "main": [
        [
          {
            "node": "Check Snooze Queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Log (Caregiver)": {
      "main": [
        [
          {
            "node": "Build Caregiver Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2013 Read Log (Missed Check)": {
      "main": [
        [
          {
            "node": "Detect Missed Doses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}