Files
smb-online/n8n/onboarding.json
T
mivanchenko a59a22b38b Phase 3: add onboarding workflow
Webhook /webhook/onboard → read Clients → compute next C-#### →
append Clients row (status onboarding, renewal_date auto from billing
cycle) → seed Projects row (checklist from services, +14d go-live) →
log Activity → Telegram confirmation. Sheets writes retry on fail.
Verified end-to-end (C-0002 created across all three tabs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 15:13:12 +02:00

366 lines
11 KiB
JSON

{
"name": "SMB \u00b7 Onboarding",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "onboard",
"responseMode": "onReceived",
"options": {
"allowedOrigins": "*"
}
},
"id": "d1a08bba-5cc5-48fa-8063-bda2d58cab15",
"name": "Onboard webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
],
"webhookId": "96c28466-ee4b-4aa5-8f06-52d098b497a7"
},
{
"parameters": {
"authentication": "serviceAccount",
"resource": "sheet",
"operation": "read",
"documentId": {
"__rl": true,
"value": "1raMSWRZw_JfHlWqOb3LbhaQ6LWx0VGblxIV4Z2pSzp8",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "470934735",
"mode": "list",
"cachedResultName": "Clients"
},
"options": {}
},
"id": "92d09e48-6cac-43fc-b203-5dde0d08f61a",
"name": "Read Clients",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
460,
300
],
"credentials": {
"googleApi": {
"id": "45TWPyl1wVk2Vxdm",
"name": "SMB Google (service account)"
}
}
},
{
"parameters": {
"jsCode": "\nconst w=$('Onboard webhook').first().json; const body=w.body||w;\nconst rows=$('Read Clients').all().map(i=>i.json);\nlet maxC=0;\nfor(const r of rows){const m=String(r.client_id||'').match(/C-(\\d+)/);if(m)maxC=Math.max(maxC,+m[1]);}\nconst cid='C-'+String(maxC+1).padStart(4,'0');\nconst s=v=>{v=(v==null?'':String(v));return /^[=+\\-@\\t\\r]/.test(v)?\"'\"+v:v;};\nconst now=new Date();\nconst nowStr=now.toISOString().replace('T',' ').slice(0,16);\nfunction pd(v){if(!v)return null;const m=String(v).match(/^(\\d{4})-(\\d{2})-(\\d{2})/);\n if(m)return new Date(Date.UTC(+m[1],+m[2]-1,+m[3]));const d=new Date(v);return isNaN(d)?null:d;}\nconst cycle=String(body.billing_cycle||'monthly').toLowerCase();\nconst start=pd(body.start_date)||new Date(Date.UTC(now.getUTCFullYear(),now.getUTCMonth(),now.getUTCDate()));\nconst startStr=start.toISOString().slice(0,10);\nlet renewal='';\nif(cycle==='monthly'){const d=new Date(start);d.setUTCMonth(d.getUTCMonth()+1);renewal=d.toISOString().slice(0,10);}\nelse if(cycle==='yearly'){const d=new Date(start);d.setUTCFullYear(d.getUTCFullYear()+1);renewal=d.toISOString().slice(0,10);}\nconst tier=String(body.tier||'A').toUpperCase().includes('B')?'B':'A';\nconst services=String(body.services||'site, booking, leads');\nconst client={client_id:cid,business_name:s(body.business_name),owner_name:s(body.owner_name),\n email:s(body.email),phone:s(body.phone),niche:s(body.niche),tier,status:'onboarding',\n domain:s(body.domain),stack_notes:s(body.stack_notes),vault_ref:s(body.vault_ref),\n services:s(services),billing_cycle:cycle,monthly_fee_eur:(body.monthly_fee_eur||''),\n start_date:startStr,renewal_date:renewal,created_at:nowStr,notes:s(body.notes)};\nconst checklist=services.split(',').map(x=>x.trim()).filter(Boolean).map(x=>x+'\u2610').join(' ');\nconst gl=new Date(start);gl.setUTCDate(gl.getUTCDate()+14);const goLive=gl.toISOString().slice(0,10);\nconst projects=[{project_id:'P-'+Date.now(),client_id:cid,deliverable:'Onboarding & Setup',\n tier,checklist,go_live_date:goLive,status:'todo'}];\nconst activity={ts:nowStr,workflow:'onboarding',client_id:cid,action:'client onboarded',\n detail:(client.business_name||'')+' / Tier '+tier+' / '+services,result:'ok'};\nconst summary='\u2705 Neuer Kunde angelegt: '+cid+'\\n'+(client.business_name||'')+' \u2014 Tier '+tier+\n '\\nServices: '+services+'\\nGeb\u00fchr: '+(client.monthly_fee_eur||'\u2014')+'\u20ac/'+cycle+\n '\\nVerl\u00e4ngerung: '+(renewal||'\u2014')+'\\nGo-Live Ziel: '+goLive;\nreturn [{json:{client,projects,activity,summary,cid}}];\n"
},
"id": "fe9a0f5d-c6f8-4328-a98e-edc022582ec3",
"name": "Compute IDs",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"jsCode": "return [{json: $('Compute IDs').first().json.client}];"
},
"id": "4abc9b06-83ec-4d90-bb53-020e2dfade0d",
"name": "Map client",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"authentication": "serviceAccount",
"resource": "sheet",
"operation": "append",
"documentId": {
"__rl": true,
"value": "1raMSWRZw_JfHlWqOb3LbhaQ6LWx0VGblxIV4Z2pSzp8",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "470934735",
"mode": "list",
"cachedResultName": "Clients"
},
"options": {},
"columns": {
"mappingMode": "autoMapInputData",
"value": {},
"matchingColumns": [],
"schema": []
}
},
"id": "330f5cec-c1dd-4197-92bf-01c66f9a795a",
"name": "Append Clients",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1120,
300
],
"credentials": {
"googleApi": {
"id": "45TWPyl1wVk2Vxdm",
"name": "SMB Google (service account)"
}
},
"retryOnFail": true,
"maxTries": 4,
"waitBetweenTries": 3000
},
{
"parameters": {
"jsCode": "return $('Compute IDs').first().json.projects.map(p=>({json:p}));"
},
"id": "cc50083b-44f6-450b-ada3-ad3f2142441b",
"name": "Map projects",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1340,
300
]
},
{
"parameters": {
"authentication": "serviceAccount",
"resource": "sheet",
"operation": "append",
"documentId": {
"__rl": true,
"value": "1raMSWRZw_JfHlWqOb3LbhaQ6LWx0VGblxIV4Z2pSzp8",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "619112786",
"mode": "list",
"cachedResultName": "Projects"
},
"options": {},
"columns": {
"mappingMode": "autoMapInputData",
"value": {},
"matchingColumns": [],
"schema": []
}
},
"id": "83b26e24-edd8-4663-b61c-aa5e25b33842",
"name": "Append Projects",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1560,
300
],
"credentials": {
"googleApi": {
"id": "45TWPyl1wVk2Vxdm",
"name": "SMB Google (service account)"
}
},
"retryOnFail": true,
"maxTries": 4,
"waitBetweenTries": 3000
},
{
"parameters": {
"jsCode": "return [{json: $('Compute IDs').first().json.activity}];"
},
"id": "8d3c0640-e186-4813-815e-8f807d7b6f4f",
"name": "Map activity",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1780,
300
]
},
{
"parameters": {
"authentication": "serviceAccount",
"resource": "sheet",
"operation": "append",
"documentId": {
"__rl": true,
"value": "1raMSWRZw_JfHlWqOb3LbhaQ6LWx0VGblxIV4Z2pSzp8",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "170940481",
"mode": "list",
"cachedResultName": "Activity Log"
},
"options": {},
"columns": {
"mappingMode": "autoMapInputData",
"value": {},
"matchingColumns": [],
"schema": []
}
},
"id": "c8773711-99d4-4722-9a13-5c8c9afa7060",
"name": "Append Activity",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1780,
460
],
"credentials": {
"googleApi": {
"id": "45TWPyl1wVk2Vxdm",
"name": "SMB Google (service account)"
}
},
"retryOnFail": true,
"maxTries": 4,
"waitBetweenTries": 3000
},
{
"parameters": {
"resource": "message",
"operation": "sendMessage",
"chatId": "5499280257",
"text": "={{ $('Compute IDs').first().json.summary }}",
"additionalFields": {
"appendAttribution": false
}
},
"id": "ae19e543-1a6b-4466-8af8-bb436f51091b",
"name": "Notify Telegram",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
2000,
300
],
"credentials": {
"telegramApi": {
"id": "d9s4Ec5ocEH8FAxh",
"name": "SMB Telegram (leads bot)"
}
}
}
],
"connections": {
"Onboard webhook": {
"main": [
[
{
"node": "Read Clients",
"type": "main",
"index": 0
}
]
]
},
"Read Clients": {
"main": [
[
{
"node": "Compute IDs",
"type": "main",
"index": 0
}
]
]
},
"Compute IDs": {
"main": [
[
{
"node": "Map client",
"type": "main",
"index": 0
}
]
]
},
"Map client": {
"main": [
[
{
"node": "Append Clients",
"type": "main",
"index": 0
}
]
]
},
"Append Clients": {
"main": [
[
{
"node": "Map projects",
"type": "main",
"index": 0
}
]
]
},
"Map projects": {
"main": [
[
{
"node": "Append Projects",
"type": "main",
"index": 0
}
]
]
},
"Append Projects": {
"main": [
[
{
"node": "Map activity",
"type": "main",
"index": 0
}
]
]
},
"Map activity": {
"main": [
[
{
"node": "Append Activity",
"type": "main",
"index": 0
}
]
]
},
"Append Activity": {
"main": [
[
{
"node": "Notify Telegram",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
}
}