From a59a22b38b98df21707ac15a24090f0db3c9389c Mon Sep 17 00:00:00 2001 From: rogalik27 Date: Wed, 24 Jun 2026 15:13:12 +0200 Subject: [PATCH] Phase 3: add onboarding workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- n8n/onboarding.json | 366 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 n8n/onboarding.json diff --git a/n8n/onboarding.json b/n8n/onboarding.json new file mode 100644 index 0000000..d078732 --- /dev/null +++ b/n8n/onboarding.json @@ -0,0 +1,366 @@ +{ + "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 + } +} \ No newline at end of file