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.
442 lines
22 KiB
Markdown
442 lines
22 KiB
Markdown
# Lead Engine: Multi-Source Automation v2.2 [31988f42]
|
||
|
||
## 🚀 Übersicht
|
||
Die **Lead Engine** ist ein spezialisiertes Modul zur autonomen Verarbeitung von B2B-Anfragen. Sie fungiert als Brücke zwischen dem E-Mail-Postfach und dem **Company Explorer**, um innerhalb von Minuten hochgradig personalisierte Antwort-Entwürfe auf "Human Expert Level" zu generieren.
|
||
|
||
## 🛠 Hauptfunktionen
|
||
|
||
### 1. Intelligenter E-Mail Ingest
|
||
* **Multi-Source:** Überwacht das Postfach `info@robo-planet.de` via **Microsoft Graph API**.
|
||
* **Filter & Routing:** Unterscheidet Anfragen von **TradingTwins** und dem **Kontaktformular**.
|
||
* **Parsing:** Spezialisierte HTML-Parser extrahieren strukturierte Daten (Firma, Kontakt, Bedarf).
|
||
|
||
### 2. Contact Research (LinkedIn Lookup)
|
||
* **Automatisierung:** Sucht via **SerpAPI** und **Gemini 2.0 Flash** nach der beruflichen Position.
|
||
* **Ergebnis:** Identifiziert Rollen (z.B. "CFO"), um den Tonfall anzupassen.
|
||
|
||
### 3. Company Explorer Sync & Monitoring
|
||
* **Integration:** Legt Accounts und Kontakte automatisch im CE an.
|
||
* **Monitor:** Hintergrund-Prozess (`monitor.py`) überwacht den Analyse-Status.
|
||
* **Daten-Pull:** Übernimmt Branche und Dossier in die lokale Lead-Datenbank.
|
||
|
||
### 4. Expert Response Generator
|
||
* **KI-Engine:** Gemini 2.0 Flash erstellt E-Mail-Entwürfe.
|
||
* **Kontext:** Kombiniert Lead-Daten + CE-Daten + Matrix-Argumente (Pains/Gains).
|
||
|
||
### 5. Trading Twins Autopilot (PRODUKTIV v2.2)
|
||
Der vollautomatische "Zero Touch" Workflow für Trading Twins Anfragen.
|
||
|
||
* **Human-in-the-Loop:** Elizabeta Melcer erhält eine Teams-Nachricht ("Approve/Deny").
|
||
* **Feedback-Server:** Ein integrierter FastAPI-Server (Port 8004) verarbeitet Klicks.
|
||
* **Direct Calendar Booking (Micro-Service):**
|
||
* **Logik:** Prüft den Kalender von `e.melcer` auf **echte Verfügbarkeit**.
|
||
* **Raster:** Termine starten nur im **15-Minuten-Takt** (:00, :15, :30, :45).
|
||
* **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 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. 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:** `http(s)://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/hot-lead`
|
||
* **Follow-up Leads:** `http(s)://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/follow-up-lead`
|
||
|
||
#### 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. **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.
|
||
|
||
---
|
||
|
||
|
||
## 🏗 Architektur
|
||
|
||
```text
|
||
/app/lead-engine/
|
||
├── app.py # Streamlit Web-Interface
|
||
├── trading_twins_ingest.py # E-Mail Importer (Graph API)
|
||
├── monitor.py # Monitor + Trigger für Orchestrator
|
||
├── trading_twins/ # Autopilot Modul
|
||
│ ├── manager.py # Orchestrator, FastAPI, Graph API Logic
|
||
│ ├── test_calendar_logic.py # Interner Test für Kalender-Zugriff
|
||
│ └── signature.html # HTML-Signatur (mit Bildern im selben Ordner)
|
||
└── db.py # Lokale SQLite Lead-Datenbank
|
||
```
|
||
|
||
## 🚨 Lessons Learned & Critical Fixes
|
||
|
||
### 1. Microsoft Graph API: Kalender-Zugriff
|
||
* **Problem:** `debug_calendar.py` scheiterte oft mit `TimeZoneNotSupportedException`.
|
||
* **Ursache:** Der API-Aufruf zur Abfrage der Verfügbarkeit (`getSchedule`) hat keine explizite Zeitzoneninformation erhalten.
|
||
* **Lösung:** Die Zeitzone ("Europe/Berlin") wird nun explizit im `payload` des API-Aufrufs mitgegeben.
|
||
|
||
### 2. Exchange AppOnly AccessPolicy (Buchungs-Workaround)
|
||
* **Problem:** `Calendars.ReadWrite` erlaubt einer App oft nicht, Termine in *fremden* Kalendern (`e.melcer@`) zu erstellen (`403 Forbidden`).
|
||
* **Lösung:** Der Termin wird im **eigenen Kalender** des Service-Accounts (`info@`) erstellt. Der Mitarbeiter (`e.melcer@`) wird als **Teilnehmer** hinzugefügt. Das umgeht die Policy.
|
||
|
||
### 3. Dynamische HTML-Signatur mit Inline-Bildern
|
||
* **Problem:** Eine statische Signatur in der Konfiguration war unflexibel und konnte keine Bilder enthalten.
|
||
* **Lösung:** Ein Skript (`scripts/extract_signature_assets.py`) extrahiert die vollständige HTML-Signatur und alle eingebetteten Bilder aus einer `.eml`-Datei. Die `send_email`-Funktion wurde überarbeitet, um alle Bilder dynamisch als Inline-Anhänge zu versenden, was eine professionelle Darstellung sicherstellt.
|
||
|
||
### 4. Race-Condition-Schutz bei Überbuchung (Live-Check)
|
||
* **Problem:** Wenn mehrere Leads E-Mails mit denselben Terminvorschlägen erhalten, konnten Doppelbuchungen entstehen.
|
||
* **Lösung:** Implementierung eines "Live-Checks" im Feedback-Server. Bevor ein Termin gebucht wird, prüft das System in Echtzeit (`is_slot_free`), ob der Slot im Kalender von `e.melcer@` noch verfügbar ist. Ist er belegt, wird die Buchung abgebrochen und ein Fallback-Szenario aktiviert.
|
||
|
||
### 5. Seamless Website Integration (WordPress iFrame)
|
||
* **Problem:** Die API-Endpoints gaben nackten Text zurück, was für Kunden unprofessionell wirkte.
|
||
* **Lösung:** Der Server liefert nun saubere HTML-Snippets zurück. Durch Setzen der `WORDPRESS_BOOKING_URL` in der `.env` führen die Links in der Kunden-E-Mail direkt auf die Kunden-Website. Dort wird das HTML-Ergebnis (Erfolg inkl. Teams-Link ODER Fallback zum Microsoft Bookings Kalender bei Doppelbuchung) unsichtbar in einem iFrame geladen.
|
||
|
||
#### 5.1 Troubleshooting der iFrame-Integration
|
||
|
||
Um sicherzustellen, dass die Buchungs-Landingpage auf WordPress immer korrekt funktioniert – sowohl mit spezifischen Terminvorschlägen als auch als Fallback zu einer allgemeinen Buchungsseite – sind mehrere Konfigurationsschritte und Fehlerbehebungen notwendig:
|
||
|
||
**1. Robuster iFrame-Code für Ihre WordPress-Seite**
|
||
Der folgende JavaScript-Code sollte in Ihre WordPress-Seite integriert werden, die als Landingpage für Terminbuchungen dient (z.B. `robo-planet.de/terminbestaetigung`). Er prüft, ob spezifische Termindaten (Job-UUID und Timestamp) über die URL übergeben werden, und lädt entsprechend entweder den spezifischen Termin-Slot oder die allgemeine Microsoft Bookings URL als Fallback.
|
||
|
||
```html
|
||
<iframe id="booking-iframe" width="100%" height="800px" style="border:none;" scrolling="no"></iframe>
|
||
<script>
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const jobUuid = urlParams.get('job_uuid');
|
||
const timestamp = urlParams.get('ts');
|
||
|
||
let iframeSrc = "";
|
||
|
||
if (jobUuid && timestamp) {
|
||
// Wenn beide Parameter vorhanden sind, den spezifischen Buchungslink verwenden
|
||
iframeSrc = "https://floke-ai.duckdns.org/feedback/book_slot/" + jobUuid + "/" + timestamp;
|
||
} else {
|
||
// Andernfalls auf die allgemeine MS Bookings URL verweisen
|
||
iframeSrc = "https://outlook.office.com/book/KennenlernenmitRoboplanet@wackler-group.de/?ismsaljsauthenabled";
|
||
}
|
||
|
||
document.getElementById('booking-iframe').src = iframeSrc;
|
||
</script>
|
||
```
|
||
|
||
**2. Nginx-Konfiguration für korrekte Pfad-Weiterleitung**
|
||
Das Laden der spezifischen `/feedback/book_slot/...`-URL im iFrame scheiterte initial, da der Nginx-Proxy die verschachtelten Pfade nicht korrekt an den `lead-engine`-Container weiterleitete. Dies führte zur "Synology-Fehlerseite".
|
||
|
||
* **Problem:** Die `location`-Regel in `nginx-proxy-clean.conf` für `/feedback/` war zu starr.
|
||
* **Lösung:** Die Konfiguration wurde mit einer `rewrite`-Regel angepasst, um sicherzustellen, dass der gesamte Pfad korrekt an den `lead-engine`-Dienst weitergegeben wird und die notwendigen Proxy-Header für moderne Webanwendungen gesetzt sind.
|
||
|
||
```nginx
|
||
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;
|
||
}
|
||
```
|
||
* **Aktion nach Änderung:** Nach dem Anpassen von `nginx-proxy-clean.conf` muss der Nginx-Container neu gestartet werden:
|
||
`docker-compose restart nginx`
|
||
|
||
**3. Behebung des `lead-engine` Service-Absturzes (`SyntaxError`)**
|
||
Der `lead-engine`-Dienst selbst stürzte aufgrund eines Python `SyntaxError` ab, der durch einen ungültigen Import-Pfad verursacht wurde, der Bindestriche enthielt. Dies verhinderte, dass der Dienst überhaupt eine Antwort senden konnte, was ebenfalls zu einer leeren iFrame-Anzeige beitrug.
|
||
|
||
* **Problem:** Eine Zeile `from connector-superoffice.superoffice_client import SuperOfficeClient` in `manager.py` verursachte einen `SyntaxError`, da Bindestriche in Python-Modulnamen nicht erlaubt sind.
|
||
* **Lösung:** Die fehlerhafte `sys.path.append`-Anweisung und die ungültige `import`-Zeile wurden aus `lead-engine/trading_twins/manager.py` entfernt, da sie Teil eines verschobenen Tasks waren.
|
||
|
||
* **Aktion nach Änderung:** Nach der Korrektur in `manager.py` muss der `lead-engine`-Container neu gebaut und neu gestartet werden:
|
||
`docker-compose up -d --build --force-recreate lead-engine`
|
||
|
||
Durch diese Maßnahmen wird die iFrame-Integration nun robust funktionieren und immer eine sinnvolle Ansicht auf der WordPress-Landingpage bieten.
|
||
|
||
## 🚀 Inbetriebnahme & Test
|
||
|
||
### Inbetriebnahme
|
||
```bash
|
||
# Neustart des Dienstes
|
||
docker-compose up -d --build --force-recreate lead-engine
|
||
```
|
||
|
||
### Test & Debugging
|
||
* **Allgemeiner Test:** Die URL `https://floke-ai.duckdns.org/feedback/test_lead` löst einen generischen Test-Lead aus.
|
||
* **Spezifischer Test pro Lead:** Im Lead-Tool (`/lead/`) kann für jeden Lead mit einem generierten E-Mail-Entwurf der Button "🧪 Test-Versand (an floke.com@gmail.com)" geklickt werden. Dies startet den gesamten End-to-End-Prozess (Teams-Nachricht & E-Mail-Versand) für den ausgewählten Lead, sendet die E-Mail aber sicher an die Test-Adresse.
|
||
|
||
**Zugriff:** `https://floke-ai.duckdns.org/lead/` (Passwortgeschützt)
|
||
|
||
## 📝 Zukünftige Erweiterungen & Todos
|
||
|
||
### Task: Automatisches Nachfassen (Follow-up)
|
||
* **Problem:** Wenn ein Lead nicht auf die E-Mail antwortet und auch keinen Termin bucht, geht der Kontakt verloren.
|
||
* **Lösung:** Einbindung eines Follow-up-Mechanismus nach 5 Tagen. Dies könnte entweder durch ein Flag im CRM-System oder durch eine geplante E-Mail direkt über die Lead-Engine realisiert werden.
|
||
|
||
### Task: Erfolgsmessung & Tracking (Microsoft Bookings Auswertung)
|
||
* **Ziel:** Übersicht gewinnen, wie viele Meetings tatsächlich über diesen neuen Kanal (Trading Twins / E-Mail) final gebucht wurden.
|
||
* **Lösungsweg (Pragmatischer Ansatz):**
|
||
1. Die E-Mail-Adresse der geteilten Bookings-Seite (`KennenlernenmitRoboplanet@wackler-group.de`) muss von der IT zur bestehenden **Exchange ApplicationAccessPolicy** der `CAL_APPID` hinzugefügt werden.
|
||
2. Dadurch kann unsere bestehende "Lese-App" auch die Termine dieses zentralen Postfachs über die MS Graph API (`GET /users/{bookings-email}/calendar/events`) auslesen.
|
||
3. Ein geplanter Job (z.B. täglich oder wöchentlich) zählt die neu hinzugekommenen Termine und erstellt einen kurzen KPI-Report.
|
||
|
||
### Task: CRM-Synchronisierung der gebuchten Termine (SuperOffice)
|
||
* **Ziel:** Die über Bookings generierten Termine müssen für die Historie und Dokumentation im CRM-System (SuperOffice) landen.
|
||
* **Lösung:** Die im vorherigen Task ausgelesenen Termine werden über den `connector-superoffice` an das CRM übergeben und dort als "Termin" oder "Aktivität" direkt beim entsprechenden Kontakt (gematcht über die E-Mail-Adresse) abgelegt.
|
||
|
||
```env
|
||
# Info-Postfach (App 1 - Schreiben)
|
||
INFO_Application_ID=...
|
||
INFO_Tenant_ID=...
|
||
INFO_Secret=...
|
||
|
||
# E.Melcer Kalender (App 2 - Lesen)
|
||
CAL_APPID=...
|
||
CAL_TENNANT_ID=...
|
||
CAL_SECRET=...
|
||
|
||
# URLs
|
||
TEAMS_WEBHOOK_URL=...
|
||
FEEDBACK_SERVER_BASE_URL=https://floke-ai.duckdns.org/feedback
|
||
WORDPRESS_BOOKING_URL=https://www.robo-planet.de/terminbestaetigung
|
||
MS_BOOKINGS_URL=https://outlook.office365.com/book/KennenlernenmitRoboplanet@wackler-group.de/
|
||
``` |