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 →
{
"name": "job.5_fsm_decision_engine",
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
0
],
"id": "fb65a333-c105-4b3e-9976-e795324690a5",
"name": "When clicking \u2018Execute workflow\u2019"
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT\n a.application_id,\n a.current_state,\n e.payload->>'email_id' AS email_id,\n MAX(ec.payload->>'category') AS email_category\nFROM job_applications a\nJOIN events e\n ON e.event_type = 'EMAIL_LINKED'\n AND e.application_id = a.application_id\nJOIN events ec\n ON ec.event_type = 'EMAIL_CLASSIFIED'\n AND ec.payload->>'email_id' = e.payload->>'email_id'\n AND ec.payload->>'category' != 'NON_JOB'\nWHERE NOT EXISTS (\n SELECT 1\n FROM events ed\n WHERE ed.event_type = 'FSM_TRANSITION_ELIGIBLE'\n AND ed.payload->>'email_id' = e.payload->>'email_id'\n)\nGROUP BY a.application_id, a.current_state, e.payload->>'email_id';",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
208,
0
],
"id": "5675ee4d-50a9-408c-809b-fba3aa06355f",
"name": "New linked but No FSM",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const FSM = {\n terminalStates: new Set([\"OFFER\", \"REJECTED\", \"ARCHIVED\"]),\n\n transitions: {\n DISCOVERED: {\n MANUAL: { APPLY: \"APPLIED\" },\n },\n\n APPLIED: {\n EMAIL: { ACKNOWLEDGED: \"ACKNOWLEDGED\",\n ASSESSMENT: \"ASSESSMENT\",\n },\n TIMEOUT: { NO_RESPONSE: \"NO_RESPONSE\" },\n },\n\n ACKNOWLEDGED: {\n EMAIL: {\n ASSESSMENT: \"ASSESSMENT\",\n INTERVIEW: \"INTERVIEW\",\n REJECTED: \"REJECTED\",\n },\n TIMEOUT: { NO_RESPONSE: \"NO_RESPONSE\" },\n },\n\n ASSESSMENT: {\n EMAIL: {\n INTERVIEW: \"INTERVIEW\",\n REJECTED: \"REJECTED\",\n },\n },\n\n INTERVIEW: {\n EMAIL: {\n OFFER: \"OFFER\",\n REJECTED: \"REJECTED\",\n },\n },\n\n NO_RESPONSE: {\n EMAIL: {\n ACKNOWLEDGED: \"ACKNOWLEDGED\",\n ASSESSMENT: \"ASSESSMENT\",\n INTERVIEW: \"INTERVIEW\",\n },\n TIMEOUT: { ARCHIVED: \"ARCHIVED\" },\n MANUAL: { REJECTED: \"REJECTED\" },\n },\n\n ANY: {\n MANUAL: { WITHDRAWN: \"WITHDRAWN\" },\n },\n },\n};\n\n// Strict inputs \u2014 no guessing allowed\nconst {\n application_id,\n email_id,\n current_state,\n trigger_type,\n intent,\n} = $json;\n\nif (!trigger_type || !intent) {\n throw new Error(\n \"FSM rules contract violation: trigger_type and intent are required\"\n );\n}\n\n// Terminal guard\nif (FSM.terminalStates.has(current_state)) {\n return [{\n json: {\n application_id,\n email_id,\n from_state: current_state,\n to_state: null,\n reason: \"TERMINAL_STATE\",\n },\n }];\n}\n\n// Resolve transition\nconst toState =\n FSM.transitions.ANY?.[trigger_type]?.[intent] ??\n FSM.transitions[current_state]?.[trigger_type]?.[intent] ??\n null;\n\nreturn [{\n json: {\n application_id,\n email_id,\n from_state: current_state,\n to_state: toState,\n trigger_type,\n intent,\n },\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
992,
0
],
"id": "f49345eb-6c8d-45ec-a6da-beb7127fba21",
"name": "FSM rules"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "57bb395a-ecdc-4d1a-8663-aeeff292d24a",
"leftValue": "={{ $json.to_state !== null }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
1168,
0
],
"id": "f0646a5a-ba44-400e-ba96-1c33d5501ffc",
"name": "Next state is not NULL"
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "events",
"mode": "list",
"cachedResultName": "events"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"application_id": "={{ $json.application_id }}",
"event_type": "FSM_TRANSITION_ELIGIBLE",
"payload": "={{\n {\n email_id: $json.email_id,\n from_state: $json.from_state,\n to_state: $json.to_state\n }\n}}",
"triggered_by": "system"
},
"matchingColumns": [],
"schema": [
{
"id": "event_id",
"displayName": "event_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "event_type",
"displayName": "event_type",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "application_id",
"displayName": "application_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true
},
{
"id": "payload",
"displayName": "payload",
"required": false,
"defaultMatch": false,
"display": true,
"type": "object",
"canBeUsedToMatch": true
},
{
"id": "triggered_by",
"displayName": "triggered_by",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1392,
-192
],
"id": "50a2076f-1897-4594-b714-fae54f0c4d37",
"name": "Emit ELIGIBLE FSM",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "events",
"mode": "list",
"cachedResultName": "events"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"application_id": "={{ $json.application_id }}",
"event_type": "FSM_NO_TRANSITION",
"payload": "={{\n {\n email_id: $json.email_id,\n reason: \"no_valid_transition\"\n }\n}}",
"triggered_by": "system"
},
"matchingColumns": [],
"schema": [
{
"id": "event_id",
"displayName": "event_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "event_type",
"displayName": "event_type",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "application_id",
"displayName": "application_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true
},
{
"id": "payload",
"displayName": "payload",
"required": false,
"defaultMatch": false,
"display": true,
"type": "object",
"canBeUsedToMatch": true
},
{
"id": "triggered_by",
"displayName": "triggered_by",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1392,
160
],
"id": "785e8644-76a6-4e1c-9724-b85543ab4f84",
"name": "Emil NO FSM ELIGIBLE",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const EMAIL_CATEGORY_TO_INTENT = {\n APPLICATION_ACK: \"ACKNOWLEDGED\",\n INTERVIEW_SIGNAL: \"INTERVIEW\",\n ASSESSMENT_SIGNAL: \"ASSESSMENT\",\n OFFER_SIGNAL: \"OFFER\",\n REJECTION_SIGNAL: \"REJECTED\",\n};\n\n// Inputs\nconst {\n application_id,\n email_id,\n current_state,\n email_category,\n} = $json;\n\n// Translate strictly\nconst intent = EMAIL_CATEGORY_TO_INTENT[email_category];\n\nif (!intent) {\n throw new Error(\n `FSM normalization failed: unmapped email_category '${email_category}'`\n );\n}\n\nreturn [{\n json: {\n application_id,\n email_id,\n current_state,\n\n trigger_type: \"EMAIL\",\n intent,\n },\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
816,
0
],
"id": "381cf251-ba2c-4f04-87de-3c06cd4d17ff",
"name": "Normalize intent"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "1b6d6ab5-080b-4975-b13c-c86db3ebeadc",
"leftValue": "={{ $json.email_category == 'NON_JOB'}}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
416,
0
],
"id": "863fe75a-e7eb-4b3f-b2f9-8c408f6e48fa",
"name": "If"
}
],
"connections": {
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "New linked but No FSM",
"type": "main",
"index": 0
}
]
]
},
"New linked but No FSM": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"FSM rules": {
"main": [
[
{
"node": "Next state is not NULL",
"type": "main",
"index": 0
}
]
]
},
"Next state is not NULL": {
"main": [
[
{
"node": "Emit ELIGIBLE FSM",
"type": "main",
"index": 0
}
],
[
{
"node": "Emil NO FSM ELIGIBLE",
"type": "main",
"index": 0
}
]
]
},
"Normalize intent": {
"main": [
[
{
"node": "FSM rules",
"type": "main",
"index": 0
}
]
]
},
"If": {
"main": [
[],
[
{
"node": "Normalize intent",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"availableInMCP": false
},
"versionId": "ecc5e18c-9d2f-4023-9371-f854c2b2bea8",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "UHQyM7KDr9TOxUh3",
"tags": []
}
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.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
job.5_fsm_decision_engine. Uses postgres. Event-driven trigger; 8 nodes.
Source: https://github.com/daemon-Ad/Job-Aggregation-and-Email-Intelligence-System/blob/main/workflows/job.5_fsm_decision_engine.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Reagendamiento_v2. Uses executeWorkflowTrigger, redis, httpRequest, n8n-nodes-evolution-api. Event-driven trigger; 89 nodes.
This workflow acts as a junior finance research analyst for a UK boutique M&A or corporate finance team. It listens for Slack messages, classifies the request, gathers company or market data, and prod
Agendamiento_v2. Uses n8n-nodes-evolution-api, redis, httpRequest, executeWorkflowTrigger. Event-driven trigger; 59 nodes.
Cancelacion_v2. Uses executeWorkflowTrigger, redis, httpRequest, n8n-nodes-evolution-api. Event-driven trigger; 46 nodes.
Components. Uses postgres, readWriteFile. Event-driven trigger; 42 nodes.