[30388f42] Recovery & Stabilization: Restored productive core stack, implemented Docker Volumes for DB persistence, and fixed frontend build issues.

This commit is contained in:
2026-03-07 08:06:50 +00:00
parent 4224206b24
commit 35c30bc39a
10 changed files with 610 additions and 225 deletions

33
.env.example Normal file
View File

@@ -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, ...}'

102
RELOCATION.md Normal file
View File

@@ -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 <repo-url> /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.

View File

@@ -1,29 +1,51 @@
# --- STAGE 1: Build Frontend --- # --- 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 FROM node:20-slim AS frontend-builder
WORKDIR /build WORKDIR /app
COPY frontend/package*.json ./ # Copy the entire frontend project into a 'frontend' subdirectory
RUN npm install COPY frontend ./frontend
COPY frontend/ ./ # Set the working directory to the new subdirectory
RUN grep "ROBOTICS EDITION" src/App.tsx || echo "Version string not found in App.tsx" 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 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 FROM python:3.11-slim
WORKDIR /app WORKDIR /app
# System Dependencies # Set non-interactive to avoid prompts
RUN apt-get update && apt-get install -y \ ENV DEBIAN_FRONTEND=noninteractive
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Copy Requirements & Install # Minimal runtime system dependencies (if any are ever needed)
COPY requirements.txt . RUN apt-get update && \
RUN pip install --no-cache-dir -r requirements.txt 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 only the installed Python packages
COPY --from=frontend-builder /build/dist /frontend_static 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 COPY backend ./backend
# Environment Variables # Environment Variables
@@ -33,5 +55,5 @@ ENV PYTHONUNBUFFERED=1
# Expose Port # Expose Port
EXPOSE 8000 EXPOSE 8000
# Start FastAPI # Start FastAPI (Production mode without --reload)
CMD ["uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] CMD ["uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -22,10 +22,7 @@
"@types/react": "^18.2.43", "@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17", "@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.8" "vite": "^5.0.10"
} }
} }

View File

@@ -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" }]
}

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@@ -1,25 +1,42 @@
FROM python:3.11-slim # --- STAGE 1: Builder ---
FROM python:3.11-slim AS builder
WORKDIR /app WORKDIR /app
# Install system dependencies # Install system dependencies needed for building C-extensions
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \ build-essential \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Install dependencies # Install dependencies system-wide
COPY requirements.txt . COPY requirements.txt .
RUN pip install --no-cache-dir -r 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 # --- STAGE 2: Final Runtime ---
COPY . . 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 port for Webhook
EXPOSE 8000 EXPOSE 8000
# Make sure scripts are executable # Start both worker and webhook directly within the CMD, using absolute path for uvicorn
RUN chmod +x start.sh CMD ["/bin/bash", "-c", "python3 worker.py & /usr/local/bin/uvicorn webhook_app:app --host 0.0.0.0 --port 8000"]
# Start both worker and webhook
CMD ["./start.sh"]

View File

