# Migration Report: Competitor Analysis Agent

## Status: Jan 11, 2026 - ✅ ROBUSTNESS UPGRADE COMPLETE

Die App ist unter `/ca/` voll funktionsfähig und verfügt nun über eine "Grounded Truth" Engine (Scraping + SerpAPI) sowie eine skalierbare **Map-Reduce Architektur**.

### 🚨 Vollständige Chronik der Fehler & Lösungen

1.  **Problem: 404 auf `/ca/`**
    *   **Ursache:** Der Container startete aufgrund von Syntaxfehlern nicht, was Nginx mit einem 404 (später 502) quittierte.

2.  **Problem: `SyntaxError: unterminated string literal` (Runde 1)**
    *   **Ursache:** Verwendung von `f"""..."""` für komplexe Prompts.
    *   **Lösung:** Umstellung auf `.format()`. **Wichtig:** Docker-Volumes synchronisierten nicht zuverlässig, was zu "Phantom-Fehlern" führte. Ein `build --no-cache` war nötig.

3.  **Problem: `ImportError: cannot import name 'Schema'`**
    *   **Ursache:** Uralte SDK-Version `google-generativeai==0.3.0` in `requirements.txt`.
    *   **Lösung:** Umstellung auf Dictionaries, später komplettes SDK-Upgrade.

4.  **Problem: `404 models/gemini-1.5-pro ... for API version v1beta`**
    *   **Ursache:** Das alte SDK nutzte veraltete Endpunkte.
    *   **Lösung:** Migration auf das moderne **`google-genai`** Paket (v1.x) und Nutzung des neuen `genai.Client`.

5.  **Problem: `TypeError: unexpected keyword argument 'client_options'`**
    *   **Analyse:** Obwohl das SDK in `requirements.txt` aktualisiert wurde, installierte Docker auf der Diskstation hartnäckig eine alte Version.
    *   **Lösung:** Erzwingen der Version `google-genai>=1.2.0`.

6.  **Problem: Das "Grounding Upgrade" & Die Syntax-Hölle (Runde 2)**
    *   **Aufgabe:** Einbau von echtem Web-Scraping und SerpAPI zur Qualitätssteigerung.
    *   **Fehler:** `SyntaxError: f-string: expecting '}'` in komplexen Listen-Generatoren (z.B. `c_sum`).
    *   **Ursache:** Python 3.11 erlaubt keine geschachtelten Anführungszeichen in F-Strings, wenn diese Backslashes oder komplexe Ausdrücke enthalten.
    *   **Lösung:** **RADIKALER VERZICHT auf F-Strings** in allen kritischen Logik-Bereichen. Umstellung auf einfache Schleifen und `.format()`.

7.  **Problem: `unterminated string literal (detected at line 203)`**
    *   **Ursache:** Einfache Anführungszeichen `'` in Kombination mit `\n` wurden im Container-Kontext falsch interpretiert.
    *   **Lösung:** **ULTIMATIVE SYNTAX:** Verwendung von **Triple Raw Quotes (`r"""..."""`)** für jeden einzelnen String, der Variablen oder Sonderzeichen enthält.

8.  **Problem: Analyse stoppt nach 5 Konkurrenten (Token Limit / Lazy LLM)**
    *   **Symptom:** Bei 9 Konkurrenten wurden nur die ersten 5 analysiert, der Rest fehlte.
    *   **Ursache:** Der riesige Prompt ("Analysiere alle 9...") überforderte das Kontext-Fenster oder führte zu Timeouts.
    *   **Lösung:** Umstellung auf **Map-Reduce**: Jeder Konkurrent wird in einem eigenen parallelen Task (`asyncio.gather`) analysiert. Erhöhung von `max_output_tokens` auf 8192.

9.  **Problem: `NameResolutionError` im Container**
    *   **Symptom:** Scraping schlug fehl ("Name or service not known").
    *   **Ursache:** Docker-Container nutzten den (instabilen) Host-DNS.
    *   **Lösung:** Explizites Setzen von Google DNS (`8.8.8.8`, `8.8.4.4`) in `docker-compose.yml`.

10. **Problem: `422 Unprocessable Entity` in Schritt 6 & 8**
    *   **Ursache:** Diskrepanz zwischen Frontend-Request (z.B. sendet `industries`) und Backend-Pydantic-Modell (erwartet `target_industries`).
    *   **Lösung:** Backend-Modelle exakt an die Frontend-Payloads angepasst.

