# Company Explorer: Architektur & Spezifikation (Robotics Edition)

**Kontext:** Zentrale Intelligence-Plattform für die Branche **Robotik & Facility Management**.
**Ziel:** Automatisierte Anreicherung, Bewertung und Klassifizierung von B2B-Leads.

## 1. Strategische Neuausrichtung

| Bereich | Alt (Legacy) | Neu (Robotics Edition) |
| :--- | :--- | :--- |
| **Daten-Basis** | Google Sheets | **SQLite** (Lokal, performant, filterbar). |
| **Ziel-Daten** | Allgemein / Kundenservice | **Quantifizierbares Potenzial** (z.B. 4500m² Fläche, 120 Betten). |
| **Branchen** | KI-Vorschlag (Freitext) | **Strict Mode:** Mapping auf definierte Notion-Liste (z.B. "Hotellerie", "Automotive"). |
| **Bewertung** | 0-100 Score (Vage) | **Data-Driven:** Rohwert (Scraper/Search) -> Standardisierung (Formel) -> Potenzial. |
| **Analytics** | Techniker-ML-Modell | **Deaktiviert**. Fokus auf harte Fakten. |
| **Operations** | D365 Sync (Broken) | **Excel-Import & Deduplizierung**. Fokus auf Matching externer Listen gegen Bestand. |

## 2. Architektur & Komponenten-Mapping

Das System wird in `company-explorer/` neu aufgebaut. Wir lösen Abhängigkeiten zur Root `helpers.py` auf.

### A. Core Backend (`backend/`)

| Komponente | Aufgabe & Neue Logik | Prio |
| :--- | :--- | :--- |
| **Database** | Ersetzt `GoogleSheetHandler`. Speichert Firmen & "Enrichment Blobs". | 1 |
| **Importer** | Ersetzt `SyncManager`. Importiert Excel-Dumps (CRM) und Event-Listen. | 1 |
| **Deduplicator** | Ersetzt `company_deduplicator.py`. **Kern-Feature:** Checkt Event-Listen gegen DB. Muss "intelligent" matchen (Name + Ort + Web). | 1 |
| **Scraper (Base)** | Extrahiert Text von Websites. Basis für alle Analysen. | 1 |
| **Classification Service** | **NEU (v0.7.0).** Zweistufige Logik: <br> 1. Strict Industry Classification. <br> 2. Metric Extraction Cascade (Web -> Wiki -> SerpAPI). | 1 |
| **Marketing Engine** | Ersetzt `generate_marketing_text.py`. Nutzt neue `marketing_wissen_robotics.yaml`. | 3 |

**Identifizierte Hauptdatei:** `company-explorer/backend/app.py`

### B. Frontend (`frontend/`) - React

*   **View 1: Der "Explorer":** DataGrid aller Firmen. Filterbar nach "Roboter-Potential" und Status.
*   **View 2: Der "Inspector":** Detailansicht einer Firma. Zeigt gefundene Signale ("Hat SPA Bereich"). Manuelle Korrektur-Möglichkeit.
    *   **Identifizierte Komponente:** `company-explorer/frontend/src/components/Inspector.tsx`
*   **View 3: "List Matcher":** Upload einer Excel-Liste -> Anzeige von Duplikaten -> Button "Neue importieren".
*   **View 4: "Settings":** Konfiguration von Branchen, Rollen und Robotik-Logik.
    *   **Frontend "Settings" Komponente:** `company-explorer/frontend/src/components/RoboticsSettings.tsx`

### C. Architekturmuster für die Client-Integration

Um externen Diensten (wie der `lead-engine`) eine einfache und robuste Anbindung an den `company-explorer` zu ermöglichen, wurde ein standardisiertes Client-Connector-Muster implementiert.

