# SE Local Trenddata SE Local Trenddata ist eine webbasierte Trend-, Dashboard- und Quellenverwaltung fuer lokale Anlagen- und WAGO-Daten. Das Projekt besteht aus einem React-Frontend, einer Node.js/Express-API, MariaDB, Redis und einem Collector-Service fuer Protokollquellen wie Modbus TCP, OPC UA, BACnet IP und KNX IP. Das Ziel ist, bestehende breite Trendtabellen wie `isp01`, `isp02` usw. weiter nutzen zu koennen und zusaetzlich neue Quellen sauber ueber eine Weboberflaeche anzulegen, zu scannen, zu loggen und im Dashboard oder in der Trendansicht auszuwerten. --- ## Inhaltsverzeichnis - [Projektaufbau](#projektaufbau) - [Architektur](#architektur) - [Services und Ports](#services-und-ports) - [Schnellstart mit Docker Compose](#schnellstart-mit-docker-compose) - [Lokale Entwicklung](#lokale-entwicklung) - [Konfiguration](#konfiguration) - [Login, Benutzer und Rollen](#login-benutzer-und-rollen) - [Frontend-Funktionen](#frontend-funktionen) - [API-Funktionen](#api-funktionen) - [Collector-Funktionen](#collector-funktionen) - [Datenbank und Speicher](#datenbank-und-speicher) - [WAGO- oder SD-Karten-Betrieb](#wago--oder-sd-karten-betrieb) - [Backup und Restore](#backup-und-restore) - [Deployment-Hinweise](#deployment-hinweise) - [Troubleshooting](#troubleshooting) - [Sicherheits-Checkliste](#sicherheits-checkliste) --- ## Projektaufbau ```text SeLTD/ ├── .env.example ├── docker-compose.yml ├── docker-compose.wago.yml ├── docker/ │ └── redis/ │ └── redis.conf ├── api/ │ ├── Dockerfile │ ├── package.json │ └── src/ │ ├── index.js │ ├── auth.js │ ├── config.js │ ├── db.js │ ├── redis.js │ └── lib/ │ ├── isp.js │ └── store.js ├── collector/ │ ├── Dockerfile │ ├── package.json │ └── src/ │ └── index.js └── web/ ├── Dockerfile ├── package.json ├── vite.config.js ├── public/ │ └── logo.png └── src/ ├── App.jsx ├── api.js ├── main.jsx ├── styles.css └── components/ ├── Gauge.jsx └── TrendChart.jsx ``` ### Hauptbereiche | Bereich | Aufgabe | | --- | --- | | `web/` | React/Vite-Frontend fuer Login, Dashboard, Trends, Admin-Bereich, Quellen, Rollen und Benutzer | | `api/` | Express-API fuer Auth, Rollen, Aliase, Trendabfragen, Dashboard, SQL-Import und Benutzerverwaltung | | `collector/` | HTTP-Service fuer Protokollquellen, Datenpunkte, Scans, Imports und zyklisches Logging | | `mariadb` | Persistente Trenddaten und Benutzer-Tabelle | | `redis` | Metadaten, Aliase, Rollen, Einheiten, Dashboards, Auswahlen und User-Praeferenzen | | `dockhand` | Docker-Verwaltung ueber Weboberflaeche | | `cadvisor` | Container-Metriken fuer Monitoring | --- ## Architektur ```text Browser │ │ http://localhost:5173 ▼ React/Vite Frontend (web) │ ├── API-Aufrufe: http://localhost:18080/api/... │ ▼ │ Express API (api, intern Port 8080) │ ├── MariaDB: Benutzer, Trendtabellen, SQL-Daten │ └── Redis: Rollen, Einheiten, Aliase, Dashboard, Auswahlen │ └── Collector-Aufrufe: http://localhost:18110/... ▼ Collector-Service ├── sources.json unter /app/data ├── Modbus TCP / OPC UA / BACnet / KNX └── schreibt aktive Datenpunkte in MariaDB-Trendtabellen ``` Wichtig: Die API laeuft im Container intern auf Port `8080`, wird aber nach aussen auf `18080` gemappt. Das Frontend muss deshalb im Browser auf `http://localhost:18080/api` zugreifen. --- ## Services und Ports | Service | Container | Interner Port | Host-Port | Zweck | | --- | --- | ---: | ---: | --- | | Web | `seltd-web` | 5173 | 5173 | React/Vite-Oberflaeche | | API | `seltd-api` | 8080 | 18080 | REST-API | | Collector | `seltd-collector` | 18110 | 18110 | Quellen, Datenpunkte, Scans, Polling | | MariaDB | `seltd-mariadb` | 3306 | 3306 | Trend- und Benutzerdaten | | Redis | `seltd-redis` | 6379 | 6379 | Metadaten und App-State | | Dockhand | `dockhand` | 3000 | 3000 | Docker-Webverwaltung | | cAdvisor | `cadvisor_ltd` | 8080 | 9090 | Container-Metriken | --- ## Schnellstart mit Docker Compose ### 1. Repository vorbereiten ```powershell cd C:\Projects\SeLTD copy .env.example .env ``` Passe danach mindestens diese Werte an: ```env JWT_SECRET=bitte-langen-zufaelligen-wert-setzen ADMIN_USERNAME=admin ADMIN_PASSWORD=ChangeMe123! MARIADB_ROOT_PASSWORD=SE3112 CORS_ORIGIN=http://localhost:5173 VITE_API_PORT=18080 ``` ### 2. Stack bauen und starten ```powershell docker compose up -d --build ``` Bei groesseren Aenderungen am Code oder wenn der Browser alten Code anzeigt: ```powershell docker compose down docker compose build --no-cache web api collector docker compose up -d ``` ### 3. Aufrufen | Anwendung | URL | | --- | --- | | Frontend | `http://localhost:5173` | | API Healthcheck | `http://localhost:18080/api/health` | | Collector Healthcheck | `http://localhost:18110/health` | | Dockhand | `http://localhost:3000` | | cAdvisor | `http://localhost:9090` | ### 4. Standard-Login ```text Username: admin Passwort: ChangeMe123! ``` Das Passwort sollte nach dem ersten Login geaendert werden. --- ## Lokale Entwicklung ### Frontend lokal starten ```powershell cd C:\Projects\SeLTD\web npm install npm run dev ``` Das Frontend laeuft dann auf: ```text http://localhost:5173 ``` ### API lokal starten ```powershell cd C:\Projects\SeLTD\api npm install npm run dev ``` Die API liest ihre Konfiguration aus `.env`. Wenn du die API lokal ohne Docker laufen laesst, muss `DB_HOST` auf den erreichbaren MariaDB-Host zeigen. ### Collector lokal starten ```powershell cd C:\Projects\SeLTD\collector npm install npm start ``` Der Collector braucht Zugriff auf MariaDB und schreibt seine lokale Konfiguration in `collector/data/sources.json`. --- ## Konfiguration Die wichtigsten Variablen liegen in `.env`. | Variable | Beispiel | Beschreibung | | --- | --- | --- | | `JWT_SECRET` | `change-me` | Signatur fuer Login-Tokens. In Produktion unbedingt aendern. | | `ADMIN_USERNAME` | `admin` | Initialer Admin-Username | | `ADMIN_EMAIL` | `admin@example.com` | Initiale Admin-E-Mail | | `ADMIN_PASSWORD` | `ChangeMe123!` | Initiales Admin-Passwort | | `ADMIN_NAME` | `System Admin` | Anzeigename des Admins | | `MARIADB_ROOT_PASSWORD` | `SE3112` | MariaDB-Root-Passwort | | `DB_PASSWORD_FALLBACK` | `root` | Fallback fuer alte Entwicklungsvolumes | | `CORS_ORIGIN` | `http://localhost:5173` | Erlaubter Browser-Ursprung fuer API-Aufrufe | | `VITE_API_PORT` | `18080` | API-Port, den das Frontend im Browser nutzt | | `POLL_TICK_MS` | `1000` | Collector-Tick fuer Polling-Pruefung | ### CORS Wenn das Frontend lokal auf `http://localhost:5173` laeuft, muss in der API stehen: ```env CORS_ORIGIN=http://localhost:5173 ``` Bei mehreren erlaubten Origins kann eine kommaseparierte Liste genutzt werden: ```env CORS_ORIGIN=http://localhost:5173,https://trend.example.local ``` --- ## Login, Benutzer und Rollen Die API legt beim Start automatisch einen Admin-Benutzer an oder aktualisiert den vorhandenen Admin. ### Systemrollen | Rolle | Rechte | | --- | --- | | `viewer` | Dashboard anzeigen, Trendansicht anzeigen | | `technician` | Dashboard, Trends, Aliase, Quellen, Debug | | `admin` | Alle Rechte inkl. Benutzer- und Rollenverwaltung | ### Rechtekatalog | Recht | Bedeutung | | --- | --- | | `view_dashboard` | Dashboard anzeigen und speichern | | `view_trends` | Trends anzeigen, Auswahlen nutzen | | `edit_aliases` | Aliase und Einheiten bearbeiten | | `manage_sources` | Quellen und Datenpunkte verwalten | | `manage_users` | Benutzer anlegen und bearbeiten | | `manage_roles` | Rollen und Rechte verwalten | | `view_debug` | Collector-Debug sehen | Benutzer, Rollen und Passwoerter werden ueber den Admin-Bereich verwaltet. --- ## Frontend-Funktionen ### Login - Username-basierter Login - JWT-Token wird im Browser gespeichert - Passwortwechsel ueber Einstellungen - Rollenbasierte Navigation ### Dashboard - Widgets aus aktueller Auswahl oder gespeicherter Auswahl - Widget-Typen: - Graph - Zahl - Zeigermanometer - Dashboard wird pro Benutzer gespeichert ### Trendansicht - Datenpunkte aus mehreren Trendtabellen kombinierbar - Auswahl speicherbar und optional fuer andere Benutzer freigebbar - Zeitraeume als Presets von 5 Minuten bis 30 Tage - Eigener Start-/Endzeitraum moeglich - Aktuelle Werte werden separat angezeigt - Fokusmodus fuer den Graphen ### Trend-Export Der Trendgraph kann exportiert werden als: - CSV - XLSX - PNG - JPG - SVG - PDF ### Admin: Aliase - Anzeigename und Beschreibung pro Trendtabelle - Alias, Einheit, Faktor, Typ, Min/Max und Farbe pro Wert - CSV-Import und CSV-Export - Encoding-/Grad-Celsius-Bereinigung ### Admin: Einheiten - Systemeinheiten wie `°C`, `%`, `K`, `V`, `A`, `Pa` - Eigene Einheiten wie `bar`, `m³/h`, `Hz` usw. - Einheitenauswahl bei Aliasen und Datenpunkten ### Admin: Quellen - Protokollquellen anlegen und bearbeiten - Unterstuetzte Protokolle in der UI: - Modbus TCP - OPC UA - BACnet IP - KNX IP - Poll-Intervall und Schreibmodus konfigurierbar - Scan-Ergebnisse und importierte Punkte koennen ins Logging uebernommen werden - Manuelle Datenpunkte koennen erstellt und bearbeitet werden --- ## API-Funktionen Die API laeuft unter: ```text http://localhost:18080/api ``` ### Authentifizierung | Methode | Pfad | Beschreibung | | --- | --- | --- | | `POST` | `/api/auth/login` | Login mit Username/Passwort | | `GET` | `/api/auth/me` | Aktuellen Benutzer lesen | | `POST` | `/api/auth/change-password` | Passwort aendern | ### Trends und ISPs | Methode | Pfad | Beschreibung | | --- | --- | --- | | `GET` | `/api/isps` | Verfuegbare Trendtabellen lesen | | `GET` | `/api/isps/:isp/aliases` | Alias-Metadaten lesen | | `PUT` | `/api/isps/:isp/aliases` | Alias-Metadaten speichern | | `POST` | `/api/trend-tables` | Neue Trendtabelle anlegen | | `POST` | `/api/trends/query` | Trenddaten abfragen | | `POST` | `/api/points/latest` | Letzte Werte lesen | ### Einheiten | Methode | Pfad | Beschreibung | | --- | --- | --- | | `GET` | `/api/units` | Einheiten lesen | | `POST` | `/api/units` | Einheit anlegen | | `PATCH` | `/api/units/:symbol` | Einheit bearbeiten | ### Benutzer und Rollen | Methode | Pfad | Beschreibung | | --- | --- | --- | | `GET` | `/api/users` | Benutzerliste | | `POST` | `/api/users` | Benutzer anlegen | | `PATCH` | `/api/users/:id` | Benutzer bearbeiten | | `GET` | `/api/roles` | Rollenliste inkl. Rechtekatalog | | `POST` | `/api/roles` | Rolle anlegen | | `PATCH` | `/api/roles/:name` | Rolle bearbeiten | ### Auswahlen und Dashboard | Methode | Pfad | Beschreibung | | --- | --- | --- | | `GET` | `/api/selections` | Gespeicherte Auswahlen lesen | | `POST` | `/api/selections` | Auswahl speichern | | `PUT` | `/api/selections/:selectionId` | Auswahl aktualisieren | | `DELETE` | `/api/selections/:selectionId` | Auswahl loeschen | | `GET` | `/api/dashboard` | Dashboard laden | | `PUT` | `/api/dashboard` | Dashboard speichern | | `POST` | `/api/dashboard/data` | Widget-Daten laden | | `GET` | `/api/preferences` | Benutzerpraeferenzen laden | | `PUT` | `/api/preferences` | Benutzerpraeferenzen speichern | --- ## Collector-Funktionen Der Collector laeuft unter: ```text http://localhost:18110 ``` Er verwaltet Quellen und Datenpunkte in einer JSON-Datei (`/app/data/sources.json`) und schreibt aktive Punkte zyklisch in MariaDB. ### Collector-Endpunkte | Methode | Pfad | Beschreibung | | --- | --- | --- | | `GET` | `/health` | Healthcheck | | `GET` | `/capabilities` | Unterstuetzte Protokolle/Funktionen | | `GET` | `/sources` | Quellen lesen | | `POST` | `/sources` | Quelle anlegen | | `PUT` | `/sources/:id` | Quelle bearbeiten | | `DELETE` | `/sources/:id` | Quelle loeschen | | `GET` | `/datapoints` | Datenpunkte lesen | | `POST` | `/datapoints/manual` | Datenpunkt manuell anlegen | | `PATCH` | `/datapoints/:id` | Datenpunkt bearbeiten, aktivieren, deaktivieren | | `POST` | `/datapoints/:id/read` | Live-Wert lesen | | `POST` | `/imports/modbus-csv` | Modbus-CSV importieren | | `POST` | `/imports/knx-xml` | KNX-XML importieren | | `POST` | `/scan/opcua` | OPC-UA-Scan starten | | `POST` | `/scan/bacnet` | BACnet-Scan starten | | `GET` | `/debug` | Debugdaten lesen | ### Schreibmodus | Modus | Bedeutung | | --- | --- | | `interval` | Jeder Poll wird geschrieben | | `cov` | Nur bei Wertaenderung wird geschrieben | ### Aktive vs. inaktive Datenpunkte - Inaktive Datenpunkte sind gefunden/importiert, werden aber nicht geloggt. - Aktive Datenpunkte werden vom Collector gepollt und in die zugehoerige Trendtabelle geschrieben. - In der Weboberflaeche entspricht das der Trennung zwischen „Gefunden / importiert“ und „Wird geloggt“. --- ## Datenbank und Speicher ### MariaDB MariaDB speichert: - `app_users` - bestehende `isp...` Tabellen - neue `trend_...` Tabellen - Registry-Tabellen fuer Quellen und Datenpunkte, falls vom Collector/API genutzt Die API kann bestehende breite Tabellen mit `Wert1`, `Wert2`, ... lesen. Neue lokale Trendtabellen koennen bis zu 2000 Werte unterstuetzen. ### Redis Redis speichert: - Rollen - Einheiten - Aliase und Tabellen-Metadaten - Auswahlen - Dashboard-Konfiguration - Benutzerpraeferenzen Redis sollte deshalb ebenfalls gebackupt werden, nicht nur MariaDB. --- ## WAGO- oder SD-Karten-Betrieb Fuer Systeme, bei denen persistente Daten auf SD-Karte liegen sollen, gibt es ein Override: ```powershell docker compose -f docker-compose.yml -f docker-compose.wago.yml up -d --build ``` Dabei werden grosse Daten nach `/media/sd/seltd/...` gelegt: ```text /media/sd/seltd/mariadb /media/sd/seltd/redis /media/sd/seltd/collector /media/sd/seltd/dockhand ``` Vorher sicherstellen: ```bash mkdir -p /media/sd/seltd/mariadb /media/sd/seltd/redis /media/sd/seltd/collector /media/sd/seltd/dockhand ``` --- ## Backup und Restore ### MariaDB Backup ```powershell docker exec seltd-mariadb mariadb-dump -uroot -pSE3112 --all-databases > seltd-mariadb-backup.sql ``` Restore: ```powershell type .\seltd-mariadb-backup.sql | docker exec -i seltd-mariadb mariadb -uroot -pSE3112 ``` ### Redis Backup Redis nutzt ein Docker-Volume. Fuer ein einfaches Dateibackup: ```powershell docker run --rm -v seltd_redis_data:/data -v ${PWD}:/backup alpine tar czf /backup/seltd-redis-backup.tar.gz -C /data . ``` ### Collector Backup ```powershell docker run --rm -v seltd_collector_data:/data -v ${PWD}:/backup alpine tar czf /backup/seltd-collector-backup.tar.gz -C /data . ``` --- ## Deployment-Hinweise ### Nach Code-Aenderungen Wenn Frontend oder API geaendert wurden: ```powershell docker compose build --no-cache web api collector docker compose up -d ``` Wenn nur `.env` geaendert wurde: ```powershell docker compose up -d ``` ### Browsercache Bei alten JavaScript-Fehlern nach einem Fix: ```text Strg + F5 ``` oder Vite/Docker neu bauen. ### Nginx Proxy Manager Wenn das Frontend hinter Nginx laeuft, muessen die API- und Collector-URLs sauber erreichbar sein. Entweder: - Frontend, API und Collector unter eigenen Subdomains veroeffentlichen, oder - Nginx so konfigurieren, dass `/api` zur API und `/collector` zum Collector weitergeleitet wird. In diesem Fall kann `VITE_API_URL` statt `VITE_API_PORT` gesetzt werden: ```env VITE_API_URL=https://trend-api.example.local/api VITE_COLLECTOR_URL=https://trend-collector.example.local ``` --- ## Troubleshooting ### Fehler: `NetworkError when attempting to fetch resource` Ursachen: - API-Container laeuft nicht - falscher Port im Frontend - CORS nicht korrekt - Browser ruft alte Version auf Pruefen: ```powershell docker ps curl http://localhost:18080/api/health ``` Wenn Frontend lokal auf `localhost:5173` laeuft: ```env CORS_ORIGIN=http://localhost:5173 ``` Danach API neu starten: ```powershell docker compose restart api ``` ### Fehler: Browser zeigt alte React-Fehler nach Fix Sehr wahrscheinlich wurde das Docker-Image nicht neu gebaut. ```powershell docker compose down docker compose build --no-cache web api collector docker compose up -d ``` Danach im Browser `Strg + F5`. ### Fehler: `ReferenceError: editingCollectorPointId is not defined` In `web/src/App.jsx` muss folgender State vorhanden sein: ```jsx const [editingCollectorPointId, setEditingCollectorPointId] = useState(""); ``` Wenn die Zeile vorhanden ist, der Fehler aber weiterhin erscheint, laeuft noch altes Build-/Container-Material. ### Fehler: `SyntaxError: missing ) after argument list` in `isp.js` Bei SQL-Template-Strings muessen Backticks im String escaped werden: ```js missing.push(`ADD COLUMN \`${columnName}\` TEXT NULL`); ``` ### Fehler: `Rollup failed to resolve import "jspdf"` Abhaengigkeiten im Frontend installieren: ```powershell cd web npm install jspdf xlsx recharts ``` Bei Docker danach neu bauen. ### Source-Map-Warnungen im Browser Warnungen wie diese sind in der Regel nicht kritisch: ```text Source map error: JSON.parse: unexpected character... ``` Sie kommen oft aus Devtools/React-Devtools oder externen Source-Maps und koennen ignoriert werden, solange keine roten Laufzeitfehler auftreten. ### MariaDB Login oder DB-Verbindung fehlgeschlagen Logs ansehen: ```powershell docker logs seltd-api --tail 100 docker logs seltd-mariadb --tail 100 ``` Pruefen, ob MariaDB healthy ist: ```powershell docker ps ``` ### Redis-Probleme ```powershell docker exec seltd-redis redis-cli ping ``` Erwartet: ```text PONG ``` --- ## Nuetzliche Befehle ### Alle Container anzeigen ```powershell docker compose ps ``` ### Logs live verfolgen ```powershell docker compose logs -f ``` Nur API: ```powershell docker logs seltd-api -f ``` Nur Frontend: ```powershell docker logs seltd-web -f ``` Nur Collector: ```powershell docker logs seltd-collector -f ``` ### Komplett neu starten ```powershell docker compose restart ``` ### Komplett neu bauen ```powershell docker compose down docker compose build --no-cache docker compose up -d ``` ### Volumes loeschen Achtung: Dadurch gehen Daten verloren. ```powershell docker compose down -v ``` --- ## Sicherheits-Checkliste Vor produktiver Nutzung: - [ ] `JWT_SECRET` auf langen zufaelligen Wert setzen - [ ] Admin-Passwort aendern - [ ] MariaDB-Root-Passwort aendern - [ ] `CORS_ORIGIN` nicht auf `*` lassen, sondern feste Domain setzen - [ ] MariaDB-Port `3306` nicht ungeschuetzt ins Internet veroeffentlichen - [ ] Redis-Port `6379` nicht ungeschuetzt ins Internet veroeffentlichen - [ ] Dockhand absichern oder nur intern bereitstellen - [ ] Backups fuer MariaDB, Redis und Collector-Daten einrichten - [ ] Reverse Proxy mit HTTPS verwenden --- ## Bekannte Hinweise - Leere Trendtabellen erscheinen nicht in der Trendauswahl, aber im Admin-Bereich. - Bestehende breite `isp...` Tabellen bleiben kompatibel. - Neue lokale Tabellen koennen als `trend_...` Tabellen angelegt werden. - Der Collector speichert seine Quellen/Datenpunkte aktuell dateibasiert in `sources.json`. - Fuer vollstaendige Protokollintegration muessen je nach Feldbus noch Details wie Adressierung, Datentyp, Byteorder und Authentifizierung sauber projektspezifisch gepflegt werden. --- ## Kurzfassung fuer Betrieb ```powershell cd C:\Projects\SeLTD copy .env.example .env notepad .env docker compose up -d --build ``` Dann aufrufen: ```text http://localhost:5173 ``` Login: ```text admin / ChangeMe123! ``` Bei Code-Aenderungen: ```powershell docker compose build --no-cache web api collector docker compose up -d ```