11. **Problem: Leere Matrizen in der Conclusion**
    *   **Ursache:** Das LLM füllte das `availability`-Array nicht korrekt oder erfand eigene Produktnamen als Zeilenbeschriftung.
    *   **Lösung:** Extrem strikter Prompt ("KEINE Produktnamen", "GENAU einen Eintrag pro Kategorie") und detailliertes JSON-Schema.

12. **Problem: Blinde KI in Schritt 8 (Referenzen)**
    *   **Symptom:** Die Referenzanalyse lieferte nur generische, oft erfundene Branchen, anstatt echter Kunden.
    *   **Ursache:** Der Prompt bat die KI, "nach Referenzen zu suchen", ohne ihr eine Datengrundlage zu geben. Die KI hat halluziniert.
    *   **Lösung:** Implementierung einer **"Grounded" Referenz-Suche**.
    *   **Ergebnis:** Die Analyse basiert nun auf Fakten von der Webseite des Wettbewerbers.

13. **Problem: Informations-Overload (Text-Wüste)**
    *   **Symptom:** In Notion landeten hunderte Produkte und Landmines, aber man konnte nicht effektiv filtern (z.B. "Zeige alle Reinigungsroboter").
    *   **Lösung:** Einführung von **Semantic Clustering & Taxonomies**.
        *   Das Backend ordnet nun jedem Produkt eine feste Kategorie zu (z.B. *Cleaning*, *Logistics*).
        *   Jede Landmine erhält ein Themen-Tag (z.B. *Price*, *Support*, *Technology*).
    *   **Ergebnis:** Das Competitive Radar ist nun ein echtes BI-Tool. In Notion können nun "Board Views" nach Kategorien erstellt werden (Level 4 Relational Model).

### 🛡️ Die finale "Grounded" Architektur
... (Scraping/Map-Reduce etc. bleiben gleich) ...

### 📊 Relationaler Notion Import (Competitive Radar v3.0 - Level 4)
Um die Analyse-Ergebnisse optimal nutzbar zu machen, wurde ein intelligenter Import-Prozess nach Notion implementiert (`import_competitive_radar.py`).

*   **Architektur:** Vier vernetzte Datenbanken mit **semantischer Klassifizierung**:
    1.  **📦 Companies (Hub):** Stammdaten und strategische Zusammenfassung.
    2.  **💣 Landmines (Satellite):** Angriffsfragen, automatisch getaggt nach Themen:
        - *Price/TCO, Service/Support, Technology/AI, Performance, Trust/Reliability*.
    3.  **🏆 References (Satellite):** Echte Kundenprojekte (Grounded Truth).
    4.  **🤖 Products (Satellite):** Einzelne Produkte, klassifiziert nach Typ:
        - *Cleaning (Indoor/Outdoor), Transport/Logistics, Service/Gastro, Security, Software*.
*   **Dual-Way Relations:** Alle Datenbanken sind bidirektional verknüpft. Auf einer Produktkarte sieht man sofort den Hersteller; auf einer Herstellerkarte sieht man das gesamte (kategorisierte) Portfolio.

### 🚀 Next-Gen Analyse-Strategie (v5) - Beschluss vom 12. Jan. 2026

Die Analyse der v4-Ergebnisse zeigte fundamentale Schwächen im monolithischen Analyse-Ansatz. Probleme wie die falsche Gruppierung von Produktlisten (z.B. "A, B, C" als ein Produkt) und die fehlende Differenzierung desselben Produkts über verschiedene Anbieter hinweg (z.B. "BellaBot" vs. "Pudu Bella Bot") machten eine strategische Neuausrichtung notwendig.

Der neue Prozess basiert auf einer **"Extract-Normalize-Enrich" Pipeline in drei Phasen:**

**Phase 1: Datensammlung (pro Wettbewerber)**
1.  **Gezieltes Scraping:** Fokussierte Suche nach Seiten mit Keywords wie "Produkte", "Portfolio", "Lösungen". Der Rohtext dieser Seiten wird extrahiert.
2.  **Rohe Produkt-Extraktion (1. LLM-Call):** Ein einfacher, isolierter Prompt extrahiert nur eine unstrukturierte Liste potenzieller Produktnamen.
3.  **Deterministische Säuberung (Python):** Die rohe Liste wird per Code aufbereitet (Trennung bei Kommas, "und", etc.), um einzelne Produkte zu isolieren.
4.  **Allgemeine Analyse (2. LLM-Call):** Ein paralleler Prompt analysiert den Rohtext auf allgemeine, nicht-produktbezogene Merkmale (`delivery_model`, `target_industries`, `differentiators`).