| Komponente | Aufgabe & Neue Logik |
| :--- | :--- |
| **`company_explorer_connector.py`** | **NEU:** Ein zentrales Python-Skript, das als "offizieller" Client-Wrapper für die API des Company Explorers dient. Es kapselt die Komplexität der asynchronen Enrichment-Prozesse. |
| **`handle_company_workflow()`** | Die Kernfunktion des Connectors. Sie implementiert den vollständigen "Find-or-Create-and-Enrich"-Workflow: <br> 1. **Prüfen:** Stellt fest, ob ein Unternehmen bereits existiert. <br> 2. **Erstellen:** Legt das Unternehmen an, falls es neu ist. <br> 3. **Anstoßen:** Startet den asynchronen `discover`-Prozess. <br> 4. **Warten (Polling):** Überwacht den Status des Unternehmens, bis eine Website gefunden wurde. <br> 5. **Analysieren:** Startet den asynchronen `analyze`-Prozess. <br> **Vorteil:** Bietet dem aufrufenden Dienst eine einfache, quasi-synchrone Schnittstelle und stellt sicher, dass die Prozessschritte in der korrekten Reihenfolge ausgeführt werden. |

### 2.1 Der End-to-End Datenfluss (Lead-Fabrik)

Diese Grafik visualisiert den gesamten Prozess von der Anlage eines Kontakts im CRM über die KI-Analyse bis zur fertigen Marketing-Automation.

```mermaid
graph TD
    %% Nodes
    User((Vertriebs-User))
    SO_CRM[SuperOffice CRM]
    Connector[Connector Service]
    CE_Core[Company Explorer Core]
    CE_AI[AI Analysis Engine]
    CE_DB[(SQLite DB)]
    MA_System[Marketing Automation]

    %% Flow
    User -- Erstellt Contact (Firma / Person) --> SO_CRM
    SO_CRM -- Webhook (New Contact) --> Connector
    Connector -- POST /provision --> CE_Core
    
    subgraph "Intelligence Phase (Asynchron)"
        CE_Core -- 1. Scrape & Research --> CE_AI
        CE_AI -- 2. Vertical & Metriken (Potential) --> CE_Core
        CE_AI -- 3. Generiere Atomic Opener --> CE_Core
    end
    
    subgraph "Matrix Logic (Matching)"
        CE_Core -- 4. Rolle & Branche Identifizieren --> CE_DB
        CE_DB -- 5. Hole Matrix-Texte (Subject/Intro) --> CE_Core
        Note[Logik: Primary vs Secondary Product<br>z.B. Healthcare: Pflege -> Transport]
    end
    
    CE_Core -- Angereichertes Profil + Texte --> Connector
    Connector -- UPDATE Person (UDFs) --> SO_CRM
    
    SO_CRM -- Daten verfügbar --> MA_System
    MA_System -- Textblöcke ins Template einsetzen --> Email(E-Mail Automation läuft an)
```

**Prozess-Schritte:**
1.  **Trigger:** Ein Vertriebsmitarbeiter legt eine Person oder Firma in SuperOffice an.
2.  **Transport:** Der Connector empfängt den Webhook und beauftragt den Company Explorer (`/provision`).
3.  **Intelligence:**
    *   Die Website wird gescraped und analysiert.
    *   Die KI bestimmt das **Vertical** (z.B. "Healthcare - Hospital") und berechnet das **Potenzial** (z.B. Bettenanzahl).
    *   Ein individueller **Atomic Opener** wird generiert, der auf die spezifische Situation des Unternehmens eingeht.
4.  **Matrix Match:**
    *   Basierend auf der Job-Rolle (z.B. "Pflegedienstleitung") wird die **Persona** ("Operativer Entscheider") bestimmt.
    *   Die Engine prüft das `Ops Focus: Secondary` Flag (z.B. bei Krankenhäusern).
    *   Die passenden Textbausteine (Betreff, Intro, Social Proof) werden aus der vor-generierten Matrix geladen.
5.  **Sync Back:** Alle Texte (Opener + Matrix-Bausteine) werden in die benutzerdefinierten Felder (UDFs) der Person in SuperOffice zurückgeschrieben.
6.  **Execution:** Die Marketing-Automation nutzt diese Felder (`{udf_opener}`, `{udf_intro}`), um hoch-personalisierte E-Mails zu versenden.

## 3. Umgang mit Shared Code (`helpers.py` & Co.)

Wir kapseln das neue Projekt vollständig ab ("Fork & Clean").

