7.0 KiB
🧠 Architekturübersicht – NodeMap
Dieses Dokument beschreibt die technische Gesamtarchitektur des Projekts NodeMap, einer kartenbasierten Webanwendung zur Anzeige, Bearbeitung und Verwaltung von GIS-Daten, POIs und Gerätestatus.
⚙️ Technologie-Stack
| Komponente | Beschreibung |
|---|---|
| Frontend | React 18 + Next.js (App Router) |
| State-Management | Redux Toolkit mit zentralem Store, Thunks & Slices |
| UI | Tailwind CSS + Leaflet + React-Icons |
| Backend-Anbindung | Webservices via WebServiceMap.asmx (IIS) + lokale Next.js API für DB |
| Datenbank | MySQL (Produktiv & Entwicklung, z. T. via Docker) |
| Deployment | Windows Server (IIS), optional per nssm als Dienst |
🗺️ Architekturüberblick
+------------------+ +------------------+ +------------------+
| Leaflet Map | <---> | Redux Store | <---> | Webservices |
| (Interaktivität) | | (Status & Data) | | (IIS, .asmx) |
+------------------+ +------------------+ +------------------+
^
|
v
+------------------+ +------------------+ +-------------------+
| POI-Komponenten | <---> | Redux Slices | <---> | Next.js API-Routen|
| (Add/Edit) | | (z. B. poiSlice) | | (Datenbank) |
+------------------+ +------------------+ +-------------------+
🔁 Datenfluss (Beispiel: POI anzeigen)
- Leaflet-Karte lädt bei
MapComponentMounting - Redux-Thunk
fetchPoiMarkersThunkwird ausgelöst - Thunk ruft
fetchPoiDataService.js(DB) oder Webservice (IIS) auf - Ergebnisse werden im Slice
readPoiMarkersStoreSlicegespeichert - Komponenten lesen POI-Daten über
useSelector(...)aus dem Store - POIs werden als Marker in Leaflet gesetzt
📁 Schlüsselfunktionen & Module
| Bereich | Datei/Modul | Aufgabe |
|---|---|---|
| Kartenlogik | MapComponent.js |
Zentrale Initialisierung und Layer-Logik |
| Webservices | services/webservice/ |
Kommunikation mit TALAS V5 Webservice |
| Datenbank | services/database/ |
Zugriff auf lokale Next.js-API & DB |
| POIs | AddPOIModal.js, PoiUpdateModal.js |
UI für POI-Erstellung & -Bearbeitung |
| Redux | redux/slices/, redux/thunks/, redux/store |
Globaler State, API-Steuerung |
| Konfiguration | .env.local, config.js, dynamic URLs |
IP, basePath, Ports |
🧩 Besonderheiten
- Konfigurierbarer basePath:
Pfad wie/talas5ist optional und kann perNEXT_PUBLIC_BASE_PATHin.env.localgesetzt werden. - Rechteabhängige UI:
Funktionen (z. B. POI bearbeiten) basieren auf Benutzerrechten (IdRight) vom Server. - Zentrale Komponentensteuerung:
Komponenten wieMapLayersControlPaneloderCoordinatePopupkontrollieren Layer & Interaktion. - Kontextmenü-Logik:
Marker & Polylinien besitzen eigene Kontextmenüs – dynamisch zusammengesetzt und verwaltet.
📦 Versionierung & Builds
- Version ist in
appVersion.jsdefiniert → wird überNEXT_PUBLIC_APP_VERSIONeingeblendet - Build erfolgt via
npm run build, Auslieferung über.next/ - Nicht benötigte Dateien wie
__tests__,docs/,scripts/etc. werden nicht in den Build aufgenommen
📚 Weiterführende Dokumentation
Dynamische Layer-Verwaltung mit Redux
flowchart TD
%% Webservice
subgraph Webservice
A1[GisSystemStatic API]
A2[GisStationsStaticDistrict API]
end
%% Redux
subgraph Redux
B1[fetchGisSystemStaticThunk]
B2[fetchGisStationsStaticDistrictThunk]
C1["gisSystemStaticSlice → selectGisSystemStatic"]
C2["gisStationsStaticDistrictSlice → selectGisStationsStaticDistrict"]
C3["mapLayersSlice → mapLayersVisibility"]
end
%% React
subgraph React-Komponente
D1[MapComponent.js]
D2["useEffect: dynamische Layer"]
D3["createAndSetDevices"]
D4["layerRefs (useRef)"]
D5["markerStates (useState)"]
D6["useEffect: Sichtbarkeit prüfen"]
D7["Map aktualisieren / add/remove"]
D8["checkOverlappingMarkers"]
end
%% Datenfluss
A1 --> B1 --> C1 --> D2
A2 --> B2 --> C2 --> D3
C3 --> D6
D2 --> D3
D3 --> D4
D3 --> D5
D5 --> D6
D6 --> D7
D6 --> D8
D7 --> D1
Jetzt (dynamisch & Redux-basiert): MapComponent.js ruft folgenden Hook auf:
js Copy Edit const { markerStates, layerRefs } = useDynamicDeviceLayers(map, GisSystemStatic, mapLayersVisibility, priorityConfig, oms); useDynamicDeviceLayers.js verarbeitet die GisSystemStatic-Liste:
Jedes System (z. B. "TALAS", "ECI", "Cisco") bekommt einen eigenen Marker-Layer.
Die Marker werden erstellt durch:
js Copy Edit createAndSetDevices(...) // Systemweise Marker erzeugen createAndSetDevices.js:
Filtert alle Stations aus staticDistrictData, deren System === IdSystem.
Erstellt Marker für jedes Gerät.
Bindet Popup, Kontextmenü, Styling, Bounce usw.
Ruft setMarkersFunction(markers) auf → Übergibt die Marker zurück an den Hook.
Der Hook speichert:
js Copy Edit setMarkerStates((prev) => ({ ...prev, [Name]: newMarkers })); MapComponent.js hat dann:
Zugriff auf alle Marker dynamisch über markerStates (ein Objekt mit Schlüssel = Systemname)
Sichtbarkeit und OverlappingMarkerSpiderfier werden damit verarbeitet.
🔁 Die Geräte-Marker sind nicht mehr fest codiert, sondern werden dynamisch erzeugt anhand der Webservice-Daten GisSystemStatic.
🔄 Sichtbarkeit (Checkbox im Control Panel) löst ein Event visibilityChanged aus → MapComponent reagiert und rendert Marker neu.
🕷️ Überlappende Marker werden mit checkOverlappingMarkers + PlusRoundIcon verarbeitet.
flowchart TD
A1[MapComponent] --> B1[useDynamicDeviceLayers]
B1 --> C1[loop über GisSystemStatic]
C1 --> D1[createAndSetDevices]
D1 --> E1[Filter stations aus Redux]
E1 --> F1[erstelle Marker /Leaflet]
F1 --> G1[Marker in LayerGroup einfügen]
G1 --> H1[setMarkerStates im Hook]
H1 --> A2[markerStates zurück nach MapComponent]
A2 --> I1[Map aktualisiert Marker]
A2 --> I2[checkOverlappingMarkers mit OMS]