Files
location-mqtt-tracker-app/README.md
2025-11-24 16:30:37 +00:00

876 lines
23 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
![Location Tracker Screenshot](./pictures/n8n-MQTT-GPS-Tracking.png)
## 📋 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**:
- 🔄 Manueller Sync von n8n
- 🧹 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:** n8n Webhook API + 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 wie gewohnt
Die n8n-Workflow holt die Daten, und die App synct automatisch alle 5 Sekunden.
### 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[⚙️ n8n MQTT Trigger]
C -->|Store| D[💾 NocoDB]
D -->|Webhook API| E[🌐 n8n Webhook<br/>/webhook/location]
F[🖥️ Browser Client] -->|GET /api/locations<br/>alle 5 Sek| G[📡 Next.js API Route]
G -->|1. Fetch Fresh Data| E
E -->|JSON Response| G
G -->|2. Sync New Locations| H[(🗄️ SQLite Cache<br/>locations.sqlite)]
H -->|3. Query Filtered Data| G
G -->|JSON Response| F
F -->|Render| I[🗺️ React Leaflet Map]
J[👤 Admin User] -->|Login| K[🔐 NextAuth.js]
K -->|Authenticated| L[📊 Admin Panel]
L -->|CRUD Operations| M[(💼 SQLite DB<br/>database.sqlite)]
style A fill:#4CAF50
style B fill:#FF9800
style C fill:#2196F3
style D fill:#9C27B0
style E fill:#F44336
style G fill:#00BCD4
style H fill:#FFC107
style I fill:#8BC34A
style K fill:#E91E63
style M fill:#FFC107
```
### Komponenten-Übersicht
```mermaid
graph LR
subgraph "External Services"
A[OwnTracks App]
B[MQTT Broker]
C[n8n Automation]
D[NocoDB]
end
subgraph "Next.js Application"
E[Frontend<br/>React/Leaflet]
F[API Routes]
G[Auth Layer<br/>NextAuth.js]
end
subgraph "Data Layer"
H[locations.sqlite<br/>Tracking Data]
I[database.sqlite<br/>Users & Devices]
end
A -->|MQTT| B
B -->|Subscribe| C
C -->|Store| D
C -->|Webhook| F
E -->|HTTP| F
F -->|Read/Write| H
F -->|Read/Write| I
E -->|Auth| G
G -->|Validate| I
style A fill:#4CAF50,color:#fff
style B fill:#FF9800,color:#fff
style C fill:#2196F3,color:#fff
style D fill:#9C27B0,color:#fff
style E fill:#00BCD4,color:#000
style F fill:#00BCD4,color:#000
style G fill:#E91E63,color:#fff
style H fill:#FFC107,color:#000
style I 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-Sync Mechanismus
Die App verwendet einen **Hybrid-Ansatz**:
1. **Frontend polling** (alle 5 Sek.) `/api/locations`
2. **API prüft** ob neue Daten in n8n verfügbar
3. **Nur neue Locations** werden in SQLite gespeichert
4. **Duplikate** werden durch UNIQUE Index verhindert
5. **Antwort** kommt aus lokalem SQLite Cache
**Vorteile:**
- Schnelle Antwortzeiten (SQLite statt n8n)
- Längere Zeiträume abrufbar (24h+)
- Funktioniert auch wenn n8n nicht erreichbar ist (Fallback auf n8n-Daten)
- Duplikate werden automatisch verhindert (UNIQUE Index)
### Datenvalidierung & Normalisierung
Die App behandelt spezielle Fälle bei speed/battery korrekt:
**speed = 0 Behandlung:**
- n8n 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
**n8n Fallback:**
- Wenn DB leer ist, gibt API direkt n8n-Daten zurück
- Alle Filter (username, timeRangeHours) funktionieren auch mit Fallback
- Ermöglicht sofortigen Betrieb ohne DB-Initialisierung
**Debug-Logging:**
- Server-Logs zeigen n8n Sync-Aktivität
- Browser Console zeigt Daten-Flow (MapView, Popup)
- Hilfreich für Troubleshooting
---
## 📡 API-Endpunkte
### Öffentlich
**GET /api/locations**
- Location-Daten abrufen (mit Auto-Sync)
- 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)
- `sync=false` - Nur Cache ohne n8n Sync
**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/sync**
- Manueller Sync von n8n
- Gibt Anzahl neu eingefügter Locations zurück
**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
### Sync von n8n
**Via Admin-Panel:**
- `/admin` Database Maintenance Sync Now
**Automatisch:**
- Passiert alle 5 Sekunden beim Abruf der Karte
### 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=<generiere-mit-openssl-rand-base64-32>
NEXTAUTH_URL=https://your-domain.com
# Optional: n8n API URL (Standard in Code definiert)
N8N_API_URL=https://n8n.example.com/webhook/location
```
**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. n8n Webhook erreichbar? `curl https://n8n.example.com/webhook/location`
2. Locations in Datenbank? `/admin` Database Statistics prüfen
3. Auto-Sync aktiv? Browser Console öffnen
### "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
- **n8n** - Workflow Automation (Backend)
- **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