**Phase 2: Marktweite Produkt-Kanonisierung (Global & Einmalig)**
5.  **Master-Liste erstellen:** Die bereinigten Produktlisten aller Wettbewerber werden zu einer globalen Master-Liste zusammengefasst.
6.  **Grounded Truth (Hersteller-Daten):** Eine vordefinierte, kanonische Produktliste der wichtigsten Hersteller (Pudu, Gausium etc.) wird als Referenz geladen.
7.  **Kanonisierungs-Prompt (3. LLM-Call):** Ein einziger, globaler Call gleicht die Master-Liste mit der "Grounded Truth" der Hersteller ab. Er gruppiert alle Namensvarianten ("Bella Bot", "Pudu BellaBot") unter einem kanonischen Namen ("BellaBot").

**Phase 3: Gezielte Anreicherung & Assemblierung (pro Wettbewerber)**
8.  **Portfolio zusammenstellen:** Das System iteriert durch die kanonische Produkt-Map aus Phase 2.
9.  **Anreicherungs-Prompt (Serie von Micro-LLM-Calls):** Für jedes kanonische Produkt, das ein Wettbewerber anbietet, wird ein kleiner, gezielter Prompt abgesetzt, um spezifische Details (`purpose`, `category`) aus dem ursprünglichen Rohtext zu extrahieren.
10. **Finale Assemblierung:** Die Ergebnisse der allgemeinen Analyse (Schritt 4) und des angereicherten Portfolios (Schritt 9) werden zum finalen, sauberen und normalisierten JSON-Objekt für den Wettbewerber zusammengefügt.

Dieser Ansatz trennt klar zwischen Datensammlung, marktweiter Normalisierung und spezifischer Anreicherung, was zu deutlich präziseren, konsistenteren und wertvolleren Analyse-Ergebnissen führt.

### ✅ Status: Jan 12, 2026 - v5 STABLE & PRODUCTION READY

Die Implementierung der v5-Pipeline ist abgeschlossen. Die initialen Kinderkrankheiten (SDK-Konflikte, Token-Limits bei Matrizen) wurden durch radikale Architektur-Entscheidungen behoben.

**Die 3 Säulen der finalen Lösung:**

1.  **Hybrid Intelligence (The "Matrix Fix"):**
    *   **Problem:** LLMs scheiterten daran, große Matrizen (Produkte x Wettbewerber) konsistent als JSON zu generieren (Abbruch wegen Token-Limit).
    *   **Lösung:** **Python übernimmt die Struktur, KI den Inhalt.** Die Matrizen (`product_matrix`, `industry_matrix`) werden nun **deterministisch im Python-Code berechnet**, basierend auf den in Phase 3 gesammelten Daten. Die KI wird nur noch für die *textliche* Zusammenfassung (`summary`, `opportunities`) gerufen. Das Ergebnis ist 100% fehlerfrei und stabil.

2.  **User-In-The-Loop (Data Rescue):**
    *   **Feature:** In Schritt 4 wurde ein "Repair"-Modus implementiert. Nutzer können nun für jeden Wettbewerber **manuelle Produkt-URLs** nachreichen und eine **isolierte Neu-Analyse** (Re-Scrape & Re-Enrich) für diesen einen Wettbewerber auslösen, ohne den gesamten Prozess neu zu starten. Dies löst das Problem von "versteckten" Produktseiten (z.B. Giobotics).

3.  **Quality Boost (CoT):**
    *   **Feature:** Der Enrichment-Prompt (Phase 3) nutzt nun **Chain-of-Thought (CoT)**. Anstatt stumpf Daten zu extrahieren, wird die KI angewiesen: *"Suche alle Erwähnungen -> Synthetisiere eine Beschreibung -> Bestimme die Kategorie"*. Dies hat die inhaltliche Qualität der Produktbeschreibungen wieder auf das hohe Niveau von v2 gehoben, bei gleichzeitiger Beibehaltung der sauberen Struktur von v3.

**Fazit:** Der Competitor Analysis Agent ist nun ein robustes, professionelles BI-Tool, das bereit für den produktiven Einsatz und den Import nach Notion ist.

### 🏆 Final Validation (Jan 12, 2026 - 14:00)

Der Validierungslauf mit `analysis_robo-planet.de-4.json` bestätigt den Erfolg aller Maßnahmen:

*   **Lückenlose Erfassung:** Dank des "Repair Mode" (Manuelle URLs) konnte das Portfolio von *Giobotics*, das zuvor leer war, vollständig mit 9 Produkten (PuduBot 2, KettyBot, etc.) erfasst werden.
*   **Hohe Datentiefe:** Die Produktbeschreibungen sind dank **Chain-of-Thought** detailliert und wertstiftend (z.B. genaue Funktionsweise des *Phantas* Roboters bei TCO Robotics), statt nur generische Einzeiler zu sein.
*   **Perfekte Matrizen:** Die Python-generierten Matrizen sind vollständig und fehlerfrei. Das Token-Limit-Problem gehört der Vergangenheit an.
*   **Stabilität:** Der gesamte Prozess lief ohne Abstürze oder API-Fehler durch.

