# Heatmap Tool (Standalone) Eine Webanwendung zur Visualisierung von Excel-Daten (XLSX) auf einer Deutschlandkarte. Das Tool aggregiert Daten basierend auf Postleitzahlen (PLZ) und stellt sie entweder als Punkte-Cluster oder als Heatmap dar. ## Features * **Excel Upload:** Lädt beliebige `.xlsx` Dateien. Erkennt automatisch die PLZ-Spalte (oder fragt nach, wenn unklar). * **Personal-Standorte:** Fest hinterlegte Standorte von Vertrieblern (Blau) und Technikern (Orange) können unabhängig von Excel-Daten eingeblendet werden. * **Einzugsgebiete (Isochronen):** * Visualisierung der Erreichbarkeit basierend auf echter Fahrtzeit über das Straßennetz (via OpenRouteService). * Berücksichtigt Autobahnen und Straßentypen (verzerrte Polygone statt perfekter Kreise). * **Fallback:** Automatisches Umschalten auf ein mathematisches Kreis-Modell (Radius = Zeit * Geschwindigkeit), falls kein API-Key vorhanden ist. * **Interaktive Planung:** Schieberegler für Fahrtzeit (bis 60 Min.) und Durchschnittsgeschwindigkeit zur Simulation von Reichweiten. * **Visualisierung:** * **Punkte-Karte:** Kreise pro PLZ, Radius = Anzahl der Einträge. Mit Marker-Clustering beim Herauszoomen. * **Heatmap:** Klassische Dichte-Darstellung. * **Interaktive Filter:** Alle anderen Spalten der Excel-Datei werden automatisch zu Filtern (Checkboxen). * **Dynamische Tooltips:** Benutzer können per Drag-and-Drop konfigurieren, welche Daten im Tooltip eines Punktes angezeigt werden. ## Installation & Start Das Projekt ist vollständig in den **GTM-Engine Stack** integriert. 1. **API Key konfigurieren:** Für echte Fahrtzeiten (Isochronen) einen kostenlosen Key auf [openrouteservice.org](https://openrouteservice.org/) erstellen und in der `.env` hinterlegen: ```env ORS_API_KEY=dein_key_hier ``` 2. Container starten (im Root-Verzeichnis): ```bash docker-compose up -d --build heatmap-frontend heatmap-backend ``` ## Architektur * **Frontend:** React 19, Vite, Leaflet (`react-leaflet`, `react-leaflet-cluster`, `react-leaflet-heatmap-layer-v3`). * **Interner Port:** 80 (Nginx) * **Routing:** `/heatmap/` (via Gateway) * **Backend:** Python FastAPI, Pandas, Requests (für ORS API). * **Interner Port:** 8000 * **Kommunikation:** Nginx (Frontend) leitet `/api/` Anfragen an das Backend weiter. ## Lessons Learned & Known Issues (WICHTIG!) ### 1. OpenRouteService (ORS) API Limits * **Limit:** Der kostenlose "Free Tier" erlaubt Isochronen bis maximal **60 Minuten**. * **Fehler:** Anfragen über 60 Min. resultieren in einem `400 Bad Request`. Das Frontend ist daher auf diesen Wert begrenzt. * **Debouncing:** Da API-Calls kontingentiert sind (500/Tag), werden Isochronen erst nach einer kurzen Pause (800ms) beim Schieben des Reglers angefordert. ### 2. Docker Networking & Nginx Proxy * **Integration:** Das Tool läuft nun hinter einem zentralen Nginx-Gateway. * **Pfad-Anpassung:** `vite.config.ts` nutzt `base: '/heatmap/'`, damit Assets korrekt geladen werden. * **API-Routing:** Das Frontend-Nginx (`nginx.conf`) proxied `/api/` an `http://heatmap-backend:8000`. Dies verhindert `405 Method Not Allowed` Fehler bei POST-Requests, die sonst vom statischen Server abgefangen würden. ### 2. React 19 vs. Leaflet Libraries * **Problem:** Viele Leaflet-Plugins (wie `react-leaflet-heatmap-layer-v3`) haben veraltete Peer-Dependencies (z.B. React 17), was bei `npm install` zu Fehlern führt. * **Lösung:** * Lokal: Installation mit `--legacy-peer-deps`. * **Docker Build:** Im `Dockerfile` des Frontends muss zwingend `RUN npm install --legacy-peer-deps` stehen, sonst schlägt der Build fehl. ### 3. Import/Export Syntax (TypeScript) * **Problem:** `Uncaught SyntaxError: The requested module ... does not provide an export named ...` * **Ursache:** Beim Importieren von TypeScript-Interfaces (z.B. `TooltipColumn`) in einer `.tsx` Datei wurde das Schlüsselwort `type` vergessen. * **Korrekt:** `import type { TooltipColumn } from '../App';` * **Falsch:** `import { TooltipColumn } from '../App';` (Führt zu Runtime-Fehlern im Browser, da Vite versucht, es als JS-Code zu kompilieren). ### 4. Endlosschleifen bei Karten-Events (Vorsicht!) * **Problem:** Versuch, eine "zoom-adaptive Legende" zu bauen, die den `maxCount` basierend auf dem sichtbaren Ausschnitt neu berechnet. * **Fehler:** Ein `useEffect` oder Event-Handler (`useMapEvents`), der den State (`visibleData`) aktualisiert, löst ein Re-Render der Karte aus. Das Re-Render löst erneut das Event aus -> **Endlosschleife / Stack Overflow**. * **Status:** Feature wurde reverted. Wenn wir das wieder einbauen, muss der Handler vom Rendering entkoppelt sein (z.B. via `useCallback` oder komplett außerhalb der Render-Logik der Map-Komponente). ### 5. Daten-Normalisierung * **Problem:** `KeyError: 'plz'`. Die Excel-Datei hatte "PLZ" (groß), das Backend erwartete "plz" (klein) oder umgekehrt. * **Lösung:** Das Backend normalisiert jetzt die Spaltennamen intern, bevor die Daten an das Frontend gesendet werden. Das Frontend verlässt sich strikt auf klein geschrieben `plz`, `lat`, `lon`.