{
  "id": "pjvCapacityPl001",
  "name": "Resource & Capacity Planner",
  "nodes": [
    {
      "parameters": {
        "content": "## Resource & Capacity Planner\nEvery Monday 08:00. Pulls allocations across projects, asks GPT to flag over/under-commitment and suggest rebalancing, and sends the PM a weekly capacity brief.\n\n**Configure:** allocation source URL, OpenAI key, and the notification webhook.",
        "height": 250,
        "width": 340
      },
      "id": "note1",
      "name": "About",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [200, 40]
    },
    {
      "parameters": {
        "rule": { "interval": [ { "field": "cronExpression", "expression": "0 8 * * 1" } ] }
      },
      "id": "sched1",
      "name": "Every Monday 08:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [240, 340]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://your-resourcing.example.com/api/allocations?window=this_week",
        "authentication": "none",
        "options": {}
      },
      "id": "http1",
      "name": "Get Allocations",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [480, 340]
    },
    {
      "parameters": {
        "jsCode": "// Build a capacity-planning prompt from per-person allocation across projects.\nconst people = $input.first().json.allocations || $input.first().json || [];\nconst prompt = `You are a resource and capacity planner. Each person has allocated hours across projects vs their weekly capacity. Flag anyone over-committed (>100%) or heavily under-utilised (<60%) and suggest concrete rebalancing moves. Return JSON: {\"overCommitted\":[{\"person\":string,\"load\":string}],\"underUtilised\":[{\"person\":string,\"load\":string}],\"suggestions\":string[]}.\\n\\nAllocations:\\n${JSON.stringify(people, null, 2)}`;\nreturn [{ json: { prompt } }];"
      },
      "id": "code1",
      "name": "Build Capacity 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 resource and capacity planner. Reply ONLY with valid JSON.\" },\n    { \"role\": \"user\", \"content\": {{ JSON.stringify($json.prompt) }} }\n  ],\n  \"temperature\": 0.3\n}",
        "options": {}
      },
      "id": "http2",
      "name": "Plan Capacity (GPT)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [960, 340]
    },
    {
      "parameters": {
        "jsCode": "let r = { overCommitted: [], underUtilised: [], suggestions: [] };\ntry { r = JSON.parse($json.choices[0].message.content); } catch (e) {}\nconst lines = [];\nlines.push('*Weekly capacity brief*');\nif ((r.overCommitted||[]).length) lines.push('Over-committed: ' + r.overCommitted.map(p => p.person + ' (' + p.load + ')').join(', '));\nif ((r.underUtilised||[]).length) lines.push('Under-utilised: ' + r.underUtilised.map(p => p.person + ' (' + p.load + ')').join(', '));\nif ((r.suggestions||[]).length) lines.push('Suggested moves:\\n- ' + r.suggestions.join('\\n- '));\nreturn [{ json: { message: lines.join('\\n') } }];"
      },
      "id": "code2",
      "name": "Format Brief",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1200, 340]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/YOUR/CAPACITY/WEBHOOK",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": {{ JSON.stringify($json.message) }}\n}",
        "options": {}
      },
      "id": "http3",
      "name": "Send Capacity Brief",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1440, 340]
    }
  ],
  "connections": {
    "Every Monday 08:00": { "main": [ [ { "node": "Get Allocations", "type": "main", "index": 0 } ] ] },
    "Get Allocations": { "main": [ [ { "node": "Build Capacity Prompt", "type": "main", "index": 0 } ] ] },
    "Build Capacity Prompt": { "main": [ [ { "node": "Plan Capacity (GPT)", "type": "main", "index": 0 } ] ] },
    "Plan Capacity (GPT)": { "main": [ [ { "node": "Format Brief", "type": "main", "index": 0 } ] ] },
    "Format Brief": { "main": [ [ { "node": "Send Capacity Brief", "type": "main", "index": 0 } ] ] }
  },
  "settings": { "executionOrder": "v1" },
  "active": false,
  "pinData": {},
  "meta": { "templateCredsSetupCompleted": false }
}
