185 lines
10 KiB
Markdown
185 lines
10 KiB
Markdown
# SuperOffice Connector & GTM Engine ("The Muscle & The Brain")
|
||
|
||
Dieses Dokument beschreibt die Architektur der **Go-to-Market (GTM) Engine**, die SuperOffice CRM mit der Company Explorer Intelligence verbindet.
|
||
|
||
Ziel des Systems ist der vollautomatisierte Versand von **hyper-personalisierten E-Mails**, die so wirken, als wären sie manuell von einem Branchenexperten geschrieben worden.
|
||
|
||
---
|
||
|
||
## 1. Das Konzept: "Static Magic"
|
||
|
||
Anders als bei üblichen KI-Tools, die E-Mails "on the fly" generieren, setzt dieses System auf **vorberechnete, statische Textbausteine**.
|
||
|
||
**Warum?**
|
||
1. **Qualitätssicherung:** Jeder Baustein kann vor dem Versand geprüft werden.
|
||
2. **Performance:** SuperOffice muss beim Versand keine KI anfragen, sondern nur Felder zusammenfügen.
|
||
3. **Konsistenz:** Ein "Finanzleiter im Maschinenbau" bekommt immer dieselbe, perfekte Argumentation – egal bei welchem Unternehmen.
|
||
|
||
### Die E-Mail-Formel
|
||
|
||
Eine E-Mail setzt sich aus **drei statischen Komponenten** zusammen, die im CRM (SuperOffice) gespeichert sind:
|
||
|
||
```text
|
||
[1. Opener (Unternehmens-Spezifisch)] + [2. Bridge (Persona x Vertical)] + [3. Social Proof (Vertical)]
|
||
```
|
||
|
||
* **1. Opener (Der Haken):** Bezieht sich zu 100% auf das spezifische Unternehmen und dessen Geschäftsmodell.
|
||
* *Quelle:* `Company`-Objekt (Feld: `ai_opener`).
|
||
* *Beispiel:* "Die präzise Just-in-Time-Fertigung von **Müller CNC** erfordert einen reibungslosen Materialfluss ohne Mikrostillstände."
|
||
* **2. Bridge (Die Relevanz):** Holt die Person in ihrer Rolle ab und verknüpft sie mit dem Branchen-Pain.
|
||
* *Quelle:* `Matrix`-Tabelle (Feld: `intro`).
|
||
* *Beispiel:* "Für Sie als **Produktionsleiter** bedeutet das, trotz Fachkräftemangel die Taktzeiten an der Linie stabil zu halten."
|
||
* **3. Social Proof (Die Lösung):** Zeigt Referenzen und den konkreten Nutzen (Gains).
|
||
* *Quelle:* `Matrix`-Tabelle (Feld: `social_proof`).
|
||
* *Beispiel:* "Unternehmen wie **Jungheinrich** nutzen unsere Transportroboter, um Fachkräfte an der Maschine zu halten und Suchzeiten um 30% zu senken."
|
||
|
||
---
|
||
|
||
## 2. Die Datenbasis (Foundation)
|
||
|
||
Die Qualität der Texte steht und fällt mit der Datenbasis. Diese wird zentral in **Notion** gepflegt und in den Company Explorer synchronisiert.
|
||
|
||
### A. Verticals (Branchen)
|
||
Definiert die **Makro-Pains** und **Gains** einer Branche sowie das **passende Produkt**.
|
||
* *Beispiel:* Healthcare -> Pain: "Pflegekräfte machen Logistik" -> Gain: "Hände fürs Bett" -> Produkt: Service-Roboter.
|
||
* *Wichtig:* Unterscheidung nach **Ops-Focus** (Operativ vs. Infrastruktur) steuert das Produkt (Reinigung vs. Service).
|
||
|
||
### B. Personas (Rollen)
|
||
Definiert die **persönlichen Pains** einer Rolle.
|
||
* *Beispiel:* Produktionsleiter -> Pain: "OEE / Taktzeit".
|
||
* *Beispiel:* Geschäftsführer -> Pain: "ROI / Amortisation".
|
||
|
||
---
|
||
|
||
## 3. Die Matrix-Engine (Multiplikation)
|
||
|
||
Das Skript `generate_matrix.py` (im Backend) ist das Herzstück. Es berechnet **alle möglichen Kombinationen** aus Verticals und Personas voraus.
|
||
|
||
**Logik:**
|
||
1. Lade alle Verticals (`V`) und Personas (`P`).
|
||
2. Für jede Kombination `V x P`:
|
||
* Lade `V.Pains` und `P.Pains`.
|
||
* Generiere via Gemini einen **perfekten Satz 2 (Bridge)** und **Satz 3 (Proof)**.
|
||
* Generiere ein **Subject**, das den Persona-Pain trifft.
|
||
3. Speichere das Ergebnis in der Tabelle `marketing_matrix`.
|
||
|
||
*Ergebnis:* Eine Lookup-Tabelle, aus der für jeden Kontakt sofort der passende Text gezogen werden kann.
|
||
|
||
---
|
||
|
||
## 4. Der "Opener" (First Sentence)
|
||
|
||
Dieser Baustein ist der einzige, der **pro Unternehmen** generiert wird (bei der Analyse/Discovery).
|
||
|
||
**Logik:**
|
||
1. Scrape Website-Content.
|
||
2. Identifiziere das **Vertical** (z.B. Maschinenbau).
|
||
3. Lade den **Core-Pain** des Verticals (z.B. "Materialfluss").
|
||
4. **Prompt:** "Analysiere das Geschäftsmodell von [Firma]. Formuliere einen Satz, der erklärt, warum [Core-Pain] für genau dieses Geschäftsmodell kritisch ist."
|
||
|
||
*Ergebnis:* Ein Satz, der beweist: "Ich habe verstanden, was ihr tut."
|
||
|
||
---
|
||
|
||
## 5. SuperOffice Connector ("The Muscle")
|
||
|
||
Der Connector ist der Bote, der diese Daten in das CRM bringt.
|
||
|
||
**Workflow:**
|
||
1. **Trigger:** Kontakt-Änderung in SuperOffice (Webhook).
|
||
2. **Enrichment:** Connector fragt Company Explorer: "Gib mir Daten für Firma X, Person Y".
|
||
3. **Lookup:** Company Explorer...
|
||
* Holt den `Opener` aus der Company-Tabelle.
|
||
* Bestimmt `Vertical` und `Persona`.
|
||
* Sucht den passenden Eintrag in der `MarketingMatrix`.
|
||
4. **Write-Back:** Connector schreibt die Texte in die UDF-Felder (User Defined Fields) des Kontakts in SuperOffice.
|
||
* `UDF_Opener`
|
||
* `UDF_Bridge`
|
||
* `UDF_Proof`
|
||
* `UDF_Subject`
|
||
|
||
---
|
||
|
||
## 6. Setup & Wartung
|
||
|
||
### Neue Branche hinzufügen
|
||
1. In **Notion** anlegen (Pains/Gains/Produkte definieren).
|
||
2. Sync-Skript laufen lassen: `python3 backend/scripts/sync_notion_industries.py`.
|
||
3. Matrix neu berechnen: `python3 backend/scripts/generate_matrix.py --live`.
|
||
|
||
### End-to-End Tests
|
||
Ein automatisierter Integrationstest (`tests/test_e2e_flow.py`) deckt den gesamten Zyklus ab:
|
||
1. **Company Creation:** Webhook -> CE Provisioning -> Write-back (Vertical).
|
||
2. **Person Creation:** Webhook -> CE Matrix Lookup -> Write-back (Texte).
|
||
3. **Vertical Change:** Änderung im CRM -> CE Update -> Cascade zu Personen -> Neue Texte.
|
||
|
||
Ausführen mittels:
|
||
```bash
|
||
python3 connector-superoffice/tests/test_e2e_flow.py
|
||
```
|
||
|
||
## 7. Troubleshooting & Known Issues
|
||
|
||
### Authentication "URL has an invalid label"
|
||
Tritt auf, wenn `SO_ENVIRONMENT` leer ist. Der Client fällt nun automatisch auf `sod` zurück.
|
||
|
||
### Pydantic V2 Compatibility
|
||
Die `config.py` wurde auf natives Python (`os.getenv`) umgestellt, um Konflikte mit `pydantic-settings` in Docker-Containern zu vermeiden.
|
||
|
||
### Address & VAT Sync (WIP)
|
||
Der Worker wurde erweitert, um auch `City` und `OrgNumber` (VAT) zurückzuschreiben.
|
||
**Status (21.02.2026):** Implementiert, aber noch im Feinschliff. Logs zeigen teils Re-Queueing während das Enrichment läuft.
|
||
|
||
### 8. Lessons Learned: Address & VAT Sync (Solved Feb 22, 2026)
|
||
|
||
Die Synchronisation von Adressdaten stellte sich als unerwartet komplex heraus. Hier die wichtigsten Erkenntnisse für zukünftige Entwickler:
|
||
|
||
1. **Das "OrgNumber"-Phantom:**
|
||
* **Problem:** In der API-Dokumentation oft als `OrgNumber` referenziert, akzeptiert die WebAPI (REST) strikt nur **`OrgNr`**.
|
||
* **Lösung:** Mapping im `worker.py` hart auf `OrgNr` umgestellt.
|
||
|
||
2. **Verschachtelte Adress-Struktur:**
|
||
* **Problem:** Ein flaches Update auf `PostalAddress` wird von der API stillschweigend ignoriert (HTTP 200, aber keine Änderung).
|
||
* **Lösung:** Das Update muss die tiefe Struktur respektieren: `Address["Postal"]["City"]` UND `Address["Street"]["City"]`. Beide müssen explizit gesetzt werden, um in der UI sichtbar zu sein.
|
||
|
||
3. **Die "Race Condition" Falle (Atomic Updates):**
|
||
* **Problem:** Wenn Adress-Daten (`PUT Contact`) und UDF-Daten (`PUT Contact/Udef`) in separaten API-Aufrufen kurz hintereinander gesendet werden, gewinnt der letzte Call. Da dieser oft auf einem *veralteten* `GET`-Stand basiert (bevor das erste Update durch war), wurde die Adresse wieder mit "Leer" überschrieben.
|
||
* **Lösung:** **Atomic Update Strategy**. Der Worker sammelt *alle* Änderungen (Adresse, VAT, Vertical, Openers) in einem einzigen Dictionary und sendet genau **einen** `PUT`-Request an den Kontakt-Endpunkt. Dies garantiert Konsistenz.
|
||
|
||
---
|
||
|
||
### 9. Lessons Learned: Appointment Simulation & Persona Matching
|
||
|
||
Die Simulation von E-Mails via Terminen (Appointments) erforderte Workarounds für das UI-Verhalten von SuperOffice.
|
||
|
||
1. **Header vs. Description (Die 42-Zeichen-Grenze):**
|
||
* SuperOffice nutzt im Kalender und in Listen den `MainHeader` als Titel. Dieser ist auf ca. 42 Zeichen begrenzt.
|
||
* Ist der Titel länger, schneidet SuperOffice ihn ab. Erscheint der Titel inkonsistent, "stiehlt" das UI oft die erste Zeile der `Description` als Titel-Ersatz.
|
||
* **Strategie:** Wir kürzen den `MainHeader` auf 40 Zeichen und stellen sicher, dass der **vollständige Betreff** als allererste Zeile in der `Description` steht. Danach folgen zwei Newlines. Damit landet der Betreff im UI-Header und die Anrede ("Hallo...") bleibt sicher im Textkörper.
|
||
|
||
2. **Mapping-Resilienz (Funktion vs. Titel):**
|
||
* Jobtitel (Funktion) landen in SuperOffice inkonsistent in den Feldern `JobTitle` oder `Title`.
|
||
* **Lösung:** Der Worker fragt nun beide Felder ab (`person.get("JobTitle") or person.get("Title")`), um die Rolle korrekt zuzuweisen.
|
||
|
||
3. **Rollen-Dynamik:**
|
||
* Um zu verhindern, dass alte Rollen (z.B. "Infrastruktur") nach einer Beförderung/Änderung in SuperOffice "kleben" bleiben, führt das System nun bei jeder Namens- oder Funktionsänderung einen **Rollen-Reset** durch.
|
||
|
||
## Appendix: The "First Sentence" Prompt
|
||
This is the core logic used to generate the company-specific opener.
|
||
|
||
**Goal:** Prove understanding of the business model + imply the pain (positive observation).
|
||
|
||
```text
|
||
Du bist ein exzellenter B2B-Stratege und Texter mit einem tiefen Verständnis für operative Prozesse.
|
||
Deine Aufgabe ist es, einen hochpersonalisierten, scharfsinnigen und wertschätzenden Einleitungssatz für eine E-Mail an ein potenzielles Kundenunternehmen zu formulieren.
|
||
|
||
--- Denkprozess & Stilvorgaben ---
|
||
1. **Analysiere den Kontext:** Verstehe das Kerngeschäft. Was ist die kritische, physische Tätigkeit vor Ort? (z.B. 'Betrieb von Hochregallagern', 'Pflege von Patienten').
|
||
2. **Identifiziere den Hebel:** Was ist der Erfolgsfaktor? (z.B. 'reibungslose Abläufe', 'maximale Hygiene').
|
||
3. **Formuliere den Satz (ca. 20-35 Wörter):**
|
||
- Wähle einen eleganten, aktiven Einstieg wie 'Speziell im Bereich...' oder 'Der reibungslose Betrieb...'.
|
||
- Verbinde die **spezifische Tätigkeit** mit dem **Hebel** und den **geschäftlichen Konsequenzen**.
|
||
- **WICHTIG:** Formuliere immer als positive Beobachtung über eine Kernkompetenz. Du implizierst die Herausforderung durch die Betonung der Wichtigkeit.
|
||
- **VERMEIDE:** Konkrete Zahlen (z.B. "35 Rutschen"), da diese veraltet sein können. Nutze abstrakte Größen ("weitläufige Anlagen").
|
||
```
|