# 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 - 🎯 **Geofencing** - Kreisförmige Geofences mit Enter/Exit-Benachrichtigungen: - Geofences erstellen, bearbeiten und löschen - Radius 50m bis 50km konfigurierbar - Visualisierung auf der Karte mit Toggle-Button - Event-Historie mit Enter/Exit-Ereignissen - E-Mail und MQTT-Benachrichtigungen bei Grenzüberschreitung - 💾 **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 16.0.7 (App Router) - **Runtime:** React 19.2.1 - **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) - **MQTT:** MQTT.js v5 + Eclipse Mosquitto - **E-Mail:** Nodemailer + React Email - **Passwort-Hashing:** bcryptjs - **Datenquelle:** MQTT Broker + lokale SQLite-Cache ### Dual-Database Architektur - **database.sqlite** - User, Geräte, MQTT-Credentials, Geofences (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 + MQTT + Geofences) - `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 ``` **Nur Geofence-Tabellen:** ```bash npm run db:init:geofence ``` ### 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 parent_user_id TEXT -- FK zu User.id (Hierarchie) 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')) ``` **MQTT Credentials Tabelle:** ```sql id INTEGER PRIMARY KEY AUTOINCREMENT device_id TEXT NOT NULL UNIQUE -- FK zu Device.id mqtt_username TEXT NOT NULL UNIQUE mqtt_password_hash TEXT NOT NULL enabled INTEGER DEFAULT 1 -- 0 oder 1 created_at TEXT DEFAULT (datetime('now')) updated_at TEXT DEFAULT (datetime('now')) ``` **MQTT ACL Rules Tabelle:** ```sql id INTEGER PRIMARY KEY AUTOINCREMENT device_id TEXT NOT NULL -- FK zu Device.id topic_pattern TEXT NOT NULL permission TEXT NOT NULL -- 'read', 'write', 'readwrite' created_at TEXT DEFAULT (datetime('now')) ``` **MQTT Sync Status Tabelle:** ```sql id INTEGER PRIMARY KEY CHECK (id = 1) -- Singleton pending_changes INTEGER DEFAULT 0 last_sync_at TEXT last_sync_status TEXT created_at TEXT DEFAULT (datetime('now')) updated_at TEXT DEFAULT (datetime('now')) ``` **Geofence Tabelle:** ```sql id TEXT PRIMARY KEY name TEXT NOT NULL description TEXT shape_type TEXT NOT NULL DEFAULT 'circle' -- Only 'circle' for MVP center_latitude REAL NOT NULL center_longitude REAL NOT NULL radius_meters INTEGER NOT NULL owner_id TEXT NOT NULL -- FK zu User.id device_id TEXT NOT NULL -- FK zu Device.id is_active INTEGER DEFAULT 1 -- 0 oder 1 color TEXT DEFAULT '#3b82f6' created_at TEXT DEFAULT (datetime('now')) updated_at TEXT DEFAULT (datetime('now')) ``` **GeofenceEvent Tabelle:** ```sql id INTEGER PRIMARY KEY AUTOINCREMENT geofence_id TEXT NOT NULL -- FK zu Geofence.id device_id TEXT NOT NULL -- FK zu Device.id location_id INTEGER NOT NULL event_type TEXT NOT NULL -- 'enter' oder 'exit' latitude REAL NOT NULL longitude REAL NOT NULL distance_from_center REAL notification_sent INTEGER DEFAULT 0 -- 0=not sent, 1=sent, 2=failed notification_error TEXT timestamp TEXT NOT NULL created_at TEXT DEFAULT (datetime('now')) ``` **GeofenceStatus Tabelle:** ```sql id INTEGER PRIMARY KEY AUTOINCREMENT device_id TEXT NOT NULL -- FK zu Device.id geofence_id TEXT NOT NULL -- FK zu Geofence.id is_inside INTEGER NOT NULL DEFAULT 0 -- 0 oder 1 last_enter_time TEXT last_exit_time TEXT last_checked_at TEXT created_at TEXT DEFAULT (datetime('now')) updated_at TEXT DEFAULT (datetime('now')) ``` **Indexes:** - `idx_user_username` ON User(username) - `idx_user_parent` ON User(parent_user_id) - `idx_device_owner` ON Device(ownerId) - `idx_device_active` ON Device(isActive) - `idx_mqtt_credentials_device` ON mqtt_credentials(device_id) - `idx_mqtt_credentials_username` ON mqtt_credentials(mqtt_username) - `idx_mqtt_acl_device` ON mqtt_acl_rules(device_id) - `idx_geofence_owner` ON Geofence(owner_id) - `idx_geofence_device` ON Geofence(device_id) - `idx_geofence_active` ON Geofence(is_active) - `idx_geofence_event_geofence` ON GeofenceEvent(geofence_id) - `idx_geofence_event_device` ON GeofenceEvent(device_id) - `idx_geofence_event_timestamp` ON GeofenceEvent(timestamp DESC) - `idx_geofence_event_notification` ON GeofenceEvent(notification_sent) - `idx_geofence_event_composite` ON GeofenceEvent(device_id, geofence_id, timestamp DESC) - `idx_geofence_status_device` ON GeofenceStatus(device_id) - `idx_geofence_status_geofence` ON GeofenceStatus(geofence_id) - `idx_geofence_status_inside` ON GeofenceStatus(is_inside) --- #### **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 publishes automatically to `owntracks//` - Example: `owntracks/device_12_4397af93/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)] C -->|Check Geofences| L[🎯 Geofence Monitor] L -->|Store Events| K[(💼 SQLite DB
database.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] E -->|Render Geofences| M[🔵 Geofence Circles] H[👤 Admin User] -->|Login| I[🔐 NextAuth.js] I -->|Authenticated| J[📊 Admin Panel] J -->|CRUD Operations| K J -->|Manage Geofences| K K -->|Query Events| J 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 style L fill:#9C27B0 style M fill:#3F51B5 ``` ### Komponenten-Übersicht ```mermaid graph LR subgraph "External Services" A[OwnTracks App] B[MQTT Broker] end subgraph "Next.js Application" C[MQTT Subscriber] I[Geofence Monitor] 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
MQTT, Geofences] end A -->|MQTT| B B -->|Subscribe| C C -->|Write Locations| G C -->|Trigger| I I -->|Check & Store Events| H 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 I fill:#9C27B0,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{ USER : "parent_user_id" USER ||--o{ DEVICE : owns USER ||--o{ GEOFENCE : owns DEVICE ||--o{ LOCATION : tracks DEVICE ||--o| MQTT_CREDENTIALS : has DEVICE ||--o{ MQTT_ACL_RULES : has DEVICE ||--o{ GEOFENCE : monitors GEOFENCE ||--o{ GEOFENCE_EVENT : triggers GEOFENCE ||--o{ GEOFENCE_STATUS : tracks DEVICE ||--o{ GEOFENCE_EVENT : generates DEVICE ||--o{ GEOFENCE_STATUS : has USER { string id PK string username UK string email string passwordHash string role string parent_user_id FK datetime createdAt datetime lastLoginAt } DEVICE { string id PK string name string color string ownerId FK boolean isActive string description datetime createdAt } MQTT_CREDENTIALS { int id PK string device_id FK_UK string mqtt_username UK string mqtt_password_hash boolean enabled datetime created_at datetime updated_at } MQTT_ACL_RULES { int id PK string device_id FK string topic_pattern string permission datetime created_at } MQTT_SYNC_STATUS { int id PK int pending_changes datetime last_sync_at string last_sync_status datetime created_at datetime updated_at } GEOFENCE { string id PK string name string description string shape_type float center_latitude float center_longitude int radius_meters string owner_id FK string device_id FK boolean is_active string color datetime created_at datetime updated_at } GEOFENCE_EVENT { int id PK string geofence_id FK string device_id FK int location_id string event_type float latitude float longitude float distance_from_center int notification_sent string notification_error datetime timestamp datetime created_at } GEOFENCE_STATUS { int id PK string device_id FK string geofence_id FK boolean is_inside datetime last_enter_time datetime last_exit_time datetime last_checked_at datetime created_at datetime updated_at } 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 - 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/ │ │ ├── admin/ │ │ │ ├── emails/ │ │ │ │ ├── preview/ # Email Template Preview │ │ │ │ └── send-test/ # Test Email versenden │ │ │ └── settings/ │ │ │ └── smtp/ # SMTP Einstellungen + Test │ │ ├── auth/ │ │ │ ├── [...nextauth]/ # NextAuth API │ │ │ ├── forgot-password/ # Passwort vergessen │ │ │ ├── register/ # User Registrierung │ │ │ └── reset-password/ # Passwort zurücksetzen │ │ ├── devices/ │ │ │ ├── [id]/ # Device CRUD (einzelnes Device) │ │ │ ├── public/ # Öffentliche Device-Liste │ │ │ └── route.ts # Device Liste + Create │ │ ├── export/ │ │ │ └── csv/ # CSV Export von Locations │ │ ├── geofences/ │ │ │ ├── [id]/ # Geofence CRUD (einzelner Geofence) │ │ │ ├── events/ # Geofence Events abfragen │ │ │ └── route.ts # Geofence Liste + Create │ │ ├── locations/ │ │ │ ├── cleanup/ # Alte Locations löschen │ │ │ ├── ingest/ # Location Import (MQTT) │ │ │ ├── optimize/ # DB Optimization (VACUUM) │ │ │ ├── stats/ # DB Statistiken │ │ │ ├── test/ # Test-Location hinzufügen │ │ │ └── route.ts # Location Query API │ │ ├── mqtt/ │ │ │ ├── acl/ │ │ │ │ ├── [id]/ # ACL Rule CRUD │ │ │ │ └── route.ts # ACL Rules Liste + Create │ │ │ ├── credentials/ │ │ │ │ ├── [device_id]/ # MQTT Credentials CRUD │ │ │ │ └── route.ts # Credentials Liste + Create │ │ │ ├── send-credentials/ # Credentials per Email versenden │ │ │ └── sync/ # Mosquitto Config Sync │ │ ├── system/ │ │ │ └── status/ # System Status (Uptime, Memory) │ │ └── users/ │ │ ├── [id]/ # User CRUD (einzelner User) │ │ └── route.ts # User Liste + Create │ ├── admin/ │ │ ├── devices/ # Device Management │ │ ├── emails/ # Email Template Management │ │ ├── geofences/ │ │ │ ├── events/ # Geofence Event History │ │ │ └── page.tsx # Geofence Management │ │ ├── mqtt/ # MQTT Provisioning │ │ ├── settings/ # SMTP Settings (Super Admin) │ │ ├── setup/ # Setup Guide │ │ ├── users/ # User Management │ │ ├── layout.tsx # Admin Layout + Navigation │ │ └── page.tsx # Dashboard │ ├── export/ # CSV Export Seite │ ├── forgot-password/ # Passwort vergessen Seite │ ├── login/ # Login-Seite │ ├── map/ # Karten-Seite (alternative Route) │ ├── register/ # Registrierungs-Seite │ ├── reset-password/ # Passwort zurücksetzen Seite │ ├── unauthorized/ # Unauthorized Access Seite │ ├── page.tsx # Öffentliche Karte (Home) │ └── layout.tsx # Root Layout ├── components/ │ ├── demo/ │ │ └── DemoMap.tsx # Demo Map Component │ ├── map/ │ │ ├── GeofenceLayer.tsx # Geofence Visualization Layer │ │ └── MapView.tsx # Leaflet Map Component │ └── AuthProvider.tsx # Auth Context Provider ├── lib/ │ ├── auth.ts # NextAuth Config │ ├── crypto-utils.ts # Encryption/Decryption Utils │ ├── db.ts # SQLite Database Layer (User/Devices) │ ├── demo-data.ts # Demo/Test Data Generator │ ├── devices.ts # Device Helper Functions │ ├── email-renderer.ts # React Email Renderer │ ├── email-service.ts # Email Service (Nodemailer) │ ├── geofence-db.ts # Geofence Database Layer │ ├── geofence-engine.ts # Geofence Detection Engine │ ├── geofence-notifications.ts # Geofence Notification Handler │ ├── geo-utils.ts # Geolocation Utils (Haversine) │ ├── mosquitto-sync.ts # Mosquitto Config File Sync │ ├── mqtt-db.ts # MQTT Database Layer │ ├── mqtt-subscriber.ts # MQTT Subscriber Service │ ├── password-reset-db.ts # Password Reset Token DB │ ├── settings-db.ts # Settings Database Layer │ ├── startup.ts # Application Startup Logic │ ├── types.ts # TypeScript Type Definitions │ └── types/ │ └── smtp.ts # SMTP Type Definitions ├── scripts/ │ ├── add-test-location.js # Test-Location hinzufügen │ ├── cleanup-old-locations.js # Alte Locations löschen │ ├── init-database.js # Database.sqlite Setup │ ├── init-geofence-db.js # Geofence Tables Setup │ ├── init-locations-db.js # Locations.sqlite Setup │ ├── remove-duplicates.js # Duplikate bereinigen │ ├── reset-admin.js # Admin User Reset │ ├── show-schema.js # DB Schema anzeigen │ ├── sync-mqtt-config.ts # MQTT Config manuell syncen │ ├── test-geofence.js # Geofence Detektion testen │ ├── test-geofence-email.js # Geofence Email testen │ ├── test-geofence-notification.js # Geofence Notification testen │ ├── test-mqtt-geofence.js # MQTT Geofence Integration testen │ ├── test-smtp.js # SMTP Connection testen │ └── test-time-filter.js # Zeitfilter debuggen ├── data/ │ ├── database.sqlite # User + Devices + MQTT + Geofences │ └── locations.sqlite # Location Tracking ├── emails/ # React Email Templates │ └── geofence-alert.tsx # Geofence Alert Email Template ├── mosquitto/ │ ├── config/ # Mosquitto Config Files │ │ ├── mosquitto.conf # Broker Config │ │ ├── password.txt # Password File (bcrypt hashes) │ │ └── acl.txt # ACL Rules File │ └── logs/ # Mosquitto Log Files ├── public/ # Static Assets ├── types/ │ └── (deprecated - moved to lib/types.ts) ├── middleware.ts # Route Protection Middleware ├── instrumentation.ts # Next.js Instrumentation Hook ├── docker-compose.yml # Docker Compose Setup ├── Dockerfile # App Docker Image └── package.json # Dependencies + Scripts ``` --- ## 📝 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