{
  "name": "LGM 06 — Approval-Gated Social Content (SIMULATED)",
  "nodes": [
    {
      "parameters": {},
      "id": "f06-start",
      "name": "Start",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        240,
        320
      ]
    },
    {
      "parameters": {
        "jsCode": "// Fictional upload payload from a marketing form.\nconst fixture = {\n  upload_id: 'UPL-' + Math.floor(Math.random() * 9000 + 1000),\n  brand: 'Bloom & Vine Landscaping',\n  topic: 'before-and-after front yard',\n  platform: 'instagram',\n  uploaded_at: new Date().toISOString(),\n  photos: ['photo://hash-A', 'photo://hash-B'],\n  suggested_caption: 'Front yard transformation — three weeks from bare dirt to a layered, low-water garden. Native saltbush and westringia framing a bluestone path. DM if you’d like a quote.',\n  branch_hint: 'approve-as-is'\n};\nreturn [{ json: fixture }];"
      },
      "id": "f06-fixture",
      "name": "Build Fixture",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        320
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.branch_hint }}",
                    "rightValue": "edit",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "outputKey": "edit",
              "renameOutput": true
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.branch_hint }}",
                    "rightValue": "reject",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "outputKey": "reject",
              "renameOutput": true
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.branch_hint }}",
                    "rightValue": "save-library",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "outputKey": "save-library",
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "id": "f06-switch",
      "name": "Approval Decision",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        680,
        320
      ]
    },
    {
      "parameters": {
        "jsCode": "// Approve as-is — record approval + queue for publish.\nconst items = $input.all();\nconst $json = items[0].json;\nconst simulatedOutputs = [\n  { type: 'heading', label: '1. Approval record (SIMULATED Twenty)' },\n  { type: 'crm', label: 'Twenty CRM', rows: [\n    { label: 'Upload', value: $json.upload_id },\n    { label: 'Decision', value: 'approve-as-is' },\n    { label: 'Approver', value: 'manager@local' },\n    { label: 'Version', value: 'v1' }\n  ]},\n  { type: 'heading', label: '2. Internal note (SIMULATED Slack/Teams)' },\n  { type: 'message', channel: 'internal', label: 'Slack/Teams',\n    body: `Caption approved by manager. Queued for ${$json.platform} publish at next scheduled slot (configurable, default 9am Melbourne).` },\n  { type: 'heading', label: '3. Publishing payload (SIMULATED Buffer/Later)' },\n  { type: 'code', label: 'Buffer/Later',\n    language: 'json',\n    body: JSON.stringify({\n      upload_id: $json.upload_id,\n      platform: $json.platform,\n      caption: $json.suggested_caption,\n      photos: $json.photos,\n      scheduled_at: 'next 9am Melbourne'\n    }, null, 2) },\n  { type: 'note', label: 'Compliance',\n    text: 'Approval recorded with version + approver for audit.' }\n];\nreturn [{ json: { ...$json, branch: 'approve-as-is', simulatedOutputs } }];"
      },
      "id": "f06-ok",
      "name": "Build Approve",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "// Editor requested changes — short-circuit back into the review queue.\nconst items = $input.all();\nconst $json = items[0].json;\nconst simulatedOutputs = [\n  { type: 'heading', label: '1. Approval record (SIMULATED Twenty)' },\n  { type: 'crm', label: 'Twenty CRM', rows: [\n    { label: 'Upload', value: $json.upload_id },\n    { label: 'Decision', value: 'edit' }\n  ]},\n  { type: 'heading', label: '2. Editor note (SIMULATED internal)' },\n  { type: 'message', channel: 'internal', label: 'Slack/Teams',\n    body: `Editor requested changes on upload ${$json.upload_id}. Suggested rewrite captured; resubmitting for approval.` }\n];\nreturn [{ json: { ...$json, branch: 'edit', simulatedOutputs } }];"
      },
      "id": "f06-edit",
      "name": "Build Edit Output",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        360
      ]
    },
    {
      "parameters": {
        "jsCode": "// Reject — record reason, no client record affected.\nconst items = $input.all();\nconst $json = items[0].json;\nconst simulatedOutputs = [\n  { type: 'heading', label: '1. Approval record (SIMULATED Twenty)' },\n  { type: 'crm', label: 'Twenty CRM', rows: [\n    { label: 'Upload', value: $json.upload_id },\n    { label: 'Decision', value: 'reject' },\n    { label: 'Reason', value: 'off-brand' }\n  ]},\n  { type: 'heading', label: '2. Editor note (SIMULATED internal)' },\n  { type: 'message', channel: 'internal', label: 'Slack/Teams',\n    body: `Draft rejected. Reason: off-brand. Skipping publish; no client record affected.` }\n];\nreturn [{ json: { ...$json, branch: 'reject', simulatedOutputs } }];"
      },
      "id": "f06-reject",
      "name": "Build Reject",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "// Save to library — no immediate publish; sibling variants generated.\nconst items = $input.all();\nconst $json = items[0].json;\nconst simulatedOutputs = [\n  { type: 'heading', label: '1. Approval record (SIMULATED Twenty)' },\n  { type: 'crm', label: 'Twenty CRM', rows: [\n    { label: 'Upload', value: $json.upload_id },\n    { label: 'Decision', value: 'save-library' }\n  ]},\n  { type: 'heading', label: '2. Editor note (SIMULATED internal)' },\n  { type: 'message', channel: 'internal', label: 'Slack/Teams',\n    body: `Draft saved to library but not scheduled. Will appear in next week's review queue with 3 sibling variants.` }\n];\nreturn [{ json: { ...$json, branch: 'save-library', simulatedOutputs } }];"
      },
      "id": "f06-save",
      "name": "Build Save",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        680
      ]
    },
    {
      "parameters": {},
      "id": "f06-sink",
      "name": "Sink",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1140,
        400
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Build Fixture",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Fixture": {
      "main": [
        [
          {
            "node": "Approval Decision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Decision": {
      "main": [
        [
          {
            "node": "Build Approve",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Edit Output",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Reject",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Save",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Approve": {
      "main": [
        [
          {
            "node": "Sink",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Edit Output": {
      "main": [
        [
          {
            "node": "Sink",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Reject": {
      "main": [
        [
          {
            "node": "Sink",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Save": {
      "main": [
        [
          {
            "node": "Sink",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "lgm-06-approval-social-content",
  "id": "lgm-06-approval-social-content",
  "meta": {
    "templateCredsSetupCompleted": false,
    "description": "SIMULATED approval-gated social content. Nothing publishes without a manager sign-off."
  },
  "tags": [
    {
      "name": "lgm-06-approval-social-content"
    }
  ]
}
