← Übersicht

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.

5
Gefahrenszenarien
5
Schutzprofile
3
Eskalationsstufen
9
Schwellwerte
10
Sensor-Typen
17
App-Services
3
Alarmkanäle (SMS + Anruf + Server)
16
Datenbank-Tabellen
14
REST-API Endpunkte
21
Android-Berechtigungen

📋 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.

📸
Screenshot: Dashboard / Startseite mit Navigationsleiste
Zeigt den Einstieg in die App mit den dynamischen Tabs (Status, Profile, Kontakte, Verlauf)

5 Gefahrenszenarien

Jedes Szenario nutzt spezifische Sensorkombinationen und Algorithmen zur Erkennung potenzieller Notfälle.

🔻
1. Sturzerkennung Kritisch
Erkennt plötzliche hohe Beschleunigung gefolgt von Stillstand — typisch für einen Sturz.

Erkennungsalgorithmus

Phasen-Erkennung (2-Phasen-Modell):
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).
ParameterStandardwertBereichBeschreibung
accelerationThreshold25.0 m/s²10–50 m/s²Mindestbeschleunigung für Spike-Erkennung
stillnessDurationSec10 s3–30 sDauer 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
}
😴
2. Ohnmacht / Bewusstlosigkeit Kritisch
Erkennt Kombination aus fehlendem Bewegungssensor-Signal und starrer GPS-Position über längere Zeit — mögliche Ohnmacht.

Erkennungsalgorithmus

Multi-Sensor-Fusion (3 Prüfungen parallel):

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.
ParameterStandardwertBereichBeschreibung
maxInactivitySec300 s (5 Min)30–900 sMax. Zeit ohne Bewegung
gpsDriftToleranceM5.0 m1–20 mMax. 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
⏸️
3. Bewegungslosigkeit Warnung
Keine Bewegung erkannt über den konfigurierten Zeitraum — Person reagiert möglicherweise nicht.

Erkennungsalgorithmus

Doppelte Stillstand-Prüfung:

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.
ParameterStandardwertBeschreibung
maxInactivitySec300 s (5 Min)Max. Zeit vollständiger Reglosigkeit

Genutzte Sensoren

Gyroskop Beschleunigungssensor

📐
4. Lageänderung (Sturz-Lage) Warnung
Erkennt ungewöhnliche Geräte-Neigung (z.B. flach liegend) über längere Zeit — möglicher Sturz.

Erkennungsalgorithmus

Winkelberechnung aus Beschleunigungsdaten:

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.
ParameterStandardwertBereichBeschreibung
tiltAngleDeg60°30–90°Kritischer Neigungswinkel
tiltDurationSec30 s5–120 sDauer 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
}
💓
5. Regelmäßiger Check-in (Heartbeat) Willensabhängig
Fordert den Mitarbeiter regelmäßig auf, per Tap zu bestätigen, dass alles OK ist. Keine Antwort → Alarm.

Funktionsweise

Countdown-basiertes Heartbeat-System:

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 checkinPendingEskalation 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.
ParameterStandardwertBereichBeschreibung
checkinIntervalSec1800 s (30 Min)300–7200 sIntervall zwischen Check-ins
📸
Screenshot: „Status"-Tab während aktiver Überwachung
Zeigt den grünen „Überwachung aktiv ✓"-Status, aktive Szenarien als Chips und den Check-in-Countdown

👷 5 Schutzprofile

Vorkonfigurierte Profile für verschiedene Arbeitssituationen. Jedes Profil definiert aktive Szenarien und optimierte Schwellwerte.

