# Location Tracker - Next.js Anwendung Eine moderne Location-Tracking Anwendung basierend auf Next.js 14 mit MQTT/OwnTracks Integration, SQLite-Datenbank, Admin-Panel und Authentifizierung. ## 📋 Inhaltsverzeichnis - [Features](#-features) - [Tech Stack](#-tech-stack) - [Installation](#-installation) - [Datenbank-Setup](#-datenbank-setup) - [Verwendung](#-verwendung) - [Architektur](#-architektur) - [API-Endpunkte](#-api-endpunkte) - [Device Management](#-device-management) - [Wartung](#-wartung) - [Deployment](#-deployment) --- ## ✹ Features ### Öffentliche Features - đŸ—ș **Interaktive Karte** - Echtzeit-Standortverfolgung mit Leaflet.js - 🎹 **Mehrere Kartenansichten** - Standard, Satellit, Dark Mode - 🔍 **Device-Filterung** - Filtern nach GerĂ€t und Zeitraum - ⏱ **Flexible Zeitfilter**: - **Quick Filters:** 1h, 3h, 6h, 12h, 24h, All - **Custom Range:** Benutzerdefinierter Zeitraum mit DateTime-Picker (z.B. 16.11.2025 16:00 - 17.11.2025 06:00) - Kompakte UI - Custom Range nur sichtbar wenn aktiviert - 🔄 **Auto-Refresh** - Automatische Aktualisierung alle 5 Sekunden mit Pause/Resume Button - 🎯 **Auto-Center** - Karte zentriert automatisch auf neueste Position - ⏞ **Pause/Resume** - Toggle-Button zum Stoppen/Starten des Auto-Refresh - đŸ“± **Responsive Design** - Optimiert fĂŒr Desktop und Mobile - 📊 **Polylines** - Bewegungspfade mit farbcodierter Darstellung - 🎹 **Marker-Sortierung** - Neueste Position immer im Vordergrund (z-index optimiert) - 📍 **Zoom-basierte Icon-Skalierung** - Marker passen sich automatisch an Zoom-Level an ### Admin-Panel (Login erforderlich) - 🔐 **Authentifizierung** - NextAuth.js v5 mit bcrypt-Hashing - 📊 **Dashboard** - Übersicht ĂŒber GerĂ€te, Statistiken und Datenbankstatus - ⏱ **System Status** - Live-Uptime, Memory Usage, Runtime Info - đŸ“± **Device Management** - GerĂ€te hinzufĂŒgen, bearbeiten, löschen - đŸ’Ÿ **Datenbank-Wartung**: - đŸ§č Cleanup alter Daten (7, 15, 30, 90 Tage) - ⚡ Datenbank-Optimierung (VACUUM) - 📈 Detaillierte Statistiken - 🟱 **Online/Offline Status** - Echtzeit-Status (< 10 Min = Online) - 🔋 **Telemetrie-Daten** - Batterie, Geschwindigkeit, letzte Position (speed=0 wird korrekt behandelt) --- ## 🛠 Tech Stack - **Framework:** Next.js 14 (App Router) - **Sprache:** TypeScript 5.9 - **Styling:** Tailwind CSS v4 - **Karten:** Leaflet 1.9.4 + React-Leaflet 5.0 - **Authentifizierung:** NextAuth.js v5 (beta) - **Datenbank:** SQLite (better-sqlite3) - **Passwort-Hashing:** bcryptjs - **Datenquelle:** MQTT Broker + lokale SQLite-Cache ### Dual-Database Architektur - **database.sqlite** - User, GerĂ€te (kritische Daten) - **locations.sqlite** - Location-Tracking (hohe Schreibrate, isoliert) --- ## 📩 Installation ### Voraussetzungen - Node.js 18+ - npm oder yarn ### Schritte 1. **Repository klonen** ```bash git clone https://github.com/yourusername/location-tracker-app.git cd location-tracker-app ``` 2. **Dependencies installieren** ```bash npm install ``` 3. **Datenbank initialisieren** ```bash npm run db:init ``` Dies erstellt: - `data/database.sqlite` (User + Devices) - `data/locations.sqlite` (Location-Tracking) - Standard Admin-User: `admin` / `admin123` - Standard Devices (ID 10, 11) 4. **Development Server starten** ```bash npm run dev ``` 5. **Im Browser öffnen** - Karte: http://localhost:3000 - Login: http://localhost:3000/login - Admin: http://localhost:3000/admin - Devices: http://localhost:3000/admin/devices --- ## đŸ—„ïž Datenbank-Setup ### Initialisierung **Beide Datenbanken erstellen:** ```bash npm run db:init ``` **Nur database.sqlite (User/Devices):** ```bash npm run db:init:app ``` **Nur locations.sqlite (Tracking):** ```bash npm run db:init:locations ``` ### Datenbank zurĂŒcksetzen **Admin-User neu anlegen:** ```bash node scripts/reset-admin.js ``` **Alte Locations löschen:** ```bash npm run db:cleanup # Älter als 7 Tage npm run db:cleanup:7d # Älter als 7 Tage npm run db:cleanup:30d # Älter als 30 Tage ``` **Duplikate entfernen (falls vorhanden):** ```bash node scripts/remove-duplicates.js ``` ### Schema #### **database.sqlite** (User & Devices) **User Tabelle:** ```sql id TEXT PRIMARY KEY username TEXT UNIQUE NOT NULL email TEXT passwordHash TEXT NOT NULL role TEXT NOT NULL DEFAULT 'VIEWER' -- ADMIN oder VIEWER createdAt TEXT DEFAULT (datetime('now')) updatedAt TEXT DEFAULT (datetime('now')) lastLoginAt TEXT ``` **Device Tabelle:** ```sql id TEXT PRIMARY KEY name TEXT NOT NULL color TEXT NOT NULL ownerId TEXT -- FK zu User.id isActive INTEGER DEFAULT 1 -- 0 oder 1 description TEXT icon TEXT createdAt TEXT DEFAULT (datetime('now')) updatedAt TEXT DEFAULT (datetime('now')) ``` **Indexes:** - `idx_user_username` ON User(username) - `idx_device_owner` ON Device(ownerId) - `idx_device_active` ON Device(isActive) --- #### **locations.sqlite** (Tracking Data) **Location Tabelle:** ```sql id INTEGER PRIMARY KEY AUTOINCREMENT latitude REAL NOT NULL -- -90 bis +90 longitude REAL NOT NULL -- -180 bis +180 timestamp TEXT NOT NULL -- ISO 8601 format user_id INTEGER DEFAULT 0 first_name TEXT last_name TEXT username TEXT -- Device Tracker ID marker_label TEXT display_time TEXT -- Formatierte Zeit fĂŒr UI chat_id INTEGER DEFAULT 0 battery INTEGER -- Batteriestand in % speed REAL -- Geschwindigkeit in km/h created_at TEXT DEFAULT (datetime('now')) ``` **Indexes:** - `idx_location_timestamp` ON Location(timestamp DESC) - `idx_location_username` ON Location(username) - `idx_location_user_id` ON Location(user_id) - `idx_location_composite` ON Location(user_id, username, timestamp DESC) - `idx_location_unique` UNIQUE ON Location(timestamp, username, latitude, longitude) **Constraints:** - Latitude: -90 bis +90 - Longitude: -180 bis +180 - UNIQUE: Kombination aus timestamp, username, latitude, longitude verhindert Duplikate **WAL Mode:** Beide Datenbanken nutzen Write-Ahead Logging fĂŒr bessere Concurrency --- ## 🚀 Verwendung ### Login Standard-Zugangsdaten: ``` Benutzername: admin Passwort: admin123 ``` ⚠ **Wichtig:** FĂŒr Production neuen User anlegen und Passwort Ă€ndern! ### GerĂ€te hinzufĂŒgen 1. Admin-Panel öffnen: `/admin/devices` 2. "Add Device" klicken 3. Device ID (muss mit OwnTracks `tid` ĂŒbereinstimmen) 4. Name und Farbe festlegen 5. Speichern **Wichtig:** Die Device ID muss mit der OwnTracks Tracker-ID ĂŒbereinstimmen! ### OwnTracks konfigurieren In der OwnTracks App: - **Tracker ID (tid):** z.B. `12` - **Topic:** `owntracks/user/12` - MQTT Broker konfigurieren (siehe MQTT Setup) Die App empfĂ€ngt die Daten direkt vom MQTT Broker. ### Zeitfilter verwenden Die App bietet zwei Modi fĂŒr die Zeitfilterung: #### **Quick Filters** (Schnellauswahl) Vordefinierte ZeitrĂ€ume fĂŒr schnellen Zugriff: - **1 Hour** - Locations der letzten Stunde - **3 Hours** - Locations der letzten 3 Stunden - **6 Hours** - Locations der letzten 6 Stunden - **12 Hours** - Locations der letzten 12 Stunden - **24 Hours** - Locations der letzten 24 Stunden - **All** - Alle verfĂŒgbaren Locations **Verwendung:** 1. Im Header unter "Time:" gewĂŒnschten Zeitraum auswĂ€hlen 2. Die Karte aktualisiert sich automatisch #### **Custom Range** (Benutzerdefiniert) FĂŒr spezifische ZeitrĂ€ume, z.B. "Route von gestern Abend 18:00 bis heute Morgen 08:00": **Verwendung:** 1. Auf den **"📅 Custom"** Button klicken 2. Custom Range Felder erscheinen: - **From:** Start-Datum und -Zeit wĂ€hlen (z.B. 16.11.2025 16:00) - **To:** End-Datum und -Zeit wĂ€hlen (z.B. 17.11.2025 06:00) 3. Die Route wird automatisch fĂŒr den gewĂ€hlten Zeitraum angezeigt 4. Zum ZurĂŒckschalten: **"📅 Quick"** Button klicken **Hinweis:** Custom Range Controls sind nur sichtbar wenn aktiviert - spart Platz im Header! --- ## 🏗 Architektur ### Datenfluss ```mermaid flowchart TD A[đŸ“± OwnTracks App] -->|MQTT Publish| B[🔌 MQTT Broker] B -->|Subscribe| C[📡 Next.js MQTT Subscriber] C -->|Store Locations| D[(đŸ—„ïž SQLite Cache
locations.sqlite)] E[đŸ–„ïž Browser Client] -->|GET /api/locations
alle 5 Sek| F[📡 Next.js API Route] D -->|Query Filtered Data| F F -->|JSON Response| E E -->|Render| G[đŸ—ș React Leaflet Map] H[đŸ‘€ Admin User] -->|Login| I[🔐 NextAuth.js] I -->|Authenticated| J[📊 Admin Panel] J -->|CRUD Operations| K[(đŸ’Œ SQLite DB
database.sqlite)] style A fill:#4CAF50 style B fill:#FF9800 style C fill:#2196F3 style D fill:#FFC107 style F fill:#00BCD4 style G fill:#8BC34A style I fill:#E91E63 style K fill:#FFC107 ``` ### Komponenten-Übersicht ```mermaid graph LR subgraph "External Services" A[OwnTracks App] B[MQTT Broker] end subgraph "Next.js Application" C[MQTT Subscriber] D[Frontend
React/Leaflet] E[API Routes] F[Auth Layer
NextAuth.js] end subgraph "Data Layer" G[locations.sqlite
Tracking Data] H[database.sqlite
Users & Devices] end A -->|MQTT| B B -->|Subscribe| C C -->|Write| G D -->|HTTP| E E -->|Read/Write| G E -->|Read/Write| H D -->|Auth| F F -->|Validate| H style A fill:#4CAF50,color:#fff style B fill:#FF9800,color:#fff style C fill:#2196F3,color:#fff style D fill:#00BCD4,color:#000 style E fill:#00BCD4,color:#000 style F fill:#E91E63,color:#fff style G fill:#FFC107,color:#000 style H fill:#FFC107,color:#000 ``` ### Datenbank-Architektur ```mermaid erDiagram USER ||--o{ DEVICE : owns DEVICE ||--o{ LOCATION : tracks USER { string id PK string username UK string email string passwordHash string role datetime createdAt datetime lastLoginAt } DEVICE { string id PK string name string color string ownerId FK boolean isActive string description datetime createdAt } LOCATION { int id PK float latitude float longitude datetime timestamp string username FK int user_id string display_time int battery float speed int chat_id } ``` ### Auto-Refresh Mechanismus Die App verwendet einen **Echtzeit-Ansatz**: 1. **MQTT Subscriber** empfĂ€ngt OwnTracks Messages direkt vom Broker 2. **Locations** werden sofort in SQLite gespeichert 3. **Frontend polling** (alle 5 Sek.) → `/api/locations` 4. **API liest** gefilterte Daten aus lokalem SQLite Cache 5. **Duplikate** werden durch UNIQUE Index verhindert **Vorteile:** - Echtzeitdaten ohne Verzögerung - Schnelle Antwortzeiten (direkter SQLite Zugriff) - LĂ€ngere ZeitrĂ€ume abrufbar (24h+) - Keine externen Dependencies (kein n8n nötig) - Duplikate werden automatisch verhindert (UNIQUE Index) ### Datenvalidierung & Normalisierung Die App behandelt spezielle FĂ€lle bei speed/battery korrekt: **speed = 0 Behandlung:** - MQTT sendet `speed: 0` (gĂŒltig - GerĂ€t steht still) - Wird mit `typeof === 'number'` Check explizit als `0` gespeichert - Wird NICHT zu `null` konvertiert (wichtig fĂŒr Telemetrie) - Popup zeigt "Speed: 0.0 km/h" an **Debug-Logging:** - Server-Logs zeigen MQTT Message-Verarbeitung - Browser Console zeigt Daten-Flow (MapView, Popup) - Hilfreich fĂŒr Troubleshooting --- ## 📡 API-Endpunkte ### Öffentlich **GET /api/locations** - Location-Daten abrufen (aus SQLite Cache) - Query-Parameter: - `username` - Device-Filter (z.B. "10", "11") - **Zeitfilter (wĂ€hle eine Methode):** - `timeRangeHours` - Quick Filter (1, 3, 6, 12, 24) - `startTime` & `endTime` - Custom Range (ISO 8601 Format) - `limit` - Max. Anzahl (Standard: 1000) **Beispiele:** ```bash # Quick Filter: Letzte 3 Stunden GET /api/locations?timeRangeHours=3 # Custom Range: Spezifischer Zeitraum GET /api/locations?startTime=2025-11-16T16:00:00.000Z&endTime=2025-11-17T06:00:00.000Z # Kombiniert: Device + Custom Range GET /api/locations?username=10&startTime=2025-11-16T16:00:00.000Z&endTime=2025-11-17T06:00:00.000Z ``` **GET /api/devices/public** - Öffentliche Device-Liste (nur ID, Name, Color) ### GeschĂŒtzt (Login erforderlich) **GET /api/devices** - Alle GerĂ€te mit Latest Location und Telemetrie **POST /api/devices** - Neues GerĂ€t erstellen - Body: `{ id, name, color, description? }` **PATCH /api/devices/:id** - GerĂ€t aktualisieren - Body: `{ name?, color?, description? }` **DELETE /api/devices/:id** - GerĂ€t löschen (soft delete) **POST /api/locations/cleanup** - Alte Locations löschen - Body: `{ retentionHours }` **POST /api/locations/optimize** - VACUUM + ANALYZE ausfĂŒhren - Gibt freigegebenen Speicher zurĂŒck **GET /api/locations/stats** - Detaillierte DB-Statistiken - GrĂ¶ĂŸe, Zeitraum, Locations pro Device **GET /api/system/status** - System-Status abrufen - Returns: Uptime, Memory Usage, Node.js Version, Platform - Auto-Refresh: Alle 10 Sekunden im Admin-Panel --- ## đŸ“± Device Management ### Device-Karte zeigt: - 🟱/⚫ **Online/Offline Status** - Online = letzte Location < 10 Minuten - Offline = letzte Location > 10 Minuten - 🕒 **Last Seen** - Zeitstempel letzter Location - 🔋 **Batterie** - Prozent (Rot bei < 20%) - 🚗 **Geschwindigkeit** - km/h (umgerechnet von m/s) - 📍 **Koordinaten** - Lat/Lon mit 5 Dezimalen ### Auto-Refresh - Devices-Seite aktualisiert sich alle 10 Sekunden - Online/Offline Status wird automatisch aktualisiert --- ## đŸ§č Wartung ### Datenbank aufrĂ€umen **Via Admin-Panel:** - `/admin` → Database Maintenance → Cleanup Buttons **Via CLI:** ```bash npm run db:cleanup # 7 Tage npm run db:cleanup:30d # 30 Tage ``` ### Datenbank optimieren **Via Admin-Panel:** - `/admin` → Database Maintenance → Optimize Button **Via CLI:** ```bash # Manuell node scripts/optimize-db.js ``` **Was macht Optimize:** - `VACUUM` - Speicherplatz freigeben - `ANALYZE` - Query-Statistiken aktualisieren ### Logs prĂŒfen ```bash # Development Server Logs npm run dev # Production Logs (PM2) pm2 logs location-tracker-app ``` ### Zeitfilter debuggen Bei Problemen mit der Zeitfilterung (z.B. alte Locations werden nicht ausgefiltert): ```bash node scripts/test-time-filter.js ``` **Das Script zeigt:** - Aktuelle Zeit (UTC und lokal) - Letzte Locations in der Datenbank - Welche Locations mit 1-Stunden-Filter angezeigt werden sollten - Vergleich zwischen alter (SQLite datetime) und neuer (JavaScript) Methode - Anzahl der gefilterten Locations **Verwendung:** 1. Script ausfĂŒhren um zu sehen, welche Locations in der DB sind 2. ÜberprĂŒfen ob die Zeitfilterung korrekt funktioniert 3. Bei Problemen: App neu starten nach Code-Updates --- ## 🚀 Deployment ### Environment Variables Erstelle `.env.local`: ```env # NextAuth AUTH_SECRET= NEXTAUTH_URL=https://your-domain.com ``` **Secret generieren:** ```bash openssl rand -base64 32 ``` ### Production Build ```bash # Build npm run build # Start npm run start ``` ### Mit PM2 (empfohlen) ```bash # PM2 installieren npm install -g pm2 # App starten pm2 start npm --name "location-tracker-app" -- start # Auto-Start bei Server-Neustart pm2 startup pm2 save ``` ### Nginx Reverse Proxy ```nginx server { listen 80; server_name your-domain.com; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } ``` --- ## 🔒 Sicherheit ### Production Checklist - [ ] `AUTH_SECRET` mit starkem Wert setzen - [ ] `NEXTAUTH_URL` auf Production-Domain setzen - [ ] Admin-Passwort Ă€ndern (nicht `admin123`) - [ ] Ggf. weitere User anlegen mit VIEWER Rolle - [ ] HTTPS aktivieren (Let's Encrypt) - [ ] Firewall-Regeln prĂŒfen - [ ] RegelmĂ€ĂŸige Backups einrichten ### User-Rollen - **ADMIN** - Voller Zugriff auf alle Admin-Funktionen - **VIEWER** - Nur lesender Zugriff (geplant, noch nicht implementiert) --- ## 📂 Projektstruktur ``` location-tracker-app/ ├── app/ │ ├── api/ │ │ ├── auth/[...nextauth]/ # NextAuth API │ │ ├── devices/ # Device CRUD │ │ ├── locations/ # Location API + Sync/Cleanup/Stats │ │ └── system/status/ # System Status (Uptime, Memory) │ ├── admin/ │ │ ├── devices/ # Device Management │ │ └── page.tsx # Dashboard │ ├── login/ # Login-Seite │ ├── page.tsx # Öffentliche Karte │ └── layout.tsx # Root Layout ├── components/ │ └── map/ │ └── MapView.tsx # Leaflet Map Component ├── lib/ │ ├── auth.ts # NextAuth Config │ └── db.ts # SQLite Database Layer ├── scripts/ │ ├── init-database.js # Database.sqlite Setup │ ├── init-locations-db.js # Locations.sqlite Setup │ ├── reset-admin.js # Admin User Reset │ ├── remove-duplicates.js # Duplikate bereinigen │ └── cleanup-old-locations.js # Alte Daten löschen ├── data/ │ ├── database.sqlite # User + Devices │ └── locations.sqlite # Location Tracking ├── types/ │ └── location.ts # TypeScript Interfaces └── middleware.ts # Route Protection ``` --- ## 📝 Changelog ### Version 1.1.0 - November 2025 #### 🆕 Neue Features - **Custom Date Range Filter** - Benutzerdefinierte ZeitrĂ€ume mit DateTime-Picker (z.B. 16.11.2025 16:00 - 17.11.2025 06:00) - Toggle-Button zwischen Quick Filters und Custom Range - Kompakte UI - Custom Range nur sichtbar wenn aktiviert - Backend-Support mit `startTime` und `endTime` API-Parametern #### 🐛 Bug Fixes - **Zeitfilter-Bug behoben** - Alte Locations (z.B. 6+ Stunden alt) werden jetzt korrekt ausgefiltert - JavaScript-basierte Zeitberechnung statt SQLite `datetime('now')` - Verhindert Zeitversatz-Probleme #### đŸ› ïž Verbesserungen - Zoom-basierte Icon-Skalierung fĂŒr bessere Sichtbarkeit - Optimierte Zeitfilter-Logik in Datenbank-Queries - Debug-Script `test-time-filter.js` fĂŒr Troubleshooting #### 📚 Dokumentation - README aktualisiert mit Custom Range Anleitung - API-Endpunkte Dokumentation erweitert - Wartungs-Abschnitt mit Debug-Script Information --- ## 🐛 Troubleshooting ### "Invalid username or password" **Lösung:** ```bash node scripts/reset-admin.js ``` ### Datenbank-Dateien fehlen **Lösung:** ```bash npm run db:init ``` ### Duplikate in locations.sqlite **Lösung:** ```bash # Erst Duplikate entfernen node scripts/remove-duplicates.js # Dann UNIQUE Index hinzufĂŒgen node scripts/init-locations-db.js ``` ### Map zeigt keine Daten 1. MQTT Broker erreichbar? `mosquitto_sub -h localhost -p 1883 -t '#'` 2. Locations in Datenbank? `/admin` → Database Statistics prĂŒfen 3. MQTT Subscriber lĂ€uft? Server-Logs prĂŒfen ### "ENOENT: no such file or directory, open 'data/database.sqlite'" **Lösung:** ```bash mkdir -p data npm run db:init ``` --- ## 📝 NPM Scripts ```bash # Development npm run dev # Dev Server starten # Production npm run build # Production Build npm run start # Production Server # Database npm run db:init # Beide DBs initialisieren npm run db:init:app # Nur database.sqlite npm run db:init:locations # Nur locations.sqlite npm run db:cleanup # Cleanup 7 Tage npm run db:cleanup:7d # Cleanup 7 Tage npm run db:cleanup:30d # Cleanup 30 Tage # Linting npm run lint # ESLint ausfĂŒhren ``` --- ## 📄 Lizenz MIT License - Open Source --- ## 📜 Open Source Lizenzen Diese Anwendung verwendet folgende Open-Source-Software: ### MIT License - [Next.js](https://github.com/vercel/next.js) - Copyright (c) Vercel, Inc. - [React](https://github.com/facebook/react) - Copyright (c) Meta Platforms, Inc. - [React-DOM](https://github.com/facebook/react) - Copyright (c) Meta Platforms, Inc. - [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss) - Copyright (c) Tailwind Labs, Inc. - [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) - Copyright (c) Joshua Wise - [bcryptjs](https://github.com/dcodeIO/bcrypt.js) - Copyright (c) Daniel Wirtz ### Apache License 2.0 - [TypeScript](https://github.com/microsoft/TypeScript) - Copyright (c) Microsoft Corporation ### ISC License - [NextAuth.js](https://github.com/nextauthjs/next-auth) - Copyright (c) NextAuth.js Contributors ### BSD-2-Clause License - [Leaflet](https://github.com/Leaflet/Leaflet) - Copyright (c) Vladimir Agafonkin ### Hippocratic License 2.1 - [React-Leaflet](https://github.com/PaulLeCam/react-leaflet) - Copyright (c) Paul Le Cam **VollstĂ€ndige Lizenztexte:** Alle vollstĂ€ndigen Lizenztexte der verwendeten Bibliotheken finden Sie in den jeweiligen GitHub-Repositories oder in der `node_modules` Directory nach Installation. --- ## 🙏 Credits - **Next.js 14** - React Framework - **Leaflet.js** - Karten-Bibliothek - **NextAuth.js** - Authentifizierung - **better-sqlite3** - SQLite fĂŒr Node.js - **Tailwind CSS** - Utility-First CSS - **MQTT.js** - MQTT Client fĂŒr Node.js - **OwnTracks** - Location Tracking Apps --- ## 📞 Support Bei Fragen oder Problemen: 1. Logs prĂŒfen (`npm run dev` Output) 2. Browser Console öffnen (F12) 3. Datenbank-Status in `/admin` prĂŒfen 4. Issues im Repository erstellen