*   **Quelle:** `helpers.py` (Root)
*   **Ziel:** `company-explorer/backend/lib/core_utils.py`
*   **Aktion:** Wir kopieren nur relevante Teile und ergänzen sie (z.B. `safe_eval_math`, `run_serp_search`).

## 4. Datenstruktur (SQLite Schema)

### Tabelle `companies` (Stammdaten & Analyse)
*   `id` (PK)
*   `name` (String)
*   `website` (String)
*   `crm_id` (String, nullable - Link zum D365)
*   `industry_crm` (String - Die "erlaubte" Branche aus Notion)
*   `city` (String)
*   `country` (String - Standard: "DE" oder aus Impressum)
*   `status` (Enum: NEW, IMPORTED, ENRICHED, QUALIFIED)
*   **NEU (v0.7.0):**
    *   `calculated_metric_name` (String - z.B. "Anzahl Betten")
    *   `calculated_metric_value` (Float - z.B. 180)
    *   `calculated_metric_unit` (String - z.B. "Betten")
    *   `standardized_metric_value` (Float - z.B. 4500)
    *   `standardized_metric_unit` (String - z.B. "m²")
    *   `metric_source` (String - "website", "wikipedia", "serpapi")

### Tabelle `signals` (Deprecated)
*   *Veraltet ab v0.7.0. Wird durch quantitative Metriken in `companies` ersetzt.*

### Tabelle `contacts` (Ansprechpartner)
*   `id` (PK)
*   `account_id` (FK -> companies.id)
*   `gender`, `title`, `first_name`, `last_name`, `email`
*   `job_title` (Visitenkarte)
*   `role` (Standardisierte Rolle: "Operativer Entscheider", etc.)
*   `status` (Marketing Status)

### Tabelle `industries` (Branchen-Fokus - Synced from Notion)
*   `id` (PK)
*   `notion_id` (String, Unique)
*   `name` (String - "Vertical" in Notion)
*   `description` (Text - "Definition" in Notion)
*   `metric_type` (String - "Metric Type")
*   `min_requirement` (Float - "Min. Requirement")
*   `whale_threshold` (Float - "Whale Threshold")
*   `proxy_factor` (Float - "Proxy Factor")
*   `scraper_search_term` (String - "Scraper Search Term")
*   `scraper_keywords` (Text - "Scraper Keywords")
*   `standardization_logic` (String - "Standardization Logic")

### Tabelle `job_role_mappings` (Rollen-Logik)
*   `id` (PK)
*   `pattern` (String - Regex für Jobtitles)
*   `role` (String - Zielrolle)

## 5. Phasenplan Umsetzung

1.  **Housekeeping:** Archivierung des Legacy-Codes (`_legacy_gsheets_system`).
2.  **Setup:** Init `company-explorer` (Backend + Frontend Skeleton).
3.  **Foundation:** DB-Schema + "List Matcher" (Deduplizierung ist Prio A für Operations).
4.  **Enrichment:** Implementierung des Scrapers + Signal Detector (Robotics).
5.  **UI:** React Interface für die Daten.
6.  **CRM-Features:** Contacts Management & Marketing Automation Status.

## 6. Spezifikation: Contacts & Marketing Status (v0.5.0)

**Konzept:**
Contacts stehen in 1:n Beziehung zu Accounts. Accounts können einen "Primary Contact" haben.

**Rollen (Funktion im Verkaufsprozess):**
*   Operativer Entscheider
*   Infrastruktur-Verantwortlicher
*   Wirtschaftlicher Entscheider
*   Innovations-Treiber

**Status (Marketing Automation):**
*   *Manuell:* Soft Denied, Bounced, Redirect, Interested, Hard denied.
*   *Automatisch:* Init, 1st Step, 2nd Step, Not replied, Unsubscribed.

### 6.1 Feature: Unsubscribe-Funktionalität (v2.1 - Feb 2026)

**Konzept:**
Um DSGVO-konforme Marketing-Automatisierung zu ermöglichen, wurde eine sichere Unsubscribe-Funktion implementiert.

