{
  "id": "pjvRiskDepTrk001",
  "name": "Risk & Dependency Tracker",
  "nodes": [
    {
      "parameters": {
        "content": "## Risk & Dependency Tracker\nA background daemon (every 3h). Pulls tasks + velocity, asks GPT to predict slipping timelines and bottlenecks, and alerts the PM only when risk is high.\n\n**Configure:** tracker API URL, OpenAI key, and the alert webhook.",
        "height": 250,
        "width": 340
      },
      "id": "note1",
      "name": "About",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [200, 40]
    },
    {
      "parameters": {
        "rule": { "interval": [ { "field": "hours", "hoursInterval": 3 } ] }
      },
      "id": "sched1",
      "name": "Every 3 hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [240, 340]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://your-tracker.example.com/api/tasks?fields=status,due,estimate,dependencies,velocity",
        "authentication": "none",
        "options": {}
      },
      "id": "http1",
      "name": "Get Tasks + Velocity",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [480, 340]
    },
    {
      "parameters": {
        "jsCode": "// Build a risk-analysis prompt from tasks, dependencies and velocity.\nconst tasks = $input.first().json.tasks || $input.first().json || [];\nconst prompt = `You are a delivery risk analyst. Given the tasks (with status, due dates, estimates, dependencies and recent velocity), identify tasks likely to slip and dependency bottlenecks. Return JSON: {\"riskLevel\":\"low|medium|high\",\"atRisk\":[{\"task\":string,\"why\":string}],\"bottlenecks\":string[]}.\\n\\nData:\\n${JSON.stringify(tasks, null, 2)}`;\nreturn [{ json: { prompt } }];"
      },
      "id": "code1",
      "name": "Build Risk Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [720, 340]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer YOUR_OPENAI_API_KEY" }, { "name": "Content-Type", "value": "application/json" } ] },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"gpt-4o-mini\",\n  \"messages\": [\n    { \"role\": \"system\", \"content\": \"You are a delivery risk analyst. Reply ONLY with valid JSON.\" },\n    { \"role\": \"user\", \"content\": {{ JSON.stringify($json.prompt) }} }\n  ],\n  \"temperature\": 0.2\n}",
        "options": {}
      },
      "id": "http2",
      "name": "Analyse Risk (GPT)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [960, 340]
    },
    {
      "parameters": {
        "jsCode": "let r = { riskLevel: 'low', atRisk: [], bottlenecks: [] };\ntry { r = JSON.parse($json.choices[0].message.content); } catch (e) {}\nreturn [{ json: r }];"
      },
      "id": "code2",
      "name": "Parse Risk",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1200, 340]
    },
    {
      "parameters": {
        "conditions": {
          "options": { "caseSensitive": true, "typeValidation": "loose" },
          "combinator": "or",
          "conditions": [
            { "leftValue": "={{ $json.riskLevel }}", "rightValue": "high", "operator": { "type": "string", "operation": "equals" } },
            { "leftValue": "={{ $json.riskLevel }}", "rightValue": "medium", "operator": { "type": "string", "operation": "equals" } }
          ]
        },
        "options": {}
      },
      "id": "if1",
      "name": "Risk medium/high?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1440, 340]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/YOUR/RISK/WEBHOOK",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": {{ JSON.stringify(\":warning: Delivery risk: \" + $json.riskLevel.toUpperCase() + \"\\nAt risk:\\n- \" + ($json.atRisk || []).map(a => a.task + \" — \" + a.why).join(\"\\n- \") + \"\\nBottlenecks: \" + ($json.bottlenecks || []).join(\", \")) }}\n}",
        "options": {}
      },
      "id": "http3",
      "name": "Alert PM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1680, 240]
    }
  ],
  "connections": {
    "Every 3 hours": { "main": [ [ { "node": "Get Tasks + Velocity", "type": "main", "index": 0 } ] ] },
    "Get Tasks + Velocity": { "main": [ [ { "node": "Build Risk Prompt", "type": "main", "index": 0 } ] ] },
    "Build Risk Prompt": { "main": [ [ { "node": "Analyse Risk (GPT)", "type": "main", "index": 0 } ] ] },
    "Analyse Risk (GPT)": { "main": [ [ { "node": "Parse Risk", "type": "main", "index": 0 } ] ] },
    "Parse Risk": { "main": [ [ { "node": "Risk medium/high?", "type": "main", "index": 0 } ] ] },
    "Risk medium/high?": { "main": [ [ { "node": "Alert PM", "type": "main", "index": 0 } ], [] ] }
  },
  "settings": { "executionOrder": "v1" },
  "active": false,
  "pinData": {},
  "meta": { "templateCredsSetupCompleted": false }
}
