# 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` * `UDF_UnsubscribeLink` --- ### 6. Monitoring & Dashboard ("The Eyes") Das System verfügt über ein integriertes Echtzeit-Dashboard zur Überwachung der Synchronisationsprozesse. **Features:** * **Account-basierte Ansicht:** Gruppiert alle Ereignisse nach SuperOffice-Account oder Person, um den aktuellen Status pro Datensatz zu zeigen. * **Phasen-Visualisierung:** Stellt den Fortschritt in vier Phasen dar: 1. **Received:** Webhook erfolgreich empfangen. 2. **Enriching:** Datenanreicherung im Company Explorer läuft (Gelb blinkend = In Arbeit). 3. **Syncing:** Rückschreiben der Daten nach SuperOffice (Gelb blinkend = In Arbeit). 4. **Completed:** Prozess für diesen Kontakt erfolgreich abgeschlossen (Grün). * **Performance-Tracking:** Anzeige der Gesamtdurchlaufzeit (Duration) pro Prozess. * **Fehler-Analyse:** Detaillierte Fehlermeldungen direkt in der Übersicht. * **Dark Mode:** Modernes UI-Design für Admin-Monitoring. **Zugriff:** Das Dashboard ist über das Company Explorer Frontend (Icon "Activity" im Header) oder direkt unter `/connector/dashboard` erreichbar. --- ## 7. 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. --- ### 10. Lessons Learned: API Optimization & Certification (Feb 24, 2026) Um die Zertifizierung für den SuperOffice App Store zu erhalten, mussten kritische Performance-Optimierungen durchgeführt werden. 1. **Die `getAllRows`-Falle:** * **Problem:** SuperOffice monierte in der Validierung API-Calls wie `getAllRows` (implizit oft durch Abfragen ganzer Objekte ohne Filter), die unnötige Last verursachen. * **Lösung:** Implementierung von **OData `$select`**. Wir fordern nun strikt nur die Felder an, die wir wirklich benötigen (z.B. `get_person(id, select=['JobTitle', 'UserDefinedFields'])`). * **Wichtig:** Niemals pauschal `get_person()` aufrufen, wenn nur die Rolle geprüft werden soll. 3. **PUT vs. PATCH (Safe Updates):** * **Problem:** Die Verwendung von `PUT` zum Aktualisieren von Entitäten (Person/Contact) erfordert, dass das *gesamte* Objekt gesendet wird. Dies birgt das Risiko, Felder zu überschreiben, die zwischenzeitlich von anderen Benutzern geändert wurden ("Race Condition"), und verursacht unnötigen Traffic. * **Lösung:** Umstellung auf **`PATCH`**. Wir senden nun nur noch die *tatsächlich geänderten Felder* (Delta). * **Implementierung:** Der Worker baut nun ein `patch_payload` (z.B. `{'Position': {'Id': 123}}`) und nutzt den dedizierten PATCH-Endpunkt. Dies wurde explizit von SuperOffice für die Zertifizierung gefordert. ### 11. Production Environment (Live Feb 27, 2026) Nach erfolgreicher Zertifizierung durch SuperOffice wurde der Connector auf die Produktionsumgebung umgestellt. * **Tenant:** `Cust26720` * **Environment:** `online3` (zuvor `sod`) * **Endpoint:** `https://online3.superoffice.com/Cust26720/api/v1` * **Authentication:** Umstellung auf Produktions-Client-ID und -Secret erfolgreich verifiziert (Health Check OK). **Wichtig:** SuperOffice nutzt Load-Balancing. Die Subdomain (`online3`) kann sich theoretisch ändern. Die Anwendung prüft dies dynamisch, aber die Basis-Konfiguration sollte den aktuellen Tenant-Status widerspiegeln. ### 12. Lessons Learned: Production Migration (Feb 27, 2026) Der Wechsel von der Staging-Umgebung (`sod`) zur Produktion (`onlineX`) brachte spezifische technische Hürden mit sich: 1. **Globaler Token-Endpunkt:** * **Problem:** Mandantenspezifische Subdomains (wie `online3.superoffice.com`) akzeptieren oft keine OAuth-Anfragen oder liefern leere Antworten. * **Lösung:** Für den Token-Refresh muss zwingend der globale Endpunkt **`https://online.superoffice.com/login/common/oauth/tokens`** verwendet werden, unabhängig davon, auf welchem Cluster der Mandant liegt. 2. **DNS-Präfixe (app- vs. direkt):** * **Problem:** In der Staging-Umgebung lautet der API-Host meist `app-sod.superoffice.com`. In der Produktion wird das `app-` Präfix oft nicht verwendet oder führt zu Zertifikatsfehlern. * **Lösung:** Der `SuperOfficeClient` wurde so flexibilisiert, dass er in der Produktion direkt auf `{env}.superoffice.com` zugreift. 3. **Environment Variables Persistence:** * **Problem:** Docker-Container behalten Umgebungsvariablen oft im Cache ("Shadow Configuration"), selbst wenn die `.env`-Datei geändert wurde. * **Lösung:** Zwingendes `docker-compose up -d --force-recreate` nach Credentials-Änderungen. ### 13. Post-Migration Configuration (Cust26720) Die Konfiguration in der `.env` Datei wurde für die Produktion wie folgt finalisiert: | Funktion | UDF / ID | Entity | | :--- | :--- | :--- | | **Subject** | `SuperOffice:19` | Person | | **Intro Text** | `SuperOffice:20` | Person | | **Social Proof** | `SuperOffice:21` | Person | | **Unsubscribe** | `SuperOffice:22` | Person | | **Campaign Tag** | `SuperOffice:23` | Person | | **Opener Primary** | `SuperOffice:86` | Contact | | **Opener Sec.** | `SuperOffice:87` | Contact | | **Vertical** | `SuperOffice:83` | Contact | | **Summary** | `SuperOffice:84` | Contact | | **Last Update** | `SuperOffice:85` | Contact | ### 14. Kampagnen-Steuerung (Usage) Das System unterstützt mehrere Outreach-Varianten über das Feld **`MA_Campaign`** (Person). 1. **Standard:** Bleibt das Feld leer, werden die Standard-Texte ("standard") für Kaltakquise geladen. 2. **Spezifisch:** Wird ein Wert gewählt (z.B. "Messe 2026"), sucht der Connector gezielt nach Matrix-Einträgen mit diesem Tag. 3. **Fallback:** Existiert für die gewählte Kampagne kein spezifischer Text für das Vertical/Persona, wird automatisch auf "standard" zurückgegriffen. ### 16. Email Sending Implementation (Feb 28, 2026) A dedicated script `create_email_test.py` has been implemented to create "Email Documents" directly in SuperOffice via the API. This bypasses the need for an external SMTP server by utilizing SuperOffice's internal document system. **Features:** * **Document Creation:** Creates a document of type "Ausg. E-Mail" (Template ID 157). * **Activity Tracking:** Automatically creates a linked "Appointment" (Task ID 6 - Document Out) to ensure the email appears in the contact's activity timeline. * **Direct Link:** Outputs a direct URL to open the created document in SuperOffice Online. **Usage:** ```bash python3 connector-superoffice/create_email_test.py # Example: python3 connector-superoffice/create_email_test.py 193036 ``` **Key API Endpoints Used:** * `POST /Document`: Creates the email body and metadata. * `POST /Appointment`: Creates the activity record linked to the document. --- 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"). ```