feat(lead-engine): setup isolated webhook test environment [31f88f42]

Created a dedicated test setup for Smartlead webhooks using docker-compose.test.yml and nginx-proxy-test.conf. This ensures a stable, minimal environment. Updated lead-engine/README.md with comprehensive instructions for local testing and production requirements for the Wackler IT.
This commit is contained in:
2026-03-16 15:08:19 +00:00
parent 9f943aea21
commit 9485cd4428
3 changed files with 423 additions and 13 deletions

89
docker-compose.test.yml Normal file
View File

@@ -0,0 +1,89 @@
version: '3.8'
services:
# --- GATEKEEPER (NGINX) ---
nginx:
image: nginx:alpine
container_name: gateway_proxy
restart: unless-stopped
ports:
- "8090:80"
volumes:
- ./nginx-proxy-test.conf:/etc/nginx/nginx.conf:ro
- ./.htpasswd:/etc/nginx/.htpasswd:ro
depends_on:
dashboard:
condition: service_started
company-explorer:
condition: service_healthy
lead-engine:
condition: service_started
# --- DASHBOARD (Required by Nginx) ---
dashboard:
image: nginx:alpine
container_name: dashboard
restart: unless-stopped
volumes:
- ./dashboard:/usr/share/nginx/html:ro
# --- COMPANY-EXPLORER (Required by Lead-Engine) ---
company-explorer:
build:
context: ./company-explorer
dockerfile: Dockerfile
container_name: company-explorer
restart: unless-stopped
ports:
- "8000:8000"
environment:
API_USER: "admin"
API_PASSWORD: "gemini"
PYTHONUNBUFFERED: "1"
DATABASE_URL: "sqlite:////data/companies_v3_fixed_2.db"
GEMINI_API_KEY: "${GEMINI_API_KEY}"
SERP_API_KEY: "${SERP_API}"
NOTION_TOKEN: "${NOTION_API_KEY}"
volumes:
- ./company-explorer:/app
- explorer_db_data:/data
- ./Log_from_docker:/app/logs_debug
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
# --- LEAD-ENGINE (Our Webhook Service) ---
lead-engine:
build:
context: ./lead-engine
dockerfile: Dockerfile
container_name: lead-engine
restart: unless-stopped
ports:
- "8501:8501" # UI (Streamlit)
- "8004:8004" # API / Monitor
- "8099:8004" # Direct Test Port
environment:
PYTHONUNBUFFERED: "1"
GEMINI_API_KEY: "${GEMINI_API_KEY}"
SERP_API: "${SERP_API}"
INFO_Application_ID: "${INFO_Application_ID}"
INFO_Tenant_ID: "${INFO_Tenant_ID}"
INFO_Secret: "${INFO_Secret}"
CAL_APPID: "${CAL_APPID}"
CAL_SECRET: "${CAL_SECRET}"
CAL_TENNANT_ID: "${CAL_TENNANT_ID}"
TEAMS_WEBHOOK_URL: "${TEAMS_WEBHOOK_URL}"
FEEDBACK_SERVER_BASE_URL: "${FEEDBACK_SERVER_BASE_URL}"
WORDPRESS_BOOKING_URL: "${WORDPRESS_BOOKING_URL}"
MS_BOOKINGS_URL: "${MS_BOOKINGS_URL}"
volumes:
- ./lead-engine:/app
- lead_engine_data:/app/data
volumes:
explorer_db_data: {}
lead_engine_data: {}

View File

