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:
2025-12-04 10:52:23 +00:00
parent 3ac82621c8
commit e096ba2600

143
README.md
View File

@@ -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 - 📊 **Dashboard** - Übersicht über Geräte, Statistiken und Datenbankstatus
- ⏱️ **System Status** - Live-Uptime, Memory Usage, Runtime Info - ⏱️ **System Status** - Live-Uptime, Memory Usage, Runtime Info
- 📱 **Device Management** - Geräte hinzufügen, bearbeiten, löschen - 📱 **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**: - 💾 **Datenbank-Wartung**:
- 🧹 Cleanup alter Daten (7, 15, 30, 90 Tage) - 🧹 Cleanup alter Daten (7, 15, 30, 90 Tage)
- ⚡ Datenbank-Optimierung (VACUUM) - ⚡ Datenbank-Optimierung (VACUUM)
@@ -51,17 +57,20 @@ Eine moderne Location-Tracking Anwendung basierend auf Next.js 14 mit MQTT/OwnTr
## 🛠 Tech Stack ## 🛠 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 - **Sprache:** TypeScript 5.9
- **Styling:** Tailwind CSS v4 - **Styling:** Tailwind CSS v4
- **Karten:** Leaflet 1.9.4 + React-Leaflet 5.0 - **Karten:** Leaflet 1.9.4 + React-Leaflet 5.0
- **Authentifizierung:** NextAuth.js v5 (beta) - **Authentifizierung:** NextAuth.js v5 (beta)
- **Datenbank:** SQLite (better-sqlite3) - **Datenbank:** SQLite (better-sqlite3)
- **MQTT:** MQTT.js v5 + Eclipse Mosquitto
- **E-Mail:** Nodemailer + React Email
- **Passwort-Hashing:** bcryptjs - **Passwort-Hashing:** bcryptjs
- **Datenquelle:** MQTT Broker + lokale SQLite-Cache - **Datenquelle:** MQTT Broker + lokale SQLite-Cache
### Dual-Database Architektur ### 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) - **locations.sqlite** - Location-Tracking (hohe Schreibrate, isoliert)
--- ---
@@ -91,7 +100,7 @@ npm run db:init
``` ```
Dies erstellt: Dies erstellt:
- `data/database.sqlite` (User + Devices) - `data/database.sqlite` (User + Devices + MQTT + Geofences)
- `data/locations.sqlite` (Location-Tracking) - `data/locations.sqlite` (Location-Tracking)
- Standard Admin-User: `admin` / `admin123` - Standard Admin-User: `admin` / `admin123`
- Standard Devices (ID 10, 11) - Standard Devices (ID 10, 11)
@@ -128,6 +137,11 @@ npm run db:init:app
npm run db:init:locations npm run db:init:locations
``` ```
**Nur Geofence-Tabellen:**
```bash
npm run db:init:geofence
```
### Datenbank zurücksetzen ### Datenbank zurücksetzen
**Admin-User neu anlegen:** **Admin-User neu anlegen:**
@@ -207,6 +221,52 @@ created_at TEXT DEFAULT (datetime('now'))
updated_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:** **Indexes:**
- `idx_user_username` ON User(username) - `idx_user_username` ON User(username)
- `idx_user_parent` ON User(parent_user_id) - `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_device` ON mqtt_credentials(device_id)
- `idx_mqtt_credentials_username` ON mqtt_credentials(mqtt_username) - `idx_mqtt_credentials_username` ON mqtt_credentials(mqtt_username)
- `idx_mqtt_acl_device` ON mqtt_acl_rules(device_id) - `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] B -->|Subscribe| C[📡 Next.js MQTT Subscriber]
C -->|Store Locations| D[(🗄️ SQLite Cache<br/>locations.sqlite)] 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] 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 F -->|JSON Response| E
E -->|Render| G[🗺️ React Leaflet Map] E -->|Render| G[🗺️ React Leaflet Map]
E -->|Render Geofences| M[🔵 Geofence Circles]
H[👤 Admin User] -->|Login| I[🔐 NextAuth.js] H[👤 Admin User] -->|Login| I[🔐 NextAuth.js]
I -->|Authenticated| J[📊 Admin Panel] 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 A fill:#4CAF50
style B fill:#FF9800 style B fill:#FF9800
@@ -348,6 +424,8 @@ flowchart TD
style G fill:#8BC34A style G fill:#8BC34A
style I fill:#E91E63 style I fill:#E91E63
style K fill:#FFC107 style K fill:#FFC107
style L fill:#9C27B0
style M fill:#3F51B5
``` ```
### Komponenten-Übersicht ### Komponenten-Übersicht
@@ -361,6 +439,7 @@ graph LR
subgraph "Next.js Application" subgraph "Next.js Application"
C[MQTT Subscriber] C[MQTT Subscriber]
I[Geofence Monitor]
D[Frontend<br/>React/Leaflet] D[Frontend<br/>React/Leaflet]
E[API Routes] E[API Routes]
F[Auth Layer<br/>NextAuth.js] F[Auth Layer<br/>NextAuth.js]
@@ -368,12 +447,14 @@ graph LR
subgraph "Data Layer" subgraph "Data Layer"
G[locations.sqlite<br/>Tracking Data] G[locations.sqlite<br/>Tracking Data]
H[database.sqlite<br/>Users & Devices] H[database.sqlite<br/>Users, Devices<br/>MQTT, Geofences]
end end
A -->|MQTT| B A -->|MQTT| B
B -->|Subscribe| C B -->|Subscribe| C
C -->|Write| G C -->|Write Locations| G
C -->|Trigger| I
I -->|Check & Store Events| H
D -->|HTTP| E D -->|HTTP| E
E -->|Read/Write| G E -->|Read/Write| G
@@ -385,6 +466,7 @@ graph LR
style A fill:#4CAF50,color:#fff style A fill:#4CAF50,color:#fff
style B fill:#FF9800,color:#fff style B fill:#FF9800,color:#fff
style C fill:#2196F3,color:#fff style C fill:#2196F3,color:#fff
style I fill:#9C27B0,color:#fff
style D fill:#00BCD4,color:#000 style D fill:#00BCD4,color:#000
style E fill:#00BCD4,color:#000 style E fill:#00BCD4,color:#000
style F fill:#E91E63,color:#fff style F fill:#E91E63,color:#fff
@@ -398,9 +480,15 @@ graph LR
erDiagram erDiagram
USER ||--o{ USER : "parent_user_id" USER ||--o{ USER : "parent_user_id"
USER ||--o{ DEVICE : owns USER ||--o{ DEVICE : owns
USER ||--o{ GEOFENCE : owns
DEVICE ||--o{ LOCATION : tracks DEVICE ||--o{ LOCATION : tracks
DEVICE ||--o| MQTT_CREDENTIALS : has DEVICE ||--o| MQTT_CREDENTIALS : has
DEVICE ||--o{ MQTT_ACL_RULES : 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 { USER {
string id PK string id PK
@@ -450,6 +538,49 @@ erDiagram
datetime updated_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 { LOCATION {
int id PK int id PK
float latitude float latitude