apps: add n8n + mail-to-gitea-issue workflow (n8n.kaleschke.info)
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
services:
|
||||
n8n:
|
||||
# TODO (Codex, erster Deploy): Digest am Container per `docker inspect` auslesen
|
||||
# und Tag durch `docker.n8n.io/n8nio/n8n:2.22.6@sha256:<digest>` ersetzen.
|
||||
image: docker.n8n.io/n8nio/n8n:2.22.6
|
||||
container_name: n8n
|
||||
restart: unless-stopped
|
||||
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
|
||||
environment:
|
||||
TZ: Europe/Berlin
|
||||
GENERIC_TIMEZONE: Europe/Berlin
|
||||
|
||||
N8N_HOST: n8n.kaleschke.info
|
||||
N8N_PORT: "5678"
|
||||
N8N_PROTOCOL: https
|
||||
N8N_EDITOR_BASE_URL: https://n8n.kaleschke.info/
|
||||
WEBHOOK_URL: https://n8n.kaleschke.info/
|
||||
N8N_PROXY_HOPS: "1"
|
||||
|
||||
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
|
||||
|
||||
N8N_DIAGNOSTICS_ENABLED: "false"
|
||||
N8N_PERSONALIZATION_ENABLED: "false"
|
||||
N8N_HIRING_BANNER_ENABLED: "false"
|
||||
N8N_RUNNERS_ENABLED: "true"
|
||||
N8N_BLOCK_ENV_ACCESS_IN_NODE: "true"
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/n8n/data:/home/node/.n8n
|
||||
|
||||
networks:
|
||||
- frontend_net
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=frontend_net"
|
||||
- "traefik.http.routers.n8n.rule=Host(`n8n.kaleschke.info`)"
|
||||
- "traefik.http.routers.n8n.entrypoints=websecure"
|
||||
- "traefik.http.routers.n8n.tls=true"
|
||||
- "traefik.http.routers.n8n.tls.certresolver=le"
|
||||
- "traefik.http.routers.n8n.middlewares=secure-headers@file"
|
||||
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
|
||||
|
||||
networks:
|
||||
frontend_net:
|
||||
external: true
|
||||
@@ -0,0 +1,284 @@
|
||||
{
|
||||
"name": "GMX -> OpenAI -> Gitea Issue (Super Productivity)",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"pollTimes": {
|
||||
"item": [
|
||||
{
|
||||
"mode": "everyMinute"
|
||||
}
|
||||
]
|
||||
},
|
||||
"format": "simple",
|
||||
"options": {
|
||||
"customEmailConfig": "[\"UNSEEN\"]",
|
||||
"forceReconnect": 15
|
||||
},
|
||||
"postProcessAction": "read"
|
||||
},
|
||||
"id": "11111111-1111-1111-1111-111111111111",
|
||||
"name": "IMAP: GMX UNSEEN",
|
||||
"type": "n8n-nodes-base.emailReadImap",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
240,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"imap": {
|
||||
"id": "REPLACE_GMX_IMAP_CRED_ID",
|
||||
"name": "GMX IMAP"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "a1",
|
||||
"name": "from",
|
||||
"value": "={{ $json.from }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a2",
|
||||
"name": "subject",
|
||||
"value": "={{ $json.subject }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a3",
|
||||
"name": "date",
|
||||
"value": "={{ $json.date }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a4",
|
||||
"name": "messageId",
|
||||
"value": "={{ $json.messageId || $json['message-id'] || '' }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a5",
|
||||
"name": "text",
|
||||
"value": "={{ ($json.text || $json.textPlain || '').toString().slice(0, 8000) }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "22222222-2222-2222-2222-222222222222",
|
||||
"name": "Extract mail fields",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
460,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.openai.com/v1/chat/completions",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpHeaderAuth",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.2,\n \"response_format\": {\n \"type\": \"json_schema\",\n \"json_schema\": {\n \"name\": \"issue_extraction\",\n \"strict\": true,\n \"schema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"title\", \"body_md\", \"priority\", \"due_date\", \"category\"],\n \"properties\": {\n \"title\": { \"type\": \"string\", \"maxLength\": 80 },\n \"body_md\": { \"type\": \"string\" },\n \"priority\": { \"type\": \"string\", \"enum\": [\"niedrig\", \"normal\", \"hoch\"] },\n \"due_date\": { \"type\": [\"string\", \"null\"], \"description\": \"ISO YYYY-MM-DD oder null\" },\n \"category\": { \"type\": \"string\" }\n }\n }\n }\n },\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"Du extrahierst aus einer E-Mail eine Aufgabe fuer ein Issue-Tracking-System. Antworte ausschliesslich gemaess JSON-Schema. Sprache: Deutsch.\\n- title: imperativ, max. 80 Zeichen, ohne abschliessenden Punkt.\\n- body_md: 2 bis 6 Saetze. Was ist zu tun, warum, bis wann. Keine Begruessungen.\\n- priority: niedrig | normal | hoch.\\n- due_date: ISO YYYY-MM-DD wenn aus Mail ableitbar, sonst null.\\n- category: kurzes Schlagwort (rechnung, termin, technik, familie, sonstiges, ...).\"\n },\n {\n \"role\": \"user\",\n \"content\": {{ JSON.stringify('Absender: ' + $json.from + '\\nDatum: ' + $json.date + '\\nBetreff: ' + $json.subject + '\\n\\nMailtext:\\n' + $json.text) }}\n }\n ]\n}",
|
||||
"options": {
|
||||
"timeout": 60000
|
||||
}
|
||||
},
|
||||
"id": "33333333-3333-3333-3333-333333333333",
|
||||
"name": "OpenAI: extract issue",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
680,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"httpHeaderAuth": {
|
||||
"id": "REPLACE_OPENAI_HEADER_AUTH_CRED_ID",
|
||||
"name": "OpenAI Bearer"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "b1",
|
||||
"name": "extracted",
|
||||
"value": "={{ JSON.parse($json.choices[0].message.content) }}",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"id": "b2",
|
||||
"name": "mail",
|
||||
"value": "={{ $('Extract mail fields').item.json }}",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "44444444-4444-4444-4444-444444444444",
|
||||
"name": "Parse OpenAI JSON",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
900,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "c1",
|
||||
"name": "title",
|
||||
"value": "={{ ($json.extracted.priority === 'hoch' ? '[P1] ' : '') + $json.extracted.title }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "c2",
|
||||
"name": "body",
|
||||
"value": "={{ $json.extracted.body_md + '\\n\\n---\\n**Kategorie:** ' + $json.extracted.category + '\\n**Prioritaet:** ' + $json.extracted.priority + ($json.extracted.due_date ? '\\n**Faellig:** ' + $json.extracted.due_date : '') + '\\n**Quelle:** Mail von ' + $json.mail.from + ' (' + $json.mail.date + ')\\n**Betreff:** ' + $json.mail.subject + '\\n**Message-ID:** ' + $json.mail.messageId }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "55555555-5555-5555-5555-555555555555",
|
||||
"name": "Build issue payload",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
1120,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://git.kaleschke.info/api/v1/repos/Micha/mails/issues",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpHeaderAuth",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"name": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"title\": {{ JSON.stringify($json.title) }},\n \"body\": {{ JSON.stringify($json.body) }},\n \"assignees\": [\"Micha\"]\n}",
|
||||
"options": {
|
||||
"timeout": 30000
|
||||
}
|
||||
},
|
||||
"id": "66666666-6666-6666-6666-666666666666",
|
||||
"name": "Gitea: create issue",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1340,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"httpHeaderAuth": {
|
||||
"id": "REPLACE_GITEA_HEADER_AUTH_CRED_ID",
|
||||
"name": "Gitea Token"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"IMAP: GMX UNSEEN": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract mail fields",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract mail fields": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "OpenAI: extract issue",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"OpenAI: extract issue": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse OpenAI JSON",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse OpenAI JSON": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build issue payload",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build issue payload": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Gitea: create issue",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"meta": {
|
||||
"instanceId": "homelab-n8n"
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
Reference in New Issue
Block a user