🏗️ Baustelle / Handwerk
Optimiert für körperliche Arbeit. Höherer Beschleunigungsschwellwert wegen ständiger Erschütterungen. Kurze Reaktionszeit bei echtem Notfall.
🔻 Sturzerkennung 😴 Ohnmacht ⏸️ Bewegungslosigkeit 📐 Lageänderung 💓 Check-in
Warum ist „Bewegungslosigkeit" deaktiviert? Auf Baustellen gibt es häufig kurze Pausen und statische Arbeiten (Schrauben, Messen). Ein aktives No-Movement-Szenario würde zu viele Fehlalarme auslösen.
Beschleunigung
30.0 m/s²
Stillstand
8 s
Max. Inaktivität
180 s (3 Min)
GPS-Toleranz
3.0 m
Neigungswinkel
70°
Neigungsdauer
20 s
Check-in
1800 s (30 Min)
Eskalationsstufe
15 s
Countdown
30 s
🏢 Büro / Innendienst
Für sitzende Tätigkeiten. Längere Inaktivitätstoleranz (10 Min), empfindlichere Sturzerkennung (20 m/s²). Längere Eskalationszeiten.
🔻 Sturzerkennung 😴 Ohnmacht ⏸️ Bewegungslosigkeit 📐 Lageänderung 💓 Check-in
Warum kein Tilt / Check-in? Im Büro liegt das Handy oft flach auf dem Tisch (→ Tilt wäre Fehlalarm). Check-in ist unnötig, da die Sensorik bei sitzender Tätigkeit ausreicht.
Beschleunigung
20.0 m/s²
Stillstand
15 s
Max. Inaktivität
600 s (10 Min)
GPS-Toleranz
2.0 m
Neigungswinkel
55°
Neigungsdauer
45 s
Check-in
3600 s (60 Min)
Eskalationsstufe
20 s
Countdown
45 s
🌿 Außendienst / Gelände
Für Arbeiten im Freien. GPS-gestützt, alle Szenarien aktiv. Standardwerte als ausgewogene Basis.
🔻 Sturzerkennung 😴 Ohnmacht ⏸️ Bewegungslosigkeit 📐 Lageänderung 💓 Check-in
Standard-Profil: Dieses Profil wird beim ersten Start der App automatisch ausgewählt. Es bietet die ausgewogensten Schwellwerte für Geländearbeit.
Beschleunigung
25.0 m/s²
Stillstand
10 s
Max. Inaktivität
300 s (5 Min)
GPS-Toleranz
5.0 m
Neigungswinkel
60°
Neigungsdauer
30 s
Check-in
1800 s (30 Min)
Eskalationsstufe
15 s
Countdown
30 s
📦 Lager / Logistik
Für Lagerarbeit. Berücksichtigt häufiges Bücken/Heben. Niedrigere Sturzschwelle, großzügigere GPS-Toleranz (Hallenbewegung).
🔻 Sturzerkennung 😴 Ohnmacht ⏸️ Bewegungslosigkeit 📐 Lageänderung 💓 Check-in
Warum keine Tilt-Erkennung? Lagerarbeiter bücken sich häufig und legen ihr Gerät auf Regale/Paletten. Ein aktivierter Tilt-Sensor würde permanent falsch auslösen. GPS-Toleranz ist höher (8m), da in Lagerhallen GPS ohnehin ungenau ist.
Beschleunigung
22.0 m/s²
Stillstand
12 s
Max. Inaktivität
240 s (4 Min)
GPS-Toleranz
8.0 m
Neigungswinkel
65°
Neigungsdauer
25 s
Check-in
2400 s (40 Min)
Eskalationsstufe
15 s
Countdown
20 s
🌙 Nachtschicht / Allein
Maximaler Schutz. ALLE Szenarien aktiv, kürzeste Reaktionszeiten. Für Situationen mit höchstem Risiko.
🔻 Sturzerkennung 😴 Ohnmacht ⏸️ Bewegungslosigkeit 📐 Lageänderung 💓 Check-in
Höchste Sensitivität: Niedrigster Beschleunigungsschwellwert (20 m/s²), kürzeste Inaktivitätstoleranz (2 Min), häufigste Check-ins (15 Min). Eskalationsstufen nur 10s — der Alarm wird schnell zum Notfall. Für Alleinarbeit in der Nacht, wenn Hilfe am weitesten entfernt ist.
Beschleunigung
20.0 m/s²
Stillstand
6 s
Max. Inaktivität
120 s (2 Min)
GPS-Toleranz
3.0 m
Neigungswinkel
50°
Neigungsdauer
15 s
Check-in
900 s (15 Min)
Eskalationsstufe
10 s
Countdown
20 s
📸
Screenshot: Profil-Tab mit allen 5 Profilen und Szenarien-Icons
Zeigt die Profilauswahl-Cards mit farbiger Markierung des aktiven Profils und den aktivierten Szenarien-Emojis

🎚️ 9 konfigurierbare Schwellwerte

Jeder Schwellwert ist per Slider im Profil-Tab anpassbar. Änderungen nur bei deaktiviertem Schutz möglich.

#ParameterStandardMinMaxEinheitBetrifft SzenarioErklärung
1accelerationThreshold25.01050m/s² Sturz Mindestbeschleunigung für Sturzspike. Höhere Werte = weniger empfindlich (gut für körperliche Arbeit).
2stillnessDurationSec10330s Sturz Wie lange nach dem Spike Stillstand herrschen muss, bevor Alarm ausgelöst wird.
3maxInactivitySec30030900s Ohnmacht Bewegungslos Maximale Dauer ohne erkannte Bewegung. Zentral für Ohnmacht- und Reglosigkeitserkennung.
4gpsDriftToleranceM5.0120m Ohnmacht GPS-Radius innerhalb dessen die Position als „statisch" gilt. Klein = empfindlicher.
5tiltAngleDeg603090° Lage Ab welchem Neigungswinkel das Gerät als „flach liegend" gilt. 0° = vertikal, 90° = horizontal.
6tiltDurationSec305120s Lage Wie lange die abnormale Neigung anhalten muss, bevor sie als Verdacht gilt.
7checkinIntervalSec18003007200s Check-in Intervall zwischen den vorgeschriebenen Check-ins. 1800s = alle 30 Minuten.
8escalationStageSec15560s Alle Dauer jeder Eskalationsstufe (Stufe 1 + Stufe 2). Gesamte Eskalation = 2 × Wert + Countdown.
9alarmCountdownSec3010120s Alle Dauer des finalen Countdowns (Stufe 3) vor dem automatischen Alarm-Versand.
Gesamtzeit bis zum Alarm: escalationStageSec × 2 + alarmCountdownSec
Bei Standardwerten: 15s + 15s + 30s = 60 Sekunden von Erkennung bis Alarmversand.
Bei Nachtschicht-Profil: 10s + 10s + 20s = 40 Sekunden.
📸
Screenshot: Schwellwert-Slider im Profil-Tab
Zeigt die Slider für alle 9 Schwellwerte mit aktuellen Werten und Labels

📢 3-Stufen Eskalationssystem

Jeder erkannte Gefahrenzustand durchläuft drei Eskalationsstufen, bevor der tatsächliche Alarm versendet wird.

1
Vibration
Intensive irreguläre Vibrationsmuster
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.
2
Akustisch + Vibration
Alarmsound auf STREAM_ALARM + aggressive Vibration
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).
3
Finaler Countdown
Letzter großer Countdown + maximale Vibration
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.
Entwarnung jederzeit möglich! Während aller drei Stufen wird ein großer grüner „ALLES OK – Entwarnung"-Button angezeigt. Drückt der Nutzer diesen, werden alle Hardware-Alarme (Vibration + Sound) sofort gestoppt, das Ereignis wird als „Entwarnt" protokolliert, und die Überwachung wird fortgesetzt.

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.

📸
Screenshot: Eskalation Stufe 2 — Countdown-Kreis und „ALLES OK"-Button
Zeigt die orangefarbene Status-Card mit dem runden Countdown-Indikator, der Fortschrittsleiste (Stufe 1→2→3) und dem grünen Entwarnung-Button

💓 Check-in Heartbeat System

Willensabhängige Sicherheitsfunktion: Fordert regelmäßige Bestätigung des Nutzers.

