Files
n8n-compose/compose.yaml
Claude Code 6b60059c00 feat: HTML email template, structured text storage and Freescout design
compose.yaml:
- Add hostname n8n.eks-intec.de to fix SMTP HELO rejection
- Add NODE_TLS_REJECT_UNAUTHORIZED=0 for internal CA trust

workflow-a-http.json:
- Replace Set node with Code node for reliable data extraction
- Strip HTML from thread bodies before AI analysis
- Preserve newlines as ¶ (pilcrow) in DB storage instead of flattening

workflow-b-http.json:
- Add Prepare Email Body node: restores ¶→\n, strips markdown,
  converts numbered lists to <ol><li>, generates HTML email template
- Switch emailSend from plain text to HTML+text (multipart)
- Fix Log Reply to Freescout: use MAX(created_at)+1s to ensure
  n8n reply appears as newest thread regardless of email header timestamps
- Fix emailSend typeVersion 1 with text field for reliable expression support
- Correct Freescout thread INSERT: type=2, cc/bcc='[]', customer_id via subquery

freescout-templates/:
- Modern reply_fancy.blade.php: blue header bar with mailbox name and
  ticket number badge, quoted thread styling with left border accent, footer
- Modern auto_reply.blade.php: matching design for auto-reply emails
- Deploy to server: scp to /tmp, apply with sudo cp + artisan view:clear

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 17:27:49 +01:00

172 lines
5.0 KiB
YAML

services:
traefik:
image: "traefik"
restart: always
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
- "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- traefik_data:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./crts:/opt/custom-certificates
n8n:
image: docker.n8n.io/n8nio/n8n
restart: always
hostname: n8n.eks-intec.de
ports:
- "127.0.0.1:5678:5678"
labels:
- traefik.enable=true
- traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
- traefik.http.routers.n8n.tls=true
- traefik.http.routers.n8n.entrypoints=web,websecure
- traefik.http.routers.n8n.tls.certresolver=mytlschallenge
- traefik.http.middlewares.n8n.headers.SSLRedirect=true
- traefik.http.middlewares.n8n.headers.STSSeconds=315360000
- traefik.http.middlewares.n8n.headers.browserXSSFilter=true
- traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
- traefik.http.middlewares.n8n.headers.forceSTSHeader=true
- traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
- traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
- traefik.http.middlewares.n8n.headers.STSPreload=true
- traefik.http.routers.n8n.middlewares=n8n@docker
environment:
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
- N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- N8N_RUNNERS_ENABLED=true
- NODE_ENV=production
- WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${GENERIC_TIMEZONE}
- NODE_TLS_REJECT_UNAUTHORIZED=0
volumes:
- n8n_data:/home/node/.n8n
- ./local-files:/files
- ./crts:/opt/custom-certificates
etcd:
image: quay.io/coreos/etcd:v3.5.5
restart: always
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
- ETCD_QUOTA_BACKEND_BYTES=4294967296
ports:
- "2379:2379"
volumes:
- etcd_data:/etcd-data
healthcheck:
test: ["CMD", "etcdctl", "endpoint", "health"]
interval: 10s
timeout: 5s
retries: 5
command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379
minio:
image: minio/minio:latest
restart: always
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/minio_data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
command: minio server /minio_data --console-address ":9001"
milvus:
image: milvusdb/milvus:v2.4.0
restart: always
command: milvus run standalone
ports:
- "19530:19530"
- "9091:9091"
environment:
- ETCD_ENDPOINTS=etcd:2379
- MINIO_ADDRESS=minio:9000
volumes:
- milvus_data:/var/lib/milvus
depends_on:
etcd:
condition: service_healthy
minio:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
postgres:
image: postgres:15-alpine
restart: always
ports:
- "5432:5432"
environment:
- POSTGRES_DB=n8n_kb
- POSTGRES_USER=kb_user
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kb_user -d n8n_kb"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
sql-executor:
build:
context: .
dockerfile: Dockerfile.sql-executor
restart: always
ports:
- "4000:4000"
environment:
- FREESCOUT_DB_HOST=10.136.40.104
- FREESCOUT_DB_PORT=3306
- FREESCOUT_DB_USER=freescout
- FREESCOUT_DB_PASSWORD=5N6fv4wIgsI6BZV
- FREESCOUT_DB_NAME=freescout
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USER=kb_user
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=n8n_kb
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 10s
timeout: 5s
retries: 5
volumes:
n8n_data:
traefik_data:
milvus_data:
postgres_data:
etcd_data:
minio_data: