# Migration Guide: Google AI Builder Apps -> Local Docker Stack > **WICHTIGER HINWEIS:** Der Gemini-Agent f"."hrt Code **innerhalb** dieses Docker-Containers aus. Er hat keinen Zugriff auf den Docker-Daemon des Host-Systems. Daher kann und wird der Agent **NIEMALS** in der Lage sein, Befehle wie `docker build`, `docker-compose up` oder andere Docker-Management-Aufgaben auszuf.hren. Diese Befehle m.ssen immer vom Benutzer auf dem Host-System ausgef.hrt werden. **Ziel:** Standardisierter Prozess, um eine von Google AI Studio generierte React-App schnell, robust und fehlerfrei in die lokale Docker/Python-Architektur zu integrieren. **Grundsatz:** "Minimalset & Robustheit". Wir bauen keine aufgebl.hten Container, und wir verhindern Timeouts und fehlende Abh.ngigkeiten proaktiv. --- ## 1. Vorbereitung & Abh.ngigkeiten (Common Pitfalls) Bevor Code kopiert wird, m.ssen die Grundlagen stimmen. ### 1.1 Package.json Check Generierte Apps haben oft kein `express`, da sie keinen Server erwarten. * **Aktion:** "."ffne `package.json` der App. * **Pr.fung:** Steht `express` unter `dependencies`? * **Fix:** ```json "dependencies": { ... "express": "^4.18.2", "cors": "^2.8.5" } ``` ### 1.2 Datenbank-Datei Docker kann keine einzelne Datei mounten, wenn sie auf dem Host nicht existiert. * **Fehler:** "Bind mount failed: ... does not exist" * **Fix:** VOR dem ersten Start die Datei anlegen: ```bash touch mein_neues_projekt.db ``` ### 1.3 Vite Base Path (White Screen Fix) Wenn die App unter einem Unterverzeichnis (z.B. `/gtm/`) l.uft, findet sie ihre JS/CSS-Dateien nicht, wenn Vite Standard-Pfade (`/`) nutzt. * **Datei:** `vite.config.ts` * **Fix:** `base` auf `./` setzen. ```typescript export default defineConfig({ base: './', // WICHTIG f.r Sub-Pfad Deployment // ... }); ``` ### 1.4 Python Dependencies & Shared Libraries (Critical Pitfall) Das Projekt nutzt ein zentrales `helpers.py`, das von mehreren Services geteilt wird. Dies f.hrt oft zu `ModuleNotFoundError`, da eine kleine App (wie `gtm-architect`) nicht alle Bibliotheken ben.tigt, die in `helpers.py` importiert werden (z.B. `gspread`, `pandas`). * **Fehler:** `ModuleNotFoundError: No module named 'gspread'` * **Ursache:** Die `gtm-architect/requirements.txt` enth.lt `gspread` nicht, aber `helpers.py` versucht es zu importieren. * **Fix (in `helpers.py`):** Machen Sie "exotische" Importe optional. Dies ist die robusteste Methode, um die Kompatibilit.t zu wahren, ohne die `requirements.txt` kleiner Apps aufzubl.hen. ```python # Beispiel in helpers.py try: import gspread GSPREAD_AVAILABLE = True except ImportError: GSPREAD_AVAILABLE = False gspread = None # Wichtig, damit Referenzen nicht fehlschlagen ``` * **Fix (in `requirements.txt`):** Stellen Sie sicher, dass die f.r die App **unmittelbar** ben.tigten Bibliotheken vorhanden sind. F.r `gtm-architect` sind das: ```text google-generativeai google-genai Pillow requests beautifulsoup4 ``` ### 1.5 Python Syntax & F-Strings Multi-Line Prompts k.nnen in Docker-Umgebungen zu **sehr hartn.ckigen Syntaxfehlern** f.hren, selbst wenn sie lokal korrekt aussehen. * **Das Problem:** Der Python-Parser (insbesondere bei `f-strings` in Kombination mit Zahlen/Punkten am Zeilenanfang oder verschachtelten Klammern) kann Multi-Line-Strings (`f"""..."""`) falsch interpretieren, was zu Fehlern wie `SyntaxError: invalid decimal literal` oder `unmatched ')'` f.hrt, auch wenn der Code scheinbar korrekt ist. * **ULTIMATIVE L.SUNG (Maximale Robustheit):** 1. **Vermeide `f"""` komplett f.r komplexe Multi-Line-Prompts.** Definiere stattdessen den Prompt als **Liste von einzelnen String-Zeilen** und f.ge sie mit `"\n".join(prompt_parts)` zusammen. 2. **Nutze die `.format()` Methode oder f-Strings in EINZEILIGEN Strings** zur Variablen-Injektion. Dies trennt die String-Definition komplett von der Variablen-Interpolation und ist die robusteste Methode. ```python # Beispiel: Maximal robust prompt_template_parts = [ "1) Mache dies: {variable_1}", "2) Mache das: {variable_2}", ] prompt_template = "\n".join(prompt_template_parts) prompt = prompt_template.format(variable_1=wert1, variable_2=wert2) # System-Instruktion muss immer noch vorangestellt werden: full_prompt = sys_instr + "\n\n" + prompt ``` * **Versionierung f.r Debugging:** Um sicherzustellen, dass die korrekte Version des Codes l.uft, f.ge Versionsnummern in die Start-Logs des Node.js Servers (`server.cjs`) und des Python Orchestrators (`gtm_architect_orchestrator.py`) ein. * `server.cjs`: `console.log(`... (Version: ${VERSION})`);` * `gtm_architect_orchestrator.py`: `print(f"DEBUG: Orchestrator v{__version__} loaded ...")` * **Signaturen pr.fen:** Shared Libraries (`helpers.py`) haben oft .ltere Signaturen. Immer die tats.chliche Definition pr.fen! * Beispiel: `call_openai_chat` unterst.tzt oft kein `system_message` Argument. Stattdessen Prompt manuell zusammenbauen (`sys_instr + "\n\n" + prompt`). --- ## 2. Die Backend-Bridge (`server.cjs`) Dies ist der Node.js Server im Container. Er muss **robust** gegen Timeouts sein und Pfade dynamisch erkennen (Dev vs. Prod). --- ## 3. Docker Optimierung (Multi-Stage) Wir nutzen **Multi-Stage Builds**, um das Image klein zu halten (kein `src`, keine Dev-Tools im Final Image). --- ## 4. Docker Compose & Mounts (WICHTIGER PITFALL) **WARNUNG: Lokale Dateien .berschreiben den Container-Code!** --- ## 5. Nginx Proxy Achtung beim Routing. Wenn die App unter `/app/` laufen soll, muss der Trailing Slash (`/`) stimmen. --- ## 6. Frontend Anpassungen (React) 1. **API Calls:** Alle direkten Aufrufe an `GoogleGenAI` entfernen. Stattdessen `fetch('/api/run', ...)` nutzen. 2. **Base URL:** In `vite.config.ts` `base: './'` setzen (siehe Punkt 1.3). --- ## Appendix A: GTM Architect Fixes & Gemini Migration ### A.1 - A.4 (Siehe .ltere Versionen f.r Prompt-Fixes & GenerativeModel API) ### A.5 Image Generation 2.0 (Hybrid Approach - Jan 04) Um die Einschr.nkungen der "Text-only" Modelle und die regionale Verf.gbarkeit von Imagen 3 zu umgehen, nutzen wir einen hybriden Ansatz. **1. Anforderungen** * **Bibliothek:** `google-genai` (v1.x) MUSS installiert sein (`pip install google-genai`). `google-generativeai` (v0.x) ist veraltet. * **Bildverarbeitung:** `Pillow` muss installiert sein (`pip install Pillow`). **2. Die Logik (Text vs. Bild)** Das System entscheidet automatisch, welches Modell genutzt wird: * **Szenario A: Generisches Bild (Text-to-Image)** * **Modell:** `imagen-4.0-generate-001`. * **Szenario B: Produkt-Integration (Image-to-Image)** * **Modell:** `gemini-2.5-flash-image`. ### A.6 Gemini SDK-Chaos & Modell-Verf.gbarkeit (Kritische Erkenntnis) Ein wiederkehrendes Problem bei der Migration ist der Konflikt zwischen SDK-Versionen und regionalen Modell-Beschr.nkungen. **1. Das SDK-Dilemma** Es existieren zwei parallele Google SDKs: 1. **`google-generativeai` (Legacy):** Veraltet, oft instabil bei neuen Modellen, wirft Deprecation-Warnungen. Import: `import google.generativeai`. 2. **`google-genai` (Modern):** Erforderlich f.r Imagen 4 und Gemini 2.x Features. Import: `from google import genai`. **L.SUNG:** Nutze den **Dual-Support-Ansatz** in `helpers.py`. Importiere beide und verwende die neue Lib f.r Bilder und die alte (da stabiler f.r bestehende Text-Prompts) f.r Flash 1.5/2.0. **2. Der "404 Not Found" Modell-Fehler** Oft liefert die API einen 404 Fehler f.r ein Modell (z.B. `gemini-1.5-flash`), obwohl es laut Dokumentation existiert. * **Ursache:** Regionale Beschr.nkungen (EU vs US) oder Account-Berechtigungen. * **Erkenntnis:** Wenn 1.5 Flash nicht geht, funktioniert oft **`gemini-2.0-flash`** problemlos. * **Best Practice:** Implementiere eine **Kandidaten-Liste** (Fallback-Loop) f.r Modelle. **3. SDK Syntax-Fallen** Das neue SDK (`google-genai`) hat ge.nderte Methodennamen: * Statt `generate_image` (Singular) wird oft **`generate_images`** (Plural) erwartet. * Modelle f.r Bildgenerierung (Imagen) reagieren allergisch auf `response_mime_type="application/json"`. Dieses Feld MUSS bei Imagen-Modellen weggelassen werden. **Gold-Standard f.r Modell-Wahl (Python):** ```python candidates = ['imagen-4.0-generate-001', 'imagen-3.0-generate-001'] for model in candidates: try: # Versuch des API-Calls break except ClientError as e: if "404" in str(e): continue raise e ``` --- ## 7. Troubleshooting & Lessons Learned (Jan 2026) ### 7.5 Double JSON Encoding (Database Trap) * **Problem:** Wenn `json.dumps()` sowohl im Backend beim Speichern als auch in der DB-Klasse aufgerufen wird, landet "Stringified JSON" in der DB. Beim Laden im Frontend crasht React, da es einen String statt eines Objekts erh.lt. * **Fix Backend:** Speichere rohe Dictionaries in der DB-Klasse. * **Fix Frontend:** Nutze eine robuste Parse-Funktion, die `JSON.parse()` mehrfach versucht: ```javascript const parseData = (d) => (typeof d === 'string' ? JSON.parse(d) : d); ```