**Technische Umsetzung:**
1.  **Token:** Jeder Kontakt in der `contacts`-Tabelle erhält ein einzigartiges, nicht erratbares `unsubscribe_token` (UUID).
2.  **Link-Generierung:** Der Company Explorer generiert einen vollständigen, personalisierten Link (z.B. `https://<APP_BASE_URL>/unsubscribe/<token>`).
3.  **API-Endpunkt:** Ein öffentlicher GET-Endpunkt `/unsubscribe/{token}` nimmt Abmeldungen ohne Authentifizierung entgegen.
4.  **Logik:**
    *   Bei Aufruf des Links wird der Status des zugehörigen Kontakts auf `"unsubscribed"` gesetzt.
    *   Der Benutzer erhält eine simple HTML-Bestätigungsseite.
5.  **CRM-Integration:** Der generierte Link wird über die Provisioning-API an den `connector-superoffice` zurückgegeben, der ihn in ein entsprechendes UDF in SuperOffice schreibt.

## 7. Historie & Fixes (Jan 2026)

    *   **[MAJOR] v0.9.0: Role Matching Optimization & Portability (March 2026)**
        *   **Pattern Optimizer:** Asynchrones Hintergrund-System zur automatischen Konsolidierung von Einzel-Matches in mächtige Regex-Regeln via Gemini. Inklusive Konfliktprüfung gegen andere Rollen. Nutzt `ast.literal_eval` für robustes Regex-Parsing.
        *   **Database Management:** Direkter Up- & Download der SQLite-Datenbank aus dem UI heraus. Automatisches Backup-System bei Upload.
        *   **Regex Sandbox:** Integriertes Test-Tool für Muster vor der Speicherung in der Datenbank.
        *   **Smart Suggestions:** Live-Analyse der Kontaktdaten zur Identifikation häufiger Schlüsselwörter pro Rolle als Klick-Vorschläge.
    *   **[CRITICAL] v0.7.4: Service Restoration & Logic Fix (Jan 24, 2026)**
    *   **[STABILITY] v0.7.3: Hardening Metric Parser & Regression Testing (Jan 23, 2026)**
    *   **[STABILITY] v0.7.2: Robust Metric Parsing (Jan 23, 2026)**
    *   **[STABILITY] v0.7.1: AI Robustness & UI Fixes (Jan 21, 2026)**
    *   **[MAJOR] v0.7.0: Quantitative Potential Analysis (Jan 20, 2026)**
    *   **[UPGRADE] v0.6.x: Notion Integration & UI Improvements**

## 8. Eingesetzte Prompts (Account-Analyse v0.7.4)

### 8.1 Strict Industry Classification

Ordnet das Unternehmen einer definierten Branche zu.

```python
prompt = f"""
Act as a strict B2B Industry Classifier.
Company: {company_name}
Context: {website_text[:3000]}

Available Industries:
{json.dumps(industry_definitions, indent=2)}

Task: Select the ONE industry that best matches the company.
If none match well, select 'Others'.
"""
```

### 8.2 Metric Extraction

Extrahiert den spezifischen Zahlenwert ("Scraper Search Term") und liefert JSON für den `MetricParser`.

```python
prompt = f"""
Extract the following metric for the company in industry '{industry_name}':
Target Metric: "{search_term}"

Source Text:
{text_content[:6000]}

Return a JSON object with 'raw_value', 'raw_unit', 'proof_text'.
"""
```

## 9. Notion Integration (Single Source of Truth)

Das System nutzt Notion als zentrales Steuerungselement für strategische Definitionen.

### 9.1 Datenfluss
1.  **Definition:** Branchen und Robotik-Kategorien werden in Notion gepflegt.
2.  **Synchronisation:** Das Skript `sync_notion_industries.py` zieht die Daten via API (Upsert).
3.  **App-Nutzung:** Der `ClassificationService` nutzt sie als "System-Anweisung" für das LLM.

## 10. Database Migration

Bei Schema-Änderungen: `docker exec -it company-explorer python3 backend/scripts/migrate_db.py`.

## 11. Lessons Learned (Retrospektive Jan 24, 2026)

1.  **FastAPI Routing:** Spezifische Endpunkte immer VOR dynamischen Endpunkten deklarieren.
2.  **Docker Persistence:** Datenbankdatei muss zwingend als Volume gemountet sein.
3.  **Formel-Robustheit:** Bereinigung von Einheiten/Kommentaren vor `eval()`.