**Status:** ✅ **MIGRATION COMPLETE & VERIFIED.**

### 📡 Zukunftsfähigkeit & Ausblick: Das Competitor Radar

Neben der reinen Analyse wurde das Fundament für ein dauerhaftes Monitoring-System ("Competitor Radar") gelegt:

1.  **Persistence (State Loading):**
    *   **Feature:** Auf der Startseite wurde eine **Lade-Funktion** implementiert. Nutzer können nun eine zuvor exportierte `.json`-Datei hochladen, um den exakten Stand einer Analyse wiederherzustellen. Dies ermöglicht das Fortsetzen oder Aktualisieren von Berichten ohne Datenverlust.
2.  **Vision: Aktives Monitoring:**
    *   In der nächsten Ausbaustufe wird das System von einer statischen On-Demand-Analyse zu einem dynamischen Radar transformiert. Ziel ist die automatisierte Überwachung der Wettbewerber auf:
        *   **Neue Produkt-Releases:** Automatischer Abgleich mit der "Grounded Truth".
        *   **Neuigkeiten & PR:** Scanning von News-Sektionen auf strategische Schwenks.
        *   **Messen & Events:** Identifikation von Marktpräsenz und Networking-Aktivitäten.
3.  **Relationaler Import (v6):**
    *   Der Notion-Import wurde auf **v6** aktualisiert. Er unterstützt nun lückenlos die neue v5-Struktur, importiert Chain-of-Thought Beschreibungen in Rich-Text-Felder und verknüpft erstmals auch die extrahierten **Referenzkunden** relational in Notion.


### 📡 Post-Migration Architectural Refactoring (Jan 22, 2026): From Unified Import to GTM-Ready Architecture

**Problem Statement:** The v6 import structure, while relational, suffered from a fundamental design flaw: the informational depth of a product entry was identical for all vendors. A product sold by RoboPlanet was captured with the same superficial data fields as a competitor's product. This prevented the mapping of our detailed Go-to-Market strategies and, due to the "Purpose" texts generated by the LLM, continued to create duplicates, as identical products received slightly different descriptions.

**Strategic Decision: Separation of "What" from "How"**

To create a true "Single Source of Truth" and to enrich our own products with the necessary depth (GTM strategy, support knowledge, etc.), a new architecture was decided upon. The system is being converted from a 2-tier model (Companies ↔ Products) to a 3-tier model.

**The New 3-Tier Architecture:**

1.  **🆕 Canonical Products (The "WHAT" Database):**
    *   A completely new database that contains each product model (e.g., "Puma M20") **only once**.
    *   Content: Objective master data (manufacturer, model, technical specs) and a relation to the `Product Categories` DB.
    *   This is the market-wide, vendor-neutral truth.

2.  ** repurposed Portfolio (The "HOW" Database):**
    *   The existing `Competitive Radar (Products)` database is being repurposed and renamed.
    *   It functions as a **junction table**. Each entry represents the relationship between a vendor and a canonical product.
    *   Example Entries:
        *   "RoboPlanet sells Puma M20"
        *   "TCO Robotics sells Puma M20"
    *   **Crucially:** This database contains the **context-specific information**. For RoboPlanet entries, the fields for the complete GTM strategy (target industries, pain points, battle cards, ROI logic, etc.) will be stored here. For competitor entries, these fields will remain empty.

3.  ** Companies (The "WHO" Database):**
    *   Remains unchanged and contains the master data of the competitors and of RoboPlanet itself.

**New Relational Link:**
`[Canonical Products]` ↔️ `[Portfolio]` ↔️ `[Companies]`

**Migration Plan:**
A one-time Python script will perform the "Operation Clean Architecture":
1.  **Schema Transformation:** Creation of the `Canonical Products` DB, conversion of the old product DB to the `Portfolio` DB.
2.  **Intelligent Migration:** Reading of the old entries, creation of the unique entries in `Canonical Products`, and subsequent re-linking of the (now) `Portfolio` entries.
3.  **Categorization:** Assignment of the canonical products to the global `Product Categories`.

**Result:** This refactoring elevates the system from a pure market intelligence tool to a true **Strategic Marketing OS** that can directly map and support our own sales and marketing processes.

---
*Dokumentation finalisiert am 12.01.2026.*

