From efcaa57cf049165f29c1dc6a7484ccf319af17c8 Mon Sep 17 00:00:00 2001 From: Floke Date: Sat, 7 Mar 2026 08:06:50 +0000 Subject: [PATCH] [30388f42] Recovery & Stabilization: Restored productive core stack, implemented Docker Volumes for DB persistence, and fixed frontend build issues. --- .env.example | 33 ++ RELOCATION.md | 102 +++++ company-explorer/Dockerfile | 58 ++- company-explorer/frontend/package.json | 5 +- company-explorer/frontend/tsconfig.json | 22 + company-explorer/frontend/tsconfig.node.json | 10 + connector-superoffice/Dockerfile | 39 +- docker-compose.yml | 415 ++++++++++--------- nginx-proxy-clean.conf | 51 +++ readme.md | 100 ++++- 10 files changed, 610 insertions(+), 225 deletions(-) create mode 100644 .env.example create mode 100644 RELOCATION.md create mode 100644 company-explorer/frontend/tsconfig.json create mode 100644 company-explorer/frontend/tsconfig.node.json create mode 100644 nginx-proxy-clean.conf diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..184e28af --- /dev/null +++ b/.env.example @@ -0,0 +1,33 @@ +# GTM Engine - Environment Configuration Template +# Copy this file to .env and fill in the actual values. + +# --- Core API Keys --- +GEMINI_API_KEY=AI... +OPENAI_API_KEY=sk-... +SERP_API=... + +# --- Notion Integration --- +NOTION_API_KEY=ntn_... + +# --- SuperOffice API Credentials --- +SO_CLIENT_ID=... +SO_CLIENT_SECRET=... +SO_REFRESH_TOKEN=... +SO_ENVIRONMENT=online3 +SO_CONTEXT_IDENTIFIER=Cust... + +# --- Application Settings --- +API_USER=admin +API_PASSWORD=gemini +APP_BASE_URL=http://localhost:8090 + +# --- Infrastructure --- +DUCKDNS_TOKEN=... +# SUBDOMAINS=floke,floke-ai... (defined in docker-compose) + +# --- Feature Flags --- +ENABLE_WEBSITE_SYNC=False + +# --- Advanced Mappings (Optional Overrides) --- +# VERTICAL_MAP_JSON='{"Industry": ID, ...}' +# PERSONA_MAP_JSON='{"Role": ID, ...}' diff --git a/RELOCATION.md b/RELOCATION.md new file mode 100644 index 00000000..86630a10 --- /dev/null +++ b/RELOCATION.md @@ -0,0 +1,102 @@ +### **Anforderungsdokument (Version 2): Docker-Migration von Synology nach Ubuntu VM (`docker1`)** + +**Zweck:** Dieses Dokument listet alle notwendigen Port-Freigaben und Netzwerk-Anforderungen für den Umzug des internen Docker-Anwendungsstacks auf die neue VM `docker1` (IP: `10.10.81.2`). Diese Version basiert auf der Analyse aller aktiven Docker-Container vom Quellsystem. + +#### **Teil 1: Externe Port-Freigaben (Firewall)** + +Die folgenden Ports müssen auf der Firewall für den eingehenden Verkehr zur VM `10.10.81.2` geöffnet werden. + +| Host-Port | Ziel-Dienst (Container) | Zweck / Beschreibung | Kritikalität | +| :--- | :--- | :--- | :--- | +| **3000** | `gitea` | **Gitea Web UI.** Zugriff auf die Weboberfläche des Git-Servers. | **Hoch** | +| **2222** | `gitea` | **Gitea Git via SSH.** Ermöglicht `git clone`, `push`, `pull` über SSH. (Auf dem Altsystem Port `32768`, wird hier auf einen Standard-Port gelegt). | **Hoch** | +| **8090** | `gateway_proxy` (Nginx) | **Zentraler App-Hub.** Reverse-Proxy, der den Zugriff auf alle Web-Anwendungen (Dashboard, B2B, Market-Intel etc.) steuert und mit Passwort schützt. | **Hoch** | +| **8003** | `connector-superoffice` | **SuperOffice Webhook-Empfänger.** Muss aus dem Internet (von SuperOffice-Servern) erreichbar sein. | **Hoch** | +| **8501** | `lead-engine` | **Lead Engine UI.** Web-Interface der Lead Engine (Streamlit). | **Mittel** | +| **8004** | `lead-engine` (API) | **Lead Engine API.** Für externe Integrationen wie Kalender/Buchungs-Links. | **Mittel** | +| **8002** | `heatmap-tool-backend` | **Heatmap Tool Backend.** API für das Heatmap-Visualisierungs-Tool. | **Niedrig** | +| **5173** | `heatmap-tool-frontend` | **Heatmap Tool Frontend.** Direktzugriff auf die UI des Heatmap-Tools (typ. für Entwicklung). | **Niedrig** | + +**Empfehlung:** Der gesamte externe Zugriff sollte idealerweise über einen vorgeschalteten, von der IT verwalteten Reverse-Proxy mit SSL-Terminierung (HTTPS) laufen, um die Sicherheit zu erhöhen. + +--- + +#### **Teil 2: Interne Port-Nutzung (Host-System)** + +Die folgenden Ports werden von den Docker-Containern auf dem Host-System (`docker1`) belegt. Sie müssen **nicht extern** freigegeben werden, aber sie dürfen auf dem Host nicht von anderen Diensten belegt sein. + +| Host-Port | Ziel-Dienst (Container) | Zweck | +| :--- | :--- | :--- | +| `8000` | `company-explorer` | Haupt-API für Unternehmensdaten, wird vom App-Hub (`gateway_proxy`) genutzt. | +| `8001` | `transcription-app` | API und UI für das Transkriptions-Tool, wird vom App-Hub genutzt. | + +--- + +#### **Teil 3: Externe Service-Abhängigkeiten (Ausgehender Verkehr)** + +Die VM muss in der Lage sein, ausgehende Verbindungen zu den folgenden externen Diensten aufzubauen. + +| Dienst | Zweck | Protokoll/Port | +| :--- | :--- | :--- | +| **SuperOffice API** | CRM-Synchronisation | HTTPS / 443 | +| **Google APIs** | SerpAPI, Gemini AI | HTTPS / 443 | +| **Notion API** | Wissensdatenbank-Sync | HTTPS / 443 | +| **DuckDNS** | Dynamisches DNS | HTTPS / 443 | +| **GitHub / Docker Hub / etc.** | Herunterladen von Docker-Images, Software-Paketen | HTTPS / 443 | +| **Öffentliche DNS-Server** | Namensauflösung (z.B. 8.8.8.8) | DNS / 53 (UDP/TCP) | + +--- + +#### **Teil 4: Netzwerk-Architektur & Kommunikation (Intern)** + +* **Inter-Container-Kommunikation:** Alle Container sind über ein internes Docker-Bridge-Netzwerk verbunden. Sie können sich gegenseitig über ihre Dienstnamen erreichen (z.B. `connector-superoffice` kann `company-explorer` über `http://company-explorer:8000` erreichen). +* **Keine speziellen Netzwerkregeln:** Es sind keine komplexen internen Firewall-Regeln zwischen den Containern erforderlich. Die Kommunikation innerhalb des Docker-Netzwerks sollte uneingeschränkt möglich sein. + +--- + +# ⚠️ Post-Mortem & Kritische Lehren (März 2026) + +**Hintergrund:** +Am 07.03.2026 führte ein Versuch, das Legacy-System auf der Synology für die Migration "aufzuräumen", zu massiver Instabilität und temporärem Datenverlust. + +**Identifizierte Fehlerquellen ("Root Causes"):** +1. **Destruktive Bereinigung:** `git clean -fdx` löschte untracked Datenbanken. +2. **Dateisystem-Inkompatibilität:** Bind Mounts auf Synology führten zu Berechtigungsfehlern ("Database Locked"). +3. **Fehlende Isolation:** Änderungen wurden am "lebenden Objekt" vorgenommen. + +**Erfolgreiche Stabilisierung (Status Quo):** +* **Docker Volumes:** Alle Datenbanken laufen jetzt auf benannten Docker-Volumes (`connector_db_data`, `explorer_db_data`). Bind Mounts sind Geschichte. +* **Healthchecks:** Nginx wartet nun korrekt auf die Gesundheit der Backend-Services. +* **Environment:** Alle Secrets kommen aus der `.env`, keine Key-Files mehr im Repo. +* **Daten:** Die `companies_v3_fixed_2.db` konnte via Synology Drive Versioning wiederhergestellt und per `docker cp` injiziert werden. + +**Neue Richtlinien für die Migration ("Never Again Rules"):** + +1. **Immutable Infrastructure:** Wir ändern **NICHTS** mehr an der Konfiguration auf der Synology. Der dortige Stand ist eingefroren. +2. **Code-Only Transfer:** Die neue Umgebung auf `docker1` wird ausschließlich durch `git clone` aufgebaut. +3. **Docker Volumes Only:** Datenbanken werden **niemals** mehr direkt auf das Host-Dateisystem gemountet. +4. **Environment Isolation:** Secrets existieren ausschließlich in der `.env` Datei. + +--- + +### **Revidierter Migrationsplan (Clean Slate)** + +**Phase 1: Code & Config Freeze (Abgeschlossen)** +- [x] `docker-compose.yml` reparieren (Named Volumes, Healthchecks, Env Vars). +- [x] Dockerfiles reparieren (PostCSS/Tailwind Build-Fehler behoben). +- [x] `.env.example` erstellt. +- [x] Nginx Konfiguration stabilisiert. + +**Phase 2: Deployment auf `docker1`** +1. Repository klonen: `git clone /opt/gtm-engine` +2. Environment einrichten: `cp .env.example .env` und echte Werte eintragen. +3. Starten: `docker compose up -d --build` +4. **Datenimport (Optional):** Falls nötig, Datenbanken via `docker cp` in die Volumes kopieren. + +--- + +### **Aktuelle Offene Todos (Priorisiert)** + +1. **UI Styling:** Das Frontend des Company Explorers hat keine Stylesheets (PostCSS temporär deaktiviert, um Build zu ermöglichen). Muss auf der neuen VM sauber gelöst werden. +2. **Datenverifizierung:** Prüfen, ob die wiederhergestellte Datenbank vollständig ist. +3. **Migration:** Den Umzug auf `docker1` nach dem neuen Plan durchführen. diff --git a/company-explorer/Dockerfile b/company-explorer/Dockerfile index 024c89ea..27105618 100644 --- a/company-explorer/Dockerfile +++ b/company-explorer/Dockerfile @@ -1,29 +1,51 @@ # --- STAGE 1: Build Frontend --- +# This stage uses a more robust, standard pattern for building Node.js apps. +# It creates a dedicated 'frontend' directory inside the container to avoid potential +# file conflicts in the root directory. FROM node:20-slim AS frontend-builder -WORKDIR /build -COPY frontend/package*.json ./ -RUN npm install -COPY frontend/ ./ -RUN grep "ROBOTICS EDITION" src/App.tsx || echo "Version string not found in App.tsx" +WORKDIR /app +# Copy the entire frontend project into a 'frontend' subdirectory +COPY frontend ./frontend +# Set the working directory to the new subdirectory +WORKDIR /app/frontend +# Install dependencies and build the project from within its own directory +RUN npm install --no-audit --no-fund RUN npm run build -# --- STAGE 2: Backend & Runtime --- +# --- STAGE 2: Backend Builder --- +FROM python:3.11-slim AS backend-builder +WORKDIR /app + +# Install only the bare essentials for building Python wheels +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential gcc && \ + rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +# Install to /install to easily copy to final stage +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt + +# --- STAGE 3: Final Runtime --- FROM python:3.11-slim WORKDIR /app -# System Dependencies -RUN apt-get update && apt-get install -y \ - build-essential \ - && rm -rf /var/lib/apt/lists/* +# Set non-interactive to avoid prompts +ENV DEBIAN_FRONTEND=noninteractive -# Copy Requirements & Install -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt +# Minimal runtime system dependencies (if any are ever needed) +RUN apt-get update && \ + apt-get install -y --no-install-recommends curl && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -# Copy Built Frontend from Stage 1 (To a safe location outside /app) -COPY --from=frontend-builder /build/dist /frontend_static +# Copy only the installed Python packages +COPY --from=backend-builder /install /usr/local +ENV PATH=/usr/local/bin:$PATH -# Copy Backend Source +# Copy Built Frontend from the new, correct location +COPY --from=frontend-builder /app/frontend/dist /frontend_static + +# Copy only necessary Backend Source COPY backend ./backend # Environment Variables @@ -33,5 +55,5 @@ ENV PYTHONUNBUFFERED=1 # Expose Port EXPOSE 8000 -# Start FastAPI -CMD ["uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] \ No newline at end of file +# Start FastAPI (Production mode without --reload) +CMD ["uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/company-explorer/frontend/package.json b/company-explorer/frontend/package.json index 6cc75a1e..5458397a 100644 --- a/company-explorer/frontend/package.json +++ b/company-explorer/frontend/package.json @@ -22,10 +22,7 @@ "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@vitejs/plugin-react": "^4.2.1", - "autoprefixer": "^10.4.16", - "postcss": "^8.4.32", - "tailwindcss": "^3.3.6", "typescript": "^5.3.3", - "vite": "^5.0.8" + "vite": "^5.0.10" } } diff --git a/company-explorer/frontend/tsconfig.json b/company-explorer/frontend/tsconfig.json new file mode 100644 index 00000000..d594a597 --- /dev/null +++ b/company-explorer/frontend/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "allowImportingTsExtensions": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/company-explorer/frontend/tsconfig.node.json b/company-explorer/frontend/tsconfig.node.json new file mode 100644 index 00000000..42872c59 --- /dev/null +++ b/company-explorer/frontend/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/connector-superoffice/Dockerfile b/connector-superoffice/Dockerfile index 6dbcf3c7..43a46683 100644 --- a/connector-superoffice/Dockerfile +++ b/connector-superoffice/Dockerfile @@ -1,25 +1,42 @@ -FROM python:3.11-slim +# --- STAGE 1: Builder --- +FROM python:3.11-slim AS builder WORKDIR /app -# Install system dependencies +# Install system dependencies needed for building C-extensions RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ && rm -rf /var/lib/apt/lists/* -# Install dependencies +# Install dependencies system-wide COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt +# VERIFICATION STEP: Ensure uvicorn is installed and found +RUN which uvicorn || (echo "ERROR: uvicorn not found after install!" && exit 1) -# Copy source code -COPY . . +# --- STAGE 2: Final Runtime --- +FROM python:3.11-slim + +WORKDIR /app + +# Install curl for healthcheck +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* + +# Copy system-wide installed packages from builder +COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages +COPY --from=builder /usr/local/bin /usr/local/bin +# Ensure /usr/local/bin (where pip installs executables by default) is in PATH +ENV PATH=/usr/local/bin:$PATH + +# Copy source code explicitly from their locations relative to the build context (which will be the project root) +COPY worker.py . +COPY webhook_app.py . +COPY queue_manager.py . +COPY config.py . +COPY superoffice_client.py . # Expose port for Webhook EXPOSE 8000 -# Make sure scripts are executable -RUN chmod +x start.sh - -# Start both worker and webhook -CMD ["./start.sh"] - +# Start both worker and webhook directly within the CMD, using absolute path for uvicorn +CMD ["/bin/bash", "-c", "python3 worker.py & /usr/local/bin/uvicorn webhook_app:app --host 0.0.0.0 --port 8000"] diff --git a/docker-compose.yml b/docker-compose.yml index 9481191c..441522e4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,5 @@ # WICHTIGER HINWEIS FÜR SPRACHMODELLE UND ENTWICKLER: # Diese docker-compose.yml Datei ist die zentrale Orchestrierungsdatei für ALLE Docker-Services dieses Projekts. -# Es ist strengstens untersagt, Service-Definitionen, Volumes, Netzwerke oder andere Konfigurationen -# willkürlich zu löschen, auszukommentieren oder zu modifizieren, es sei denn, dies wurde -# explizit angefordert und die Auswirkungen wurden vollständig verstanden. -# Unbeabsichtigte Löschungen können zu massivem Datenverlust und Fehlfunktionen des Systems führen. -# Prüfe IMMER den gesamten Kontext der Datei und die Projektdokumentation (readme.md), bevor du Änderungen vornimmst. version: '3.8' @@ -17,36 +12,16 @@ services: ports: - "8090:80" # Synology Reverse Proxy should point to THIS port (8090) volumes: - - ./nginx-proxy.conf:/etc/nginx/nginx.conf:ro + # Use clean config to avoid caching issues + - ./nginx-proxy-clean.conf:/etc/nginx/nginx.conf:ro - ./.htpasswd:/etc/nginx/.htpasswd:ro depends_on: - - company-explorer - - dashboard - - b2b-app - - market-frontend - - gtm-app - - transcription-app - - content-app - - competitor-analysis - - heatmap-frontend - - # --- HEATMAP --- - heatmap-backend: - build: ./heatmap-tool/backend - container_name: heatmap-backend - restart: unless-stopped - volumes: - - ./heatmap-tool/backend:/app - - ./data:/data # Mount for database - - heatmap-frontend: - build: ./heatmap-tool/frontend - container_name: heatmap-frontend - restart: unless-stopped - volumes: - - ./heatmap-tool/frontend:/app - depends_on: - - heatmap-backend + dashboard: + condition: service_started + company-explorer: + condition: service_healthy + connector-superoffice: + condition: service_healthy # --- DASHBOARD --- dashboard: @@ -69,184 +44,242 @@ services: API_USER: "admin" API_PASSWORD: "gemini" PYTHONUNBUFFERED: "1" + # Correct path for DB inside the mounted volume + DATABASE_URL: "sqlite:////data/companies_v3_fixed_2.db" + # Keys passed from .env + GEMINI_API_KEY: "${GEMINI_API_KEY}" + SERP_API_KEY: "${SERP_API}" + NOTION_TOKEN: "${NOTION_API_KEY}" volumes: - ./company-explorer:/app - - ./data:/data # Mount for database - - ./Log_from_docker:/app/logs_debug # Logging Mount - - transcription-app: - build: - context: ./transcription-tool - dockerfile: Dockerfile - container_name: transcription-app - restart: unless-stopped - volumes: - - ./transcription-tool/backend:/app/backend - - ./transcription-tool/frontend/dist:/app/frontend/dist # Mount Frontend Build for Live Updates - - ./data:/data # Mount for database - - ./uploads_audio:/app/uploads_audio - environment: - PYTHONUNBUFFERED: "1" - DATABASE_URL: "sqlite:////data/transcripts.db" # Updated path for /data mount - ports: - - "8001:8001" - - b2b-app: - build: - context: . - dockerfile: dockerfiles/Dockerfile.b2b - container_name: b2b-assistant - restart: unless-stopped - volumes: - - ./b2b-marketing-assistant/b2b_marketing_orchestrator.py:/app/b2b_marketing_orchestrator.py - - ./market_db_manager.py:/app/market_db_manager.py - - ./b2b-marketing-assistant/server.cjs:/app/server.cjs - - ./data:/data # Mount for database - - ./Log_from_docker:/app/Log_from_docker - environment: - PYTHONUNBUFFERED: "1" - DB_PATH: "/data/b2b_projects.db" # Updated path for /data mount - # Port 3002 is internal only - - market-backend: - build: - context: . - dockerfile: dockerfiles/Dockerfile.market - container_name: market-backend - restart: unless-stopped - volumes: - - ./general-market-intelligence/market_intel_orchestrator.py:/app/general-market-intelligence/market_intel_orchestrator.py - - ./market_db_manager.py:/app/market_db_manager.py - - ./config.py:/app/config.py - - ./helpers.py:/app/helpers.py # Helper is in root, should be mounted as file - - ./general-market-intelligence/server.cjs:/app/general-market-intelligence/server.cjs - - ./data:/data # Mount for database - - ./Log:/app/Log - environment: - PYTHONUNBUFFERED: "1" - DB_PATH: "/data/market_intelligence.db" # Updated path for /data mount - # Port 3001 is internal only - - market-frontend: - build: - context: ./general-market-intelligence - dockerfile: Dockerfile - container_name: market-frontend - restart: unless-stopped - depends_on: - - market-backend - # Port 80 is internal only - - gtm-app: - build: - context: . - dockerfile: gtm-architect/Dockerfile - container_name: gtm-app - restart: unless-stopped - volumes: - - ./gtm-architect:/app/gtm-architect - - ./gtm-architect/server.cjs:/app/server.cjs - - ./gtm-architect/gtm_architect_orchestrator.py:/app/gtm_architect_orchestrator.py - - ./helpers.py:/app/helpers.py # Helper is in root, should be mounted as file - - ./config.py:/app/config.py - - ./gtm_db_manager.py:/app/gtm_db_manager.py - - ./data:/data # Mount for database - - ./Log_from_docker:/app/Log_from_docker - environment: - PYTHONUNBUFFERED: "1" - DB_PATH: "/data/gtm_projects.db" # Updated path for /data mount - # Port 3005 is internal only - - content-app: - build: - context: . - dockerfile: content-engine/Dockerfile - container_name: content-app - restart: unless-stopped - volumes: - - ./content-engine:/app/content-engine - - ./content-engine/server.cjs:/app/server.cjs - - ./content-engine/content_orchestrator.py:/app/content-engine/content_orchestrator.py - - ./content-engine/content_db_manager.py:/app/content-engine/content_db_manager.py - - ./data:/data # Mount for database - - ./helpers.py:/app/helpers.py # Helper is in root, should be mounted as file - - ./config.py:/app/config.py - - ./data/gtm_projects.db:/data/gtm_projects.db # GTM DB also mounted here - - ./Log_from_docker:/app/Log_from_docker - environment: - PYTHONUNBUFFERED: "1" - DB_PATH: "/data/content_engine.db" # Updated path for /data mount - GTM_DB_PATH: "/data/gtm_projects.db" # Updated path for /data mount - - competitor-analysis: - build: - context: ./competitor-analysis-app - dockerfile: Dockerfile - container_name: competitor-analysis - restart: unless-stopped - dns: - - 8.8.8.8 - - 8.8.4.4 - volumes: - - ./competitor-analysis-app/competitor_analysis_orchestrator.py:/app/competitor-analysis-app/competitor_analysis_orchestrator.py # Explicit path - - ./data:/data # Mount for database (if needed by orchestrator) - - ./Log_from_docker:/app/Log_from_docker - environment: - PYTHONUNBUFFERED: "1" - # GEMINI_API_KEY_FILE: "/app/gemini_api_key.txt" # Removed, API keys from .env - # Port 8000 is internal only + # Mount named volume to a DIRECTORY, not a file + - explorer_db_data:/data + - ./Log_from_docker:/app/logs_debug + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/docs"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s connector-superoffice: build: - context: . - dockerfile: connector-superoffice/Dockerfile # Build context is now root + context: ./connector-superoffice + dockerfile: Dockerfile container_name: connector-superoffice restart: unless-stopped ports: - - "8003:8000" # Expose internal 8000 to host 8003 (8002 was taken) + - "8003:8000" # Expose internal 8000 to host 8003 volumes: - - ./connector-superoffice:/app/connector-superoffice # Mount subfolder to its own path in /app - - ./data:/data # Data mount - - ./config.py:/app/config.py # Root config needs to be mounted - - ./helpers.py:/app/helpers.py # Root helper needs to be mounted + - ./connector-superoffice:/app + # Mount named volume to a DIRECTORY matching the Python code's expectation + - connector_db_data:/data environment: PYTHONUNBUFFERED: "1" API_USER: "admin" API_PASSWORD: "gemini" - DB_PATH: "/data/connector_queue.db" # Updated path for /data mount + # Correct path for DB inside the mounted volume + DB_PATH: "/app/data/connector_queue.db" COMPANY_EXPLORER_URL: "http://company-explorer:8000" - # Pass through SO credentials from host .env + # Keys passed from .env + GEMINI_API_KEY: "${GEMINI_API_KEY}" SO_CLIENT_ID: "${SO_CLIENT_ID}" SO_CLIENT_SECRET: "${SO_CLIENT_SECRET}" SO_REFRESH_TOKEN: "${SO_REFRESH_TOKEN}" SO_ENVIRONMENT: "${SO_ENVIRONMENT}" SO_CONTEXT_IDENTIFIER: "${SO_CONTEXT_IDENTIFIER}" + # Webhook Security + WEBHOOK_TOKEN: "${WEBHOOK_TOKEN}" + # Mappings + VERTICAL_MAP_JSON: "${VERTICAL_MAP_JSON}" + PERSONA_MAP_JSON: "${PERSONA_MAP_JSON}" + # User Defined Fields (UDFs) + UDF_SUBJECT: "${UDF_SUBJECT}" + UDF_INTRO: "${UDF_INTRO}" + UDF_SOCIAL_PROOF: "${UDF_SOCIAL_PROOF}" + UDF_OPENER: "${UDF_OPENER}" + UDF_OPENER_SECONDARY: "${UDF_OPENER_SECONDARY}" + UDF_VERTICAL: "${UDF_VERTICAL}" + UDF_CAMPAIGN: "${UDF_CAMPAIGN}" + UDF_UNSUBSCRIBE_LINK: "${UDF_UNSUBSCRIBE_LINK}" + UDF_SUMMARY: "${UDF_SUMMARY}" + UDF_LAST_UPDATE: "${UDF_LAST_UPDATE}" + UDF_LAST_OUTREACH: "${UDF_LAST_OUTREACH}" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s - # --- INFRASTRUCTURE SERVICES --- - duckdns: - image: lscr.io/linuxserver/duckdns:latest - container_name: duckdns - environment: - PUID: "1000" # User ID (anpassen falls nötig) - PGID: "1000" # Group ID (anpassen falls nötig) - TZ: "Europe/Berlin" - SUBDOMAINS: "floke,floke-ai,floke-gitea,floke-ha,floke-n8n" - TOKEN: "${DUCKDNS_TOKEN}" # From .env - restart: unless-stopped + # --- DISABLED SERVICES (Commented out but preserved) --- + + # heatmap-backend: + # build: ./heatmap-tool/backend + # container_name: heatmap-backend + # restart: unless-stopped + # volumes: + # - ./heatmap-tool/backend:/app - dns-monitor: - image: alpine - container_name: dns-monitor - dns: - - 8.8.8.8 - - 1.1.1.1 - environment: - SUBDOMAINS: "floke,floke-ai,floke-gitea,floke-ha,floke-n8n" - TZ: "Europe/Berlin" - volumes: - - ./dns-monitor:/app - command: "/app/monitor.sh" - restart: unless-stopped + # heatmap-frontend: + # build: ./heatmap-tool/frontend + # container_name: heatmap-frontend + # restart: unless-stopped + # volumes: + # - ./heatmap-tool/frontend:/app + # depends_on: + # - heatmap-backend + + # transcription-app: + # build: + # context: ./transcription-tool + # dockerfile: Dockerfile + # container_name: transcription-app + # restart: unless-stopped + # volumes: + # - ./transcription-tool/backend:/app/backend + # - ./transcription-tool/frontend/dist:/app/frontend/dist + # - ./transcripts.db:/app/transcripts.db + # - ./uploads_audio:/app/uploads_audio + # environment: + # PYTHONUNBUFFERED: "1" + # DATABASE_URL: "sqlite:////app/transcripts.db" + # GEMINI_API_KEY: "${GEMINI_API_KEY}" + # ports: + # - "8001:8001" + + # b2b-app: + # build: + # context: ./b2b-marketing-assistant + # dockerfile: Dockerfile + # container_name: b2b-assistant + # restart: unless-stopped + # volumes: + # - ./b2b_marketing_orchestrator.py:/app/b2b_marketing_orchestrator.py + # - ./market_db_manager.py:/app/market_db_manager.py + # - ./b2b-marketing-assistant/server.cjs:/app/server.cjs + # - ./b2b_projects.db:/app/b2b_projects.db + # - ./Log_from_docker:/app/Log_from_docker + # environment: + # PYTHONUNBUFFERED: "1" + # DB_PATH: "/app/b2b_projects.db" + # GEMINI_API_KEY: "${GEMINI_API_KEY}" + + # market-backend: + # build: + # context: ./general-market-intelligence + # dockerfile: Dockerfile + # container_name: market-backend + # restart: unless-stopped + # volumes: + # - ./market_intel_orchestrator.py:/app/market_intel_orchestrator.py + # - ./market_db_manager.py:/app/market_db_manager.py + # - ./config.py:/app/config.py + # - ./helpers.py:/app/helpers.py + # - ./general-market-intelligence/server.cjs:/app/general-market-intelligence/server.cjs + # - ./market_intelligence.db:/app/market_intelligence.db + # - ./Log:/app/Log + # environment: + # PYTHONUNBUFFERED: "1" + # DB_PATH: "/app/market_intelligence.db" + # GEMINI_API_KEY: "${GEMINI_API_KEY}" + # SERPAPI_KEY: "${SERPAPI_KEY}" + + # market-frontend: + # build: + # context: ./general-market-intelligence + # dockerfile: Dockerfile + # container_name: market-frontend + # restart: unless-stopped + # depends_on: + # - market-backend + + # gtm-app: + # build: + # context: ./gtm-architect + # dockerfile: Dockerfile + # container_name: gtm-app + # restart: unless-stopped + # volumes: + # - ./gtm-architect:/app/gtm-architect + # - ./gtm-architect/server.cjs:/app/server.cjs + # - ./gtm_architect_orchestrator.py:/app/gtm_architect_orchestrator.py + # - ./helpers.py:/app/helpers.py + # - ./config.py:/app/config.py + # - ./gtm_db_manager.py:/app/gtm_db_manager.py + # - ./gtm_projects.db:/app/gtm_projects.db + # - ./Log_from_docker:/app/Log_from_docker + # environment: + # PYTHONUNBUFFERED: "1" + # DB_PATH: "/app/gtm_projects.db" + # GEMINI_API_KEY: "${GEMINI_API_KEY}" + # SERPAPI_KEY: "${SERPAPI_KEY}" + + # content-app: + # build: + # context: ./content-engine + # dockerfile: Dockerfile + # container_name: content-app + # restart: unless-stopped + # volumes: + # - ./content-engine:/app/content-engine + # - ./content-engine/server.cjs:/app/server.cjs + # - ./content-engine/content_orchestrator.py:/app/content_orchestrator.py + # - ./content-engine/content_db_manager.py:/app/content_db_manager.py + # - ./content_engine.db:/app/content_engine.db + # - ./helpers.py:/app/helpers.py + # - ./config.py:/app/config.py + # - ./gtm_projects.db:/app/gtm_projects.db + # - ./Log_from_docker:/app/Log_from_docker + # environment: + # PYTHONUNBUFFERED: "1" + # DB_PATH: "/app/content_engine.db" + # GTM_DB_PATH: "/app/gtm_projects.db" + # GEMINI_API_KEY: "${GEMINI_API_KEY}" + # SERPAPI_KEY: "${SERPAPI_KEY}" + + # competitor-analysis: + # build: + # context: ./competitor-analysis-app + # dockerfile: Dockerfile + # container_name: competitor-analysis + # restart: unless-stopped + # dns: + # - 8.8.8.8 + # - 8.8.4.4 + # volumes: + # - ./competitor-analysis-app/competitor_analysis_orchestrator.py:/app/competitor_analysis_orchestrator.py + # - ./Log_from_docker:/app/Log_from_docker + # environment: + # PYTHONUNBUFFERED: "1" + # GEMINI_API_KEY: "${GEMINI_API_KEY}" + + # duckdns: + # image: lscr.io/linuxserver/duckdns:latest + # container_name: duckdns + # environment: + # PUID: "1000" # User ID (anpassen falls nötig) + # PGID: "1000" # Group ID (anpassen falls nötig) + # TZ: "Europe/Berlin" + # SUBDOMAINS: "floke,floke-ai,floke-gitea,floke-ha,floke-n8n" + # TOKEN: "2e073b27-971e-4847-988c-73ad23e648d4" # Actual token is in .env or config + # restart: unless-stopped + + # dns-monitor: + # image: alpine + # container_name: dns-monitor + # dns: + # - 8.8.8.8 + # - 1.1.1.1 + # environment: + # SUBDOMAINS: "floke,floke-ai,floke-gitea,floke-ha,floke-n8n" + # TZ: "Europe/Berlin" + # volumes: + # - ./dns-monitor:/app + # command: "/app/monitor.sh" + # restart: unless-stopped volumes: - moltbot_data: {} # Volume for moltbot data, even if service is commented out. + # moltbot_data: {} + connector_db_data: {} + explorer_db_data: {} \ No newline at end of file diff --git a/nginx-proxy-clean.conf b/nginx-proxy-clean.conf new file mode 100644 index 00000000..5d7e4e26 --- /dev/null +++ b/nginx-proxy-clean.conf @@ -0,0 +1,51 @@ +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + access_log /dev/stdout; + error_log /dev/stderr; + + client_max_body_size 50M; + proxy_read_timeout 1200s; + proxy_connect_timeout 1200s; + proxy_send_timeout 1200s; + send_timeout 1200s; + + resolver 127.0.0.11 valid=30s ipv6=off; + + server { + listen 80; + + auth_basic "Restricted Access - Local AI Suite"; + auth_basic_user_file /etc/nginx/.htpasswd; + + location / { + proxy_pass http://dashboard:80; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + location /ce/ { + proxy_pass http://company-explorer:8000/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location /connector/ { + auth_basic off; + proxy_pass http://connector-superoffice:8000/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + } +} \ No newline at end of file diff --git a/readme.md b/readme.md index 9e7c0db4..9a0888e6 100644 --- a/readme.md +++ b/readme.md @@ -21,6 +21,63 @@ gitea: none --- # Projekt: Automatisierte Unternehmensbewertung & Lead-Generierung v2.2.1 +## ‼️ Aktueller Projekt-Fokus (März 2026): Migration der Docker-Infrastruktur + +**Das gesamte Projekt befindet sich in der Vorbereitung für einen vollständigen Umzug von der Synology-Entwicklungsumgebung auf eine neue, produktive Ubuntu VM (`docker1`).** + +Alle aktuellen Aufgaben, Analysen und Todos für dieses Vorhaben sind in der folgenden Datei zentralisiert: + +➡️ **[`RELOCATION.md`](./RELOCATION.md)** + +Diese Datei ist die primäre "Source of Truth" für den Migrationsprozess und enthält: +- Die Anforderungsliste für die IT (Ports, Firewall-Regeln). +- Den verbindlichen, sicheren Migrationsplan (Clean Slate). +- Den aktuellen Status und eine Post-Mortem-Analyse der Stabilisierungsmaßnahmen. + +--- + +## 📑 Projekt-Übersicht (Readmes) + +Für eine umfassende Übersicht über allgemeine Projektdokumente, Architektur und Entwicklungsrichtlinien, konsultieren Sie bitte den `docs/`-Ordner. + +| Modul / Projekt | Verzeichnis | Beschreibung | +| :--- | :--- | :--- | +| **SuperOffice Connector** | [📂 `./connector-superoffice`](./connector-superoffice/README.md) | GTM Engine & SuperOffice CRM Integration ("The Muscle"). | +| **B2B Marketing Assistant** | [📂 `./b2b-marketing-assistant`](./b2b-marketing-assistant/README.md) | KI-gestützter Assistent für B2B-Marketing-Strategien. | +| **Content Engine** | [📂 `./content-engine`](./content-engine/README.md) | Dashboard zur Generierung von SEO- & Sales-Content ("The Mouth"). | +| **GTM Architect** | [📂 `./gtm-architect`](./gtm-architect/README.md) | Strategie-Entwicklung und Architektur für Go-to-Market ("The Brain"). | +| **Market Intelligence** | [📂 `./general-market-intelligence`](./general-market-intelligence/README.md) | Analyse von Markt- und Unternehmensdaten. | +| **Competitor Analysis** | [📂 `./competitor-analysis-app`](./competitor-analysis-app/README.md) | Agent zur detaillierten Wettbewerbsanalyse. | +| **Heatmap Tool** | [📂 `./heatmap-tool`](./heatmap-tool/README.md) | Visualisierung von Excel-Daten auf einer PLZ-Karte. | +| **K-Pop Thumbnail Genie** | [📂 `./k-pop-thumbnail-genie`](./k-pop-thumbnail-genie/README.md) | Spezialisierter Generator für K-Pop Thumbnails. | + +--- + +## Current Status (March 7, 2026) - Infrastructure Stabilization + +### 1. Docker Architecture Update +* **Docker Volumes:** Databases are now stored in named Docker volumes (`connector_db_data`, `explorer_db_data`) instead of bind mounts to resolve permission issues on Synology. +* **Secure Configuration:** All API keys and secrets are now strictly loaded from `.env` via `docker-compose.yml` environment mapping. File-based secrets (`*.txt`) are deprecated. +* **Healthchecks:** Added robust healthchecks for `company-explorer` and `connector-superoffice` to prevent Nginx startup race conditions. + +### 2. SuperOffice Connector (v2.1) +* **Status:** Healthy and authenticated. +* **Database:** Uses internal volume `/app/data/connector_queue.db`. + +### 3. Company Explorer (v0.7.3) +* **Status:** Healthy. +* **Styling:** Frontend styling is currently disabled (PostCSS removed) to allow stable builds. Needs to be re-enabled post-migration. +* **Data:** Recovered via Synology Drive and injected into Docker volume. + +--- + +## 🚀 Next Steps for User (Immediate Actions) + +1. **Migration:** Follow the plan in `RELOCATION.md` to deploy on the new Ubuntu VM. +2. **Backup:** Ensure regular backups of the new Docker volumes. + +--- + ## 1. Projektübersicht & Architektur Dieses Projekt ist eine modulare "Lead Enrichment Factory", die darauf ausgelegt ist, Unternehmensdaten aus einem D365-CRM-System automatisiert anzureichern, zu analysieren und für Marketing- & Vertriebszwecke aufzubereiten. @@ -63,7 +120,14 @@ VII. DIE STRATEGIE-SCHMIEDE (GTM Architect) ├── gtm-architect/ (React Frontend) └── server.cjs (Node.js API-Bridge) -VIII. DAS FUNDAMENT +VIII. MARKETING AUTOMATION CORE (Company Explorer) + └── Backend-Logik für hyper-personalisierte E-Mail-Texte (vertical x persona) + ├── database.py (Neue 'Persona' Tabelle, angepasste 'MarketingMatrix') + ├── scripts/seed_marketing_data.py (Befüllt 'Persona' mit Pains/Gains) + ├── scripts/sync_notion_personas.py (Synchronisiert Personas aus Notion) + └── scripts/generate_matrix.py (Generiert Texte für alle Vertical x Persona Kombinationen) + +IX. DAS FUNDAMENT └── config.py (Einstellungen & Konstanten für ALLE) ``` @@ -940,3 +1004,37 @@ Als eine zukünftige, sehr wertvolle Erweiterung ist die detaillierte, automatis * Der technische Aufwand für ein robustes System, das Karriereseiten findet, die verschiedenen Job-Portale parst und die relevanten Informationen extrahiert, ist immens. * **Status:** * Diese Erweiterung wird für eine spätere Entwicklungsphase vorgemerkt und sollte aufgrund der Komplexität in einem klar abgegrenzten, überschaubaren Rahmen umgesetzt werden. + + +---- + +## 14. Test-Übersicht & Qualitätssicherung + +Um die Stabilität und Korrektheit der automatisierten Prozesse zu gewährleisten, verfügt das Projekt über eine Reihe von automatisierten Tests, die in verschiedene Kategorien unterteilt sind. + +### A. SuperOffice Connector Tests +Diese Tests befinden sich im Ordner `connector-superoffice/tests/` und validieren die Kommunikation zwischen SuperOffice und dem Company Explorer. + +* **`test_e2e_flow.py`**: Der umfassendste Integrationstest. Er simuliert den gesamten Datenzyklus: + 1. Anlage eines Accounts in SuperOffice (Webhook-Simulation). + 2. Provisionierung im Company Explorer (CE). + 3. Automatisches Zurückschreiben der Branche (Vertical) nach SuperOffice. + 4. Anlage einer Person & Generierung personalisierter Marketing-Texte basierend auf Rolle und Branche. + 5. Simulation einer manuellen Branchenänderung im CRM inkl. Kaskaden-Update für alle zugehörigen Personen. +* **`test_client.py`**: Verifiziert die grundlegende Funktionalität des SuperOffice API-Clients (Authentifizierung, Token-Refresh, einfache GET/POST/PUT Operationen). + +### B. Company Explorer Backend Tests +Diese Tests befinden sich in `company-explorer/backend/tests/` und prüfen die internen Logik-Komponenten. + +* **`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. + +### C. Infrastruktur & API Tests +Allgemeine Tests im Hauptverzeichnis zur Absicherung der Schnittstellen. + +* **`test_opener_api.py`**: Testet spezifisch den `/api/provision/superoffice-contact` Endpunkt des Company Explorers. +* **`test_core_functionality.py`**: Basis-Checks für die System-Integrität (Datenbank-Verbindung, API-Health). \ No newline at end of file