## 12. Deployment & Access Notes

*   **Pfad auf NAS:** `/volume1/homes/Floke/python/brancheneinstufung/company-explorer`
*   **Sync:** `docker exec -it company-explorer python backend/scripts/sync_notion_to_ce_enhanced.py`

## 13. Feature: Report Mistakes

Benutzer können Fehler im Inspector melden. Diese werden in `reported_mistakes` gespeichert und in den Settings zur Prüfung angezeigt.

## 14. Upgrade v2.0 (Feb 18, 2026): "Lead-Fabrik" Erweiterung

Dieses Upgrade transformiert den Company Explorer in das zentrale Gehirn der Lead-Generierung (Vorratskammer).

### 14.1 Detaillierte Logik der neuen Datenfelder

*   **`confidence_score` (FLOAT):** Indikator für die Sicherheit der KI-Klassifizierung. `> 0.8` = Grün.
*   **`data_mismatch_score` (FLOAT):** Abweichung zwischen CRM-Bestand und Web-Recherche (z.B. Umzug).
*   **`crm_name`, `crm_address`, `crm_website`, `crm_vat`:** Read-Only Snapshot aus SuperOffice zum Vergleich.
*   **Status-Flags:** `website_scrape_status` und `wiki_search_status`.

#### Tabelle `industries` (Strategie-Parameter)

*   **`pains` / `gains`:** Strukturierte Textblöcke (getrennt durch `[Primary Product]` und `[Secondary Product]`).
*   **`ops_focus_secondary` (BOOLEAN):** Steuerung für rollenspezifische Produkt-Priorisierung.

---

## 15. Offene Arbeitspakete (Bauleitung)

### Task 1: UI-Anpassung - Side-by-Side CRM View & Settings
(In Arbeit / Teilweise erledigt durch Gemini CLI)

### Task 2: Intelligenter CRM-Importer (Bestandsdaten)

**Ziel:** Importieren der `demo_100.xlsx` in die SQLite-Datenbank.
1.  **PLZ-Handling:** Zwingend als **String** einlesen.
2.  **Matching:** Kaskade über CRM-ID, VAT, Domain, Fuzzy Name.

---

## 16. Deployment-Referenz (NAS)
*   **Pfad:** `/volume1/homes/Floke/python/brancheneinstufung/company-explorer`
*   **DB:** `/app/companies_v3_fixed_2.db`

---

## 17. Analyse-Logik v3.0 (Feb 2026): Quantitative Potenzialanalyse & "Atomic Opener"

### 17.1 Das Gesamtbild: Vom Content zur fertigen Analyse

1. Branchen-Klassifizierung -> 2. Quantitative Potenzialanalyse -> 3. "Atomic Opener" Generierung -> 4. Finales Commit.

### 17.2 Quantitative Potenzialanalyse im Detail

**Ziel:** Für jedes Unternehmen einen `standardized_metric_value` in `m²` zu ermitteln.
*   **Stufe 1:** Direkte Flächensuche ("Fläche", "m²").
*   **Stufe 2:** Proxy-Metrik-Suche (z.B. Betten * 100).

### 17.3 "Atomic Opener" Generierung im Detail (Zweistufiger Prozess, Feb 22, 2026)

**Ziel:** Zwei hoch-personalisierte, schlagkräftige Einleitungssätze (2-3 Sätze).
*   **Schritt 1:** Das Website-Dossier (Extraktion & Komprimierung).
*   **Schritt 2:** Formulierung des Openers (Scharfsinnige Beobachtung).

### 17.7 Marketing Matrix Schärfung (v3.2 - Feb 22, 2026)

Die Qualität der Marketing-Matrix (Subject, Intro, Social Proof) ist entscheidend für den Erfolg des Outreachs.

**Kern-Konzept: Der Strategische Brückenschlag**
Die KI agiert nicht mehr als reiner Copywriter, sondern als **scharfsinniger B2B-Strategieberater** ("Lösungsberater"). 

**Neues Feature: "Ops Focus: Secondary" (Die Rollen-Weiche)**
Wenn in Notion das Flag `Ops Focus: Secondary` aktiv ist, wechselt die Engine für die Persona **"Operativer Entscheider"** automatisch auf das **Sekundärprodukt** (z.B. Service-Roboter/Transport).