@@ -1,10 +1,5 @@
# WICHTIGER HINWEIS FÜR SPRACHMODELLE UND ENTWICKLER: # WICHTIGER HINWEIS FÜR SPRACHMODELLE UND ENTWICKLER:
# Diese docker-compose.yml Datei ist die zentrale Orchestrierungsdatei für ALLE Docker-Services dieses Projekts. # 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' version: '3.8'
@@ -17,36 +12,16 @@ services:
ports: ports:
- "8090:80" # Synology Reverse Proxy should point to THIS port (8090) - "8090:80" # Synology Reverse Proxy should point to THIS port (8090)
volumes: 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 - ./.htpasswd:/etc/nginx/.htpasswd:ro
depends_on: depends_on:
- company-explorer dashboard:
- dashboard condition: service_started
- b2b-app company-explorer:
- market-frontend condition: service_healthy
- gtm-app connector-superoffice:
- transcription-app condition: service_healthy
- 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 --- # --- DASHBOARD ---
dashboard: dashboard:
@@ -69,184 +44,242 @@ services:
API_USER: "admin" API_USER: "admin"
API_PASSWORD: "gemini" API_PASSWORD: "gemini"
PYTHONUNBUFFERED: "1" 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: volumes:
- ./company-explorer:/app - ./company-explorer:/app
- ./data:/data # Mount for database # Mount named volume to a DIRECTORY, not a file
- ./Log_from_docker:/app/logs_debug # Logging Mount - explorer_db_data:/data
- ./Log_from_docker:/app/logs_debug
transcription-app: healthcheck:
build: test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
context: ./transcription-tool interval: 10s
dockerfile: Dockerfile timeout: 5s
container_name: transcription-app retries: 5
restart: unless-stopped start_period: 30s
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
connector-superoffice: connector-superoffice:
build: build:
context: . context: ./connector-superoffice
dockerfile: connector-superoffice/Dockerfile # Build context is now root dockerfile: Dockerfile
container_name: connector-superoffice container_name: connector-superoffice
restart: unless-stopped restart: unless-stopped
ports: ports:
- "8003:8000" # Expose internal 8000 to host 8003 (8002 was taken) - "8003:8000" # Expose internal 8000 to host 8003
volumes: volumes:
- ./connector-superoffice:/app/connector-superoffice # Mount subfolder to its own path in /app - ./connector-superoffice:/app
- ./data:/data # Data mount # Mount named volume to a DIRECTORY matching the Python code's expectation
- ./config.py:/app/config.py # Root config needs to be mounted - connector_db_data:/data
- ./helpers.py:/app/helpers.py # Root helper needs to be mounted
environment: environment:
PYTHONUNBUFFERED: "1" PYTHONUNBUFFERED: "1"
API_USER: "admin" API_USER: "admin"
API_PASSWORD: "gemini" 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" 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_ID: "${SO_CLIENT_ID}"
SO_CLIENT_SECRET: "${SO_CLIENT_SECRET}" SO_CLIENT_SECRET: "${SO_CLIENT_SECRET}"
SO_REFRESH_TOKEN: "${SO_REFRESH_TOKEN}" SO_REFRESH_TOKEN: "${SO_REFRESH_TOKEN}"
SO_ENVIRONMENT: "${SO_ENVIRONMENT}" SO_ENVIRONMENT: "${SO_ENVIRONMENT}"
SO_CONTEXT_IDENTIFIER: "${SO_CONTEXT_IDENTIFIER}" 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 --- # --- DISABLED SERVICES (Commented out but preserved) ---
duckdns:
image: lscr.io/linuxserver/duckdns:latest # heatmap-backend:
container_name: duckdns # build: ./heatmap-tool/backend
environment: # container_name: heatmap-backend
PUID: "1000" # User ID (anpassen falls nötig) # restart: unless-stopped
PGID: "1000" # Group ID (anpassen falls nötig) # volumes:
TZ: "Europe/Berlin" # - ./heatmap-tool/backend:/app
SUBDOMAINS: "floke,floke-ai,floke-gitea,floke-ha,floke-n8n"
TOKEN: "${DUCKDNS_TOKEN}" # From .env
restart: unless-stopped
dns-monitor: # heatmap-frontend:
image: alpine # build: ./heatmap-tool/frontend
container_name: dns-monitor # container_name: heatmap-frontend
dns: # restart: unless-stopped
- 8.8.8.8 # volumes:
- 1.1.1.1 # - ./heatmap-tool/frontend:/app
environment: # depends_on:
SUBDOMAINS: "floke,floke-ai,floke-gitea,floke-ha,floke-n8n" # - heatmap-backend
TZ: "Europe/Berlin"
volumes: # transcription-app:
- ./dns-monitor:/app # build:
command: "/app/monitor.sh" # context: ./transcription-tool
restart: unless-stopped # 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: volumes:
moltbot_data: {} # Volume for moltbot data, even if service is commented out. # moltbot_data: {}
connector_db_data: {}
explorer_db_data: {}

51
nginx-proxy-clean.conf Normal file
View File

@@ -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";
}
}
}

100
readme.md
View File

@@ -21,6 +21,63 @@ gitea: none
--- ---
# Projekt: Automatisierte Unternehmensbewertung & Lead-Generierung v2.2.1 # 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 ## 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. 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) ├── gtm-architect/ (React Frontend)
└── server.cjs (Node.js API-Bridge) └── 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) └── 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. * Der technische Aufwand für ein robustes System, das Karriereseiten findet, die verschiedenen Job-Portale parst und die relevanten Informationen extrahiert, ist immens.
* **Status:** * **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. * 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).