Update README: Add geofencing architecture and update tech stack
Documentation updates: - Add geofencing feature description with capabilities - Update database architecture ER diagram with Geofence, GeofenceEvent, and GeofenceStatus tables - Add complete schema documentation for all geofence tables and indexes - Update data flow diagram to show geofence monitoring pipeline - Update component overview with Geofence Monitor - Update Tech Stack versions: Next.js 16.0.7, React 19.2.1 - Add MQTT.js, Eclipse Mosquitto, Nodemailer, React Email to tech stack - Update dual-database architecture description - Add npm run db:init:geofence command documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
143
README.md
143
README.md
@@ -40,6 +40,12 @@ Eine moderne Location-Tracking Anwendung basierend auf Next.js 14 mit MQTT/OwnTr
|
||||
- 📊 **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)
|
||||
@@ -51,17 +57,20 @@ Eine moderne Location-Tracking Anwendung basierend auf Next.js 14 mit MQTT/OwnTr
|
||||
|
||||
## 🛠 Tech Stack
|
||||
|
||||
- **Framework:** Next.js 14 (App Router)
|
||||
- **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 (kritische Daten)
|
||||
- **database.sqlite** - User, Geräte, MQTT-Credentials, Geofences (kritische Daten)
|
||||
- **locations.sqlite** - Location-Tracking (hohe Schreibrate, isoliert)
|
||||
|
||||
---
|
||||
@@ -91,7 +100,7 @@ npm run db:init
|
||||
```
|
||||
|
||||
Dies erstellt:
|
||||
- `data/database.sqlite` (User + Devices)
|
||||
- `data/database.sqlite` (User + Devices + MQTT + Geofences)
|
||||
- `data/locations.sqlite` (Location-Tracking)
|
||||
- Standard Admin-User: `admin` / `admin123`
|
||||
- Standard Devices (ID 10, 11)
|
||||
@@ -128,6 +137,11 @@ npm run db:init:app
|
||||
npm run db:init:locations
|
||||
```
|
||||
|
||||
**Nur Geofence-Tabellen:**
|
||||
```bash
|
||||
npm run db:init:geofence
|
||||
```
|
||||
|
||||
### Datenbank zurücksetzen
|
||||
|
||||
**Admin-User neu anlegen:**
|
||||
@@ -207,6 +221,52 @@ 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)
|
||||
@@ -215,6 +275,17 @@ updated_at TEXT DEFAULT (datetime('now'))
|
||||
- `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)
|
||||
|
||||
---
|
||||
|
||||
@@ -328,6 +399,8 @@ flowchart TD
|
||||
B -->|Subscribe| C[📡 Next.js MQTT Subscriber]
|
||||
|
||||
C -->|Store Locations| D[(🗄️ SQLite Cache<br/>locations.sqlite)]
|
||||
C -->|Check Geofences| L[🎯 Geofence Monitor]
|
||||
L -->|Store Events| K[(💼 SQLite DB<br/>database.sqlite)]
|
||||
|
||||
E[🖥️ Browser Client] -->|GET /api/locations<br/>alle 5 Sek| F[📡 Next.js API Route]
|
||||
|
||||
@@ -335,10 +408,13 @@ flowchart TD
|
||||
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[(💼 SQLite DB<br/>database.sqlite)]
|
||||
J -->|CRUD Operations| K
|
||||
J -->|Manage Geofences| K
|
||||
K -->|Query Events| J
|
||||
|
||||
style A fill:#4CAF50
|
||||
style B fill:#FF9800
|
||||
@@ -348,6 +424,8 @@ flowchart TD
|
||||
style G fill:#8BC34A
|
||||
style I fill:#E91E63
|
||||
style K fill:#FFC107
|
||||
style L fill:#9C27B0
|
||||
style M fill:#3F51B5
|
||||
```
|
||||
|
||||
### Komponenten-Übersicht
|
||||
@@ -361,6 +439,7 @@ graph LR
|
||||
|
||||
subgraph "Next.js Application"
|
||||
C[MQTT Subscriber]
|
||||
I[Geofence Monitor]
|
||||
D[Frontend<br/>React/Leaflet]
|
||||
E[API Routes]
|
||||
F[Auth Layer<br/>NextAuth.js]
|
||||
@@ -368,12 +447,14 @@ graph LR
|
||||
|
||||
subgraph "Data Layer"
|
||||
G[locations.sqlite<br/>Tracking Data]
|
||||
H[database.sqlite<br/>Users & Devices]
|
||||
H[database.sqlite<br/>Users, Devices<br/>MQTT, Geofences]
|
||||
end
|
||||
|
||||
A -->|MQTT| B
|
||||
B -->|Subscribe| C
|
||||
C -->|Write| G
|
||||
C -->|Write Locations| G
|
||||
C -->|Trigger| I
|
||||
I -->|Check & Store Events| H
|
||||
|
||||
D -->|HTTP| E
|
||||
E -->|Read/Write| G
|
||||
@@ -385,6 +466,7 @@ graph LR
|
||||
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
|
||||
@@ -398,9 +480,15 @@ graph LR
|
||||
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
|
||||
@@ -450,6 +538,49 @@ erDiagram
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user