**Der "Lösungsberater" Prompt (Auszug):**
```python
prompt = f"""
Du bist ein kompetenter Lösungsberater und brillanter Texter.
AUFGABE: Erstelle 3 Textblöcke (Subject, Introduction_Textonly, Industry_References_Textonly) für eine E-Mail an einen Entscheider.

--- KONTEXT ---
ZIELBRANCHE: {industry.name}
BRANCHEN-HERAUSFORDERUNGEN (PAIN POINTS): {industry_pains}
FOKUS-PRODUKT (LÖSUNG): {target_scope} ({product_context})
ANSPRECHPARTNER (ROLLE): {persona.name}
PERSÖNLICHE HERAUSFORDERUNGEN: {persona_pains}
"""
```

### 17.8 Erweiterte Matrix-Multiplikation: Primary vs. Secondary (Update Feb 24, 2026)

**Konzept:** Strikte Trennung zwischen `[Primary Product]` und `[Secondary Product]` zur Vermeidung logischer Brüche.

### 17.9 Deep Persona Injection (Update Feb 24, 2026)

**Ziel:** Maximale Relevanz durch Einbezug psychografischer und operativer Rollen-Details ("Voll ins Zentrum").

**Die Erweiterung:**
- **Vollständiger Daten-Sync:** Übernahme von `Beschreibung/Denkweise`, `Was ihn überzeugt` und `KPIs` aus der Notion "Personas / Roles" Datenbank in das lokale Schema.
- **Rollenspezifische Tonalität:** Die KI nutzt diese Details, um den "Ton" der jeweiligen Persona perfekt zu treffen (z.B. technischer Fokus beim Infrastruktur-Leiter vs. betriebswirtschaftlicher Fokus beim CFO).

**Beispiel-Kaskade (Klinikum Erding):**
1. **Opener:** "Klinikum Erding trägt maßgeblich zur regionalen Versorgung bei... Dokumentation lückenloser Hygiene stellt eine operative Herausforderung dar."
2. **Matrix-Anschluss (Infrastruktur):** "...minimieren Ausfallzeiten um 80-90% durch proaktives Monitoring... planbare Wartung und Transparenz durch feste **SLAs**." (Direkter Bezug auf hinterlegte Überzeugungsargumente).
3. **Matrix-Anschluss (Wirtschaftlich):** "...Reduktion operativer Personalkosten um 10-25%... wirkt sich direkt auf **ROI** und **Amortisationszeit** aus." (Direkter Bezug auf hinterlegte KPIs).

### 17.10 Production Switch & Multi-Campaign Architecture (Feb 27, 2026)

Das System wurde erfolgreich von der Sandbox auf die SuperOffice-Produktionsumgebung migriert. Alle technischen Hürden (Auth, ProgIDs, REST-Besonderheiten) wurden beseitigt.

#### A. Umgebungsparameter (Production)
*   **Base URL (OAuth):** `https://online.superoffice.com/login/common/oauth/tokens`
*   **Base URL (API):** `https://online3.superoffice.com/Cust26720/api/v1/`
*   **Tenant ID:** `Cust26720`
*   **Client ID:** `0fd8272803551846f7212a961a1a0046`

#### B. Finales UDF Mapping (ProgIDs)
Verifizierte IDs für den Mandanten `Cust26720`:

| Zweck | Entität | ProgID | Format / Logik |
| :--- | :--- | :--- | :--- |
| **MA Subject** | Person | `SuperOffice:19` | Text |
| **MA Intro** | Person | `SuperOffice:20` | Text |
| **MA Social Proof** | Person | `SuperOffice:21` | Text |
| **MA Unsubscribe** | Person | `SuperOffice:22` | URL (DSGVO konform) |
| **MA Campaign** | Person | `SuperOffice:23` | Liste (Auflösung via `:DisplayText`) |
| **Vertical** | Contact | `SuperOffice:83` | Liste (Mapping siehe unten) |
| **AI Summary** | Contact | `SuperOffice:84` | Truncated (< 135 Zeichen) |
| **AI Last Update** | Contact | `SuperOffice:85` | Datum: `[D:MM/DD/YYYY HH:MM:SS]` |
| **Opener Primary** | Contact | `SuperOffice:86` | Text (Infrastruktur/Cleaning) |
| **Opener Secondary**| Contact | `SuperOffice:87` | Text (Service/Logistik) |
| **Last Outreach** | Contact | `SuperOffice:88` | Datum |