⏱️ Funktionsablauf

Start Schutz wird aktiviert → _startCheckinTimerIfNeeded() startet Countdown
Tick Jede Sekunde wird checkinCountdownProvider decrementiert, UI zeigt MM:SS
OK? Nutzer drückt „Bin OK"-Button → performCheckin() → Countdown resettet
Ablauf Countdown erreicht 0 → Zustand → AlertState.checkinPending → Eskalation beginnt
Alarm Keine Reaktion während aller 3 Eskalationsstufen → Alarm an Notfallkontakte

📱 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

ProfilCheck-in IntervallAktiv?
Baustelle30 Min✅ Ja
Büro60 Min❌ Nein
Außendienst30 Min✅ Ja
Lager40 Min✅ Ja
Nachtschicht15 Min✅ Ja
📸
Screenshot: Check-in-Card mit Countdown und „Bin OK"-Button
Die blaue Card im Status-Tab mit der großen Monospace-Anzeige „28:45" und dem grünen Button rechts

📱 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.

Kein doppelter SMS-Versand: Die Methode 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):

EndpunktRichtungIntervallInhalt
heartbeat.php?action=pingApp → Serveralle 30 s (konfigurierbar)Battery-Level, GPS, Monitoring-Status, App-Version
alarms.php?action=reportApp → Serverbei GefahrSzenario, Schweregrad, GPS, Sensorwerte, Nachricht
user_config.php?action=effectiveServer → Appbei Login/SyncGlobale Config + User-Overrides + Profil + Kontakte
protocol.php?action=logApp → Serverbei EventsEvent-Typ, Kategorie, Details, Metadaten
Heartbeat-Timeout serverseitig: Die 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.
GPS-Position: Wenn zum Zeitpunkt des Alarms GPS-Daten verfügbar sind (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)

  1. Countdown in Stufe 3 erreicht 0 → _triggerAlarm() wird aufgerufen
  2. AlarmEvent mit Typ confirmed wird in der History geloggt
  3. Max-Vibration + Alarmsound werden gestartet (bleiben auch nach Versand aktiv)
  4. _sendNotifications() wird aufgerufen
  5. GPS-Position wird aus dem letzten bekannten Wert gelesen
  6. Alarm-Nachricht wird per buildAlarmMessage() aufgebaut
  7. Kanal 1 — SMS: AlarmNotificationService.sendAlarm() sendet SMS an alle Kontakte (SmsManager Direktversand)
  8. Kanal 2 — Anruf: Für jeden Kontakt: Direktanruf über Standard-Telefon-App (skipSms: true, kein doppelter SMS-Versand)
  9. Kanal 3 — Server: Alarm-Event wird per REST-API an Server gemeldet + Server leitet an Forwarding-Server weiter
  10. Ergebnis-String wird in alarmNotificationResultProvider gespeichert
  11. Alle Aktionen werden per _logProtocol() im Server-Protokoll erfasst
Kein Kontakt hinterlegt? Wenn die Kontaktliste leer ist, wird der Alarm trotzdem an den Server gemeldet (+ lokaler Alarm mit Vibration + Sound + Fullscreen-Overlay im Admin-Panel). Für SMS und Anruf werden Kontakte benötigt.

👥 Notfallkontakte

Verwaltung der Empfänger für automatische Alarm-Nachrichten. Dual: Lokal (SharedPreferences) + Server-verwaltet (Admin-Panel).

📇 Datenmodell: EmergencyContact

FeldTypBeschreibung
nameStringName des Kontakts (z.B. „Chef", „Kollegin Maria")
phoneStringTelefonnummer mit Landesvorwahl (z.B. +4917612345678)
smsEnabledboolSMS-Benachrichtigung aktiviert (Standard: true)
whatsappEnabledboolWhatsApp-Benachrichtigung aktiviert
relationshipString?Beziehung (z.B. „Vorgesetzter", „Kollege") — nur Server
priorityintPrioritä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

MethodeQuelleBeschreibung
addContact(contact)LokalNeuen Kontakt hinzufügen + SharedPreferences aktualisieren
removeContact(index)LokalKontakt an Position entfernen + SharedPreferences aktualisieren
updateContact(index, contact)LokalKontakt bearbeiten + SharedPreferences aktualisieren
contacts.php?action=createServer (Admin)Neuen server-verwalteten Kontakt erstellen
contacts.php?action=deleteServer (Admin)Server-Kontakt löschen
contacts.php?action=syncServer → AppAlle Kontakte des Benutzers synchronisieren
📸
Screenshot: Kontakte-Tab mit Kontaktkarten und SMS-Badge
Zeigt die Kontaktliste mit Avataren, Telefonnummern und dem SMS-Fallback-Badge

📜 Alarm-Verlauf (History)

Vollständige Protokollierung aller Alarm-Ereignisse mit Zeitstempel, Szenario und Status.

📊 AlarmEvent-Typen

TypEnumFarbeBedeutungWann erzeugt?
⚠️ PotenziellAlarmEventType.potential Gelb Gefahr erkannt, Eskalation gestartet Beim Übergang in Eskalation Stufe 1
🚨 BestätigtAlarmEventType.confirmed Rot Alarm tatsächlich gesendet Wenn Countdown abläuft + Benachrichtigungsergebnis
✅ EntwarntAlarmEventType.cancelled Grün Nutzer hat Entwarnung bestätigt Wenn „ALLES OK"-Button gedrückt wird

📋 AlarmEvent-Datenstruktur

