AutomationFlowsData & Sheets › Wf 002 Topic Scoring

Wf 002 Topic Scoring

WF-002-topic-scoring. Uses postgres. Scheduled trigger; 10 nodes.

Cron / scheduled trigger★★★★☆ complexity10 nodesPostgres
Data & Sheets Trigger: Cron / scheduled Nodes: 10 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "wf002-topic-scoring-000000000",
  "name": "WF-002-topic-scoring",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "*/30 * * * *"
            }
          ]
        }
      },
      "id": "c3000000-0002-0002-0002-000000000001",
      "name": "Schedule 30min",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        240,
        500
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT id, title, description, source, source_url FROM topics WHERE status = 'discovered' ORDER BY created_at ASC LIMIT 10",
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000002",
      "name": "Poll Discovered Topics",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        460,
        500
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "c3000000-0002-0002-0002-000000000030",
              "leftValue": "={{ $json.id }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000003",
      "name": "Has Topics?",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        680,
        500
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "={{ `SELECT pv.system_prompt, pv.user_prompt_template, pv.model_params FROM prompt_versions pv JOIN prompts p ON p.id = pv.prompt_id WHERE p.name = 'research_score' AND pv.version = p.current_version AND p.is_active = true LIMIT 1` }}",
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000005",
      "name": "Load Prompt",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1120,
        500
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT auto_approve_threshold FROM brand_profiles WHERE channel_id = 1 LIMIT 1",
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000011",
      "name": "Load Threshold",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1230,
        500
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const topic = $('Poll Discovered Topics').item.json;\nconst prompt = $('Load Prompt').item.json;\n\nconst userPrompt = (prompt.user_prompt_template || '')\n  .replace('{{ topic_title }}', topic.title || '')\n  .replace('{{ topic_description }}', topic.description || topic.title || '')\n  .replace('{{ topic_source }}', topic.source || '');\n\nreturn [{\n  json: {\n    topic_id: topic.id,\n    topic_title: topic.title,\n    system_prompt: prompt.system_prompt,\n    user_prompt: userPrompt,\n    task_type: 'research_score',\n    output_format: 'json',\n    workflow_name: 'WF-002-topic-scoring'\n  }\n}];"
      },
      "id": "c3000000-0002-0002-0002-000000000006",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        500
      ]
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "2673a82a-e155-4d0c-85b4-92922b74849d",
          "mode": "id"
        },
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000007",
      "name": "Call SUB-001",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.1,
      "position": [
        1560,
        500
      ]
    },
    {
      "parameters": {
        "jsCode": "const raw = $input.item.json;\nconst topicId = $('Build Prompt').item.json.topic_id;\nconst topicTitle = $('Build Prompt').item.json.topic_title;\nconst threshold = parseFloat($('Load Threshold').item.json.auto_approve_threshold) || 7.5;\n\nlet parsed = {};\ntry {\n  if (raw.response_json && typeof raw.response_json === 'object' && raw.response_json.value_score !== undefined) {\n    parsed = raw.response_json;\n  } else {\n    const text = raw.response_text || raw.response_json || '';\n    const match = String(text).match(/\\{[\\s\\S]*\\}/);\n    if (match) parsed = JSON.parse(match[0]);\n  }\n} catch(e) {\n  parsed = { value_score: 0, evergreen_score: 0, cpm_tier: 'low', reason: 'parse error: ' + e.message };\n}\n\nconst score = parseFloat(parsed.value_score) || 0;\nreturn [{\n  json: {\n    topic_id: topicId,\n    topic_title: topicTitle,\n    value_score: score,\n    evergreen_score: parseFloat(parsed.evergreen_score) || 0,\n    cpm_tier: parsed.cpm_tier || 'low',\n    reason: parsed.reason || '',\n    threshold: threshold,\n    new_status: score >= threshold ? 'approved' : 'archived'\n  }\n}];"
      },
      "id": "c3000000-0002-0002-0002-000000000008",
      "name": "Parse Score",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1780,
        500
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "={{ `UPDATE topics SET status = '${$json.new_status}', value_score = ${$json.value_score}, evergreen_score = ${$json.evergreen_score}, cpm_tier = '${$json.cpm_tier}', updated_at = NOW() WHERE id = ${$json.topic_id} RETURNING id, title, status, value_score` }}",
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000009",
      "name": "Update Topic",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        2000,
        500
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "={{ `INSERT INTO workflow_logs (workflow_name, workflow_id, execution_id, status, input_summary, output_summary, created_at) VALUES ('WF-002-topic-scoring', 'wf002-topic-scoring-000000000', '${$execution.id}', 'completed', '{}', '{}', NOW())` }}",
        "options": {}
      },
      "id": "c3000000-0002-0002-0002-000000000010",
      "name": "Log Result",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        2220,
        500
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Schedule 30min": {
      "main": [
        [
          {
            "node": "Poll Discovered Topics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Discovered Topics": {
      "main": [
        [
          {
            "node": "Has Topics?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Topics?": {
      "main": [
        [
          {
            "node": "Load Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Prompt": {
      "main": [
        [
          {
            "node": "Load Threshold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Threshold": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Prompt": {
      "main": [
        [
          {
            "node": "Call SUB-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call SUB-001": {
      "main": [
        [
          {
            "node": "Parse Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Score": {
      "main": [
        [
          {
            "node": "Update Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Topic": {
      "main": [
        [
          {
            "node": "Log Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

WF-002-topic-scoring. Uses postgres. Scheduled trigger; 10 nodes.

Source: https://github.com/navin-labs/content-factory-os/blob/main/n8n/workflows/main/WF-002-topic-scoring.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.

Item Lists, Postgres, Email Send +1
Data & Sheets

공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.

Postgres, HTTP Request, N8N Nodes Solapi
Data & Sheets

QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.

Postgres, Postgres Trigger, HTTP Request
Data & Sheets

QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.

Postgres, Postgres Trigger, HTTP Request
Data & Sheets

QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.

Postgres, Postgres Trigger, HTTP Request