#### C. Vollständige Vertical-Liste (Produktiv-IDs)
Die Liste `udlist331` steuert die Branchenzuordnung. Der Connector nutzt folgendes Mapping:
`Automotive - Dealer: 1613, Corporate - Campus: 1614, Energy - Grid & Utilities: 1615, Energy - Solar/Wind: 1616, Healthcare - Care Home: 1617, Healthcare - Hospital: 1618, Hospitality - Gastronomy: 1619, Hospitality - Hotel: 1620, Industry - Manufacturing: 1621, Infrastructure - Communities: 1622, Infrastructure - Public: 1623, Infrastructure - Transport: 1624, Infrastructure - Parking: 1625, Leisure - Entertainment: 1626, Leisure - Fitness: 1627, Leisure - Indoor Active: 1628, Leisure - Outdoor Park: 1629, Leisure - Wet & Spa: 1630, Logistics - Warehouse: 1631, Others: 1632, Reinigungsdienstleister: 1633, Retail - Food: 1634, Retail - Non-Food: 1635, Retail - Shopping Center: 1636, Tech - Data Center: 1637`.

#### D. Technische Meilensteine (Lessons Learned)

1.  **Atomic PATCH Workflow:** Um API-Timeouts und Inkonsistenzen zu vermeiden, bündelt der `worker.py` (v1.8) alle Änderungen an einem Kontakt in einem einzigen `PATCH`-Request an `/Contact/{id}`.
2.  **Website-Sync (REST-Korrektur):** Die Aktualisierung der Website erfolgt über das `Urls`-Array (nicht `UrlAddress`). Format: `"Urls": [{"Value": "...", "Description": "AI Discovered"}]`.
3.  **Listen-Auflösung (Optimierung):** Kampagnen-Namen werden ohne zusätzliche API-Calls über das Pseudo-Feld `ProgID:DisplayText` (z.B. `SuperOffice:23:DisplayText`) direkt im Payload des Personen-Abrufs gelesen.
4.  **Längenbegrenzung:** Da viele UDFs in SuperOffice standardmäßig auf 254 Zeichen begrenzt sind, wird das AI-Dossier (Summary) hart auf 132 Zeichen (+ "...") gekürzt, um 400er Fehler beim Update zu vermeiden.
5.  **Docker Orchestrierung:** Der Wechsel auf `env_file: .env` in der `docker-compose.yml` stellt sicher, dass alle Services (CE + Connector) konsistent auf dieselben Mappings zugreifen.

#### E. Kampagnen-Steuerung (Multi-Template)
Der Company Explorer unterstützt nun den Parameter `campaign_tag`. Der Connector sendet den Namen des gewählten Listeneintrags (z.B. "First Contact") an den CE. Dieser liefert spezifische Texte aus der `MarketingMatrix`, sofern vorhanden (Fallback: "standard").

---

## 19. External Lead Ingestion & Contact API (v3.5 - March 2, 2026)

**Kontext:** Automatisierte Verarbeitung von externen Lead-Quellen (Tradingtwins) direkt in den Company Explorer.

### 19.1 API-Erweiterung: Externer Kontakt-Sync
Um Kontakte von externen Tools (wie der Lead-Engine) ohne SuperOffice-Kontext zu übernehmen, wurde die API erweitert.

*   **Neuer Endpunkt:** `POST /api/contacts`
*   **Funktionalität:** 
    *   Anlage von Personen-Stammdaten (Vorname, Nachname, E-Mail).
    *   **Automatisches Role-Mapping:** Der Endpunkt integriert den `RoleMappingService`. Eingehende Job-Titel (z.B. "CFO") werden automatisch gegen die interne Muster-Datenbank geprüft und der passenden Persona (z.B. "Wirtschaftlicher Entscheider") zugeordnet.
    *   **De-Duplizierung:** Existiert eine E-Mail bereits für ein Unternehmen, wird der Datensatz aktualisiert statt neu angelegt.