FeldTypBeschreibung
timestampDateTimeZeitpunkt des Ereignisses
scenarioDangerScenarioWelches Szenario den Alarm ausgelöst hat
severityAlertSeveritySchweregrad (warning / critical / emergency)
messageStringDetailnachricht mit Sensorwerten
wasCancelledboolOb der Alarm storniert wurde
eventTypeAlarmEventTypepotential / confirmed / cancelled
Anzeige im Verlauf-Tab: Die History wird umgekehrt chronologisch angezeigt (neueste zuerst). Jede Card zeigt das Szenario-Icon links, den farbcodierten Status-Text, die Detailnachricht und den formatierten Zeitstempel (DD.MM.YYYY HH:MM:SS). Die Hintergrundfarbe der Card spiegelt den Typ wider: Gelb = Potenziel, Rot = Bestätigt, Grün = Entwarnt.
📸
Screenshot: Verlauf-Tab mit verschiedenen Alarm-Ereignissen
Zeigt mehrere Cards in verschiedenen Farben (Gelb/Rot/Grün) mit Icons, Zeitstempeln und Beschreibungen

🔄 Zustandsautomat (AlertState)

8 definierte Zustände steuern das gesamte Schutzsystem. Die UI reagiert auf jeden Zustandswechsel.

Idle
Monitoring
Checkin Pending
Escalation 1
Escalation 2
Countdown
Alert Sent
ZustandEnumUI-FarbeIconBeschreibungMögliche Übergänge
Inaktividle Grau🛡️ Schutz nicht gestartet → monitoring (Start-Button)
Überwachung aktivmonitoring Grün Normalbetrieb: Sensoren werden ausgewertet (alle 500ms) → checkinPending, → escalation1, → idle (Stop)
Check-in fälligcheckinPending Blau🔔 Check-in-Countdown abgelaufen, Bestätigung nötig → escalation1 (kein Tap), → monitoring (Tap)
Stufe 1escalation1 Gelb📳 Vibration läuft, Nutzer soll reagieren → escalation2 (Timer), → monitoring (OK)
Stufe 2escalation2 Orange🔊 Alarmsound + Vibration → countdown (Timer), → monitoring (OK)
Countdowncountdown Rot⚠️ Letzter Countdown vor Alarmversand → alertSent (0 erreicht), → monitoring (OK)
Alarm gesendetalertSent Dunkelrot🚨 Alarm an Server gesendet / SMS verschickt → monitoring (Reset-Button)
preAlarm ist ein zusätzlicher Enum-Wert, der aktuell dem 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.

Dynamische Tab-Anzahl: Die Methode _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
📸
Screenshot: Alle Tabs nebeneinander oder als Collage
Status (grün, mit Funktionstest), Profile (Slider, bedingt sichtbar), Kontakte (Liste mit Badges), Verlauf (farbige Event-Cards)

📡 Sensor-Infrastruktur (Technische Grundlage)

Die Sensoren bilden die Datengrundlage für das Alleinarbeiter-Schutzsystem. Ohne Sensordaten ist keine automatische Gefahrenerkennung möglich.

Kernnutzung für den Schutz: Vom Schutzsystem werden primär 3 Sensoren genutzt: Beschleunigungssensor (Sturz, Ohnmacht, Bewegungslosigkeit, Lage), Gyroskop (Ohnmacht, Bewegungslosigkeit) und GPS (Ohnmacht, Position in Alarmnachricht). Die übrigen 7 Sensoren dienen zur allgemeinen Sensoranalyse und Datenaufzeichnung.

📊 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.

EndpunktAuthActionsBeschreibung
api/auth.phpÖffentlich/App login, register_device, change_password, master_check Authentifizierung: Login, Geräteregistrierung, Passwort-Änderung, Master-PW-Prüfung.
api/users.phpAdmin list, get, create, update, delete, stats, login Benutzerverwaltung mit Telefon/SMS-Nummer, Profil-Zuweisung, Kontakte + Protokolle
api/alarms.phpApp/Admin report, list, get, stats, acknowledge SOS-Alarme melden + verwalten. Weiterleitung an Forwarding-Server. Admin-Benachrichtigung.
api/heartbeat.phpApp/Admin ping, status, user Periodische Lebenszeichen der App. Online/Offline-Status pro Benutzer.
api/protocol.phpApp/Admin log, log_batch, my, list, user App-Aktivitätsprotokoll: Events, Alarme, Statuswechsel — 1:1 Server-Sync.
api/contacts.phpApp/Admin list, my, create, update, delete, sync Notfallkontakte pro Benutzer. Admin verwaltet zentral, App synchronisiert.
api/user_config.phpApp/Admin get, set, effective, list, delete User-spezifische Konfiguration (überschreibt globale app_config). effective = Single Source of Truth.
api/config.phpAdmin list, get, set, bulk_set Globale App-Konfiguration (app_config-Tabelle). Tab-Sichtbarkeit, Feature-Locks, Heartbeat-Intervall.
api/profiles.phpAdmin list, get, create, update, delete Schutzprofile verwalten. Szenarien, Schwellwerte, Aktivierung.
api/servers.phpAdmin list, create, update, delete, test Dynamische Forwarding-Server für Alarm-/Heartbeat-Weiterleitung.
api/reports.phpAdmin 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.phpAdmin system_logs, audit_logs, combined, stats, cleanup Zentralisiertes Logging. Combined-Timeline über alle 3 Log-Quellen + Alarme. Aufräumfunktion.
api/selfcheck.phpAdmin full, db, config System-Selbsttest: Datenbankverbindung, Tabellen-Integrität, PHP-Erweiterungen, Verzeichnisse. Einzelne Checks möglich.
api/upload.phpAdmin upload Datei-Upload (z.B. Branding-Logos) für das Admin-Panel.
Effective-Endpoint (Single Source of Truth): 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

KeyTypStandardWirkung in der App
show_sensors_tabboolfalseSensoren-Tab ein/ausblenden
show_analysis_tabboolfalseAnalyse-Tab ein/ausblenden
show_dashboard_tabboolfalseDashboard-Tab ein/ausblenden
start_pagestringprotectionStartseite: protection, dashboard, sensors, analysis
allow_profile_changebooltrueProfil-Auswahl sperren/erlauben
allow_threshold_changeboolfalseSchwellwert-Slider sperren/erlauben
allow_scenario_toggleboolfalseSzenario-Toggles sperren/erlauben
heartbeat_interval_secint30Heartbeat-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