@@ -34,25 +34,264 @@ Der vollautomatische "Zero Touch" Workflow für Trading Twins Anfragen.
* **Abstand:** Bietet zwei Termine an, mit ca. **3 Stunden Pause** dazwischen.
* **Buchung:** Klick auf Link -> Server erstellt Outlook-Termin von `info@` mit `e.melcer` als Teilnehmer.
### 6. Smartlead Webhook Integration (NEU)
* **Zweck:** Empfang von Echtzeit-Lead-Benachrichtigungen direkt aus der Smartlead-Plattform.
* **Event-basiert:** Das System empfängt nur Daten für *neue* Ereignisse (z.B. "Lead als heiß markiert"), keine historischen Daten.
### 6. Smartlead Webhook Test & Integration [31f88f42]
#### 🚀 Übersicht
Dieses Modul ist für den Empfang von Echtzeit-Lead-Benachrichtigungen direkt aus der Smartlead-Plattform konzipiert. Es verarbeitet eingehende Daten von Hot Leads und Follow-up Leads, um automatisierte Prozesse in unserer Infrastruktur anzustoßen.
#### Endpunkte
Die folgenden Endpunkte werden für Smartlead bereitgestellt. Die Basis-URL ist flexibel und kann bei einem Serverumzug einfach angepasst werden. Der Platzhalter `{IHRE_AKTUELLE_DOMAIN}` sollte durch die aktuell aktive URL (z.B. `floke-ai.duckdns.org` oder die zukünftige neue Domain) ersetzt werden.
Die folgenden Endpunkte werden für Smartlead bereitgestellt. Der Platzhalter `{IHRE_AKTUELLE_DOMAIN}` sollte durch die aktuell aktive URL Ihrer Diskstation (z.B. `floke-ai.duckdns.org:8090`) oder später durch die produktive Domain ersetzt werden. Beachten Sie, dass für den Produktivbetrieb bei Wackler **HTTPS** obligatorisch sein wird.
* **Hot Leads:** `https://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/hot-lead`
* **Follow-up Leads:** `https://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/follow-up-lead`
* **Hot Leads:** `http(s)://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/hot-lead`
* **Follow-up Leads:** `http(s)://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/follow-up-lead`
#### Inbetriebnahme & Test-Prozess
Die Integration wird in einem kontrollierten Prozess ausgerollt, um die Datenstruktur sicher zu analysieren:
#### Lokales Test-Setup (Diskstation)
Um die Smartlead-Webhooks auf Ihrer Diskstation zu testen, stellen Sie sicher, dass nur die notwendigen Dienste aktiv sind. Hierfür verwenden wir eine schlanke `docker-compose.test.yml` und eine angepasste Nginx-Konfiguration.
1. **URLs an Smartlead übergeben:** Die oben genannten URLs werden an den Smartlead-Support oder in deren Admin-Oberfläche eingetragen.
2. **Test-Auslösung anfordern:** Smartlead wird gebeten, für jeden der beiden Endpunkte einen einzelnen Test-Lead manuell auszulösen.
3. **Datenanalyse:** Alle eingehenden Anfragen werden ungefiltert in die Log-Datei `lead-engine/Log/smartlead_webhooks.log` geschrieben. Dies ermöglicht eine genaue Analyse der von Smartlead gesendeten JSON-Struktur.
4. **Implementierung der Logik:** Basierend auf den analysierten Test-Daten wird die eigentliche Geschäftslogik (z.B. Eintrag in die Datenbank, Teams-Benachrichtigung) implementiert.
1. **Vorbereiten der `docker-compose.test.yml`:**
Stellen Sie sicher, dass die Datei `docker-compose.test.yml` im Projekt-Root-Verzeichnis existiert und folgenden Inhalt hat (wurde bereits von Gemini erstellt):
```yaml
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: gateway_proxy
restart: unless-stopped
ports:
- "8090:80"
volumes:
- ./nginx-proxy-test.conf:/etc/nginx/nginx.conf:ro
- ./.htpasswd:/etc/nginx/.htpasswd:ro
depends_on:
dashboard:
condition: service_started
company-explorer:
condition: service_healthy
lead-engine:
condition: service_started
dashboard:
image: nginx:alpine
container_name: dashboard
restart: unless-stopped
volumes:
- ./dashboard:/usr/share/nginx/html:ro
company-explorer:
build:
context: ./company-explorer
dockerfile: Dockerfile
container_name: company-explorer
restart: unless-stopped
ports:
- "8000:8000"
environment:
API_USER: "admin"
API_PASSWORD: "gemini"
PYTHONUNBUFFERED: "1"
DATABASE_URL: "sqlite:////data/companies_v3_fixed_2.db"
GEMINI_API_KEY: "${GEMINI_API_KEY}"
SERP_API_KEY: "${SERP_API}"
NOTION_TOKEN: "${NOTION_API_KEY}"
volumes:
- ./company-explorer:/app
- explorer_db_data:/data
- ./Log_from_docker:/app/logs_debug
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
lead-engine:
build:
context: ./lead-engine
dockerfile: Dockerfile
container_name: lead-engine
restart: unless-stopped
ports:
- "8501:8501" # UI (Streamlit)
- "8004:8004" # API / Monitor
- "8099:8004" # Direct Test Port
environment:
PYTHONUNBUFFERED: "1"
GEMINI_API_KEY: "${GEMINI_API_KEY}"
SERP_API: "${SERP_API}"
INFO_Application_ID: "${INFO_Application_ID}"
INFO_Tenant_ID: "${INFO_Tenant_ID}"
INFO_Secret: "${INFO_Secret}"
CAL_APPID: "${CAL_APPID}"
CAL_SECRET: "${CAL_SECRET}"
CAL_TENNANT_ID: "${CAL_TENNANT_ID}"
TEAMS_WEBHOOK_URL: "${TEAMS_WEBHOOK_URL}"
FEEDBACK_SERVER_BASE_URL: "${FEEDBACK_SERVER_BASE_URL}"
WORDPRESS_BOOKING_URL: "${WORDPRESS_BOOKING_URL}"
MS_BOOKINGS_URL: "${MS_BOOKINGS_URL}"
volumes:
- ./lead-engine:/app
- lead_engine_data:/app/data
volumes:
explorer_db_data: {}
lead_engine_data: {}
```
2. **Vorbereiten der `nginx-proxy-test.conf`:**
Stellen Sie sicher, dass die Datei `nginx-proxy-test.conf` im Projekt-Root-Verzeichnis existiert und folgenden Inhalt hat (wurde bereits von Gemini erstellt):
```nginx
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /dev/stdout;
error_log /dev/stderr;
client_max_body_size 50M;
proxy_read_timeout 1200s;
proxy_connect_timeout 1200s;
proxy_send_timeout 1200s;
send_timeout 1200s;
resolver 127.0.0.11 valid=30s ipv6=off;
server {
listen 80;
location / {
auth_basic "Restricted Access - Local AI Suite";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://dashboard:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /ce/ {
auth_basic "Restricted Access - Local AI Suite";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://company-explorer:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /lead/ {
auth_basic "Restricted Access - Local AI Suite";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://lead-engine:8501/;\
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_read_timeout 86400;
}
location /feedback/ {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
rewrite ^/feedback/(.*)$ /$1 break;
proxy_pass http://lead-engine:8004;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /public/smartlead/ {
auth_basic off;
rewrite ^/public/smartlead/(.*)$ /webhook/$1 break;
proxy_pass http://lead-engine:8004;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
```
3. **Log-Datei vorbereiten:**
Erstellen Sie das Log-Verzeichnis und die Datei im `lead-engine` Kontext (falls noch nicht geschehen):
```bash
mkdir -p lead-engine/Log && touch lead-engine/Log/smartlead_webhooks.log && chmod 777 lead-engine/Log/smartlead_webhooks.log
```
4. **Test-Setup starten:**
Um das lokale Test-Setup zu starten, führen Sie diese Befehle aus:
```bash
# Bestehende (potenziell fehlerhafte) Container stoppen und entfernen
docker-compose -f docker-compose.test.yml down
# Neues, schlankes Setup starten
docker-compose -f docker-compose.test.yml up -d
```
#### Test-Prozess & Datenanalyse (Diskstation)
1. **URLs an Smartlead übergeben:**
Geben Sie die folgenden URLs an Smartlead weiter, um Test-Events auszulösen. Ersetzen Sie `<Ihre_Diskstation_IP_oder_Domain>` durch die tatsächliche IP/Domain Ihrer Diskstation:
* **Hot Lead Webhook:** `http://<Ihre_Diskstation_IP_oder_Domain>:8090/public/smartlead/hot-lead`
* **Follow-up Lead Webhook:** `http://<Ihre_Diskstation_IP_oder_Domain>:8090/public/smartlead/follow-up-lead`
Wenn Sie HTTPS nutzen, ändern Sie `http` zu `https` und verwenden Sie Ihren Domainnamen.
2. **Test-Auslösung bestätigen:**
Informieren Sie Gemini, sobald Smartlead die Test-Auslösung bestätigt hat.
3. **Log-Daten analysieren:**
Nach Erhalt der Test-Events lesen wir die Datei `/app/lead-engine/Log/smartlead_webhooks.log` aus, um die exakte JSON-Struktur der Payloads und die Quell-IP-Adressen von Smartlead zu ermitteln.
#### Anforderungen für Wackler IT (Produktivumgebung)
Basierend auf den Analysen aus dem lokalen Test-Setup werden wir die Anforderungen an die IT-Abteilung von Wackler formulieren, um die Smartlead-Webhooks in der Produktivumgebung sicher freizuschalten.
1. **Externe Erreichbarkeit:**
* **Domain:** `gtm.robo-planet.de`
* **Protokoll:** **HTTPS** (Port 443)
* **Öffentliche Pfade:** `/smartlead/hot-lead` und `/smartlead/follow-up-lead`
2. **Firewall-Regel (Quell-IPs):**
* Smartlead sendet Webhooks von spezifischen IP-Adressen (diese werden aus den Test-Logs ermittelt). Die Firewall muss so konfiguriert werden, dass nur Anfragen von diesen **erlaubten Smartlead-IPs** den externen Nginx-Server erreichen dürfen. Alle anderen IPs sind zu blockieren.
3. **Nginx-Konfiguration (Externer Server `gtm.robo-planet.de`):**
Der externe Nginx-Server muss um einen `location`-Block erweitert werden, der dem folgenden Beispiel ähnelt (die genaue `proxy_pass`-IP (`10.10.81.2`) sollte von der Wackler IT bestätigt werden, da dies die interne IP Ihres GTM-Gateways im Wackler-Netzwerk ist):
```nginx
location /smartlead/ {
auth_basic off; # Keine Authentifizierung für öffentliche Webhooks
# Erlaubte Smartlead-IPs (Platzhalter - aus Test-Logs zu befüllen)
# Beispiel:
# allow 192.0.2.0/24;
# allow 203.0.113.0/24;
deny all; # Alle anderen IPs blockieren
rewrite ^/smartlead/(.*)$ /public/smartlead/$1 break;
proxy_pass http://10.10.81.2:8090; # Weiterleitung zum internen GTM-Gateway (Port 8090)
# Standard Proxy Header
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
4. **Wichtiger Sicherheitshinweis:**
Es muss explizit sichergestellt werden, dass der **SuperOffice Connector** in der Produktivumgebung nicht gestartet oder so konfiguriert ist, dass er keine Verbindung zu Wacklers SuperOffice-System herstellt, um Datenkonflikte zu vermeiden.
---
Dieser Prozess stellt sicher, dass wir nicht "blind" entwickeln, sondern auf Basis der realen Datenstruktur von Smartlead aufbauen.
## 🏗 Architektur

82
nginx-proxy-test.conf Normal file
View File

@@ -0,0 +1,82 @@
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /dev/stdout;
error_log /dev/stderr;
client_max_body_size 50M;
proxy_read_timeout 1200s;
proxy_connect_timeout 1200s;
proxy_send_timeout 1200s;
send_timeout 1200s;
resolver 127.0.0.11 valid=30s ipv6=off;
server {
listen 80;
# Route for the main Dashboard
location / {
auth_basic "Restricted Access - Local AI Suite";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://dashboard:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Route for Company Explorer
location /ce/ {
auth_basic "Restricted Access - Local AI Suite";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://company-explorer:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Route for Lead Engine UI
location /lead/ {
auth_basic "Restricted Access - Local AI Suite";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://lead-engine:8501/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_read_timeout 86400;
}
# Route for Lead Engine Feedback (public)
location /feedback/ {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
rewrite ^/feedback/(.*)$ /$1 break;
proxy_pass http://lead-engine:8004;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Smartlead Webhooks (public)
location /public/smartlead/ {
auth_basic off;
rewrite ^/public/smartlead/(.*)$ /webhook/$1 break;
proxy_pass http://lead-engine:8004;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}