{
  "name": "WF-003 Usage Aggregator",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 1 * * *"
            }
          ]
        }
      },
      "id": "wf003-node-schedule",
      "name": "Daily 1AM ET",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "tenants",
        "returnAll": true,
        "filterType": "string",
        "filterString": "subscription_status=eq.active"
      },
      "id": "wf003-node-get-tenants",
      "name": "Get Active Tenants",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        250,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "id": "wf003-node-loop",
      "name": "Loop Over Tenants",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "calls",
        "returnAll": true,
        "filterType": "string",
        "filterString": "={{ 'tenant_id=eq.' + $json.id + '&created_at=gte.' + new Date(Date.now() - 86400000).toISOString().split('T')[0] }}"
      },
      "id": "wf003-node-get-calls",
      "name": "Get Calls (Last 24h)",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        750,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Aggregate call data for the current tenant\nconst items = $input.all();\nconst tenantItem = $('Loop Over Tenants').item;\nconst tenantId = tenantItem.json.id;\n\nconst calls = items.map(i => i.json);\nconst today = new Date();\nconst dateStr = today.toISOString().split('T')[0];\n\nconst totalCalls = calls.length;\nconst totalMinutes = Math.round(\n  calls.reduce((sum, c) => sum + (c.duration_seconds || 0), 0) / 60 * 100\n) / 100;\nconst answered = calls.filter(c => c.status === 'answered').length;\nconst missed = calls.filter(c => c.status === 'missed').length;\nconst voicemail = calls.filter(c => c.status === 'voicemail').length;\nconst escalations = calls.filter(c => c.escalated === true).length;\n\nreturn [\n  {\n    json: {\n      date: dateStr,\n      tenant_id: tenantId,\n      total_calls: totalCalls,\n      total_minutes: totalMinutes,\n      answered: answered,\n      missed: missed,\n      voicemail: voicemail,\n      escalations: escalations\n    }\n  }\n];"
      },
      "id": "wf003-node-aggregate",
      "name": "Aggregate Daily Stats",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1000,
        300
      ]
    },
    {
      "parameters": {
        "operation": "upsert",
        "tableId": "usage_daily",
        "conflictColumns": "date,tenant_id",
        "columns": "date,tenant_id,total_calls,total_minutes,answered,missed,voicemail,escalations"
      },
      "id": "wf003-node-upsert-daily",
      "name": "Upsert usage_daily",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1250,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Build monthly aggregation record from daily data\nconst item = $input.all()[0].json;\nconst tenantId = item.tenant_id;\nconst date = new Date(item.date);\nconst yearMonth = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;\n\nreturn [\n  {\n    json: {\n      year_month: yearMonth,\n      tenant_id: tenantId,\n      total_calls_increment: item.total_calls,\n      total_minutes_increment: item.total_minutes,\n      answered_increment: item.answered,\n      missed_increment: item.missed,\n      voicemail_increment: item.voicemail,\n      escalations_increment: item.escalations\n    }\n  }\n];"
      },
      "id": "wf003-node-monthly-prep",
      "name": "Prepare Monthly Update",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1500,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://yepggeqhtspgzlkhqhgo.supabase.co/rest/v1/rpc/upsert_usage_monthly",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Prefer",
              "value": "return=representation"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ p_year_month: $json.year_month, p_tenant_id: $json.tenant_id, p_total_calls: $json.total_calls_increment, p_total_minutes: $json.total_minutes_increment, p_answered: $json.answered_increment, p_missed: $json.missed_increment, p_voicemail: $json.voicemail_increment, p_escalations: $json.escalations_increment }) }}"
      },
      "id": "wf003-node-upsert-monthly",
      "name": "Upsert usage_monthly",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1750,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Daily 1AM ET": {
      "main": [
        [
          {
            "node": "Get Active Tenants",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Active Tenants": {
      "main": [
        [
          {
            "node": "Loop Over Tenants",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Tenants": {
      "main": [
        null,
        [
          {
            "node": "Get Calls (Last 24h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Calls (Last 24h)": {
      "main": [
        [
          {
            "node": "Aggregate Daily Stats",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Daily Stats": {
      "main": [
        [
          {
            "node": "Upsert usage_daily",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert usage_daily": {
      "main": [
        [
          {
            "node": "Prepare Monthly Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Monthly Update": {
      "main": [
        [
          {
            "node": "Upsert usage_monthly",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert usage_monthly": {
      "main": [
        [
          {
            "node": "Loop Over Tenants",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "timezone": "America/New_York"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "active": false,
  "tags": [
    {
      "name": "usage"
    },
    {
      "name": "daily"
    },
    {
      "name": "aggregation"
    }
  ]
}