FeldBeschreibung
nameBezeichnung des externen Systems
urlHTTP(S)-Endpunkt, an den weitergeleitet wird
api_keyOptionaler API-Key für Authentifizierung
forward_alarmsAlarme weiterleiten (Standard: ja)
forward_heartbeatsHeartbeats weiterleiten
forward_user_infoBenutzer-Infos weiterleiten
headersZusätzliche HTTP-Header (JSON)
Test-Funktion: Im Admin-Panel kann jeder Forwarding-Server per Klick getestet werden. Der Server sendet ein Test-Paket und zeigt den HTTP-Statuscode. Letzter Erfolg/Fehler wird in der Datenbank protokolliert.

🖥️ 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

ActionMethodeBeschreibung
system_logsGETPaginierte System-Logs mit Filter (Level, Kategorie, User, Datum, Suche)
audit_logsGETPaginierte Audit-Einträge mit Filter (Entity-Type, User, Datum, Aktion)
combinedGETUNION ALL Timeline aller 4 Quellen (max. 500 Einträge)
statsGET24h-Statistiken: Anzahl pro Quelle, Level-Verteilung, Fehler-Quote
cleanupPOSTAlte Einträge löschen (min. 7 Tage). Audit-Logs bleiben permanent erhalten.

📝 Protokollierte Aktionen (alle 14 PHP-Endpunkte)

EndpunktProtokollierte Ereignisse
auth.phpLogin (Erfolg/Fehlschlag), Passwort-Änderung, Master-PW-Check, Geräteregistrierung
users.phpErstellen, Aktualisieren, Deaktivieren, Passwort-Reset, Profil-Zuweisung, Master-PW-Änderung
config.phpConfig-Änderung (Einzel + Bulk)
profiles.phpProfil erstellen, aktualisieren, deaktivieren
contacts.phpKontakt erstellen, aktualisieren, löschen
servers.phpServer erstellen, aktualisieren, löschen, Test (Erfolg/Fehlschlag)
user_config.phpUser-Config geändert
heartbeat.phpForwarding-Erfolg/-Fehler (Debug/Warning/Error)
alarms.phpAlarm gemeldet (dynamisch: critical/error/warning nach Schweregrad)
protocol.phpApp-Protokolleinträge (Events, Statuswechsel, Alarme)
selfcheck.phpSystem-Selbsttest (Ergebnis protokolliert)
logger.phpLog-Abfragen, Cleanup-Aktionen
reports.phpReport-Generierung, -Abruf, -Löschung (5 Typen)
upload.phpDatei-Uploads (Branding)
Rechtssicherheit: Audit-Logs werden permanent gespeichert und können nicht gelöscht werden. Sie dokumentieren alle sicherheitsrelevanten Aktionen mit Zeitstempel, Benutzer-ID, IP-Adresse und Vorher/Nachher-Werten. Im Ernstfall ist jede Aktion im System lückenlos nachvollziehbar.

🔗 Kommunikations-Zuverlässigkeit

Drei dedizierte Services stellen sicher, dass Alarme und Protokolldaten niemals verloren gehen — auch bei instabiler Netzwerkverbindung.

DGUV-Anforderung: Alarme und Heartbeat dürfen NIEMALS stille Fallbacks haben. Fehlgeschlagene Übertragungen werden in der Offline-Queue gespeichert und beim nächsten erfolgreichen Verbindungsaufbau automatisch nachgesendet. Jeder Fehler wird explizit protokolliert.

📦 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

MethodeBeschreibung
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.

Warum nötig? Android kann Hintergrund-Services drosseln oder beenden, um Akku zu sparen. Für ein Alleinarbeiter-Schutzsystem ist das inakzeptabel — der Foreground Service, Heartbeat und Sensor-Monitoring müssen jederzeit laufen. Die Batterie-Ausnahme wird über einen System-Dialog abgefragt.

Initialisierungsreihenfolge (app.dart)

  1. Config-SyncConfigSyncService.syncFromServer(ref) (Profil, Kontakte, UI-Flags)
  2. Protocol-Logapp_started Event an Server
  3. Konnektivitäts-MonitorConnectivityMonitor().start(intervalSeconds: 30)
  4. Offline-QueueOfflineQueueService().startPeriodicFlush(intervalSeconds: 60)
  5. Batterie-Optimierung_requestBatteryOptimizationExemption()
  6. Geräte-DiagnostikDeviceDiagnostics.reportToServer()
  7. Geräte-Registrierungapi.registerDevice() (DGUV 112-139)
  8. Startseite setzen — aus Server-Config (startPageIndexProvider)
  9. Heartbeat startenHeartbeatService().start(intervalSeconds: hbInterval)
  10. Auth-Callback — Redirect bei 401
  11. Batterie-CallbackbatteryLevelProvider aktualisieren
  12. Verbindungs-CallbacksmarkOffline()/markOnline() + Alarm-Eskalation bei aktiver Überwachung
  13. Config-Change-Callback — Heartbeat erkennt Änderung → ConfigSyncService.syncFromServer()
