Alleinarbeiter-Schutzsystem
get-it-soft care — Vollständige Sicherheitslösung für Alleinarbeitende. Erkennt Stürze, Bewusstlosigkeit, Bewegungslosigkeit und Lageanomalien in Echtzeit durch intelligente Auswertung von 10 Hardware-Sensoren. 3-stufiges Eskalationssystem mit automatischer Notfallbenachrichtigung per TCP/IP Server-Heartbeat und SMS-Fallback. Mit Offline-Queue, Konnektivitätsüberwachung und Gerätediagnostik für maximale Zuverlässigkeit.
Systemkonzept
Das Alleinarbeiter-Schutzsystem bildet den Kern der Anwendung. Die Sensorik dient ausschließlich als Datenquelle.
🎯 Zielsetzung
Alleinarbeitende Personen sind in Notsituationen (Sturz, Bewusstlosigkeit, medizinischer Notfall) besonders gefährdet, da keine Kollegen in der Nähe sind. get-it-soft care überwacht kontinuierlich Bewegung, Lage und Position des Smartphones und löst bei erkannter Gefahr ein mehrstufiges Alarmsystem aus — das ohne Bestätigung des Nutzers automatisch Notfallkontakte benachrichtigt.
🔄 Grundprinzip
1. Sensoren liefern kontinuierlich Rohdaten (Beschleunigung, Gyroskop, GPS) →
2. Algorithmen erkennen Gefahrensituationen anhand konfigurierbarer Schwellwerte →
3. 3-stufige Eskalation gibt dem Nutzer Chance zur Entwarnung →
4. Bei Nicht-Reaktion: Automatischer Alarm per TCP/IP an Server (+ SMS-Fallback) mit GPS-Position
⚖️ Regulatorischer Hintergrund
Alleinarbeit ist in vielen Branchen (Bau, Lager, Nachtschicht) gesetzlich geregelt. DGUV Regel 112-139 fordert Personen-Notsignal-Anlagen (PNA) für gefährliche Alleinarbeit. Diese App bietet eine Smartphone-basierte Lösung, die die Kernanforderungen einer PNA umsetzt: willensabhängige (Check-in) und willensunabhängige (Sturz/Reglosigkeit) Alarmierung.
5 Gefahrenszenarien
Jedes Szenario nutzt spezifische Sensorkombinationen und Algorithmen zur Erkennung potenzieller Notfälle.
Erkennungsalgorithmus
Phase 1 — Spike-Erkennung: Der Betrag des Beschleunigungsvektors √(x² + y² + z²) wird alle 500ms berechnet. Überschreitet er den konfigurierten
accelerationThreshold (Standard: 25.0 m/s²), wird ein Spike erkannt
und der Zeitstempel gespeichert.Phase 2 — Stillstandsbestätigung: Nach dem Spike wird geprüft, ob der Beschleunigungsbetrag unter 12.0 m/s² fällt (nahe Erdbeschleunigung = Reglosigkeit). Hält dieser Zustand für
stillnessDurationSec (Standard: 10s) an → Alarm-Eskalation startet.Timeout: Wenn nach 3×
stillnessDurationSec kein Stillstand erkannt wird,
wird der Spike verworfen (Fehlalarm-Vermeidung).
| Parameter | Standardwert | Bereich | Beschreibung |
|---|---|---|---|
accelerationThreshold | 25.0 m/s² | 10–50 m/s² | Mindestbeschleunigung für Spike-Erkennung |
stillnessDurationSec | 10 s | 3–30 s | Dauer der Reglosigkeit nach Spike |
Genutzte Sensoren
Beschleunigungssensor — Primärer Sensor für Spike + Stillstand
// Algorithmus (vereinfacht)
final totalAccel = sqrt(x² + y² + z²); // Betrag
// Phase 1: Spike?
if (totalAccel > accelerationThreshold) {
fallSpikeDetected = true;
fallSpikeTime = now;
}
// Phase 2: Stillstand nach Spike?
if (fallSpikeDetected && elapsed >= stillnessDurationSec) {
if (totalAccel < 12.0) → ALARM ESKALATION
if (elapsed > stillnessDurationSec * 3) → Spike verwerfen
}
Erkennungsalgorithmus
1. Gyroskop-Check: Betrag des Drehratenvektors √(x²+y²+z²). Liegt dieser unter 0.3 rad/s → keine Drehbewegung → kein Motion.
2. Beschleunigungs-Check: Wenn |√(x²+y²+z²) − 9.81| > 1.5 m/s² → Gerät wird bewegt (Abweichung von Erdschwere). Sonst: statisch.
3. GPS-Drift-Check: Haversine-Distanz zwischen letzter und aktueller Position. Liegt unter
gpsDriftToleranceM (Standard: 5.0m) → GPS statisch.Verdacht: Wenn alle 3 Checks „statisch" ergeben UND die letzte erkannte Bewegung länger als
maxInactivitySec (Standard: 300s = 5 Min) zurückliegt → Alarm-Eskalation.
| Parameter | Standardwert | Bereich | Beschreibung |
|---|---|---|---|
maxInactivitySec | 300 s (5 Min) | 30–900 s | Max. Zeit ohne Bewegung |
gpsDriftToleranceM | 5.0 m | 1–20 m | Max. GPS-Abweichung ohne Ortswechsel |
Genutzte Sensoren
Gyroskop Beschleunigungssensor GPS
// Immobility-Check
bool motionDetected = false;
if (gyroMagnitude > 0.3) motionDetected = true; // Drehung
if (|accelMag - 9.81| > 1.5) motionDetected = true; // Linearbewegung
if (gpsDrift > gpsDriftToleranceM) gpsStatic = false; // Ortswechsel
if (!motionDetected && gpsStatic && inactiveSec >= maxInactivitySec)
→ ALARM ESKALATION
Erkennungsalgorithmus
Gyroskop: Betrag < 0.2 rad/s (geringste Drehrate) UND
Beschleunigung: |Betrag − 9.81| < 0.5 m/s² (nur Erdschwere, keine Eigenbewegung)
Beide Bedingungen müssen gleichzeitig erfüllt sein. Unterschied zu „Ohnmacht": Kein GPS-Check, strengere Bewegungsschwellen. Gedacht als Warnstufe, wenn Person möglicherweise eingeschlafen oder handlungsunfähig ist.
| Parameter | Standardwert | Beschreibung |
|---|---|---|
maxInactivitySec | 300 s (5 Min) | Max. Zeit vollständiger Reglosigkeit |
Genutzte Sensoren
Gyroskop Beschleunigungssensor
Erkennungsalgorithmus
Der Winkel zur Vertikalen wird über die Z-Komponente des Beschleunigungsvektors berechnet:
cosAngle = |z| / √(x² + y² + z²)angleDeg = acos(cosAngle) × 180 / πWenn
angleDeg > tiltAngleDeg (Standard: 60°), beginnt ein Timer.
Hält die Neigung für tiltDurationSec (Standard: 30s) an → Alarm-Eskalation.Kehrt das Gerät in die Normalposition zurück, wird der Timer zurückgesetzt.
| Parameter | Standardwert | Bereich | Beschreibung |
|---|---|---|---|
tiltAngleDeg | 60° | 30–90° | Kritischer Neigungswinkel |
tiltDurationSec | 30 s | 5–120 s | Dauer abnormaler Neigung vor Alarm |
Genutzte Sensoren
Beschleunigungssensor — Z-Achse = Vertikalreferenz
// Tilt-Check
final cosAngle = |accel.z| / magnitude(accel);
final angleDeg = acos(cosAngle) × 180 / π;
if (angleDeg > tiltAngleDeg) {
tiltStartTime ??= now;
if (now - tiltStartTime >= tiltDurationSec) → ALARM
} else {
tiltStartTime = null; // Reset
}
Funktionsweise
1. Beim Aktivieren des Schutzes startet ein Countdown von
checkinIntervalSec (Standard: 1800s = 30 Min).2. Der verbleibende Countdown wird sekundengenau in der UI angezeigt.
3. Vor Ablauf kann der Nutzer jederzeit über den „Bin OK"-Button bestätigen → Countdown startet neu.
4. Läuft der Countdown ab → Zustand wechselt zu
checkinPending → Eskalation startet.5. Auch während der Eskalation kann der Nutzer noch Entwarnung geben.
Unterschied zu anderen Szenarien: Dies ist das einzige willensabhängige Szenario — es erfordert aktive Bestätigung statt passiver Sensorerkennung.
| Parameter | Standardwert | Bereich | Beschreibung |
|---|---|---|---|
checkinIntervalSec | 1800 s (30 Min) | 300–7200 s | Intervall zwischen Check-ins |
5 Schutzprofile
Vorkonfigurierte Profile für verschiedene Arbeitssituationen. Jedes Profil definiert aktive Szenarien und optimierte Schwellwerte.
9 konfigurierbare Schwellwerte
Jeder Schwellwert ist per Slider im Profil-Tab anpassbar. Änderungen nur bei deaktiviertem Schutz möglich.
| # | Parameter | Standard | Min | Max | Einheit | Betrifft Szenario | Erklärung |
|---|---|---|---|---|---|---|---|
| 1 | accelerationThreshold | 25.0 | 10 | 50 | m/s² | Sturz | Mindestbeschleunigung für Sturzspike. Höhere Werte = weniger empfindlich (gut für körperliche Arbeit). |
| 2 | stillnessDurationSec | 10 | 3 | 30 | s | Sturz | Wie lange nach dem Spike Stillstand herrschen muss, bevor Alarm ausgelöst wird. |
| 3 | maxInactivitySec | 300 | 30 | 900 | s | Ohnmacht Bewegungslos | Maximale Dauer ohne erkannte Bewegung. Zentral für Ohnmacht- und Reglosigkeitserkennung. |
| 4 | gpsDriftToleranceM | 5.0 | 1 | 20 | m | Ohnmacht | GPS-Radius innerhalb dessen die Position als „statisch" gilt. Klein = empfindlicher. |
| 5 | tiltAngleDeg | 60 | 30 | 90 | ° | Lage | Ab welchem Neigungswinkel das Gerät als „flach liegend" gilt. 0° = vertikal, 90° = horizontal. |
| 6 | tiltDurationSec | 30 | 5 | 120 | s | Lage | Wie lange die abnormale Neigung anhalten muss, bevor sie als Verdacht gilt. |
| 7 | checkinIntervalSec | 1800 | 300 | 7200 | s | Check-in | Intervall zwischen den vorgeschriebenen Check-ins. 1800s = alle 30 Minuten. |
| 8 | escalationStageSec | 15 | 5 | 60 | s | Alle | Dauer jeder Eskalationsstufe (Stufe 1 + Stufe 2). Gesamte Eskalation = 2 × Wert + Countdown. |
| 9 | alarmCountdownSec | 30 | 10 | 120 | s | Alle | Dauer des finalen Countdowns (Stufe 3) vor dem automatischen Alarm-Versand. |
escalationStageSec × 2 + alarmCountdownSecBei Standardwerten: 15s + 15s + 30s = 60 Sekunden von Erkennung bis Alarmversand.
Bei Nachtschicht-Profil: 10s + 10s + 20s = 40 Sekunden.
3-Stufen Eskalationssystem
Jeder erkannte Gefahrenzustand durchläuft drei Eskalationsstufen, bevor der tatsächliche Alarm versendet wird.
Dauer:
escalationStageSec (Standard: 15s)Unregelmäßige Bursts mit variierten Amplituden (180-255):
[0, 200, 80, 400, 50, 150, 120, 600, 60, 250, 90, 350]Wird alle 3 Sekunden wiederholt.
Dauer:
escalationStageSec (Standard: 15s)Alarmsound wird über
STREAM_ALARM abgespielt — umgeht Lautlos-/DND-Modus.Aggressivere Vibration alle 2s:
[0, 400, 40, 700, 30, 250, 60, 900, ...]Amplitude: durchgehend 255 (Maximum).
Dauer:
alarmCountdownSec (Standard: 30s)Durchgehende Max-Vibration mit kurzen Pausen:
[0, 800, 30, 800, 30, 800, 30, 800]Erreicht 0 → ALARM GESENDET!
Alarm per TCP/IP an Server + SMS-Fallback mit GPS-Position.
Vibrationsmuster im Detail
📳 Stufe 1: Aufmerksamkeit
Pattern: [0, 200, 80, 400, 50, 150, 120, 600, 60, 250, 90, 350]
Amplituden: [0, 180, 0, 255, 0, 200, 0, 255, 0, 230, 0, 255]
Abwechselnd kurze und lange Bursts, steigende Intensität. Fühlt sich „unruhig" an — weckt Aufmerksamkeit.
📳📳 Stufe 2: Aggressiv
Pattern: [0, 400, 40, 700, 30, 250, 60, 900, 40, 500, 50, 600]
Amplituden: [0, 255, 0, 255, 0, 220, 0, 255, 0, 255, 0, 255]
Längere Vibrationsblöcke, kürzere Pausen, durchgehend max. Amplitude. Zusammen mit Alarm-Sound.
📳📳📳 Stufe 3: Maximum
Pattern: [0, 800, 30, 800, 30, 800, 30, 800]
Amplituden: [0, 255, 0, 255, 0, 255, 0, 255]
Nahezu durchgehende Vibration (800ms on, 30ms off). Maximale Intensität. Letzter Versuch, den Nutzer zu erreichen.
Technische Umsetzung: Alarmsound
Der Alarmsound wird über einen nativen Android MethodChannel (com.sensorsuite/alarm_sound)
auf dem STREAM_ALARM Audio-Stream abgespielt.
Warum STREAM_ALARM? Dieser Android-Audio-Stream hat eine Sonderstellung:
- Wird nicht vom Lautlos-Modus beeinflusst
- Wird nicht vom „Nicht stören"-Modus (DND) blockiert
- Nutzt die Alarm-Lautstärke (separat von Medien/Klingelton)
- Garantiert, dass der Warnton auch bei stummgeschaltetem Gerät ertönt
Bei Fehler (z.B. Kanal nicht verfügbar) wird auf SystemSound.play(SystemSoundType.alert) zurückgefallen.
Wichtig: Der Fallback zeigt einen Toast-Hinweis an — Alarme dürfen NIEMALS stille Fallbacks haben.
Check-in Heartbeat System
Willensabhängige Sicherheitsfunktion: Fordert regelmäßige Bestätigung des Nutzers.
⏱️ Funktionsablauf
_startCheckinTimerIfNeeded() startet Countdown
checkinCountdownProvider decrementiert, UI zeigt MM:SS
performCheckin() → Countdown resettet
AlertState.checkinPending → Eskalation beginnt
📱 UI-Element: Check-in Card
Im Status-Tab wird eine blaue Card mit dem Countdown in großer Monospace-Schrift angezeigt (z.B. „28:45"). Daneben ein grüner „Bin OK"-Button. Die Card ist nur sichtbar, wenn:
- Schutz aktiv ist (
protectionActiveProvider == true) - Zustand =
AlertState.monitoring - Check-in im Profil aktiviert ist
⚙️ Konfiguration nach Profil
| Profil | Check-in Intervall | Aktiv? |
|---|---|---|
| Baustelle | 30 Min | ✅ Ja |
| Büro | 60 Min | ❌ Nein |
| Außendienst | 30 Min | ✅ Ja |
| Lager | 40 Min | ✅ Ja |
| Nachtschicht | 15 Min | ✅ Ja |
Alarmbenachrichtigungen
3-Kanal-System: SMS-Nachricht → Telefonanruf (Standard-Telefon-App) → Server-Meldung. Kein doppelter SMS-Versand. Jeder Kontakt erhält die vollständige Alarmnachricht.
📨 Schritt 1: SMS an alle Kontakte
Automatischer Versand der Alarm-Nachricht per SMS-Direktversand über den nativen Android
SmsManager — kein Nutzer-Tap erforderlich.
Inhalt: Szenario, Details, Zeitstempel, GPS-Position als Google-Maps-Link.
Fallback: Wenn SMS-Berechtigung fehlt → automatischer Permission-Request,
dann Fallback auf native SMS-App mit vorausgefüllter Nachricht (sms: URI).
📞 Schritt 2: Anruf an alle Kontakte
Nach dem SMS-Versand wird jeder Notfallkontakt automatisch angerufen
über MethodChannel('com.sensorsuite/phone_call') → Android ACTION_CALL Intent,
gezielt an die Standard-Telefon-App via TelecomManager.defaultDialerPackage.
Kein doppelter SMS-Versand: Der Parameter skipSms: true (Standard) verhindert,
dass vor jedem Anruf erneut eine SMS gesendet wird. Die SMS wurde bereits in Schritt 1 versendet.
Kein App-Chooser: Der Anruf wird direkt über die Standard-Telefon-App initiiert —
kein launchUrl(tel:), das den App-Chooser-Dialog öffnen würde.
Fallback: Bei fehlender CALL_PHONE-Permission → ACTION_DIAL
(öffnet Wählhilfe, Nutzer muss manuell starten).
🌐 Schritt 3: Server-Meldung
Das Alarm-Paket wird parallel an den REST-API Server gesendet mit Szenario,
Schweregrad, GPS und Sensorwerten.
Admin-Panel: Roter Fullscreen-Alarm-Overlay mit Acknowledge-Button.
Polling alle 10 Sekunden.
Weiterleitung: Server leitet den Alarm automatisch an konfigurierte externe Systeme
(Leitstelle, andere Server) weiter.
initiateEmergencyCall(contact, skipSms: true)
sendet standardmäßig keine SMS vor dem Anruf — die SMS wurde bereits in Schritt 1 an alle
Kontakte versendet. Der Anruf wird über MethodChannel('com.sensorsuite/phone_call') initiiert
und nutzt die Standard-Telefon-App (via TelecomManager.defaultDialerPackage).
Bei fehlender CALL_PHONE-Permission wird auf ACTION_DIAL (manueller Anruf) zurückgefallen.
Heartbeat-Protokoll (HTTP REST-API)
💓 Heartbeat-System
Die App sendet periodisch einen HTTP-POST-Request an den Server (HeartbeatService):
| Endpunkt | Richtung | Intervall | Inhalt |
|---|---|---|---|
heartbeat.php?action=ping | App → Server | alle 30 s (konfigurierbar) | Battery-Level, GPS, Monitoring-Status, App-Version |
alarms.php?action=report | App → Server | bei Gefahr | Szenario, Schweregrad, GPS, Sensorwerte, Nachricht |
user_config.php?action=effective | Server → App | bei Login/Sync | Globale Config + User-Overrides + Profil + Kontakte |
protocol.php?action=log | App → Server | bei Events | Event-Typ, Kategorie, Details, Metadaten |
last_heartbeat-Spalte in der users-Tabelle
zeigt den letzten Ping-Zeitpunkt. Das Admin-Panel zeigt Online/Offline-Status basierend auf dem Zeitstempel.
Server kann externe Systeme bei Heartbeat-Ausfall über Forwarding-Server benachrichtigen.
Nachrichtenformat
SOS-ALARM - get-it-soft care
Szenario: Sturzerkennung
Details: Möglicher Sturz erkannt! Hohe Beschleunigung (32.5 m/s²)
gefolgt von 10s Stillstand.
Zeit: 2025-01-15 14:32:07
Position:
https://maps.google.com/?q=51.1657,10.4515
Diese Nachricht wurde automatisch von get-it-soft care gesendet.
sensorInfoProvider(SensorType.gps)), wird ein Google-Maps-Link mit den Koordinaten
in die Nachricht aufgenommen. Der Empfänger kann den Standort direkt in Google Maps öffnen.
Versandablauf (3-Kanal)
- Countdown in Stufe 3 erreicht 0 →
_triggerAlarm()wird aufgerufen AlarmEventmit Typconfirmedwird in der History geloggt- Max-Vibration + Alarmsound werden gestartet (bleiben auch nach Versand aktiv)
_sendNotifications()wird aufgerufen- GPS-Position wird aus dem letzten bekannten Wert gelesen
- Alarm-Nachricht wird per
buildAlarmMessage()aufgebaut - Kanal 1 — SMS:
AlarmNotificationService.sendAlarm()sendet SMS an alle Kontakte (SmsManager Direktversand) - Kanal 2 — Anruf: Für jeden Kontakt: Direktanruf über Standard-Telefon-App (
skipSms: true, kein doppelter SMS-Versand) - Kanal 3 — Server: Alarm-Event wird per REST-API an Server gemeldet + Server leitet an Forwarding-Server weiter
- Ergebnis-String wird in
alarmNotificationResultProvidergespeichert - Alle Aktionen werden per
_logProtocol()im Server-Protokoll erfasst
Notfallkontakte
Verwaltung der Empfänger für automatische Alarm-Nachrichten. Dual: Lokal (SharedPreferences) + Server-verwaltet (Admin-Panel).
📇 Datenmodell: EmergencyContact
| Feld | Typ | Beschreibung |
|---|---|---|
name | String | Name des Kontakts (z.B. „Chef", „Kollegin Maria") |
phone | String | Telefonnummer mit Landesvorwahl (z.B. +4917612345678) |
smsEnabled | bool | SMS-Benachrichtigung aktiviert (Standard: true) |
whatsappEnabled | bool | WhatsApp-Benachrichtigung aktiviert |
relationship | String? | Beziehung (z.B. „Vorgesetzter", „Kollege") — nur Server |
priority | int | Priorität (1 = höchste) — Reihenfolge bei Anrufen |
🔄 Dual-Quellen-System
Lokale Kontakte: Vom Benutzer in der App gepflegt, gespeichert in SharedPreferences
unter dem Key emergency_contacts.
Server-Kontakte: Vom Admin im Web-Panel verwaltet, pro Benutzer zugewiesen.
Werden per user_config.php?action=effective synchronisiert.
Priorität: Server-Kontakte haben Vorrang. Wenn Server-Kontakte vorhanden sind,
werden lokale Kontakte ignoriert. In der App sind Server-Kontakte schreibgeschützt (🔒).
// Server-Kontakt JSON Format
{
"name": "Chef",
"phone": "+4917612345678",
"sms_enabled": true,
"notify_call": true,
"relationship": "Vorgesetzter",
"priority": 1
}
🔧 CRUD-Operationen
| Methode | Quelle | Beschreibung |
|---|---|---|
addContact(contact) | Lokal | Neuen Kontakt hinzufügen + SharedPreferences aktualisieren |
removeContact(index) | Lokal | Kontakt an Position entfernen + SharedPreferences aktualisieren |
updateContact(index, contact) | Lokal | Kontakt bearbeiten + SharedPreferences aktualisieren |
contacts.php?action=create | Server (Admin) | Neuen server-verwalteten Kontakt erstellen |
contacts.php?action=delete | Server (Admin) | Server-Kontakt löschen |
contacts.php?action=sync | Server → App | Alle Kontakte des Benutzers synchronisieren |
Alarm-Verlauf (History)
Vollständige Protokollierung aller Alarm-Ereignisse mit Zeitstempel, Szenario und Status.
📊 AlarmEvent-Typen
| Typ | Enum | Farbe | Bedeutung | Wann erzeugt? |
|---|---|---|---|---|
| ⚠️ Potenziell | AlarmEventType.potential |
Gelb | Gefahr erkannt, Eskalation gestartet | Beim Übergang in Eskalation Stufe 1 |
| 🚨 Bestätigt | AlarmEventType.confirmed |
Rot | Alarm tatsächlich gesendet | Wenn Countdown abläuft + Benachrichtigungsergebnis |
| ✅ Entwarnt | AlarmEventType.cancelled |
Grün | Nutzer hat Entwarnung bestätigt | Wenn „ALLES OK"-Button gedrückt wird |
📋 AlarmEvent-Datenstruktur
| Feld | Typ | Beschreibung |
|---|---|---|
timestamp | DateTime | Zeitpunkt des Ereignisses |
scenario | DangerScenario | Welches Szenario den Alarm ausgelöst hat |
severity | AlertSeverity | Schweregrad (warning / critical / emergency) |
message | String | Detailnachricht mit Sensorwerten |
wasCancelled | bool | Ob der Alarm storniert wurde |
eventType | AlarmEventType | potential / confirmed / cancelled |
Zustandsautomat (AlertState)
8 definierte Zustände steuern das gesamte Schutzsystem. Die UI reagiert auf jeden Zustandswechsel.
| Zustand | Enum | UI-Farbe | Icon | Beschreibung | Mögliche Übergänge |
|---|---|---|---|---|---|
| Inaktiv | idle |
Grau | 🛡️ | Schutz nicht gestartet | → monitoring (Start-Button) |
| Überwachung aktiv | monitoring |
Grün | ✅ | Normalbetrieb: Sensoren werden ausgewertet (alle 500ms) | → checkinPending, → escalation1, → idle (Stop) |
| Check-in fällig | checkinPending |
Blau | 🔔 | Check-in-Countdown abgelaufen, Bestätigung nötig | → escalation1 (kein Tap), → monitoring (Tap) |
| Stufe 1 | escalation1 |
Gelb | 📳 | Vibration läuft, Nutzer soll reagieren | → escalation2 (Timer), → monitoring (OK) |
| Stufe 2 | escalation2 |
Orange | 🔊 | Alarmsound + Vibration | → countdown (Timer), → monitoring (OK) |
| Countdown | countdown |
Rot | ⚠️ | Letzter Countdown vor Alarmversand | → alertSent (0 erreicht), → monitoring (OK) |
| Alarm gesendet | alertSent |
Dunkelrot | 🚨 | Alarm an Server gesendet / SMS verschickt | → monitoring (Reset-Button) |
countdown-Zustand
in der UI gleichgestellt ist (gleiche Farbe und Icon). Er existiert für mögliche zukünftige Erweiterungen.
Benutzeroberfläche: Dynamische Tabs
Die LoneWorkerPage ist eine TabBarView mit dynamischen Tabs — die Anzahl der Tabs (3–4) hängt von der Server-Konfiguration ab.
_buildVisibleTabs() erstellt die Tabs basierend auf Server-Konfiguration.
Der Profile-Tab erscheint nur, wenn mindestens eine der folgenden Einstellungen aktiv ist:
allowProfileChange, allowThresholdChange oder allowScenarioToggle.
Minimum: 3 Tabs (Status, Kontakte, Verlauf). Maximum: 4 Tabs. Der TabController wird automatisch neu erstellt, wenn sich die Tab-Anzahl ändert.
🟢 Tab 1: Status
Hauptbildschirm mit Echtzeit-Überwachungsstatus. Layout-Reihenfolge optimiert.
- Warnhinweise: Anzeige aller aktiven Warnungen (fehlende Kontakte, Berechtigungen etc.)
- Status-Card: Farbcodierte Großkarte mit Icon, Statustext und Eskalations-Fortschritt
- Check-in Card: Blaue Card mit MM:SS-Countdown und „Bin OK"-Button (nur wenn aktiv)
- Funktionstest: DGUV §4.7 Pre-Shift-Test (nur wenn Schutz inaktiv, einklappbar nach bestandenem Test)
- Start/Stop-Button: Großer grüner „Schutz aktivieren" / roter „Schutz deaktivieren"
- SOS-Button: Manueller Notfall-Auslöser (nur wenn Schutz aktiv)
- Aktive Szenarien: Chip-Wrap mit Emojis aller aktiven Szenarien
- Schwellwert-Übersicht: Kompakte Key-Value-Tabelle mit allen aktuellen Werten
- Profil-Card: Aktives Profil mit Name und Beschreibung (unten positioniert)
⚙️ Tab 2: Profile Bedingt sichtbar
Profilauswahl, Schwellwert-Anpassung und Szenario-Toggles. Nur sichtbar wenn Server mindestens eine Änderung erlaubt.
- Profil-Auswahl: 5 Cards mit Radio-Button-Icons, aktives Profil hervorgehoben
- 9 Threshold-Slider: Jeder Parameter einzeln anpassbar mit Label + aktuellem Wert
- Szenario-Toggles: SwitchListTile für jedes der 5 Szenarien mit Icon und Beschreibung
- Sperrhinweis: Warnung, dass Änderungen nur bei deaktiviertem Schutz möglich sind
📞 Tab 3: Kontakte
Verwaltung der Notfallkontakte.
- Info-Header: Icon + Erklärung zur Funktionsweise
- Kontaktliste: Avatar (Initiale), Name, Telefonnummer, SMS-Badge
- Bearbeiten/Löschen: Edit- und Delete-Icons pro Kontakt
- Kontakt-Dialog: AlertDialog mit Name, Telefon, SMS-Switch
- Leerzustand: Freundliche Anzeige wenn keine Kontakte vorhanden
📜 Tab 4: Verlauf
Chronologische Protokollierung aller Alarm-Ereignisse.
- Sortierung: Neueste Ereignisse zuerst
- Farbcodierung: Gelb (potenziell), Rot (bestätigt), Grün (entwarnt)
- Pro Event: Szenario-Icon, Label, Nachricht (max. 2 Zeilen), Zeitstempel
- Leerzustand: „Noch keine Alarm-Ereignisse" mit History-Icon
Sensor-Infrastruktur (Technische Grundlage)
Die Sensoren bilden die Datengrundlage für das Alleinarbeiter-Schutzsystem. Ohne Sensordaten ist keine automatische Gefahrenerkennung möglich.
📊 Beschleunigungssensor
Kritisch für Schutz
3-Achsen (X, Y, Z) in m/s². Liefert Daten für Sturz-Spike, Stillstandserkennung, Tilt-Berechnung und Bewegungsprüfung.
Plugin: sensors_plus
Nutzung: 4 von 5 Szenarien
🌀 Gyroskop
Wichtig für Schutz
3-Achsen Drehrate in rad/s. Erkennt Drehbewegungen zur Unterscheidung „bewegt/reglos".
Plugin: sensors_plus
Nutzung: 2 Szenarien (Ohnmacht, Bewegungslosigkeit)
📍 GPS
Wichtig für Schutz
Koordinaten (Lat, Lon), Höhe, Geschwindigkeit, Genauigkeit. Drift-Check + Position in Alarmnachricht.
Plugin: geolocator
Nutzung: 1 Szenario (Ohnmacht) + GPS-Link in SMS
🧲 Magnetometer
3-Achsen Magnetfeld in µT. Sensor-Fusion (Roll/Pitch/Yaw).
Plugin: sensors_plus
🌡️ Barometer
Umgebungsdruck in hPa, Höhenableitung.
Plugin: environment_sensors
🚶 Schrittzähler
Kumulative Schrittanzahl.
Plugin: pedometer
💡 Lichtsensor
Umgebungshelligkeit in Lux.
Kanal: Native EventChannel
📏 Näherungssensor
Entfernung in cm (binär oder Distanz).
Kanal: Native EventChannel
🌡️ Temperatursensor
Umgebungstemperatur in °C (selten vorhanden).
Kanal: Native EventChannel
🎤 Mikrofon
dB-Pegel in Echtzeit.
Kanal: Native EventChannel + MediaRecorder
Sensor-Datenfluss zum Schutzsystem
sensors_plus / geolocator / Native Channels
│
▼
MotionSensorService / EnvironmentSensorService / LocationService
│
▼
SensorService (zentraler Orchestrator)
│
▼
sensorInfoProvider(SensorType) — Riverpod StateNotifierProvider.family
│
▼
AlertStateNotifier._evaluateSensors() ← liest alle 500ms
│
▼
Gefahrenerkennung → Eskalation → Alarm
Server REST-API
PHP REST-API mit JWT-Authentifizierung auf MariaDB 5.5+. Single Source of Truth für Konfiguration und Kontakte.
| Endpunkt | Auth | Actions | Beschreibung |
|---|---|---|---|
api/auth.php | Öffentlich/App | login, register_device, change_password, master_check | Authentifizierung: Login, Geräteregistrierung, Passwort-Änderung, Master-PW-Prüfung. |
api/users.php | Admin | list, get, create, update, delete, stats, login | Benutzerverwaltung mit Telefon/SMS-Nummer, Profil-Zuweisung, Kontakte + Protokolle |
api/alarms.php | App/Admin | report, list, get, stats, acknowledge | SOS-Alarme melden + verwalten. Weiterleitung an Forwarding-Server. Admin-Benachrichtigung. |
api/heartbeat.php | App/Admin | ping, status, user | Periodische Lebenszeichen der App. Online/Offline-Status pro Benutzer. |
api/protocol.php | App/Admin | log, log_batch, my, list, user | App-Aktivitätsprotokoll: Events, Alarme, Statuswechsel — 1:1 Server-Sync. |
api/contacts.php | App/Admin | list, my, create, update, delete, sync | Notfallkontakte pro Benutzer. Admin verwaltet zentral, App synchronisiert. |
api/user_config.php | App/Admin | get, set, effective, list, delete | User-spezifische Konfiguration (überschreibt globale app_config). effective = Single Source of Truth. |
api/config.php | Admin | list, get, set, bulk_set | Globale App-Konfiguration (app_config-Tabelle). Tab-Sichtbarkeit, Feature-Locks, Heartbeat-Intervall. |
api/profiles.php | Admin | list, get, create, update, delete | Schutzprofile verwalten. Szenarien, Schwellwerte, Aktivierung. |
api/servers.php | Admin | list, create, update, delete, test | Dynamische Forwarding-Server für Alarm-/Heartbeat-Weiterleitung. |
api/reports.php | Admin | generate, list, get, delete | Reports generieren (HTML), auflisten, anzeigen, löschen. 5 Typen: user_summary, alarm_report, dguv_compliance, shift_protocol, system_overview. |
api/logger.php | Admin | system_logs, audit_logs, combined, stats, cleanup | Zentralisiertes Logging. Combined-Timeline über alle 3 Log-Quellen + Alarme. Aufräumfunktion. |
api/selfcheck.php | Admin | full, db, config | System-Selbsttest: Datenbankverbindung, Tabellen-Integrität, PHP-Erweiterungen, Verzeichnisse. Einzelne Checks möglich. |
api/upload.php | Admin | upload | Datei-Upload (z.B. Branding-Logos) für das Admin-Panel. |
user_config.php?action=effective
liefert in einem einzigen Aufruf: Globale Konfiguration + User-Overrides + zugewiesenes Schutzprofil +
Server-Notfallkontakte. Die App nutzt diesen Endpunkt als alleinige Konfigurationsquelle nach dem Login.
Heartbeat-Service
Periodische Lebenszeichenüberwachung. App sendet alle 30 Sek. einen Ping, Server erkennt Online/Offline-Status.
📱 App-Seite (HeartbeatService)
Singleton-Service (heartbeat_service.dart) sendet periodisch einen HTTP-POST an
heartbeat.php?action=ping.
Gesendet: Battery-Level, GPS-Position, Monitoring-aktiv, App-Version, last_config_synced_at
Intervall: Server-konfigurierbar (Standard: 30s)
Start: Automatisch nach ConfigSyncService.syncFromServer()
Methoden: start(), stop(), updateInterval()
Config-Erkennung: Vergleicht config_changed_at aus Heartbeat-Response — loggt alt→neu Zeitstempel
🖥️ Server-Seite (heartbeat.php)
Speichert jeden Ping in der heartbeats-Tabelle und aktualisiert users.last_heartbeat.
Protokollierung: Alle 2 Min. wird ein Eintrag in user_protocols geschrieben.
Config-Staleness: Prüft last_config_synced_at vs. config_changed_at — loggt config_stale-Warnung bei veralteter Config
Weiterleitung: Heartbeats werden an konfigurierte Forwarding-Server weitergeleitet
(wenn forward_heartbeats = 1).
Admin: ?action=status zeigt Online/Offline aller Benutzer, ?action=user zeigt Verlauf.
Server-Konfiguration (Single Source of Truth)
Der Server steuert zentral, welche Tabs sichtbar sind, welche Einstellungen der Benutzer ändern darf und welches Profil gilt.
🔧 Konfigurationsschlüssel
| Key | Typ | Standard | Wirkung in der App |
|---|---|---|---|
show_sensors_tab | bool | false | Sensoren-Tab ein/ausblenden |
show_analysis_tab | bool | false | Analyse-Tab ein/ausblenden |
show_dashboard_tab | bool | false | Dashboard-Tab ein/ausblenden |
start_page | string | protection | Startseite: protection, dashboard, sensors, analysis |
allow_profile_change | bool | true | Profil-Auswahl sperren/erlauben |
allow_threshold_change | bool | false | Schwellwert-Slider sperren/erlauben |
allow_scenario_toggle | bool | false | Szenario-Toggles sperren/erlauben |
heartbeat_interval_sec | int | 30 | Heartbeat-Intervall in Sekunden |
🔒 UI-Sperren in der App
Wenn der Server Einstellungen sperrt, zeigt die App:
• 🔒 Banner „Vom Server verwaltet" auf betroffenen Feldern
• Profil-Auswahl wird ausgegraut
• Schwellwert-Slider werden nicht-interaktiv
• Szenario-Toggles werden gesperrt
• Notfallkontakte sind schreibgeschützt (wenn Server-Kontakte vorhanden)
• Settings-Seite zeigt „Single Source of Truth"-Hinweis
📋 Effective-Endpoint Antwort
{
"config": {
"ui": { "show_sensors_tab": false, ... },
"protection": { "allow_threshold_change": false, ... }
},
"user_overrides": { ... },
"profile": { "name": "Außendienst", ... },
"contacts": [
{ "name": "Chef", "phone": "+49...", "priority": 1 }
],
"synced_at": "2026-02-20T10:30:00+01:00"
}
Dynamische Weiterleitungen
Alarme und Heartbeats können an beliebig viele externe Systeme weitergeleitet werden.
🖥️ Forwarding-Server Konfiguration
| Feld | Beschreibung |
|---|---|
name | Bezeichnung des externen Systems |
url | HTTP(S)-Endpunkt, an den weitergeleitet wird |
api_key | Optionaler API-Key für Authentifizierung |
forward_alarms | Alarme weiterleiten (Standard: ja) |
forward_heartbeats | Heartbeats weiterleiten |
forward_user_info | Benutzer-Infos weiterleiten |
headers | Zusätzliche HTTP-Header (JSON) |
Admin-Panel
Single-Page-Application (SPA) unter server/admin/. Vanilla HTML/CSS/JS mit JWT-Auth.
� Dashboard
Übersicht: Benutzer (Online/Offline), Alarme, Profile, letzter Heartbeat. Statistik-Kacheln mit Echtzeitdaten. Automatische Aktualisierung.
👥 Benutzerverwaltung
3-Tab-Modal: Stammdaten (Name, Telefon, SMS-Nr., Rolle, Profil), Notfallkontakte (CRUD pro Benutzer), Konfiguration (User-spezifische Overrides der globalen Config).
🚨 Alarm-Übersicht
Roter Fullscreen-Overlay bei neuem Alarm. Pulsierend + Alarmsound (Web Audio API). Alle 10 Sek. Polling. Muss per Bestätigen-Button quittiert werden — unübersehbar. Alarm-Liste mit Filterung und Acknowledge-Funktion.
📱 Geräteverwaltung
Registrierte Geräte mit Benutzer-Zuordnung, letztem Heartbeat, App-Version und Geräteinformationen.
👷 Schutzprofile
CRUD für Profile. Szenarien aktivieren/deaktivieren, Schwellwerte anpassen, Profil Benutzern zuweisen.
⚙️ App-Konfiguration
Globale und User-spezifische Konfiguration. Steuert Tab-Sichtbarkeit, Feature-Locks, Heartbeat-Intervall, Startseite.
📜 Benutzer-Protokolle
Aktivitätsprotokoll mit Filterung nach Benutzer, Kategorie und Zeitraum. Paginierung. 1:1-Sync mit der App-Historie.
📊 Logging (3-Tier)
Kombinierte Timeline über 3 Log-Quellen: system_logs (Server), audit_log (Änderungen), user_protocols (App-Events). Filter: Level, Kategorie, Benutzer, Datum, Freitextsuche. CSV-Export + Aufräumfunktion.
📄 Reports
5 Report-Typen: user_summary, alarm_report, dguv_compliance, shift_protocol, system_overview. Generierung als HTML, Inline-Vorschau, Druck als PDF via Browser, Löschen von Berichten.
🔀 Server-Weiterleitungen
CRUD für Forwarding-Server. Test-Button prüft Erreichbarkeit. Zeigt letzten Erfolg/Fehler-Zeitstempel.
🎨 Branding
Anpassung des App-Namens und Logos. Upload-Funktion für eigene Branding-Elemente.
💾 Backup
Datenbank-Backup erstellen und wiederherstellen. Sicherung der Konfiguration und Benutzerdaten.
3-Tier Logging-System
Zentralisiertes, 3-stufiges Protokollierungssystem für lückenlose Nachvollziehbarkeit aller Systemereignisse.
🏗️ Architektur
Zentraler Logging-Service (api/logger.php) wird automatisch von db_config.php
in alle PHP-Endpunkte geladen. Dual-Mode: Als Library (require) stellt er Logging-Funktionen bereit,
als API-Endpunkt liefert er Logs für das Admin-Panel.
Funktionen: logSystem(), logAudit(), logInfo(),
logWarning(), logError()
Automatisch erfasst: IP-Adresse, User-Agent, Endpunkt, User-ID
📋 3 Logging-Tiers
1. system_logs — Server-seitige Systemereignisse (debug/info/warning/error/critical)
2. audit_log — Sicherheitsrelevante Änderungen (Login, CRUD, Konfiguration) — nie löschbar
3. user_protocols — App-seitige Events (Statuswechsel, Alarme, Check-ins)
Combined-Timeline: Im Admin-Panel werden alle 3 Quellen in einer einheitlichen Timeline zusammengeführt.
🔌 Logger API-Endpunkte
| Action | Methode | Beschreibung |
|---|---|---|
system_logs | GET | Paginierte System-Logs mit Filter (Level, Kategorie, User, Datum, Suche) |
audit_logs | GET | Paginierte Audit-Einträge mit Filter (Entity-Type, User, Datum, Aktion) |
combined | GET | UNION ALL Timeline aller 4 Quellen (max. 500 Einträge) |
stats | GET | 24h-Statistiken: Anzahl pro Quelle, Level-Verteilung, Fehler-Quote |
cleanup | POST | Alte Einträge löschen (min. 7 Tage). Audit-Logs bleiben permanent erhalten. |
📝 Protokollierte Aktionen (alle 14 PHP-Endpunkte)
| Endpunkt | Protokollierte Ereignisse |
|---|---|
auth.php | Login (Erfolg/Fehlschlag), Passwort-Änderung, Master-PW-Check, Geräteregistrierung |
users.php | Erstellen, Aktualisieren, Deaktivieren, Passwort-Reset, Profil-Zuweisung, Master-PW-Änderung |
config.php | Config-Änderung (Einzel + Bulk) |
profiles.php | Profil erstellen, aktualisieren, deaktivieren |
contacts.php | Kontakt erstellen, aktualisieren, löschen |
servers.php | Server erstellen, aktualisieren, löschen, Test (Erfolg/Fehlschlag) |
user_config.php | User-Config geändert |
heartbeat.php | Forwarding-Erfolg/-Fehler (Debug/Warning/Error) |
alarms.php | Alarm gemeldet (dynamisch: critical/error/warning nach Schweregrad) |
protocol.php | App-Protokolleinträge (Events, Statuswechsel, Alarme) |
selfcheck.php | System-Selbsttest (Ergebnis protokolliert) |
logger.php | Log-Abfragen, Cleanup-Aktionen |
reports.php | Report-Generierung, -Abruf, -Löschung (5 Typen) |
upload.php | Datei-Uploads (Branding) |
Kommunikations-Zuverlässigkeit
Drei dedizierte Services stellen sicher, dass Alarme und Protokolldaten niemals verloren gehen — auch bei instabiler Netzwerkverbindung.
📦 Offline-Queue Service
Persistente Warteschlange für fehlgeschlagene API-Aufrufe. Speichert Daten in
SharedPreferences unter dem Key gis_care_offline_queue.
Kapazität: Max. 500 Einträge, 5 Wiederholungsversuche pro Eintrag
Periodischer Flush: Alle 60 Sekunden werden ausstehende Einträge gesendet
Batch-Upload: Protokoll-Logs werden in 50er-Batches via logProtocolBatch() gesendet
Alarm-Reports: Werden einzeln via reportAlarm() gesendet (höchste Priorität)
📡 Konnektivitäts-Monitor
DNS-basierte Server-Erreichbarkeitsprüfung (kein einfacher WiFi-Check).
Methode: InternetAddress.lookup(serverHost) mit 5s Timeout
Intervall: Alle 30 Sekunden
Server: Prüft den tatsächlichen Server-Host aus ApiConfig.baseUrl
Fallback: google.com wenn kein Server konfiguriert
Aktion: Benachrichtigt Offline-Queue bei Zustandswechsel
(markOnline() / markOffline())
🔍 Geräte-Diagnostik
Sammelt Geräteinformationen und sendet sie als Protokoll-Eintrag an den Server.
Erfasste Daten: Hersteller, Marke, Modell, Android-Version, SDK-Level,
Build-ID, Prozessoranzahl, Locale
Quelle: Android getprop-Befehle + Dart Platform-APIs
Zeitpunkt: Einmalig nach Login (_initializeAfterLogin())
Event-Typ: device_diagnostics (Kategorie: system)
Offline-Queue: Öffentliche API
| Methode | Beschreibung |
|---|---|
enqueueProtocolLog({eventType, category?, details?, latitude?, longitude?}) | Fehlgeschlagenen Protokoll-Eintrag in Queue speichern |
enqueueAlarmReport(Map<String, dynamic>) | Fehlgeschlagenen Alarm-Report in Queue speichern |
enqueueGeneric({type, payload}) | Beliebigen Payload in Queue speichern |
flush() | Alle ausstehenden Einträge senden (Batches für Protokolle, einzeln für Alarme) |
markOnline() / markOffline() | Verbindungsstatus aktualisieren (markOnline löst automatisch flush() aus) |
startPeriodicFlush({intervalSeconds: 60}) | Periodischen Timer starten |
stopPeriodicFlush() | Periodischen Timer stoppen |
queueSize / getQueueSnapshot() | Aktuelle Queue-Größe / Inhalt abfragen |
clear() | Gesamte Queue leeren |
Integration in ApiService
Die Offline-Queue ist direkt in den ApiService integriert. Bei fehlgeschlagenen API-Aufrufen
werden die Daten automatisch in die Queue geschrieben:
// ApiService.reportAlarm() — bei Fehler:
await OfflineQueueService().enqueueAlarmReport({
'scenario': scenario, 'severity': severity, 'message': message,
'latitude': latitude, 'longitude': longitude, ...
});
// Log: "ALARM-ÜBERTRAGUNG FEHLGESCHLAGEN — in Offline-Queue gespeichert"
// ApiService.logProtocol() — bei Fehler:
await OfflineQueueService().enqueueProtocolLog(
eventType: eventType, category: category, details: details, ...
);
// Log: "Protocol-Log fehlgeschlagen, wird gespeichert"
Batterie-Optimierung
Die App fordert beim Start die Ausnahme von Androids Batterie-Optimierung an
(REQUEST_IGNORE_BATTERY_OPTIMIZATIONS). Dies verhindert, dass Android
die Hintergrund-Services einschränkt oder die App bei geringem Akkustand beendet.
Initialisierungsreihenfolge (app.dart)
- Config-Sync —
ConfigSyncService.syncFromServer(ref)(Profil, Kontakte, UI-Flags) - Protocol-Log —
app_startedEvent an Server - Konnektivitäts-Monitor —
ConnectivityMonitor().start(intervalSeconds: 30) - Offline-Queue —
OfflineQueueService().startPeriodicFlush(intervalSeconds: 60) - Batterie-Optimierung —
_requestBatteryOptimizationExemption() - Geräte-Diagnostik —
DeviceDiagnostics.reportToServer() - Geräte-Registrierung —
api.registerDevice()(DGUV 112-139) - Startseite setzen — aus Server-Config (
startPageIndexProvider) - Heartbeat starten —
HeartbeatService().start(intervalSeconds: hbInterval) - Auth-Callback — Redirect bei 401
- Batterie-Callback —
batteryLevelProvideraktualisieren - Verbindungs-Callbacks —
markOffline()/markOnline()+ Alarm-Eskalation bei aktiver Überwachung - Config-Change-Callback — Heartbeat erkennt Änderung →
ConfigSyncService.syncFromServer()
AppLifecycleState.resumed) wird automatisch
die Offline-Queue geflusht, der Heartbeat neu gestartet und die Config erneut synchronisiert.
Umfassende Log-/Event-Referenz
Vollständige Übersicht aller Events und Log-Einträge, die von App, Server und Admin-Panel erfasst werden.
App-seitige Events (user_protocols via protocol.php)
| Event-Typ | Kategorie | Beschreibung | Wann ausgelöst? |
|---|---|---|---|
app_started | system | App gestartet nach Login | Nach _initializeAfterLogin() |
device_diagnostics | system | Geräteinformationen (Hersteller, Modell, OS, SDK) | Einmalig nach Login |
config_applied | config | Server-Konfiguration angewendet (fetched_at + applied_at) | Nach Config-Sync |
config_delivered | config | Server bestätigt Config-Zustellung | Nach erfolgreichem Sync |
config_stale | config | Gerät hat veraltete Konfiguration | Heartbeat-Erkennung serverseitig |
| 🛡️ Schutz-Events | |||
protection_started | protection | Überwachung aktiviert | Start-Button gedrückt |
protection_stopped | protection | Überwachung deaktiviert | Stop-Button gedrückt |
profile_changed | protection | Schutzprofil gewechselt (alt → neu) | Profilauswahl geändert |
| 🚨 Alarm-Events | |||
alarm_potential | alarm | Gefahr erkannt, Eskalation gestartet | Übergang Eskalation Stufe 1 |
alarm_confirmed | alarm | Alarm tatsächlich gesendet (Countdown abgelaufen) | Countdown erreicht 0 |
alarm_cancelled | alarm | Nutzer hat Entwarnung bestätigt | „ALLES OK"-Button |
alarm_sent | alarm | Benachrichtigungsergebnis (SMS/Anruf/Server-Status) | Nach Alarm-Versand |
escalation_stage_1 | alarm | Eskalation Stufe 1 (Vibration) | Eskalationsübergang |
escalation_stage_2 | alarm | Eskalation Stufe 2 (Akustisch + Vibration) | Eskalationsübergang |
escalation_countdown | alarm | Finaler Countdown gestartet | Eskalationsübergang |
| 📱 Benachrichtigungs-Events | |||
sms_sent | notification | SMS erfolgreich versendet an Kontakt | Nach SmsManager-Aufruf |
sms_failed | notification | SMS-Versand fehlgeschlagen (+ Fehlergrund) | Bei SmsManager-Fehler |
call_initiated | notification | Telefonanruf gestartet an Kontakt | Nach MethodChannel-Aufruf |
call_failed | notification | Telefonanruf fehlgeschlagen (+ Fehlergrund) | Bei MethodChannel-Fehler |
server_alarm_reported | notification | Alarm erfolgreich an Server gemeldet | Nach API-Aufruf |
server_alarm_failed | notification | Server-Meldung fehlgeschlagen (→ Offline-Queue) | Bei API-Fehler |
| 💓 Check-in & Heartbeat | |||
checkin_performed | protection | Check-in bestätigt (Countdown reset) | „Bin OK"-Button |
checkin_expired | protection | Check-in-Timer abgelaufen → Eskalation | Countdown erreicht 0 |
heartbeat_started | connection | Heartbeat-Service gestartet | Nach Login |
heartbeat_stopped | connection | Heartbeat-Service gestoppt | Bei Logout/Beenden |
| 🔗 Verbindungs-Events | |||
connection_lost | connection | Server nicht erreichbar (DNS-Probe fehlgeschlagen) | ConnectivityMonitor |
connection_restored | connection | Server wieder erreichbar | ConnectivityMonitor |
offline_queue_flushed | connection | Offline-Queue erfolgreich gesendet (n Einträge) | Nach flush() |
battery_low | system | Batterie-Level kritisch niedrig | Batterie-Callback |
| 🔧 Funktionstest & Schicht | |||
functional_test_passed | dguv | DGUV §4.7 Pre-Shift-Funktionstest bestanden | Test durchgeführt |
functional_test_failed | dguv | Funktionstest fehlgeschlagen (+ Details) | Test fehlgeschlagen |
shift_started | dguv | Schicht gestartet (DGUV §4.8) | Schichtprotokoll |
shift_ended | dguv | Schicht beendet (Zusammenfassung) | Schichtprotokoll |
| 📋 Kontakte & Foreground | |||
contact_added | contacts | Notfallkontakt hinzugefügt | Kontakt-CRUD |
contact_removed | contacts | Notfallkontakt entfernt | Kontakt-CRUD |
foreground_service_started | system | Foreground Service gestartet | Schutz aktiviert |
foreground_service_stopped | system | Foreground Service gestoppt | Schutz deaktiviert |
Server-seitige System-Logs (system_logs)
| Kategorie | Level | Ereignisse |
|---|---|---|
auth | info / warning | Login Erfolg/Fehlschlag, Passwort-Änderung, Master-PW-Check, Token-Verifikation |
alarm | critical / error / warning | Alarm empfangen (dynamischer Level nach Schweregrad), Forwarding Erfolg/Fehler, Acknowledge |
heartbeat | debug / info / warning | Heartbeat empfangen, Config-Staleness erkannt, Forwarding-Ergebnis |
config | info / warning | Config-Änderung (Einzel + Bulk), Config-Abruf, Sync-Bestätigung |
user | info | Benutzer CRUD, Profil-Zuweisung, Passwort-Reset |
profile | info | Profil erstellen/aktualisieren/deaktivieren |
contact | info | Kontakt erstellen/aktualisieren/löschen |
forwarding | info / warning / error | Server erstellen/löschen/testen, Forwarding-Ergebnis |
report | info | Report-Generierung, -Abruf, -Löschung (5 Typen) |
system | info / error | Self-Check Ergebnis, Cleanup-Aktionen, Upload |
protocol | info | App-Protokolleinträge empfangen (Einzel + Batch) |
Audit-Log (audit_log) — Permanent, nicht löschbar
| Entity-Typ | Aktionen | Erfasste Daten |
|---|---|---|
user | create, update, delete, password_reset, assign_profile, set_master_password | Vorher/Nachher-Werte, User-ID, IP, User-Agent |
profile | create, update, delete | Profilname, geänderte Felder |
config | set, set_bulk | Schlüssel, alter Wert → neuer Wert |
user_config | set | User-Overrides mit Schlüssel + Wert |
contact | create, update, delete | Kontaktname, Telefon, Benutzer-Zuordnung |
server | create, update, delete, test | Server-Name, URL, Test-Ergebnis |
auth | login, login_failed, password_change | Benutzername, IP-Adresse, User-Agent |
report | generate, download, delete | Report-Typ, Datumbereich |
upload | upload | Dateiname, Typ, Größe |
Admin-Panel: Log-Darstellung
📜 Benutzer-Protokolle
Zeigt alle user_protocols-Einträge mit Filterung nach Benutzer, Kategorie und Zeitraum.
Paginierung. Auto-Refresh alle 5 Sekunden. 1:1-Sync mit der App-Historie.
📊 System-Logs
Server-seitige Logs mit Filter: Level (debug–critical), Kategorie, Benutzer, Datum, Freitextsuche. Statistiken (24h): Anzahl pro Quelle, Level-Verteilung, Fehler-Quote. CSV-Export.
🔒 Audit-Log
Sicherheitsprotokoll mit Entity-Typ-Filter, Aktions-Filter, Benutzer-Filter. Permanent: Audit-Logs können nicht gelöscht werden (auch nicht via Cleanup-Funktion).
🔗 Combined-Timeline
UNION ALL über alle 4 Quellen (system_logs, audit_log, user_protocols, alarm_events). Einheitliche Timeline mit max. 500 Einträgen. Filtert nach Datum und Benutzer.
logger.php?action=cleanup) löscht alte
System-Logs und Benutzer-Protokolle (min. 7 Tage Aufbewahrung). Audit-Logs bleiben permanent erhalten
und werden nie gelöscht — dies ist für DGUV-Compliance und Rechtssicherheit erforderlich.
Datenbank & Setup
Vollständiges Datenbankschema mit 16 Tabellen. Setup über den 7-Schritt Setup-Wizard (setup.php).
🚀 Setup-Wizard (setup.php)
Der Setup-Wizard (setup.php) führt in 7 Schritten durch die
Ersteinrichtung des Servers:
- Datenbank-Verbindung prüfen — Verbindung zu MariaDB/MySQL testen
- Tabellen erstellen —
database_schema.sqlwird importiert (16 Tabellen) - Admin-Benutzer anlegen — Initialer Administrator-Account
- Master-Passwort setzen — Schutz für Setup und kritische Operationen
- App-Name konfigurieren — Branding/Name der Installation
- Standard-Profile erstellen — 5 Schutzprofile initialisieren
- Konfiguration abschließen — Standardwerte in
app_configschreiben
🗃️ 16 Datenbank-Tabellen
| Tabelle | Zweck | Besonderheit |
|---|---|---|
users | Benutzerkonten | Telefon, SMS-Nr., letzter Heartbeat, Profil-Zuweisung, Rolle |
master_passwords | Master-Passwort | Schützt Setup und kritische Admin-Aktionen |
protection_profiles | Schutzprofile | 5 Profile mit Szenarien + Schwellwerten |
app_config | Globale Konfiguration | Key-Value-Paare: Tab-Sichtbarkeit, Feature-Locks, Heartbeat-Intervall |
alarm_events | Alarm-Ereignisse | Szenarien, Schweregrad, GPS, Sensorwerte, Acknowledge-Status |
emergency_contacts | Notfallkontakte | Pro Benutzer zugewiesen, Priorität, SMS/Anruf-Flags |
devices | Registrierte Geräte | Geräte-ID, App-Version, Benutzer-Zuordnung |
audit_log | Sicherheitsprotokoll | Nie löschbar. Login, CRUD, Config-Änderungen mit IP + Vorher/Nachher |
heartbeats | Verbindungsüberwachung | Jeder Ping = eine Zeile. Automatisch per HeartbeatService |
user_protocols | App-Aktivitätsprotokoll | 1:1 Sync der App-Historie mit Server |
user_config | User-spezifische Overrides | Überschreibt globale app_config pro Benutzer |
system_logs | Technische System-Logs | Level (debug–critical), Kategorie, Kontext (JSON), IP, User-Agent |
forwarding_servers | Alarm-/Heartbeat-Weiterleitung | Dynamisch konfigurierbar im Admin-Panel |
functional_tests | Funktionale Tests | Ergebnisse der System-Selbsttests |
shifts | Schichtdaten | Schichtprotokolle für DGUV-Compliance |
reports | Generierte Berichte | HTML-Reports: 5 Typen, Vorschau, PDF-Druck, löschbar |
database_schema.sql
eingerichtet (keine separaten Migrationsdateien). Der Setup-Wizard importiert dieses Schema automatisch.
Bei Neuinstallation: setup.php aufrufen → der Wizard erledigt alles.
📁 Server-Dateien
| Datei | Zweck |
|---|---|
setup.php | 7-Schritt Setup-Wizard (erstellt Tabellen, Admin, Master-PW, App-Name) |
database_schema.sql | Vollständiges DB-Schema (16 Tabellen) |
db_config.php | Datenbank-Verbindung + Logger-Integration |
credentials.php | JWT-Auth Hilfsfunktionen |
.htaccess | URL-Rewriting und Sicherheitsregeln |
admin/index.html | Admin-Panel SPA (HTML/CSS/JS) |
admin/admin.js | Admin-Panel Logik |
api/ (14 Dateien) | REST-API Endpunkte (siehe Server-API Sektion) |
Architektur (MVVM)
Model-View-ViewModel Architektur mit Riverpod als State-Management-Lösung.
📦 Model-Schicht
lone_worker_models.dart— DangerScenario, AlertState, ScenarioThresholds, ProtectionProfile, AlarmEventemergency_contact.dart— EmergencyContact + EmergencyContactStoresensor_data.dart— SensorData (timestamp, x, y?, z?)sensor_info.dart— SensorInfo (Sensor-Metadaten + aktueller Wert + History)recording_session.dart— RecordingSession für Datenaufzeichnung
🖥️ View-Schicht
lone_worker_page.dart— Kern-UI (2.551 Zeilen): Dynamische Tabs mit Status, Profile (bedingt), Kontakte, Verlaufdashboard_page.dart— Startseite mit Navigationsensor_list_page.dart— Sensorübersichtsensor_detail_page.dart— Sensor-Detailansicht mit Live-Chartanalysis_page.dart— Sensoranalysesettings_page.dart— App-Einstellungentest_mode_page.dart— DGUV Testmodus (Sensorprüfung)setup_wizard_page.dart— Ersteinrichtungs-Assistentlogin_page.dart— Login-Seite
🧠 ViewModel-Schicht
lone_worker_providers.dart— Herzstück (938 Zeilen): AlertStateNotifier, SMS+Anruf-Logik, Protocol-Loggingserver_config_providers.dart— Server-Config State (Tab-Sichtbarkeit, Feature-Locks, Server-Kontakte)auth_providers.dart— Login/Logout, ApiService-Providerproviders.dart— Sensor-Provider, Recording-Provider, Sampling-Rate-Provider
⚙️ Service-Schicht
alarm_hardware_service.dart— Vibration + Alarmsound via MethodChannelalarm_notification_service.dart— SMS + Anruf (Standard-Telefon-App, kein doppelter SMS-Versand) + Serverforeground_service.dart— Foreground Service:flutter_foreground_task+wakelock_plusheartbeat_service.dart— Periodischer Heartbeat-Ping an Serverconfig_sync_service.dart— Server → App Config-Sync (Single Source of Truth)api_service.dart— REST-API Client mit Offline-Queue-Integration (525 Zeilen)offline_queue_service.dart— ⭐ Persistente Offline-Warteschlange (273 Zeilen)connectivity_monitor.dart— ⭐ DNS-basierte Konnektivitätsüberwachung (84 Zeilen)device_diagnostics.dart— ⭐ Geräteinformationen + Server-Report (89 Zeilen)sensor_service.dart— Zentraler Sensor-Orchestrator- + 6 weitere: motion_sensor, environment_sensor, location, audio, native_sensor, calibration, export
Tech-Stack
Verwendete Technologien, Frameworks und Abhängigkeiten.
🎯 Flutter
Cross-platform Framework (letzte stabile Version). Android API 21+ (Lollipop).
🎯 Dart ^3.5.4
Programmiersprache mit Null-Safety.
🔗 flutter_riverpod ^2.6.1
Compile-safe State Management. StateNotifierProvider, StateProvider, .family.
📊 fl_chart ^0.69.2
Live-Charts für Sensor-Visualisierung.
📡 sensors_plus ^6.1.1
Accel, Gyro, Magnetometer via Flutter Plugin.
📍 geolocator ^13.0.2
GPS-Positionsbestimmung.
🔐 permission_handler ^11.3.1
Runtime-Berechtigungen für Sensoren & SMS.
💾 shared_preferences ^2.3.4
Persistierung (Kontakte, Einstellungen).
📤 share_plus / url_launcher
Share-API, CSV-Export, URI-Handling.
🔒 flutter_foreground_task
Foreground Service für robuste Hintergrundüberwachung. Hält Monitoring aktiv bei gesperrtem Bildschirm.
💡 wakelock_plus
Verhindert CPU-Sleep. Ergänzt Foreground Service für zuverlässigen Dauerbetrieb.
🔋 battery_plus
Batterie-Status und -Level. Wird im Heartbeat an den Server gesendet.
State Management (Provider-Übersicht)
Alle Riverpod-Provider des Alleinarbeiter-Schutzsystems auf einen Blick.
| Provider | Typ | Initialer Wert | Beschreibung |
|---|---|---|---|
emergencyContactsProvider | StateNotifierProvider<…, List<EmergencyContact>> | [] (aus SharedPrefs) | Lokale Notfallkontakte mit CRUD |
serverEmergencyContactsProvider | StateNotifierProvider<…, List<EmergencyContact>> | [] | Server-verwaltete Kontakte (Vorrang) |
selectedProfileProvider | StateProvider<ProtectionProfile> | Außendienst (Index 2) | Aktuell gewähltes Profil |
customThresholdsProvider | StateProvider<ScenarioThresholds> | Profil-Standardwerte | Slider-Anpassungen |
protectionActiveProvider | StateProvider<bool> | false | Schutz aktiv/inaktiv |
alertStateProvider | StateNotifierProvider<AlertStateNotifier, AlertState> | AlertState.idle | Kern-Zustandsautomat |
alarmHistoryProvider | StateProvider<List<AlarmEvent>> | [] | Alarm-Ereignisprotokoll |
countdownSecondsProvider | StateProvider<int> | 0 | Restzeit Eskalation |
lastDetectionProvider | StateProvider<String> | '' | Letzte Detektions-Nachricht |
escalationStageProvider | StateProvider<int> | 0 | Aktuelle Stufe (1/2/3) |
checkinCountdownProvider | StateProvider<int> | 0 | Sekunden bis Check-in |
alarmNotificationResultProvider | StateProvider<String> | '' | Ergebnis des Alarm-Versands |
| Server-Config Provider (NEU — server_config_providers.dart) | |||
showSensorsTabProvider | StateProvider<bool> | true | Sensoren-Tab sichtbar? |
showAnalysisTabProvider | StateProvider<bool> | true | Analyse-Tab sichtbar? |
showDashboardTabProvider | StateProvider<bool> | true | Dashboard-Tab sichtbar? |
startPageIndexProvider | StateProvider<int> | 3 (Protection) | Startseite-Tab-Index |
allowThresholdChangeProvider | StateProvider<bool> | true | Schwellwerte änderbar? |
allowScenarioToggleProvider | StateProvider<bool> | true | Szenarien umschaltbar? |
allowProfileChangeProvider | StateProvider<bool> | true | Profil wechselbar? |
heartbeatIntervalProvider | StateProvider<int> | 30 | Heartbeat-Intervall (Sek.) |
serverProfileProvider | StateProvider<Map?> | null | Vom Server zugewiesenes Profil |
Native Android APIs & Foreground Service
Die App nutzt native MethodChannels/EventChannels sowie flutter_foreground_task + wakelock_plus für robuste Hintergrundüberwachung.
🔒 Foreground Service (Hintergrundschutz)
Die App verwendet flutter_foreground_task zusammen mit wakelock_plus, um die
Überwachung auch bei gesperrtem Bildschirm und minimierter App zuverlässig aufrechtzuerhalten.
AndroidManifest Berechtigungen
| Permission | Zweck |
|---|---|
FOREGROUND_SERVICE_LOCATION | GPS-Überwachung im Hintergrund |
FOREGROUND_SERVICE_HEALTH | Gesundheitsüberwachung (Sensor-Auswertung) im Hintergrund |
WAKE_LOCK | CPU wach halten (verhindert Sleep) |
POST_NOTIFICATIONS | Foreground-Service-Benachrichtigung anzeigen (Android 13+) |
RECEIVE_BOOT_COMPLETED | Automatischer Neustart nach Geräte-Reboot |
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS | Ausnahme von Batterie-Optimierung (verhindert Hintergrund-Einschränkungen) |
SEND_SMS | Direkter SMS-Versand über SmsManager (kein Nutzer-Tap) |
CALL_PHONE | Direkter Telefonanruf über Standard-Telefon-App |
VIBRATE | Custom Vibrationsmuster mit Amplituden |
AndroidManifest Service-Element
<service
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
android:foregroundServiceType="location|health"
android:exported="false" />
Native MethodChannels / EventChannels
| Channel | Typ | Methoden | Zweck |
|---|---|---|---|
com.sensorsuite/vibration | MethodChannel | vibrate({pattern, amplitudes, repeat}), cancel() |
Custom Vibrationsmuster mit Amplituden — übersteigt Standard-HapticFeedback |
com.sensorsuite/alarm_sound | MethodChannel | play(), stop() |
Alarmsound auf STREAM_ALARM — umgeht Lautlos/DND |
com.sensorsuite/sms | MethodChannel | sendSms({phone, message}), requestPermission() |
Direkter SMS-Versand über Android SmsManager |
com.sensorsuite/phone_call | MethodChannel | call({phone}), checkPermission(), requestPermission() |
Telefonanruf über Standard-Telefon-App (TelecomManager.defaultDialerPackage). ACTION_CALL mit Permission, Fallback auf ACTION_DIAL |
com.sensorsuite/light_sensor | EventChannel | Stream<double> | Lichtsensor (Lux) |
com.sensorsuite/proximity_sensor | EventChannel | Stream<double> | Näherungssensor (cm) |
com.sensorsuite/temperature_sensor | EventChannel | Stream<double> | Temperatursensor (°C) |
com.sensorsuite/audio_level | EventChannel | Stream<double> | Mikrofon dB-Pegel |
Dateistruktur
Übersicht der relevanten Dateien mit Fokus auf Schutzsystem-Dateien.
├── main.dart — Einstiegspunkt (ProviderScope)
├── app.dart — ⭐ MaterialApp, dynamische Tab-Sichtbarkeit, Server-Start-Page, Initialisierung (471 Z.)
│
├── models/
│ ├── lone_worker_models.dart — ⭐ DangerScenario, AlertState, Thresholds, Profiles, AlarmEvent (378 Z.)
│ ├── emergency_contact.dart — ⭐ EmergencyContact + Store (relationship, priority, dual JSON)
│ ├── sensor_data.dart — SensorData Basisklasse
│ ├── sensor_info.dart — SensorInfo Metadaten
│ └── recording_session.dart — Aufzeichnungssession
│
├── services/
│ ├── alarm_hardware_service.dart — ⭐ Vibration + Alarmsound (100 Z.)
│ ├── alarm_notification_service.dart — ⭐ SMS + Anruf (Standard-Telefon-App, skipSms) + Server (151 Z.)
│ ├── foreground_service.dart — ⭐ Foreground Service (
flutter_foreground_task + wakelock_plus)│ ├── heartbeat_service.dart — ⭐ Periodischer Heartbeat-Ping
│ ├── config_sync_service.dart — ⭐ Server→App Config-Sync (effective endpoint)
│ ├── api_service.dart — ⭐ REST-API Client mit Offline-Queue-Integration (525 Z.)
│ ├── offline_queue_service.dart — ⭐ Persistente Offline-Warteschlange (273 Z.) 🆕
│ ├── connectivity_monitor.dart — ⭐ DNS-basierte Server-Erreichbarkeitsprüfung (84 Z.) 🆕
│ ├── device_diagnostics.dart — ⭐ Geräteinformationen + Server-Report (89 Z.) 🆕
│ ├── api_config.dart — API-Endpunkte Konfiguration
│ ├── sensor_service.dart — Zentraler Orchestrator
│ ├── motion_sensor_service.dart — Accel/Gyro/Magnet
│ ├── environment_sensor_service.dart — Barometer/Pedometer
│ ├── location_service.dart — GPS
│ ├── audio_service.dart — Mikrofon
│ ├── native_sensor_service.dart — Licht/Nähe/Temp
│ ├── calibration_service.dart — Kalibrierung
│ └── export_service.dart — CSV Export
│
├── viewmodels/
│ ├── lone_worker_providers.dart — ⭐ AlertStateNotifier, SMS+Anruf, Protocol-Logging (938 Z.)
│ ├── server_config_providers.dart — ⭐ Tab-Sichtbarkeit, Feature-Locks, Server-Kontakte
│ ├── auth_providers.dart — Login/Logout, ApiService
│ └── providers.dart — Sensor-Provider
│
├── views/
│ ├── lone_worker_page.dart — ⭐ Dynamische Tabs mit Server-Locks (🔒 Profile/Schwellwerte/Kontakte) (2.551 Z.)
│ ├── dashboard_page.dart — Startseite
│ ├── sensor_list_page.dart — Sensorübersicht
│ ├── sensor_detail_page.dart — Sensor-Detailansicht
│ ├── analysis_page.dart — Analyse
│ ├── settings_page.dart — Einstellungen (Server-Enforcement Banner)
│ ├── login_page.dart — Login-Seite
│ ├── test_mode_page.dart — ⭐ DGUV Testmodus (Sensorprüfung) 🆕
│ └── setup_wizard_page.dart — ⭐ Ersteinrichtungs-Assistent 🆕
│
├── widgets/
│ ├── sensor_card.dart — Sensor-Card Widget
│ ├── sensor_tile.dart — Kompakte Sensor-Anzeige
│ ├── live_chart.dart — Echtzeit-Graph
│ ├── mini_sparkline.dart — Mini-Sparkline
│ ├── data_logger.dart — Daten-Logger Widget
│ └── master_password_gate.dart — Master-Passwort Abfrage
│
├── theme/
│ └── app_theme.dart — Material 3, Seed #006A6A
│
└── utils/
├── constants.dart — SensorType Enum, Kategorien (155 Z.)
├── sensor_fusion.dart — Roll/Pitch/Yaw
├── formatters.dart — Datum/Zeit-Formatierung (22 Z.)
├── logger.dart — Zentraler App-Logger (55 Z.) 🆕
└── storage_keys.dart — SharedPreferences Schlüssel-Konstanten (11 Z.) 🆕
server/
├── database_schema.sql — Komplettes DB-Schema (16 Tabellen)
├── db_config.php — Datenbank-Verbindung + Logger-Integration
├── credentials.php — JWT-Auth Hilfsfunktionen
├── setup.php — 7-Schritt Setup-Wizard (Tabellen, Admin, Master-PW, App-Name)
├── .htaccess — URL-Rewriting und Sicherheitsregeln
├── api/ (14 Dateien)
│ ├── auth.php — Authentifizierung (Login, Geräteregistrierung, Master-PW)
│ ├── users.php — Benutzer-API (Telefon/SMS-Felder)
│ ├── alarms.php — SOS-Alarm-API (+ Forwarding)
│ ├── heartbeat.php — Heartbeat-Ping API
│ ├── protocol.php — Benutzer-Protokoll API
│ ├── contacts.php — Notfallkontakte API
│ ├── user_config.php — User-Config + Effective Endpoint
│ ├── config.php — Globale App-Konfiguration
│ ├── profiles.php — Schutzprofile API
│ ├── servers.php — Forwarding-Server API
│ ├── reports.php — Reports (5 Typen: HTML-Generierung, Vorschau, Löschen)
│ ├── logger.php — ⭐ Zentralisiertes 3-Tier Logging (Library + API)
│ ├── selfcheck.php — System-Selbsttest
│ └── upload.php — Datei-Upload (Branding)
└── admin/
├── index.html — SPA Admin-Panel (Dashboard, Users, Alarme, Geräte, Profile, Config, Protokolle, Logs, Reports, Server, Branding, Backup)
└── admin.js — Admin-Logik
Changelog
Alle relevanten Änderungen am System, chronologisch dokumentiert.
🔧 Update — Juli 2025 (4)
Kommunikations-Zuverlässigkeit & Offline-Queue
- Offline-Queue Service (273 Zeilen) — Neuer persistenter Queue-Service für fehlgeschlagene API-Aufrufe. Max. 500 Einträge, 5 Retries, 60s periodischer Flush, Batch-Upload für Protokolle
- Konnektivitäts-Monitor (84 Zeilen) — DNS-basierte Server-Erreichbarkeitsprüfung alle 30s. Prüft den tatsächlichen Server-Host, nicht nur WiFi-Status
- Geräte-Diagnostik (89 Zeilen) — Sammelt Geräteinformationen (Hersteller, Modell, OS, SDK, Build-ID) und sendet als Protocol-Log an Server
- Batterie-Optimierung —
REQUEST_IGNORE_BATTERY_OPTIMIZATIONSPermission hinzugefügt, wird beim Start angefordert - ApiService-Integration —
reportAlarm()undlogProtocol()speichern fehlgeschlagene Aufrufe automatisch in Offline-Queue - foreground_service.dart — Stille Catches behoben → explizites Error-Logging (DGUV: Alarme dürfen NIEMALS stille Fallbacks haben)
- app.dart — Erweiterter Initialisierungsfluss: Config → Protocol → Connectivity Monitor → Offline Queue → Battery Opt → Device Diagnostics → Device Registration → Heartbeat
- Resume-Handler — Flusht Offline-Queue, startet Heartbeat neu, synchronisiert Config bei App-Wiederaufnahme
🔧 Update — Juli 2025 (3)
3 Benutzer-gemeldete Bugs behoben
- Telefon-App-Chooser behoben — Standard-Telefon-App wird jetzt über
TelecomManager.defaultDialerPackageermittelt und direkt angesteuert (kein App-Chooser-Dialog mehr). Neuer MethodChannelcom.sensorsuite/phone_callin MainActivity.kt - Doppelter SMS-Versand behoben —
initiateEmergencyCall()hat nunskipSms: trueals Standard. SMS wird nur einmal insendAlarm()an alle Kontakte versendet, nicht nochmal vor jedem Anruf - Layout-Neuordnung (Status-Tab) — Reihenfolge optimiert: Warnungen → Status-Card → Check-in → Funktionstest (einklappbar nach bestandenem Test) → Start-Button → SOS → Szenarien → Schwellwerte → Profil-Card (unten)
🔧 Update — Juli 2025 (2)
GPS-Fix & Admin-Panel Überarbeitung
- GPS-Fix —
Permission.locationAlways.request()aus dem upfront Batch entfernt → verhindert unerwarteten Sprung zu Standort-Einstellungen - Admin-Panel: Alarm-Badge — Zeigt nur unbestätigte Alarme (nicht alle)
- Admin-Panel: Status-Farben — Polling-Status: Grün = Online, Rot = Offline, Orange = Schutz inaktiv
- Admin-Panel: Effektive Werte — User-Config-Tab zeigt jetzt effektive Werte (Global + Override) mit Vorschau
- Admin-Panel: Config-Gruppen — Vorschau-Badges und Zusammenfassungsleiste pro Gruppe
- Admin-Panel: Reaktionszeit — Formatierung: Sekunden, Minuten oder "Nicht gemessen"
- Admin-Panel: Notfallkontakte — Nur nach Master-PW-Eingabe sichtbar
- Admin-Panel: Alarmsound-Fallback — Toast-Hinweis bei Fallback (kein stiller Fallback)
🔧 Update — Juli 2025 (1)
UTF-8 Fix, Test-Härtung, APK-Build
- UTF-8 Encoding — 9 Dart-Dateien korrigiert (Umlaute/Sonderzeichen in Strings und Kommentaren)
- Tests — 11 Hardware-Tests vereinheitlicht (echte AlarmHardwareService-Aufrufe statt Mocks), 3 Implementierungen zusammengeführt, nicht-blockierende Permission-Fehler
- APK gebaut — 52,6 MB (erste Version), 52,8 MB (mit Offline-Queue)
🔧 Update — Juni 2025
Kommunikations-Audit, Profil-Fix, Logging-Erweiterung
1. Kommunikations-Audit (App ↔ Server)
- alarms.php — Stille Catches bei Alarm-Forwarding und Protokoll-INSERT behoben →
logError()statt leerercatch - heartbeat.php — Stille Catches bei config_changed_at und forwardToServers behoben
- auth.php —
logWarning()inhandleVerify()ergänzt - reports.php —
logAudit()für Downloads, bedingte Logging-Guards (function_exists) entfernt - upload.php —
$authkorrekt erfasst,function_exists-Guard entfernt - api_service.dart — Logging für
reportAlarm()(DGUV-kritisch),checkMasterPassword(),changePassword()ergänzt - Geräteregistrierung — Neuer Endpoint
auth.php?action=register_device, neueregisterDevice()-Methode in ApiService, automatischer Aufruf nach Login
2. Profil-Persistenz (Kritischer Bugfix)
- Race Condition behoben (admin.js) —
loadProfilesForSelect()warasyncaber nichtawait-ed → Dropdown-Optionen noch nicht geladen beim Setzen vonprofile_id→ Profil wurde stets alsnull(Standard-Profil) gespeichert - users.php —
updated_at = NOW()inhandleUpdate()ergänzt → Änderungen per Heartbeat erkennbar - heartbeat.php —
users.updated_atinGREATEST()-Query fürconfig_changed_ataufgenommen → Profilzuweisung wird vom Gerät erkannt - admin.js loadUserConfig() —
data.configs→data.config(Property-Name korrigiert, PHP liefert Singular)
3. Bidirektionale Config-Zustellungsbestätigung
- user_config.php — Neues Event
config_deliveredmitconfig_changed_at-Korrelation +last_app_sync-Update - heartbeat_service.dart — Config-Änderungs-Log enthält jetzt alt→neu Zeitstempel + Erkennungszeitpunkt
- heartbeat_service.dart — Sendet
last_config_synced_atim Heartbeat-Payload an Server - heartbeat.php — Neue Staleness-Erkennung: loggt
config_stale-Warnung wenn Gerät veraltete Config hat - config_sync_service.dart —
config_synced→config_appliedmitfetched_at+applied_atZeitstempeln - api_service.dart —
sendHeartbeat()akzeptiert neuenlastConfigSyncedAt-Parameter
Korrelationskette: Config geändert → Heartbeat erkennt → App lädt → Server bestätigt Zustellung (config_delivered) → App bestätigt Anwendung (config_applied) → Heartbeat meldet aktuelle Version
4. Config-Sync Fixes (vorherige Sitzung)
- config.php —
updated_atwird jetzt korrekt bei Änderungen gesetzt - user_config.php — Server-seitiges Logging bei Config-Abruf ergänzt
- config_sync_service.dart — Protokoll-Logging für Sync-Erfolg ergänzt
- profiles.php —
updated_atwird bei Profiländerungen gesetzt - contacts.php —
updated_atbei INSERT ergänzt