### 19.2 Standardisierung der Datenfelder
Zur Verbesserung der asynchronen Zusammenarbeit zwischen Lead-Engine und CE wurden die Feldnamen in der API-Antwort vereinheitlicht:
*   **Branche:** `industry_ai` (Primärfeld für die KI-Klassifizierung).
*   **Analyse:** `research_dossier` (Das vollständige KI-generierte Firmendossier).

### 19.3 Synchronisations-Workflow (Connector)
Der `company_explorer_connector.py` unterstützt nun den erweiterten Workflow:
1. `check_company_existence` (Suche via Name)
2. `create_company` (Anlage falls neu)
3. `create_contact` (Integration der Person inkl. Role-Mapping)
4. `trigger_discovery` / `trigger_analysis` (Asynchroner Start der Intelligence-Phase)

---

## 💎 Critical Lessons Learned & Bugfixes (Parser & AI)

Diese Erkenntnisse stammen aus der harten Debugging-Phase (Jan/Feb 2026) und sind essenziell für die Stabilität des Metric Parsers.

1.  **Numeric Extraction (German Locale):**
    *   **Problem:** "1.005 Mitarbeiter" wurde als "1" extrahiert (Punkt als Dezimaltrenner).
    *   **Lösung:** Kontext-Logik. Punkt gefolgt von exakt 3 Ziffern (ohne Komma) = Tausendertrennzeichen.
    *   **Revenue:** Bei Umsatz (`is_revenue=True`) werden Punkte meist als Dezimalzeichen gewertet (z.B. "375.6 Mio"), außer es ist eindeutig.

2.  **The Wolfra/Greilmeier/Erding Fixes (Advanced Metric Parsing):**
    *   **Problem:** Einfache Regex scheitert an komplexen Sätzen mit Jahreszahlen oder Präfixen.
    *   **Solution (Hybrid Extraction & Regression Testing):** 
        1. **LLM Guidance:** LLM liefert `expected_value` (z.B. "8.000 m²").
        2. **Robust Python Parser (`MetricParser`):** Reinigt `expected_value` und sucht intelligent im Text.
        3. **Specific Bug Fixes:**
            - **Year-Suffix:** Entfernt angehängte Jahreszahlen (z.B. "802020" -> "80").
            - **Year-Prefix:** Ignoriert Jahreszahlen (1900-2100) als Metrik-Kandidaten.
            - **Sentence Truncation:** Logik entfernt, die Sätze zu früh abschnitt.
    *   **Safeguard:** Diese Fälle sind nun in `test_metric_parser.py` als Regressionstests fixiert.

3.  **LLM JSON Stability:**
    *   **Problem:** Markdown-Blöcke (` ```json `) zerstören `json.loads()`.
    *   **Solution:** Immer `clean_json_response` Helper nutzen.

## 🧪 Test-Übersicht & Qualitätssicherung

Die Stabilität des Company Explorers wird durch folgende Tests abgesichert:

### Company Explorer Backend Tests
Pfad: `company-explorer/backend/tests/`

*   **`test_metric_parser.py`**: **Kritische Regressions-Tests** für die numerische Extraktion (deutsche Lokalisierung). Prüft komplexe Fälle wie:
    *   Tausender-Trennzeichen vs. Dezimalpunkte.
    *   Verkettete Zahlen und Jahre (z.B. "802020").
    *   Ignorieren von Jahreszahlen als Kennzahlen.
*   **`test_classification_service.py`**: Validiert die KI-basierte Einstufung von Unternehmen in Branchen-Verticals und die Bewertung des Automatisierungspotenzials.
*   **`test_opener_logic.py`**: Prüft die Generierung der personalisierten Einleitungssätze (Openers) basierend auf Website-Scrapes und Branchen-Pains.

### Connector Integration Tests
Pfad: `connector-superoffice/tests/`

*   **`test_e2e_flow.py`**: Der umfassendste Integrationstest. Er simuliert den gesamten Datenzyklus (Webhook -> CE -> SuperOffice).