Resume-Handler: Bei App-Wiederaufnahme (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-TypKategorieBeschreibungWann ausgelöst?
app_startedsystemApp gestartet nach LoginNach _initializeAfterLogin()
device_diagnosticssystemGeräteinformationen (Hersteller, Modell, OS, SDK)Einmalig nach Login
config_appliedconfigServer-Konfiguration angewendet (fetched_at + applied_at)Nach Config-Sync
config_deliveredconfigServer bestätigt Config-ZustellungNach erfolgreichem Sync
config_staleconfigGerät hat veraltete KonfigurationHeartbeat-Erkennung serverseitig
🛡️ Schutz-Events
protection_startedprotectionÜberwachung aktiviertStart-Button gedrückt
protection_stoppedprotectionÜberwachung deaktiviertStop-Button gedrückt
profile_changedprotectionSchutzprofil gewechselt (alt → neu)Profilauswahl geändert
🚨 Alarm-Events
alarm_potentialalarmGefahr erkannt, Eskalation gestartetÜbergang Eskalation Stufe 1
alarm_confirmedalarmAlarm tatsächlich gesendet (Countdown abgelaufen)Countdown erreicht 0
alarm_cancelledalarmNutzer hat Entwarnung bestätigt„ALLES OK"-Button
alarm_sentalarmBenachrichtigungsergebnis (SMS/Anruf/Server-Status)Nach Alarm-Versand
escalation_stage_1alarmEskalation Stufe 1 (Vibration)Eskalationsübergang
escalation_stage_2alarmEskalation Stufe 2 (Akustisch + Vibration)Eskalationsübergang
escalation_countdownalarmFinaler Countdown gestartetEskalationsübergang
📱 Benachrichtigungs-Events
sms_sentnotificationSMS erfolgreich versendet an KontaktNach SmsManager-Aufruf
sms_failednotificationSMS-Versand fehlgeschlagen (+ Fehlergrund)Bei SmsManager-Fehler
call_initiatednotificationTelefonanruf gestartet an KontaktNach MethodChannel-Aufruf
call_failednotificationTelefonanruf fehlgeschlagen (+ Fehlergrund)Bei MethodChannel-Fehler
server_alarm_reportednotificationAlarm erfolgreich an Server gemeldetNach API-Aufruf
server_alarm_failednotificationServer-Meldung fehlgeschlagen (→ Offline-Queue)Bei API-Fehler
💓 Check-in & Heartbeat
checkin_performedprotectionCheck-in bestätigt (Countdown reset)„Bin OK"-Button
checkin_expiredprotectionCheck-in-Timer abgelaufen → EskalationCountdown erreicht 0
heartbeat_startedconnectionHeartbeat-Service gestartetNach Login
heartbeat_stoppedconnectionHeartbeat-Service gestopptBei Logout/Beenden
🔗 Verbindungs-Events
connection_lostconnectionServer nicht erreichbar (DNS-Probe fehlgeschlagen)ConnectivityMonitor
connection_restoredconnectionServer wieder erreichbarConnectivityMonitor
offline_queue_flushedconnectionOffline-Queue erfolgreich gesendet (n Einträge)Nach flush()
battery_lowsystemBatterie-Level kritisch niedrigBatterie-Callback
🔧 Funktionstest & Schicht
functional_test_passeddguvDGUV §4.7 Pre-Shift-Funktionstest bestandenTest durchgeführt
functional_test_faileddguvFunktionstest fehlgeschlagen (+ Details)Test fehlgeschlagen
shift_starteddguvSchicht gestartet (DGUV §4.8)Schichtprotokoll
shift_endeddguvSchicht beendet (Zusammenfassung)Schichtprotokoll
📋 Kontakte & Foreground
contact_addedcontactsNotfallkontakt hinzugefügtKontakt-CRUD
contact_removedcontactsNotfallkontakt entferntKontakt-CRUD
foreground_service_startedsystemForeground Service gestartetSchutz aktiviert
foreground_service_stoppedsystemForeground Service gestopptSchutz deaktiviert

Server-seitige System-Logs (system_logs)

KategorieLevelEreignisse
authinfo / warningLogin Erfolg/Fehlschlag, Passwort-Änderung, Master-PW-Check, Token-Verifikation
alarmcritical / error / warningAlarm empfangen (dynamischer Level nach Schweregrad), Forwarding Erfolg/Fehler, Acknowledge
heartbeatdebug / info / warningHeartbeat empfangen, Config-Staleness erkannt, Forwarding-Ergebnis
configinfo / warningConfig-Änderung (Einzel + Bulk), Config-Abruf, Sync-Bestätigung
userinfoBenutzer CRUD, Profil-Zuweisung, Passwort-Reset
profileinfoProfil erstellen/aktualisieren/deaktivieren
contactinfoKontakt erstellen/aktualisieren/löschen
forwardinginfo / warning / errorServer erstellen/löschen/testen, Forwarding-Ergebnis
reportinfoReport-Generierung, -Abruf, -Löschung (5 Typen)
systeminfo / errorSelf-Check Ergebnis, Cleanup-Aktionen, Upload
protocolinfoApp-Protokolleinträge empfangen (Einzel + Batch)

Audit-Log (audit_log) — Permanent, nicht löschbar

Entity-TypAktionenErfasste Daten
usercreate, update, delete, password_reset, assign_profile, set_master_passwordVorher/Nachher-Werte, User-ID, IP, User-Agent
profilecreate, update, deleteProfilname, geänderte Felder
configset, set_bulkSchlüssel, alter Wert → neuer Wert
user_configsetUser-Overrides mit Schlüssel + Wert
contactcreate, update, deleteKontaktname, Telefon, Benutzer-Zuordnung
servercreate, update, delete, testServer-Name, URL, Test-Ergebnis
authlogin, login_failed, password_changeBenutzername, IP-Adresse, User-Agent
reportgenerate, download, deleteReport-Typ, Datumbereich
uploaduploadDateiname, 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.

Cleanup-Policy: Die Cleanup-Funktion (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:

  1. Datenbank-Verbindung prüfen — Verbindung zu MariaDB/MySQL testen
  2. Tabellen erstellendatabase_schema.sql wird importiert (16 Tabellen)
  3. Admin-Benutzer anlegen — Initialer Administrator-Account
  4. Master-Passwort setzen — Schutz für Setup und kritische Operationen
  5. App-Name konfigurieren — Branding/Name der Installation
  6. Standard-Profile erstellen — 5 Schutzprofile initialisieren
  7. Konfiguration abschließen — Standardwerte in app_config schreiben

🗃️ 16 Datenbank-Tabellen

TabelleZweckBesonderheit
usersBenutzerkontenTelefon, SMS-Nr., letzter Heartbeat, Profil-Zuweisung, Rolle
master_passwordsMaster-PasswortSchützt Setup und kritische Admin-Aktionen
protection_profilesSchutzprofile5 Profile mit Szenarien + Schwellwerten
app_configGlobale KonfigurationKey-Value-Paare: Tab-Sichtbarkeit, Feature-Locks, Heartbeat-Intervall
alarm_eventsAlarm-EreignisseSzenarien, Schweregrad, GPS, Sensorwerte, Acknowledge-Status
emergency_contactsNotfallkontaktePro Benutzer zugewiesen, Priorität, SMS/Anruf-Flags
devicesRegistrierte GeräteGeräte-ID, App-Version, Benutzer-Zuordnung
audit_logSicherheitsprotokollNie löschbar. Login, CRUD, Config-Änderungen mit IP + Vorher/Nachher
heartbeatsVerbindungsüberwachungJeder Ping = eine Zeile. Automatisch per HeartbeatService
user_protocolsApp-Aktivitätsprotokoll1:1 Sync der App-Historie mit Server
user_configUser-spezifische OverridesÜberschreibt globale app_config pro Benutzer
system_logsTechnische System-LogsLevel (debug–critical), Kategorie, Kontext (JSON), IP, User-Agent
forwarding_serversAlarm-/Heartbeat-WeiterleitungDynamisch konfigurierbar im Admin-Panel
functional_testsFunktionale TestsErgebnisse der System-Selbsttests
shiftsSchichtdatenSchichtprotokolle für DGUV-Compliance
reportsGenerierte BerichteHTML-Reports: 5 Typen, Vorschau, PDF-Druck, löschbar
Nur eine Schema-Datei: Die Datenbank wird ausschließlich über 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

DateiZweck
setup.php7-Schritt Setup-Wizard (erstellt Tabellen, Admin, Master-PW, App-Name)
database_schema.sqlVollständiges DB-Schema (16 Tabellen)
db_config.phpDatenbank-Verbindung + Logger-Integration
credentials.phpJWT-Auth Hilfsfunktionen
.htaccessURL-Rewriting und Sicherheitsregeln
admin/index.htmlAdmin-Panel SPA (HTML/CSS/JS)
admin/admin.jsAdmin-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, AlarmEvent
  • emergency_contact.dart — EmergencyContact + EmergencyContactStore
  • sensor_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.dartKern-UI (2.551 Zeilen): Dynamische Tabs mit Status, Profile (bedingt), Kontakte, Verlauf
  • dashboard_page.dart — Startseite mit Navigation
  • sensor_list_page.dart — Sensorübersicht
  • sensor_detail_page.dart — Sensor-Detailansicht mit Live-Chart
  • analysis_page.dart — Sensoranalyse
  • settings_page.dart — App-Einstellungen
  • test_mode_page.dart — DGUV Testmodus (Sensorprüfung)
  • setup_wizard_page.dart — Ersteinrichtungs-Assistent
  • login_page.dart — Login-Seite

🧠 ViewModel-Schicht

  • lone_worker_providers.dartHerzstück (938 Zeilen): AlertStateNotifier, SMS+Anruf-Logik, Protocol-Logging
  • server_config_providers.dart — Server-Config State (Tab-Sichtbarkeit, Feature-Locks, Server-Kontakte)
  • auth_providers.dart — Login/Logout, ApiService-Provider
  • providers.dart — Sensor-Provider, Recording-Provider, Sampling-Rate-Provider

⚙️ Service-Schicht

  • alarm_hardware_service.dart — Vibration + Alarmsound via MethodChannel
  • alarm_notification_service.dart — SMS + Anruf (Standard-Telefon-App, kein doppelter SMS-Versand) + Server
  • foreground_service.dartForeground Service: flutter_foreground_task + wakelock_plus
  • heartbeat_service.dart — Periodischer Heartbeat-Ping an Server
  • config_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
Gesamt: 48 Dart-Dateien (~10.476 Zeilen) + 21 Server-Dateien (~8.000 Zeilen) + Admin-Panel (index.html: 1.718 Z., admin.js: 2.467 Z.)

📦 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.

ProviderTypInitialer WertBeschreibung
emergencyContactsProviderStateNotifierProvider<…, List<EmergencyContact>>[] (aus SharedPrefs)Lokale Notfallkontakte mit CRUD
serverEmergencyContactsProviderStateNotifierProvider<…, List<EmergencyContact>>[]Server-verwaltete Kontakte (Vorrang)
selectedProfileProviderStateProvider<ProtectionProfile>Außendienst (Index 2)Aktuell gewähltes Profil
customThresholdsProviderStateProvider<ScenarioThresholds>Profil-StandardwerteSlider-Anpassungen
protectionActiveProviderStateProvider<bool>falseSchutz aktiv/inaktiv
alertStateProviderStateNotifierProvider<AlertStateNotifier, AlertState>AlertState.idleKern-Zustandsautomat
alarmHistoryProviderStateProvider<List<AlarmEvent>>[]Alarm-Ereignisprotokoll
countdownSecondsProviderStateProvider<int>0Restzeit Eskalation
lastDetectionProviderStateProvider<String>''Letzte Detektions-Nachricht
escalationStageProviderStateProvider<int>0Aktuelle Stufe (1/2/3)
checkinCountdownProviderStateProvider<int>0Sekunden bis Check-in
alarmNotificationResultProviderStateProvider<String>''Ergebnis des Alarm-Versands
Server-Config Provider (NEU — server_config_providers.dart)
showSensorsTabProviderStateProvider<bool>trueSensoren-Tab sichtbar?
showAnalysisTabProviderStateProvider<bool>trueAnalyse-Tab sichtbar?
showDashboardTabProviderStateProvider<bool>trueDashboard-Tab sichtbar?
startPageIndexProviderStateProvider<int>3 (Protection)Startseite-Tab-Index
allowThresholdChangeProviderStateProvider<bool>trueSchwellwerte änderbar?
allowScenarioToggleProviderStateProvider<bool>trueSzenarien umschaltbar?
allowProfileChangeProviderStateProvider<bool>trueProfil wechselbar?
heartbeatIntervalProviderStateProvider<int>30Heartbeat-Intervall (Sek.)
serverProfileProviderStateProvider<Map?>nullVom 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

PermissionZweck
FOREGROUND_SERVICE_LOCATIONGPS-Überwachung im Hintergrund
FOREGROUND_SERVICE_HEALTHGesundheitsüberwachung (Sensor-Auswertung) im Hintergrund
WAKE_LOCKCPU wach halten (verhindert Sleep)
POST_NOTIFICATIONSForeground-Service-Benachrichtigung anzeigen (Android 13+)
RECEIVE_BOOT_COMPLETEDAutomatischer Neustart nach Geräte-Reboot
REQUEST_IGNORE_BATTERY_OPTIMIZATIONSAusnahme von Batterie-Optimierung (verhindert Hintergrund-Einschränkungen)
SEND_SMSDirekter SMS-Versand über SmsManager (kein Nutzer-Tap)
CALL_PHONEDirekter Telefonanruf über Standard-Telefon-App
VIBRATECustom Vibrationsmuster mit Amplituden

AndroidManifest Service-Element

<service
    android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
    android:foregroundServiceType="location|health"
    android:exported="false" />
Warum Foreground Service? Android beendet Hintergrund-Services nach kurzer Zeit. Ein Foreground Service mit permanenter Benachrichtigung ist die einzige Möglichkeit, Sensor-Monitoring zuverlässig im Hintergrund auszuführen — essenziell für Alleinarbeiter-Schutz.

Native MethodChannels / EventChannels

ChannelTypMethodenZweck
com.sensorsuite/vibrationMethodChannel vibrate({pattern, amplitudes, repeat}), cancel() Custom Vibrationsmuster mit Amplituden — übersteigt Standard-HapticFeedback
com.sensorsuite/alarm_soundMethodChannel play(), stop() Alarmsound auf STREAM_ALARM — umgeht Lautlos/DND
com.sensorsuite/smsMethodChannel sendSms({phone, message}), requestPermission() Direkter SMS-Versand über Android SmsManager
com.sensorsuite/phone_callMethodChannel call({phone}), checkPermission(), requestPermission() Telefonanruf über Standard-Telefon-App (TelecomManager.defaultDialerPackage). ACTION_CALL mit Permission, Fallback auf ACTION_DIAL
com.sensorsuite/light_sensorEventChannel Stream<double> Lichtsensor (Lux)
com.sensorsuite/proximity_sensorEventChannel Stream<double> Näherungssensor (cm)
com.sensorsuite/temperature_sensorEventChannel Stream<double> Temperatursensor (°C)
com.sensorsuite/audio_levelEventChannel Stream<double> Mikrofon dB-Pegel

📂 Dateistruktur

Übersicht der relevanten Dateien mit Fokus auf Schutzsystem-Dateien.

lib/
├── 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
⭐ = Kerncode: 48 Flutter-Dart-Dateien (~10.476 Zeilen) + 14 Server-API-Dateien (~4.100 Zeilen) + Admin-Panel (4.185 Zeilen) bilden das komplette Alleinarbeiter-Schutzsystem mit Foreground Service, zentraler Server-Konfiguration, Heartbeat-Überwachung, 3-Kanal-Alarmierung (SMS + Anruf + Server), Offline-Queue, Konnektivitäts-Monitor, Geräte-Diagnostik, Admin-Panel mit 12 Bereichen, 3-Tier Logging, Reports und DGUV-Compliance.

📝 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-OptimierungREQUEST_IGNORE_BATTERY_OPTIMIZATIONS Permission hinzugefügt, wird beim Start angefordert
  • ApiService-IntegrationreportAlarm() und logProtocol() 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.defaultDialerPackage ermittelt und direkt angesteuert (kein App-Chooser-Dialog mehr). Neuer MethodChannel com.sensorsuite/phone_call in MainActivity.kt
  • Doppelter SMS-Versand behobeninitiateEmergencyCall() hat nun skipSms: true als Standard. SMS wird nur einmal in sendAlarm() 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-FixPermission.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 leerer catch
  • heartbeat.php — Stille Catches bei config_changed_at und forwardToServers behoben
  • auth.phplogWarning() in handleVerify() ergänzt
  • reports.phplogAudit() für Downloads, bedingte Logging-Guards (function_exists) entfernt
  • upload.php$auth korrekt 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, neue registerDevice()-Methode in ApiService, automatischer Aufruf nach Login

2. Profil-Persistenz (Kritischer Bugfix)

  • Race Condition behoben (admin.js)loadProfilesForSelect() war async aber nicht await-ed → Dropdown-Optionen noch nicht geladen beim Setzen von profile_id → Profil wurde stets als null (Standard-Profil) gespeichert
  • users.phpupdated_at = NOW() in handleUpdate() ergänzt → Änderungen per Heartbeat erkennbar
  • heartbeat.phpusers.updated_at in GREATEST()-Query für config_changed_at aufgenommen → Profilzuweisung wird vom Gerät erkannt
  • admin.js loadUserConfig()data.configsdata.config (Property-Name korrigiert, PHP liefert Singular)

3. Bidirektionale Config-Zustellungsbestätigung

  • user_config.php — Neues Event config_delivered mit config_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_at im Heartbeat-Payload an Server
  • heartbeat.php — Neue Staleness-Erkennung: loggt config_stale-Warnung wenn Gerät veraltete Config hat
  • config_sync_service.dartconfig_syncedconfig_applied mit fetched_at + applied_at Zeitstempeln
  • api_service.dartsendHeartbeat() akzeptiert neuen lastConfigSyncedAt-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.phpupdated_at wird 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.phpupdated_at wird bei Profiländerungen gesetzt
  • contacts.phpupdated_at bei INSERT ergänzt