diff --git a/n8n-workflows/financial-brief.json b/n8n-workflows/financial-brief.json new file mode 100644 index 0000000..3aa7f1c --- /dev/null +++ b/n8n-workflows/financial-brief.json @@ -0,0 +1,264 @@ +{ + "name": "CEO OS — Financial Weekly Brief", + "nodes": [ + { + "id": "n4-trigger", + "name": "Every Friday 17:00", + "type": "n8n-nodes-base.scheduleTrigger", + "typeVersion": 1, + "position": [ + 0, + 300 + ], + "parameters": { + "rule": { + "interval": [ + { + "field": "cronExpression", + "expression": "0 17 * * 5" + } + ] + } + } + }, + { + "id": "n4-vars", + "name": "Config", + "type": "n8n-nodes-base.set", + "typeVersion": 3, + "position": [ + 220, + 300 + ], + "parameters": { + "mode": "manual", + "assignments": { + "assignments": [ + { + "id": "d1", + "name": "api", + "value": "={{$env['CEO_OS_API_URL'] ?? 'https://boardmind.dev/api'}}", + "type": "string" + }, + { + "id": "d2", + "name": "tenantId", + "value": "={{$env['CEO_OS_TENANT_ID']}}", + "type": "string" + }, + { + "id": "d3", + "name": "serviceKey", + "value": "={{$env['CEO_OS_SERVICE_KEY']}}", + "type": "string" + } + ] + } + } + }, + { + "id": "n4-contracts", + "name": "Get Contracts", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 440, + 200 + ], + "parameters": { + "url": "={{$json.api}}/v1/contracts?tenantId={{$json.tenantId}}", + "method": "GET", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$json.serviceKey}}" + } + ] + } + } + }, + { + "id": "n4-obs", + "name": "Get Expense Observations", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 440, + 400 + ], + "parameters": { + "url": "={{$('Config').item.json.api}}/v1/observations?tenantId={{$('Config').item.json.tenantId}}&subjectType=expense", + "method": "GET", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$('Config').item.json.serviceKey}}" + } + ] + } + } + }, + { + "id": "n4-build", + "name": "Build Financial Context", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 680, + 300 + ], + "parameters": { + "jsCode": "const cfg = $('Config').item.json;\nconst contracts = $('Get Contracts').all().map(i => i.json);\nconst expenses = $('Get Expense Observations').all().map(i => i.json);\n\nconst now = Date.now();\nconst monthAgo = now - 30 * 86400000;\n\nconst activeContracts = contracts.filter(c => c.status === 'signed' || c.status === 'active');\nconst totalRevenue = activeContracts.reduce((s, c) => s + (parseFloat(c.value) || 0), 0);\n\nconst monthlyExpenses = expenses.filter(e => new Date(e.observedAt || e.createdAt).getTime() > monthAgo);\nconst totalExpenses = monthlyExpenses.reduce((s, e) => s + (parseFloat(e.value) || 0), 0);\n\nconst prompt = [\n `Generează un brief financiar săptămânal. Vineri, ${new Date().toLocaleDateString('ro-RO')}.`,\n '',\n `## Date financiare:`,\n `- Contracte active: ${activeContracts.length} → Total valoare: ${totalRevenue.toLocaleString('ro-RO')} EUR`,\n `- Cheltuieli luna curentă: ${totalExpenses.toLocaleString('ro-RO')} EUR (${monthlyExpenses.length} tranzacții)`,\n `- Sold net estimat: ${(totalRevenue - totalExpenses).toLocaleString('ro-RO')} EUR`,\n '',\n 'Structurează în: 💰 Situație actuală, 📈 Tendință, ⚠️ Atenție la, ✅ Recomandate. Max 200 cuvinte.',\n].join('\\n');\n\nreturn [{ json: {\n prompt, totalRevenue, totalExpenses,\n api: cfg.api, tenantId: cfg.tenantId, serviceKey: cfg.serviceKey,\n}}];" + } + }, + { + "id": "n4-ai", + "name": "Generate Financial Brief", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 900, + 300 + ], + "parameters": { + "url": "={{$json.api}}/v1/ai/ask", + "method": "POST", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$json.serviceKey}}" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={\"messages\": [{\"role\": \"user\", \"content\": {{JSON.stringify($json.prompt)}}}], \"context\": \"{\\\"financialBrief\\\": true}\"}" + } + }, + { + "id": "n4-save", + "name": "Save Financial Brief", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 1120, + 300 + ], + "parameters": { + "url": "={{$('Build Financial Context').item.json.api}}/v1/observations", + "method": "POST", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$('Build Financial Context').item.json.serviceKey}}" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={\"tenantId\": \"{{$('Build Financial Context').item.json.tenantId}}\", \"metric\": \"financial-brief\", \"value\": {{JSON.stringify($json.reply)}}, \"unit\": \"{{$('Build Financial Context').item.json.totalRevenue}} EUR\", \"subjectType\": \"finance\", \"confidence\": 0.95}" + } + } + ], + "connections": { + "Every Friday 17:00": { + "main": [ + [ + { + "node": "Config", + "type": "main", + "index": 0 + } + ] + ] + }, + "Config": { + "main": [ + [ + { + "node": "Get Contracts", + "type": "main", + "index": 0 + }, + { + "node": "Get Expense Observations", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get Contracts": { + "main": [ + [ + { + "node": "Build Financial Context", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get Expense Observations": { + "main": [ + [ + { + "node": "Build Financial Context", + "type": "main", + "index": 0 + } + ] + ] + }, + "Build Financial Context": { + "main": [ + [ + { + "node": "Generate Financial Brief", + "type": "main", + "index": 0 + } + ] + ] + }, + "Generate Financial Brief": { + "main": [ + [ + { + "node": "Save Financial Brief", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "tags": [ + { + "name": "ceo-os" + }, + { + "name": "finance" + } + ] +} \ No newline at end of file