Arbeitssicherheit · Unterweisung · PSA-Check · BG-Unfallmeldung
Feinkonzept · Arbeitssicherheit, Unterweisung & Unfallmeldung (§4.10)
Abschnitt betitelt „Feinkonzept · Arbeitssicherheit, Unterweisung & Unfallmeldung (§4.10)“Feature-ID:
handwerk/10-arbeitssicherheit· Stand: 2026-04-19 · Autor: Senior-Berater-Rolle Arbeitsschutz / DGUV / BG BAU Verwandte Feinkonzepte:01-bautagebuch(PSA-Check ist eigener Eintragstyp im Bautagebuch; Unfall-Foto-Pipeline nutzt dieselbe S3/Geo-Stempel-Strecke),11-fuehrerschein-zertifikate(Qualifikations-/DGUV-Scheine laufen im selben Ampel-Register, Planungs-Gate an derselben Stelle),03-dienstplanung(Unterweisungs-Fälligkeit blockiert Schichtzuweisung),08-audit-log(jede Unterweisung, jeder Unfall, jede PSA-Verweigerung schreibt eine Hash-verkettete Audit-Zeile).
1. Header & Metadaten
Abschnitt betitelt „1. Header & Metadaten“feature_id: handwerk/10-arbeitssicherheittitle: Arbeitssicherheit · Unterweisung · PSA-Check · BG-Unfallmeldungfunktionsumfang_ref: §4.10roadmap_horizont: V1.5plattformen: mobile: vollständig # Unterweisung, PSA-Check, Unfallmeldung → Feld-Realität web: mit-Bulk # HSSE/SiFa-Dashboard, Fälligkeits-Liste, BG-F1000-Export desktop: aus # Desktop bringt keinen Mehrwert gegenüber Webowner_rolle: SiFa # Sicherheitsfachkraft (ASiG §5) ist Eigentümer des Modulsmodul_gate_flag: module.handwerk.arbeitssicherheitcompliance_flags: gobd: true # Unterweisungsnachweise und Unfall-Akten = GoBD-relevant, §147 AO 10 Jahre arbzg: false # Zeit bleibt in §3.1 vob: false dsgvo: true # DSGVO Art. 9 Gesundheitsdaten bei Unfall bfsg: false # Kein öffentlicher ESS-Flow, interne Pflichtunterweisung betrvg: true # Unterweisungs-Tracking ist mittelbare Leistungskontrolle stvg: false weitere: - "DGUV Vorschrift 1 §4 (Grundsätze der Prävention, jährliche Unterweisung)" - "DGUV Vorschrift 1 §26 (Ersthelfer-Quote)" - "DGUV Information 211-005 (Unterweisungsthemen)" - "DGUV Vorschrift 2 (Betriebsärzte/SiFa)" - "ArbSchG §5 + §6 (Gefährdungsbeurteilung)" - "ArbSchG §12 (Unterweisungspflicht)" - "§193 SGB VII (Unfallanzeigepflicht ab 3 Tagen AU)" - "§8 Abs. 1 SGB VII (Arbeitsunfall-Begriff)" - "PSA-Benutzungsverordnung (PSA-BV)"referenzkunde: status: TBD name: "zu klären mit Sales — Kandidat: SHK-Gebrüder-Schmidt (NRW, 80 MA), heute Excel-Liste Unterweisungen + WhatsApp-Fotos bei Unfall; Sales-Call 2026-02 'BG-Meldung ist unser Horror, wir verpassen die 3-Tage-Frist regelmäßig'" quelle: Sales-Call + Referenz-Interview SiFa Thomas Schmidtestimate_eng_tage: 42 # 16 Mobile (Unterweisungs-Player, PSA, Unfall) + 12 Backend + 8 Web-Dashboard + 3 F1000-Adapter + 3 Test/Complianceabhängigkeiten: - kern/03-projekte-baustellen - kern/08-audit-log - kern/09-foto-upload-pipeline # Unfall-Fotos über dieselbe S3-Multipart-Strecke - kern/11-dsgvo-toolkit # Gesundheitsdaten-Kapselung, getrennter KMS-Key - handwerk/01-bautagebuch # PSA-Check als Eintragstyp - handwerk/11-fuehrerschein-zertifikate # Gemeinsamer Ablauf-/Ampel-Mechanismus2. Kontext & Problem
Abschnitt betitelt „2. Kontext & Problem“Marktrealität (DE-Handwerk). Arbeitssicherheit im Handwerk läuft heute bei den meisten 10–80-MA-Betrieben über einen Ordner im Büro, eine Excel-Liste mit „Unterweisung am 12.03. erledigt“ und eine Papiertüte im SiFa-Büro. Die rechtlichen Schrauben sind aber deutlich enger angezogen, als dieses Bild vermuten lässt:
- DGUV Vorschrift 1 §4 („Unterweisung der Versicherten“) verlangt eine Unterweisung vor Aufnahme der Tätigkeit, bei Veränderung des Aufgabenbereichs, bei Einführung neuer Arbeitsmittel oder Arbeitsverfahren und mindestens einmal jährlich. Sie muss arbeitsplatzspezifisch sein (eine allgemeine „Büro-Sicherheitsunterweisung“ erfüllt den §4 bei einem Dachdecker nicht).
- ArbSchG §12 spiegelt das staatlich-arbeitsrechtlich: Unterweisung in „ausreichender und angemessener Form“, nachweispflichtig.
- ArbSchG §5 + §6 verlangen eine Gefährdungsbeurteilung pro Tätigkeit/Arbeitsplatz, schriftlich dokumentiert, fortgeschrieben, mit Unterschrift der verantwortlichen Person. Für Baustellen heißt das: pro Baustelle, nicht pro Firma.
- PSA-Benutzungsverordnung §2: Arbeitgeber muss PSA bereitstellen und sicherstellen, dass sie benutzt wird. Benutzungs-Nachweis ist ein weicher Punkt — aber spätestens nach einem Unfall fragt die BG, und dann ist Papier schlecht.
- §193 SGB VII: Anzeige des Versicherungsfalls bei der BG sofort, wenn ein Arbeitsunfall zum Tode geführt hat oder mehr als drei Tage Arbeitsunfähigkeit erwarten lässt — spätestens am 3. Werktag nach Kenntnisnahme. Formular: BG BAU F1000 (Online-Formular über
serviceportal.bgbau.de), parallel verfügbar als PDF-Import. - DGUV Vorschrift 1 §26: bestellte Ersthelfer-Quote — in Betrieben mit 2–20 Versicherten mindestens ein Ersthelfer, über 20 Versicherten mindestens 10 % (Verwaltungs-/Handelsbetriebe 5 %). Bauhandwerk fällt in die 10 %-Quote.
Heute bedeutet das in den Zielbetrieben: Der SiFa hat ein Ordner mit Unterweisungs-Unterschriften, keiner weiß verlässlich, wer im Dezember 2025 unterwiesen wurde, wer diese Woche schon überfällig ist. Die BG-Meldung F1000 wird per Kugelschreiber ausgefüllt, gescannt, per E-Mail an die BG geschickt — oft nach der 3-Werktage-Frist, weil der Monteur erst am Donnerstag nachkommt und der Unfall am Freitag war. Auf der Baustelle selbst macht keiner einen PSA-Check, weil der Check keine wirksame Konsequenz hat: wer keinen Helm hat, arbeitet trotzdem.
Schmerzpunkt der Alt-App. Die Alt-App (zeitapp) hat das Thema komplett nicht adressiert. In den ~69 Screens fand sich kein einziger mit Bezug auf DGUV / BG / ArbSchG — obwohl sich die Zielbranche jede Woche daran messen lassen muss. Für ein Feature-Portfolio, das „Whistleblower-Portal“ proaktiv aktivierte, aber Pflicht-Unterweisung nicht lieferte, war die Abstimmung mit dem Markt bereits verloren (vgl. LESSONS-LEARNED §5). Daraus die Schärfung:
- Arbeitsschutz ist kein Add-on, sondern Kern-Handwerk-V1.5, damit der Design-Partner SHK-Schmidt seine nächste BG-Meldung binnen 72 Stunden digital liefern kann.
- PSA-Check ist ein Gate, keine Info-Meldung — ohne Check keine Zeit-Stempelung an Gewerke-Typ „Abbruch / Dach / Gerüst“. Konsequenz vor Komfort.
- Unterweisungsnachweis ist Append-only + Hash-Chain + Signatur, nicht nur ein PDF-Anhang an einen Stammdaten-Satz.
- Unfall-Workflow bedient F1000 direkt, nicht „wir exportieren was, was du ausfüllen kannst“ — die Felder müssen im F1000-Format rausgehen, mit Fristen-Überwachung.
Erwarteter Outcome (messbar am Referenzkunden SHK-Gebrüder-Schmidt, 80 MA):
| KPI | Heute | Ziel nach 90 Tagen Werkszeit |
|---|---|---|
| Anteil der MA mit gültiger Jahresunterweisung | ~65 % (Schätzung SiFa) | >98 % |
| BG-F1000-Frist-Einhaltung (≤3 Werktage) | ~60 % | 100 % |
| PSA-Compliance auf Abbruch-/Dach-Baustellen (Stichprobe) | nicht gemessen | ≥95 % (objektiv über PSA-Check) |
| Manuelle SiFa-Stunden pro Monat (Listenpflege) | 8–12 h | <2 h |
3. Personas & Rollen
Abschnitt betitelt „3. Personas & Rollen“| Rolle | Aktion | Scope | Plattform |
|---|---|---|---|
| Mitarbeiter | Unterweisung absolvieren, PSA-Check machen, Unfall melden (eigenen/Kollegen) | own | 📱 |
| Vorarbeiter / Polier | PSA-Check-Übersicht vor Schichtbeginn, Unfall-Ersterfassung für Team | team | 📱 |
| SiFa (Sicherheitsfachkraft, ASiG §5) | Unterweisungs-Inhalte pflegen, Gefährdungsbeurteilung erstellen, BG-Meldung finalisieren, Ersthelfer-Quote sichern | all | 🌐 (📱 nur Erfassung Gefährdungsbeurteilung auf Baustelle) |
| Ersthelfer (bestellt, DGUV V1 §26) | Unfall-Erstversorgung dokumentieren (Verbandbuch-Eintrag) | team | 📱 |
| Manager | Status-Dashboard Tenant, Eskalation bei überfälliger Unterweisung | team/all | 🌐 |
| HR | Bestellungen (Ersthelfer, Sicherheitsbeauftragter) verwalten, PDF-Bescheinigungen | all | 🌐 |
| BG (extern, DAV-Schnittstelle) | F1000 empfangen — Werkszeit ist Client, nicht Server | extern | — |
Persona-Skizzen:
- Mehmet Yılmaz (Maler-Helfer, 24, Tenant
musterbetrieb-maler) — steigt Leitern, Absturzrisiko ab 2 m. Spricht Türkisch-Deutsch, Deutsch-Lesekompetenz B1. Unterweisung Absturzsicherung Leitern fällig am 18.04.2026; Fälligkeits-Push kommt am 18., 11., 4., 1. Tag vorher. Er öffnet die App morgens um 07:08 im Auto, spielt 6-min-Video ab, beantwortet 4 Quiz-Fragen, unterschreibt auf dem Phone. - Thomas Schmidt (SiFa, Tenant
shk-gebruder-schmidt) — bestellte Sicherheitsfachkraft nach ASiG §5, 60 % Stelle. Pflegt Unterweisungs-Inhalte im Web, erstellt Gefährdungsbeurteilung pro Baustelle auf iPad vor Ort. Hat eine persönliche Haftung — wenn er einen Mitarbeiter ohne gültige Unterweisung auf eine Leiter lässt, trägt er mit. - Frau Brehm (Ersthelferin, Sekretärin, Tenant
musterbetrieb-maler) — DGUV-Lehrgang gemacht, bekommt bei jedem Unfall automatisch Push zur Mitunterschrift des Verbandbuch-Eintrags. - Hannes Krüger (Monteur, 38, Tenant
musterbetrieb-maler) — stürzt von der Leiter, 4 Tage AU. Unfall-Meldung wird von Polier ausgelöst, Hannes signiert nachträglich seine Zeugenaussage.
4. User-Stories
Abschnitt betitelt „4. User-Stories“US-01 [V1.5] Als Mitarbeiter möchte ich meine Jahresunterweisung als Video + 4 Quizfragen in der App absolvieren (6–10 min), damit ich nicht zum Schulungstermin ins Büro reisen muss und trotzdem DGUV V1 §4 erfüllt ist.
US-02 [V1.5] Als Mitarbeiter möchte ich vor Schichtbeginn in 10 Sekunden einen PSA-Check abhaken (Helm, Schuhe, Warnweste, je nach Tätigkeit), damit der Polier sieht, dass ich einsatzbereit bin.
US-03 [V1.5] Als Polier möchte ich einen Arbeitsunfall direkt auf der Baustelle erfassen (Fotos, Zeugen, GPS, Verletzungsart), damit die BG-Meldung binnen der 3-Werktage-Frist rausgehen kann.
US-04 [V1.5] Als SiFa möchte ich eine Gefährdungsbeurteilung pro Baustelle strukturiert erstellen (Gewerke, Gefährdungen, Schutzmaßnahmen, Restrisiko) und unterschreiben, damit ArbSchG §5/§6 belegbar sind.
US-05 [V1.5] Als SiFa möchte ich im Dashboard sofort sehen, welche Mitarbeiter in den nächsten 30/14/7 Tagen unterwiesen werden müssen und wer bereits überfällig ist, damit niemand durchs Netz fällt.
US-06 [V1.5] Als Manager möchte ich ab dem Moment, in dem ein Monteur mit überfälliger Unterweisung in einen Dienstplan kommt, eine harte Blockade sehen (nicht nur einen Hinweis), damit Haftung klar ist.
US-07 [V1.5] Als SiFa möchte ich die BG-BAU F1000-Meldung aus der Unfall-Erfassung auto-generieren und direkt an die BG übermitteln (oder als PDF zum Upload ins Serviceportal herunterladen), damit ich nicht doppelt tippe.
US-08 [V2] Als HR möchte ich die Ersthelfer-Quote pro Tenant tracken und einen Hinweis bekommen, wenn wir unter 10 % fallen (DGUV V1 §26), damit wir rechtzeitig einen neuen Ersthelfer ausbilden lassen.
US-09 [V2] Als Mitarbeiter mit Sprache != Deutsch möchte ich die Unterweisung in meiner Muttersprache (TR/PL/RO) erhalten, weil eine Unterweisung, die ich nicht verstehe, rechtlich keine Unterweisung ist (BAG-Rechtsprechung zu Sprach-Barrieren in DGUV-Unterweisungen).5. Funktionale Anforderungen
Abschnitt betitelt „5. Funktionale Anforderungen“5.1 Mobile App (📱) — iOS + Android
Abschnitt betitelt „5.1 Mobile App (📱) — iOS + Android“- F-M-01 Unterweisung abspielen. Video (MP4/HLS, bis 15 min) + 3–8 Quiz-Fragen (Single/Multiple Choice). Mindestens 80 % Video angeschaut + ≥75 % Quiz-richtig sind Pflicht — sonst keine Abschluss-Signatur. Abspielzeit wird serverseitig via
segment_watched_seconds-Heartbeats validiert, damit der Mitarbeiter nicht „skippen“ kann (Anti-Klick-Mechanik). - F-M-02 Unterweisungs-Signatur. Abschluss per Touch-Signatur oder 4-stelligem PIN (aus E-Mail-Link für Betriebe ohne Signatur-Kultur). Signatur wird mit
tenant_id,user_id,unterweisung_id,signed_at_utc,device_id,video_completion_pct,quiz_scoregebündelt SHA-256-gehasht und als Hash-Chain-Nachfolger inunterweisungs_nachweisegespeichert. - F-M-03 Sprachwahl Unterweisung. Wenn das Tenant-Profil mehrsprachige Inhalte hinterlegt hat, bietet die App die vom Mitarbeiter im Profil gewählte Sprache (DE/EN/TR/PL/RO) an. Ohne hinterlegte Übersetzung: DE mit Warn-Banner „keine Übersetzung verfügbar — bitte bei SiFa melden, falls Verständnis unklar“. Rechtliche Grundlage: BAG 9 AZR 475/19 zur Sprach-Barriere.
- F-M-04 PSA-Check vor Schichtbeginn. Checkliste pro Tätigkeits-Profil:
- Profil „Maler-Helfer Leiter“: Helm ☐, Sicherheitsschuhe S3 ☐, Warnweste ☐, Schutzbrille ☐.
- Profil „Dachdecker“: + Auffanggurt ☐, Helm mit Kinnriemen ☐.
- Profil „Abbruch“: + Atemschutz FFP3 ☐, Gehörschutz ☐. Jedes ☐ hat drei Zustände: ✓ (OK), ✕ (fehlt), ⚠ (beschädigt — öffnet Foto-Pflichtfeld „Beleg“). PSA-Check wird pro Schicht maximal einmal erfragt (Cache 12 h), bei Baustellen-Wechsel erneut.
- F-M-05 PSA-Check-Gate. Bei unvollständigem PSA-Check (mindestens ein ✕) wird der Stempel-Button blockiert für Gewerke-Profile mit Pflicht-PSA. Alternativ: Mitarbeiter wählt „PSA verweigert — Grund“ (freier Text), was einen Audit-Eintrag
psa.deniedund eine Push-Benachrichtigung an den Polier erzeugt. Der Stempel bleibt gesperrt. - F-M-06 Arbeitsunfall melden. Pflichtfelder auf Mobile:
- Verletzte Person (eigene Auswahl oder Kollege aus Team-Liste),
- Zeitpunkt (Datum+Uhrzeit, default
now()), - Unfallort (GPS + Baustellen-Auswahl, default nächste Baustelle),
- Verletzungsart (Multi-Select nach DGUV-Schlüssel: Schnitt, Quetschung, Fraktur, Sturz, Verätzung, Verbrennung, Elektro, Sonstiges),
- Körperteil (DGUV-Diagramm, Tap auf Silhouette),
- Hergang (Freitext 200–2000 Zeichen, Voice-Dictation verfügbar),
- Zeugen (Multi-Select MA + Freitext-Name externe Zeugen),
- Fotos 0–12 (Geo-Stempel-Pipeline aus
handwerk/01-bautagebuch), - Erwartete AU-Dauer (0 / 1–3 Tage / >3 Tage / tödlich). Bei >3 Tage oder tödlich wird ein Countdown-Banner aktiv: „BG-Meldung muss bis [Datum] 23:59 übermittelt werden (§193 SGB VII)“.
- F-M-07 Verbandbuch-Eintrag. Separater, leichter Flow für kleine Vorfälle ohne Meldepflicht (DGUV-Empfehlung: Verbandbuch 5 Jahre aufbewahren). Felder: Datum, Person, Art der Erste-Hilfe-Leistung, Ersthelfer. Keine Fotos, keine BG-Pflicht — aber append-only und hash-verkettet.
- F-M-08 Gefährdungsbeurteilung vor Ort. SiFa oder Bauleiter kann auf der Baustelle eine Gefährdungsbeurteilung nach ArbSchG §5 starten: Tätigkeiten auswählen, zugehörige Gefährdungen aus TRBS/BGI-Katalog filtern, Schutzmaßnahmen aus Standard-Katalog oder Freitext, Restrisiko (niedrig/mittel/hoch). Abschluss per Signatur der verantwortlichen Person (SiFa oder Vorgesetzter).
- F-M-09 Offline-Profil. Voll-offline für Unterweisungs-Videos (vorab geladen in Kolonne
downloaded_for_offlinebei WLAN-Verbindung, 7-Tage-Frische-Check), PSA-Check, Unfall-Erfassung (inkl. Fotos in App-Sandbox), Gefährdungsbeurteilung. Sync-Priorität: Unfall > PSA-Verweigerung > Unterweisungs-Signatur > Gefährdungsbeurteilung > Verbandbuch.
5.2 Web-App (🌐)
Abschnitt betitelt „5.2 Web-App (🌐)“- F-W-01 SiFa-Fälligkeits-Dashboard. Tabelle aller MA × Unterweisungs-Themen mit Ampel: 🟢 >90 Tage gültig, 🟡 30–90 Tage, 🔴 ≤30 Tage oder abgelaufen, ⚫ noch nie absolviert. Filter: Themen-Typ, Team/Kolonne, Baustelle, Status. Bulk-Aktion „Jahresunterweisung 2026 zuweisen“ (Batch-Push an ausgewählte MA).
- F-W-02 Unterweisungs-Content-Verwaltung. CRUD für Themen: Titel, Beschreibung, Video-Upload (S3, direkt), Quiz-Fragen (JSON-Struktur), Gültigkeits-Intervall (Default 12 Monate, konfigurierbar — etwa Staplerschein DGUV G25 ebenfalls jährlich, Ersthelfer 2 Jahre), Ziel-Gruppen (Tätigkeits-Profil). Themen-Katalog kommt mit 24 vorbereiteten DGUV-211-005-Standard-Unterweisungen out-of-box (Absturzsicherung, Elektro, Leitern/Tritte, Gefahrstoff, Gerüst, PSA, Brandschutz, Erste Hilfe, Lärm, Hautschutz, …).
- F-W-03 Gefährdungsbeurteilung-Register. Pro Baustelle: alle Beurteilungen chronologisch, PDF-Export, Fortschreibungs-Pflicht-Check (ältere als 12 Monate werden rot markiert).
- F-W-04 BG-Unfall-Akte und F1000-Export. Pro Unfall: alle Felder, Fotos, Zeugen, Audit-Trail. Aktion „F1000 generieren“: Werkszeit erstellt das PDF nach aktuellem BG-BAU-F1000-Layout (PDF/A-2b, ausfüllbar); optional Direkt-Upload ins BG-Serviceportal via
bgbau_api-Adapter (falls BG-BAU-API-Zugang freigeschaltet — heute noch manuell). Frist-Ticker an oberster Stelle. - F-W-05 Ersthelfer-Register + Quoten-Check. Liste aller bestellten Ersthelfer pro Tenant mit Lehrgangs-Datum, Gültigkeit (2 Jahre nach DGUV), Zuordnung Team/Filiale. KPI-Kachel „Ist-Quote 8,7 % / Soll 10,0 % — Unterdeckung“.
- F-W-06 SiFa-Bestellung-PDF. Generiert Bestellungsurkunde nach ASiG §5 für den SiFa (oder externen Dienstleister), versioniert.
- F-W-07 Monatsabschluss-Arbeitsschutz. PDF-Report für die Geschäftsführung: Unterweisungs-Quote, offene Gefährdungsbeurteilungen, Unfälle mit AU-Tagen, Near-Misses, Ersthelfer-Quote.
5.3 Cross-Plattform (🔄)
Abschnitt betitelt „5.3 Cross-Plattform (🔄)“- F-X-01 Append-only mit Hash-Chain.
unterweisungs_nachweise,unfaelle,psa_checks,gefaehrdungsbeurteilungen,verbandbuch_eintraegesind alle append-only mithash_prev/hash_self. Korrektur = neuer Eintrag mitcorrects_id+ Begründung ≥ 20 Zeichen. - F-X-02 Status-Maschinen.
- Unterweisung:
zugewiesen → gestartet → video_abgeschlossen → quiz_bestanden → signiert → guelt_bis_<datum>(auto-abgelaufenvia Scheduler). - Unfall:
erfasst → ersthilfe_geleistet → an_bg_gemeldet → bg_bestaetigt → abgeschlossen; paralleler Flagmeldepflichtig(>3 AU-Tage oder tödlich). - PSA-Check:
offen → bestaetigtoderverweigert(kein Rückwärts-Übergang). - Gefährdungsbeurteilung:
entwurf → signiert → aktiv → veraltet(nach 12 Monaten auto-veraltet).
- Unterweisung:
- F-X-03 Cross-Link Dienstplanung. Der Planer-Web-UI (
kern/03-dienstplanung) liest ausunterweisungs_fristen_view, ob der MA eine gültige, zur Tätigkeit passende Unterweisung hat. Blockade bei Fehlen (hart) oder Ablauf in <7 Tagen (weich, mit Override-Button; Override erzeugt Audit-Eintragplanung.override.unterweisungsfrist). - F-X-04 Push-Scheduler. 90/30/14/7/1-Tage-Erinnerungs-Push vor Ablauf einer Unterweisung, 3/2/1-Tage-Ticker vor BG-Meldefrist, sofort-Push bei PSA-Verweigerung im Team an den Polier.
5.4 Admin-Konfiguration
Abschnitt betitelt „5.4 Admin-Konfiguration“- F-A-01 Tätigkeits-Profile. Admin definiert welche Rolle (Maler-Helfer, Dachdecker, SHK-Monteur, Abbruch-Facharbeiter, Elektriker) welche PSA-Items erfordert und welche Unterweisungen pflicht sind.
- F-A-02 Unterweisungs-Intervalle. Default 12 Monate; Ausnahme-Intervalle konfigurierbar (z. B. „Erste Hilfe Auffrischung alle 2 Jahre“, „Gefahrstoff alle 12 Monate“).
- F-A-03 BR-Freigabe Unterweisungs-Tracking. Default: ein — aber nur „Pflicht-Unterweisung wurde absolviert ja/nein“-Sicht. Detaillierte Video-Seek-Heatmap / Quiz-Antwort-Analyse ist standardmäßig aus (BetrVG §87(1)6) und braucht dokumentierte BR-Zustimmung.
- F-A-04 BG-Zuordnung. Pro Tenant wird die zuständige Berufsgenossenschaft gepflegt (BG BAU, BG ETEM, BG Holz+Metall — bestimmt Formular-Schema und Meldungs-Endpoint).
- F-A-05 Gefährdungsbeurteilung-Templates. Admin lädt Tenant-eigene Beurteilungs-Vorlagen hoch (Word → Parsed) oder wählt aus Bibliothek BGI 579, BGI 5088, …
5.5 Roadmap-Schichtung
Abschnitt betitelt „5.5 Roadmap-Schichtung“| Anforderung-ID | MVP | V1 | V1.5 | V2 |
|---|---|---|---|---|
| F-M-01 Unterweisung Player | ✅ | |||
| F-M-04 PSA-Check | ✅ | |||
| F-M-05 PSA-Gate Stempel | ✅ | |||
| F-M-06 Unfall-Erfassung | ✅ | |||
| F-M-07 Verbandbuch | ✅ | |||
| F-M-08 Gefährdungsbeurteilung Mobile | ✅ | |||
| F-W-01 SiFa-Dashboard | ✅ | |||
| F-W-02 Content-CRUD | ✅ | |||
| F-W-04 F1000-PDF-Export | ✅ | |||
| F-W-04 F1000-API-Direktlieferung BG | ✅ (bei BG-Zugang) | |||
| F-M-03 Mehrsprachige Unterweisung | ✅ | |||
| F-W-05 Ersthelfer-Quoten-Check | ✅ | |||
| KI-Vorschlag Gefährdung (opt-in) | ❔ (bei Referenzkunde) |
6. Mockups & Flows
Abschnitt betitelt „6. Mockups & Flows“HTML-Hero-Mockup: 10-arbeitssicherheit.html — Mobile + Web Side-by-Side. Mobile-Persona: Mehmet Yılmaz auf Baustelle „Lehrer Allee 7, München“ am 18.04.2026 (Jahresunterweisung „Absturzsicherung Leitern“). Web-Persona: Thomas Schmidt (SiFa) im SHK-Schmidt-Büro am 20.04.2026 mit offener BG-Unfallmeldung für Hannes Krüger.
6.1 Mobile — Unterweisungs-Player
Abschnitt betitelt „6.1 Mobile — Unterweisungs-Player“┌────────────────────────────────┐│ ← Unterweisung ⚙ │├────────────────────────────────┤│ 🛡 DGUV V1 §4 · GoBD · DSGVO │├────────────────────────────────┤│ ABSTURZSICHERUNG LEITERN 🔴 ││ Jahres-Unterweisung 2026 ││ Fällig heute · Sa 18.04.2026 ││ ││ ╭──────────────────────────╮ ││ │ │ ││ │ ▶ 6:42 min │ ││ │ │ ││ │ ▓▓▓▓▓▓░░░░░░░░░░░░ 38%│ ││ ╰──────────────────────────╯ ││ ││ Fortschritt: 38 % (mind. 80 %) ││ Sprache: Deutsch ▼ ││ ││ Quiz kommt nach Video ││ ☐ Frage 1 / 4 ││ ☐ Frage 2 / 4 ││ ☐ Frage 3 / 4 ││ ☐ Frage 4 / 4 ││ ││ ┌────────────────────────────┐ ││ │ Video pausieren (speichert │ ││ │ Fortschritt offline) │ ││ └────────────────────────────┘ │├────────────────────────────────┤│ [Zeit] [Plan] [Doku] [Mehr] │└────────────────────────────────┘6.2 Mobile — Quiz + Signatur (Abschluss)
Abschnitt betitelt „6.2 Mobile — Quiz + Signatur (Abschluss)“┌────────────────────────────────┐│ ← Unterweisung ✓ │├────────────────────────────────┤│ Video abgeschlossen (92 %) ✅ ││ Quiz bestanden (4/4) ✅ ││ ││ FRAGE 4 / 4 ││ Ab welcher Absturzhöhe ist ││ PSA gegen Absturz Pflicht? ││ ││ ( ) 1,00 m ││ ( ) 2,00 m ││ (•) 3,00 m │ ← richtig│ ( ) 5,00 m ││ ││ ✅ Richtig (ArbStättV Anh. 2.1)││ ││ SIGNATUR-NACHWEIS 🔴 ││ Ich bestätige, die Unterweisung││ vollständig erhalten zu haben. ││ ││ Name: Mehmet Yılmaz ││ Rolle: Maler-Helfer ││ Datum: Sa 18.04.2026 · 07:18 ││ ││ ╭───────────────────────────╮ ││ │ M̳. Y̳ı̳l̳m̳a̳z̳ │ ││ │ │ ││ ╰───────────────────────────╯ ││ [✕ leeren] ││ ││ ┌────────────────────────────┐ ││ │ UNTERWEISUNG ABSCHLIESSEN│ │ ← Primary│ └────────────────────────────┘ ││ ││ Gültig bis: So 18.04.2027 │└────────────────────────────────┘6.3 Mobile — PSA-Check vor Schichtbeginn
Abschnitt betitelt „6.3 Mobile — PSA-Check vor Schichtbeginn“┌────────────────────────────────┐│ ← PSA-Check vor Schicht │├────────────────────────────────┤│ 🛡 PSA-BV · DGUV V1 §30 │├────────────────────────────────┤│ Baustelle: Lehrer Allee 7 ││ Profil: Maler-Helfer Leiter ││ Datum: Mo 20.04.2026 06:58 ││ ││ PFLICHT-PSA ││ ┌────────────────────────────┐ ││ │ 🪖 Schutzhelm │ ││ │ (•) ✓ ( ) ✕ ( ) ⚠ │ ││ ├────────────────────────────┤ ││ │ 👟 Sicherheitsschuhe S3 │ ││ │ (•) ✓ ( ) ✕ ( ) ⚠ │ ││ ├────────────────────────────┤ ││ │ 🦺 Warnweste │ ││ │ ( ) ✓ (•) ✕ ( ) ⚠ │ ││ │ 🔴 Fehlt — Grund: │ ││ │ ▼ im Bus vergessen │ ││ ├────────────────────────────┤ ││ │ 🥽 Schutzbrille │ ││ │ (•) ✓ ( ) ✕ ( ) ⚠ │ ││ └────────────────────────────┘ ││ ││ 🔴 PSA unvollständig ││ Schichtbeginn-Stempel blockiert││ bis Warnweste vorhanden ODER ││ Polier die Abweichung freigibt.││ ││ ┌────────────────────────────┐ ││ │ POLIER BENACHRICHTIGEN │ ││ └────────────────────────────┘ ││ [ Unbewusst weiter (Audit) ] │ ← danger-text└────────────────────────────────┘6.4 Mobile — Unfallmeldung Schritt 2/3
Abschnitt betitelt „6.4 Mobile — Unfallmeldung Schritt 2/3“┌────────────────────────────────┐│ ← Unfall erfassen (2/3) ⋯ │├────────────────────────────────┤│ 🛡 §193 SGB VII · DSGVO Art.9 │├────────────────────────────────┤│ 🔴 Meldefrist läuft ││ Di 21.04.2026 · 23:59 ││ (Unfall Mo 20.04. · 11:42) ││ ││ VERLETZTE PERSON 🔴 ││ ▼ Hannes Krüger ││ ││ VERLETZUNGSART 🔴 ││ [✓ Sturz] [✓ Fraktur] [ ]... ││ ││ KÖRPERTEIL 🔴 ││ ╭─────────╮ ││ │ ○ │ ← Kopf ││ │ ─┼─ │ ││ │ │ │ ││ │ ─┤─ │ ││ │ │● │ ← Knöchel rechts ││ │ ─┘ └─ │ (angetippt) ││ ╰─────────╯ ││ ││ HERGANG 🔴 ││ ┌────────────────────────────┐ ││ │ Sturz von Leiter, │ ││ │ 3. Sprosse, Verdreh. │ ││ │ Leiter nicht ausreichend │ ││ │ gesichert (weicher Boden) │ ││ │ 🎤 │ ││ └────────────────────────────┘ ││ ││ ZEUGEN ││ [✓ Mehmet Y.] [✓ Frank D.] ││ ││ FOTOS (2/12) ││ ┌──┐┌──┐┌──┐ ││ │📷││📷││ +│ ││ └──┘└──┘└──┘ ││ 🟢 Geo-Stempel aktiv ││ ││ ERWARTETE AU 🔴 ││ ( ) keine ( ) 1–3 Tage ││ (•) >3 Tage — meldepflichtig! ││ ( ) tödlich ││ ││ ┌────────────────────────────┐ ││ │ WEITER zu Schritt 3/3 │ ││ └────────────────────────────┘ │└────────────────────────────────┘6.5 Web — SiFa-Dashboard Unterweisungs-Fälligkeit
Abschnitt betitelt „6.5 Web — SiFa-Dashboard Unterweisungs-Fälligkeit“┌────────────────────────────────────────────────────────────────────────────────┐│ Werkszeit · shk-gebruder-schmidt Thomas Schmidt · SiFa [▾] │├────────────────────────────────────────────────────────────────────────────────┤│ Sidebar │ Arbeitssicherheit · Fälligkeit Unterweisungen Stand 20.04.26 ││ ───────── │ ───────────────────────────────────────────────────────────── ││ Zeit │ KPI ││ Plan │ ┌──────────┬──────────┬──────────┬──────────┐ ││ Bautage │ │ Gültig │ 🟢 67 │ 🟡 9 │ 🔴 4 │ ││ Mängel │ │ MA gesamt│ 90 Tage+ │ 30–90 d │ ≤30 d │ ││ ▶ Safety │ └──────────┴──────────┴──────────┴──────────┘ ││ Zertif. │ Ersthelfer-Quote: 8,7 % / Soll 10 % 🔴 Unterdeckung ││ Projekte │ ││ Audit │ Filter: [Thema ▼ Absturzsicherung] [Team ▼ alle] [🔍 Suche] ││ │ ││ │ ┌─────────────┬──────────────┬──────────┬──────────┬───────┐ ││ │ │ Mitarbeiter │ Thema │ Letzte │ Fällig │ Ampel │ ││ │ ├─────────────┼──────────────┼──────────┼──────────┼───────┤ ││ │ │ Yılmaz, M. │ Absturz/Ltr. │ — │ 18.04.26 │ 🔴 │ ││ │ │ Krüger, H. │ Absturz/Ltr. │ 14.03.25 │ 14.03.26 │ 🔴 │ ││ │ │ Demir, F. │ Absturz/Ltr. │ 22.05.25 │ 22.05.26 │ 🟡 │ ││ │ │ Wirth, A. │ Gefahrstoff │ 11.07.25 │ 11.07.26 │ 🟢 │ ││ │ │ Schmidt, L. │ Erste Hilfe │ 09.04.24 │ 09.04.26 │ 🔴 │ ││ │ │ (Ersthelferin · Bestellung läuft 09.04.26 aus) │ │ ││ │ │ Maier, S. │ Brandschutz │ 02.11.25 │ 02.11.26 │ 🟢 │ ││ │ └─────────────┴──────────────┴──────────┴──────────┴───────┘ ││ │ ││ │ [ Bulk · 4 MA „Absturz" zuweisen ] [⤓ PDF-Report] ││ │ │└────────────────────────────────────────────────────────────────────────────────┘6.6 Web — Unfall-Akte mit F1000-Export
Abschnitt betitelt „6.6 Web — Unfall-Akte mit F1000-Export“┌────────────────────────────────────────────────────────────────────────────────┐│ Werkszeit · shk-gebruder-schmidt SiFa Thomas Schmidt [Ausloggen] │├────────────────────────────────────────────────────────────────────────────────┤│ ← Unfälle · Hannes Krüger · Unfall #2026-0017 ││ ││ 🔴 MELDEFRIST §193 SGB VII · Di 21.04.2026 23:59 · verbleiben 37:18 h ││ ││ ┌─ Sachverhalt ─────────────────────────────────────────────────────────────┐ ││ │ Person: Hannes Krüger, 38, Monteur, Maler-Betrieb │ ││ │ Zeitpunkt: Mo 20.04.2026 · 11:42 Uhr │ ││ │ Unfallort: Lehrer Allee 7, 80331 München (Baustelle) │ ││ │ Verletzung: Sturz · Fraktur · Knöchel rechts │ ││ │ Hergang: Sturz von Leiter, 3. Sprosse, Verdrehen des Knöchels. │ ││ │ Leiter nicht ausreichend gesichert (weicher Boden, keine │ ││ │ Leiterfußverbreiterung). │ ││ │ Erwartete AU: >3 Tage — meldepflichtig │ ││ │ Zeugen: Mehmet Yılmaz · Frank Demir │ ││ │ Ersthelfer: Frau Brehm (Erstversorgung, Rettungsdienst gerufen 11:43) │ ││ └───────────────────────────────────────────────────────────────────────────┘ ││ ││ ┌─ Fotos (3) ───────────────────────────────────────────────────────────────┐ ││ │ [📷] [📷] [📷] │ ││ │ Geo 48.1374 · 11.5755 · 20.04.26 11:44 · SHA-256 7a8c...ef2 │ ││ └───────────────────────────────────────────────────────────────────────────┘ ││ ││ ┌─ BG-Meldung F1000 ────────────────────────────────────────────────────────┐ ││ │ Vorschau: BG BAU F1000 (PDF/A-2b, ausfüllbar) │ ││ │ Status: Entwurf — noch nicht übermittelt │ ││ │ Felder vorausgefüllt: │ ││ │ ✓ Unternehmensdaten (aus Tenant-Profil) │ ││ │ ✓ Versicherte Person (aus User-Profil) │ ││ │ ✓ Unfalldaten (aus Erfassung) │ ││ │ ⚠ Frage 4.3 „Maßnahmen zur Verhütung?" — frei formulieren │ ││ │ │ ││ │ [ F1000-PDF herunterladen ] [ Direkt an BG BAU senden (Serviceportal) ] │ ││ └───────────────────────────────────────────────────────────────────────────┘ ││ ││ Audit-Chain (Hash-verkettet): ││ 20.04. 11:43 · unfall.erfasst · Thomas Schmidt · 7a8c…ef2 ││ 20.04. 11:45 · unfall.foto_hinzugefuegt · Thomas Schmidt · b4d1…fe7 ││ 20.04. 14:02 · unfall.ersthilfe_dokumentiert · Fr. Brehm · 0c9e…4aa │└────────────────────────────────────────────────────────────────────────────────┘7. Datenmodell-Skizze
Abschnitt betitelt „7. Datenmodell-Skizze“Pseudo-Drizzle-Schema (Postgres 17 + RLS + pgcrypto).
export const unterweisungsThemenTable = pgTable('unterweisungs_themen', { id: uuid('id').primaryKey().defaultRandom(), // UUID v7 tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), code: text('code').notNull(), // z.B. 'DGUV-211-005.ABSTURZ' titel: text('titel').notNull(), // 'Absturzsicherung Leitern' beschreibung: text('beschreibung'), videoS3Key: text('video_s3_key'), // S3-Multipart videoDurationSec:integer('video_duration_sec'), quizSchema: jsonb('quiz_schema').notNull(), // Array von Frage-Objekten mindVideoPct: integer('mind_video_pct').notNull().default(80), mindQuizPct: integer('mind_quiz_pct').notNull().default(75), intervallMonate: integer('intervall_monate').notNull().default(12), zielProfileCodes:text('ziel_profile_codes').array().notNull(), // ['maler_helfer_leiter', 'dachdecker'] sprachen: text('sprachen').array().notNull().default(['de']), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), createdBy: uuid('created_by').notNull().references(() => usersTable.id), archiviertAm: timestamp('archiviert_am', { withTimezone: true }),}, (t) => ({ tenantCodeIdx: uniqueIndex('unterw_themen_tenant_code_uq').on(t.tenantId, t.code),}));
export const unterweisungsNachweiseTable = pgTable('unterweisungs_nachweise', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), themaId: uuid('thema_id').notNull().references(() => unterweisungsThemenTable.id), userId: uuid('user_id').notNull().references(() => usersTable.id), sprache: text('sprache').notNull(), // 'de' | 'tr' | 'pl' | 'ro' videoWatchedPct: integer('video_watched_pct').notNull(), quizScorePct: integer('quiz_score_pct').notNull(), quizAntwortenJson:jsonb('quiz_antworten_json').notNull(), // nur mit BR-Freigabe F-A-03 gefüllt; sonst nur aggregiertes Score signedAtUtc: timestamp('signed_at_utc', { withTimezone: true }).notNull(), signatureBlobId: uuid('signature_blob_id').references(() => blobsTable.id), signatureKind: signatureKind('signature_kind').notNull(), // 'touch_vector' | 'pin_token' deviceFingerprint:text('device_fingerprint').notNull(), gueltigBis: date('gueltig_bis').notNull(), // signedAt + intervall_monate status: unterweisungsStatus('status').notNull(), // 'zugewiesen' | 'gestartet' | 'video_abgeschlossen' | 'quiz_bestanden' | 'signiert' | 'abgelaufen' hashPrev: bytea('hash_prev'), hashSelf: bytea('hash_self').notNull(), idempotencyKey: uuid('idempotency_key').notNull().unique(), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), correctsId: uuid('corrects_id').references(() => unterweisungsNachweiseTable.id), correctionReason:text('correction_reason'),}, (t) => ({ tenantUserIdx: index('unterw_nachw_tenant_user_idx').on(t.tenantId, t.userId, t.gueltigBis.desc()), themaUserIdx: index('unterw_nachw_thema_user_idx').on(t.themaId, t.userId, t.signedAtUtc.desc()),}));
export const psaProfileTable = pgTable('psa_profile', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), code: text('code').notNull(), // 'maler_helfer_leiter' titel: text('titel').notNull(), pflichtItems: jsonb('pflicht_items').notNull(), // [{code:'helm',label:'Schutzhelm'}, …]}, (t) => ({ tenantCodeIdx: uniqueIndex('psa_profile_tenant_code_uq').on(t.tenantId, t.code),}));
export const psaChecksTable = pgTable('psa_checks', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), userId: uuid('user_id').notNull().references(() => usersTable.id), baustelleId: uuid('baustelle_id').notNull().references(() => baustellenTable.id), profilId: uuid('profil_id').notNull().references(() => psaProfileTable.id), itemsState: jsonb('items_state').notNull(), // [{code:'helm',state:'ok'|'fehlt'|'beschaedigt',fotoBlobId?:uuid,grund?:string}] ergebnis: psaErgebnis('ergebnis').notNull(), // 'bestaetigt' | 'verweigert' | 'bedingt_mit_freigabe' verweigerungsGrund:text('verweigerungs_grund'), freigabeDurchUserId:uuid('freigabe_durch_user_id').references(() => usersTable.id), capturedAtUtc: timestamp('captured_at_utc', { withTimezone: true }).notNull().defaultNow(), gpsLat: decimal('gps_lat', { precision: 9, scale: 6 }), gpsLon: decimal('gps_lon', { precision: 9, scale: 6 }), hashPrev: bytea('hash_prev'), hashSelf: bytea('hash_self').notNull(), idempotencyKey: uuid('idempotency_key').notNull().unique(),}, (t) => ({ tenantUserBsIdx: index('psa_check_tenant_user_bs_idx') .on(t.tenantId, t.userId, t.baustelleId, t.capturedAtUtc.desc()),}));
export const unfaelleTable = pgTable('unfaelle', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), laufnummerJahr: text('laufnummer_jahr').notNull(), // '2026-0017' verletztUserId: uuid('verletzt_user_id').references(() => usersTable.id), verletztFreitextPerson:text('verletzt_freitext_person'), // wenn externer (Sub/Bauherr) baustelleId: uuid('baustelle_id').references(() => baustellenTable.id), unfallAt: timestamp('unfall_at', { withTimezone: true }).notNull(), gpsLat: decimal('gps_lat', { precision: 9, scale: 6 }), gpsLon: decimal('gps_lon', { precision: 9, scale: 6 }), verletzungsArten:text('verletzungs_arten').array().notNull(), // ['sturz','fraktur'] koerperteil: text('koerperteil').notNull(), // 'knoechel_rechts' hergang: text('hergang').notNull(), // GESUNDHEITSDATEN — siehe §10.4 zeugenUserIds: uuid('zeugen_user_ids').array(), zeugenFreitext: text('zeugen_freitext'), erwarteteAuKategorie:auErwartung('erwartete_au_kategorie').notNull(), // 'keine' | '1_bis_3' | 'ueber_3' | 'toedlich' meldepflichtig: boolean('meldepflichtig').notNull(), // berechnet aus erwarteteAuKategorie meldefrist: timestamp('meldefrist', { withTimezone: true }),// unfallAt + 3 Werktage 23:59 bgKey: text('bg_key').notNull(), // 'BG_BAU' | 'BG_ETEM' | 'BG_HM' bgStatus: bgStatus('bg_status').notNull().default('entwurf'), // 'entwurf' | 'pdf_generiert' | 'serviceportal_uebermittelt' | 'bg_bestaetigt' | 'abgeschlossen' bgMeldungAt: timestamp('bg_meldung_at', { withTimezone: true }), f1000PdfBlobId: uuid('f1000_pdf_blob_id').references(() => blobsTable.id), ersthelferUserId:uuid('ersthelfer_user_id').references(() => usersTable.id), ersthilfeProtokoll:text('ersthilfe_protokoll'), hashPrev: bytea('hash_prev'), hashSelf: bytea('hash_self').notNull(), idempotencyKey: uuid('idempotency_key').notNull().unique(), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), createdBy: uuid('created_by').notNull().references(() => usersTable.id), // Gesundheitsdaten-Key: getrenntes KMS-Feld (envelope encryption) gesundheitsdatenKmsKeyId:text('gesundheitsdaten_kms_key_id').notNull(),}, (t) => ({ tenantJahrIdx: uniqueIndex('unfaelle_tenant_laufnr_uq').on(t.tenantId, t.laufnummerJahr), meldefristIdx: index('unfaelle_meldefrist_idx').on(t.meldepflichtig, t.meldefrist),}));
export const unfallFotosTable = pgTable('unfall_fotos', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), unfallId: uuid('unfall_id').notNull().references(() => unfaelleTable.id), s3Key: text('s3_key').notNull(), // Object Lock Compliance 10 Jahre contentSha256: bytea('content_sha256').notNull(), geoStampSha256: bytea('geo_stamp_sha256').notNull(), gpsLat: decimal('gps_lat', { precision: 9, scale: 6 }), gpsLon: decimal('gps_lon', { precision: 9, scale: 6 }), capturedAtUtc: timestamp('captured_at_utc', { withTimezone: true }).notNull(),});
export const gefaehrdungsbeurteilungenTable = pgTable('gefaehrdungsbeurteilungen', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), baustelleId: uuid('baustelle_id').notNull().references(() => baustellenTable.id), taetigkeiten: text('taetigkeiten').array().notNull(), gefaehrdungen: jsonb('gefaehrdungen').notNull(), // [{code, beschreibung, schutzmassnahmen[], restrisiko}] erstelltVonSifaId:uuid('erstellt_von_sifa_id').notNull().references(() => usersTable.id), signedAtUtc: timestamp('signed_at_utc', { withTimezone: true }), signatureBlobId: uuid('signature_blob_id').references(() => blobsTable.id), gueltigBis: date('gueltig_bis').notNull(), // signedAt + 12 Monate status: gbStatus('status').notNull().default('entwurf'), hashPrev: bytea('hash_prev'), hashSelf: bytea('hash_self').notNull(), idempotencyKey: uuid('idempotency_key').notNull().unique(),}, (t) => ({ tenantBsIdx: index('gb_tenant_bs_idx').on(t.tenantId, t.baustelleId, t.signedAtUtc.desc()),}));
export const verbandbuchEintraegeTable = pgTable('verbandbuch_eintraege', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), verletztUserId: uuid('verletzt_user_id').references(() => usersTable.id), zeitpunkt: timestamp('zeitpunkt', { withTimezone: true }).notNull(), art: text('art').notNull(), // Freitext ersthelferUserId:uuid('ersthelfer_user_id').references(() => usersTable.id), hashPrev: bytea('hash_prev'), hashSelf: bytea('hash_self').notNull(),});
export const ersthelferBestellungenTable = pgTable('ersthelfer_bestellungen', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), userId: uuid('user_id').notNull().references(() => usersTable.id), lehrgangDatum: date('lehrgang_datum').notNull(), gueltigBis: date('gueltig_bis').notNull(), // lehrgangDatum + 2 Jahre lehrgangAnbieter:text('lehrgang_anbieter'), urkundeBlobId: uuid('urkunde_blob_id').references(() => blobsTable.id),});RLS-Policy-Sketch:
ALTER TABLE unterweisungs_nachweise ENABLE ROW LEVEL SECURITY;
CREATE POLICY unterw_nachw_tenant ON unterweisungs_nachweise USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY unterw_nachw_scope ON unterweisungs_nachweise FOR SELECT USING ( tenant_id = current_setting('app.tenant_id')::uuid AND ( current_setting('app.scope') = 'all' OR (current_setting('app.scope') = 'team' AND user_id IN (SELECT uid FROM user_team_membership WHERE manager_id = current_setting('app.user_id')::uuid)) OR (current_setting('app.scope') = 'own' AND user_id = current_setting('app.user_id')::uuid) ) );
-- Append-only: UPDATE nur auf status (für auto-'abgelaufen'-Übergang). Inhalt eingefroren.CREATE POLICY unterw_nachw_no_content_update ON unterweisungs_nachweise FOR UPDATE USING (tenant_id = current_setting('app.tenant_id')::uuid) WITH CHECK ( video_watched_pct = (SELECT video_watched_pct FROM unterweisungs_nachweise u WHERE u.id = unterweisungs_nachweise.id) AND quiz_score_pct = (SELECT quiz_score_pct FROM unterweisungs_nachweise u WHERE u.id = unterweisungs_nachweise.id) AND signed_at_utc = (SELECT signed_at_utc FROM unterweisungs_nachweise u WHERE u.id = unterweisungs_nachweise.id) );
REVOKE DELETE ON unterweisungs_nachweise FROM PUBLIC;
-- Unfaelle: Gesundheitsdaten → separate Policy, strenger Scope (nur SiFa, HR, Unfall-Eigentümer):ALTER TABLE unfaelle ENABLE ROW LEVEL SECURITY;CREATE POLICY unfaelle_scope ON unfaelle FOR SELECT USING ( tenant_id = current_setting('app.tenant_id')::uuid AND ( current_setting('app.role') IN ('sifa','hr','admin') OR verletzt_user_id = current_setting('app.user_id')::uuid OR current_setting('app.user_id')::uuid = ANY(zeugen_user_ids) ) );REVOKE DELETE ON unfaelle FROM PUBLIC;ER-Bezug. Referenzierte Tabellen: tenants, users, baustellen, blobs, audit_log, teams, und Views user_team_membership, unterweisungs_fristen_view (Aggregation für Dashboard und Dienstplanung-Gate).
8. API-Endpunkte
Abschnitt betitelt „8. API-Endpunkte“Pfad-Konvention: /v1/handwerk/arbeitssicherheit/.... Alle hinter Hono-Modul-Gate module.handwerk.arbeitssicherheit.
| Methode | Pfad | Auth-Scope | Rate-Limit | Idempotenz | Beschreibung |
|---|---|---|---|---|---|
GET |
/v1/handwerk/arbeitssicherheit/unterweisungen/faellig |
safety:read:<scope> |
Standard | — | Fälligkeiten für Dashboard / eigene Sicht |
POST |
/v1/handwerk/arbeitssicherheit/unterweisungen/{themaId}/start |
safety:write:own |
Standard | Pflicht | Unterweisung starten |
POST |
/v1/handwerk/arbeitssicherheit/unterweisungen/{themaId}/progress |
safety:write:own |
Hoch | Pflicht (Heartbeat-Key) | Video-Fortschritts-Heartbeat |
POST |
/v1/handwerk/arbeitssicherheit/unterweisungen/{themaId}/quiz |
safety:write:own |
Standard | Pflicht | Quiz-Antworten submitten |
POST |
/v1/handwerk/arbeitssicherheit/unterweisungen/{themaId}/sign |
safety:write:own |
Privileged | Pflicht | Signatur → Nachweis final |
POST |
/v1/handwerk/arbeitssicherheit/psa-checks |
safety:write:own |
Standard | Pflicht | PSA-Check anlegen |
POST |
/v1/handwerk/arbeitssicherheit/unfaelle |
safety:write |
Standard | Pflicht | Unfall erfassen |
PATCH |
/v1/handwerk/arbeitssicherheit/unfaelle/{id} |
safety:write |
Standard | Pflicht | Ergänzen (erzeugt Korrektur-Eintrag) |
POST |
/v1/handwerk/arbeitssicherheit/unfaelle/{id}/fotos/presign |
safety:write |
Standard | Pflicht | Pre-Signed URL |
POST |
/v1/handwerk/arbeitssicherheit/unfaelle/{id}/f1000/pdf |
safety:approve |
Heavy | Pflicht | F1000-PDF erzeugen |
POST |
/v1/handwerk/arbeitssicherheit/unfaelle/{id}/f1000/submit |
safety:approve |
Heavy | Pflicht | Direkt-Upload BG-Serviceportal |
POST |
/v1/handwerk/arbeitssicherheit/gefaehrdungsbeurteilungen |
safety:write:team |
Standard | Pflicht | Gefährdungsbeurteilung anlegen |
POST |
/v1/handwerk/arbeitssicherheit/gefaehrdungsbeurteilungen/{id}/sign |
safety:approve |
Privileged | Pflicht | Signatur SiFa |
GET |
/v1/handwerk/arbeitssicherheit/ersthelfer/quote |
safety:read:all |
Standard | — | Quoten-KPI |
POST |
/v1/handwerk/arbeitssicherheit/themen |
safety:admin |
Standard | Pflicht | Unterweisungs-Thema anlegen (Admin) |
OpenAPI-Schema-Skizze (gekürzt):
paths: /v1/handwerk/arbeitssicherheit/unfaelle: post: operationId: createUnfall x-werkszeit-scope: safety:write x-werkszeit-module-gate: module.handwerk.arbeitssicherheit x-werkszeit-rate-limit: standard x-werkszeit-compliance: [gobd, dsgvo-art9, sgb-vii-193] requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/UnfallCreateInput' } responses: '201': { content: { application/json: { schema: { $ref: '#/components/schemas/Unfall' } } } } '409': { description: 'Idempotency conflict' }components: schemas: UnfallCreateInput: type: object required: [idempotencyKey, unfallAt, verletzungsArten, koerperteil, hergang, erwarteteAuKategorie] properties: idempotencyKey: { type: string, format: uuid } verletztUserId: { type: string, format: uuid, nullable: true } baustelleId: { type: string, format: uuid, nullable: true } unfallAt: { type: string, format: date-time } verletzungsArten: { type: array, items: { type: string, enum: [sturz,schnitt,quetschung,fraktur,veraetzung,verbrennung,elektro,sonstiges] } } koerperteil: { type: string } hergang: { type: string, minLength: 200, maxLength: 2000 } erwarteteAuKategorie: { type: string, enum: [keine, 1_bis_3, ueber_3, toedlich] }Webhook-Events (AsyncAPI 3.0):
safety.unterweisung.signedsafety.unterweisung.abgelaufen(Scheduler)safety.psa.deniedsafety.psa.override_grantedsafety.unfall.erfasstsafety.unfall.meldefrist_droht(T-48h vor Frist, wennbg_status != 'serviceportal_uebermittelt')safety.unfall.bg_meldung_uebermitteltsafety.ersthelfer.quote_unterdeckungsafety.gefaehrdungsbeurteilung.signed
9. Offline-Profil
Abschnitt betitelt „9. Offline-Profil“| Profil | Begründung | Mechanik |
|---|---|---|
| Voll-offline (alle Flows außer F1000-Submit) | Unterweisungen müssen auf Baustellen ohne LTE abschließbar sein. Ein Unfall passiert dort, wo gerade kein Empfang ist. PSA-Check muss morgens in der Tiefgarage funktionieren. | Outbox-Pattern mit UUID-v7-Idempotency-Key. Videos werden bei WLAN (z. B. abends im Betriebsparkplatz) in App-Sandbox vorgeladen (downloaded_for_offline, 7-Tage-Frische). Fotos aus Unfall gehen über S3-Multipart nach presigned URL. |
| Online-only für F1000-Direkt-Submit an BG | BG-Serviceportal ist Online-Service, keine Queue möglich (Bestätigung zurück an Tenant). | UI blockiert submit-Button bei connectivity == none mit Banner „PDF-Export möglich, Direkt-Submit braucht Netz“. |
Konflikt-Strategie. Append-only — Korrektur = neuer Eintrag mit corrects_id. Einzige Ausnahme: PSA-Check-Override durch Polier („Abweichung freigegeben“) wird als separater Status-Eintrag gespeichert, der auf den ursprünglichen Check verweist, nicht diesen überschreibt.
Foto-Sync. S3-Multipart, identisch zu handwerk/01-bautagebuch §9. Unfall-Fotos haben zusätzlich KMS-Envelope-Encryption auf S3-Objekt-Ebene (Gesundheitsdaten-Kontext), separater KMS-Key pro Tenant (gesundheitsdatenKmsKeyId).
Unterweisungs-Videos offline. Flutter lädt bei WLAN-Detektion und explizitem User-Opt-in („Videos für Offline laden?“) alle fälligen Themen herunter. Cache wird nach 7 Tagen als „möglicherweise veraltet” markiert, nach 30 Tagen gelöscht — neue Version muss über Netz geholt werden, weil SiFa sonst nicht sicher sein kann, dass der Mitarbeiter die aktuelle Version gesehen hat (Audit-Anforderung DGUV V1 §4).
10. Compliance-Mapping
Abschnitt betitelt „10. Compliance-Mapping“10.1 GoBD
Abschnitt betitelt „10.1 GoBD“- Append-only-Tabelle. Alle Kern-Tabellen (
unterweisungs_nachweise,psa_checks,unfaelle,gefaehrdungsbeurteilungen,verbandbuch_eintraege) mithash_prev/hash_self. Hash ist SHA-256 über kanonisierte Feld-Reihenfolge einschließlich aller Foreign-Key-Hashes (Signatur-Blob, Foto-Hashes). - Aufbewahrung. 10 Jahre gem. §147 AO, Fotos in S3 Object Lock Compliance Mode. Unterweisungsnachweise als Teil der Personalakte — aufbewahrungsrechtlich ebenfalls 10 Jahre (LAG-Rechtsprechung). Gefährdungsbeurteilungen: DGUV empfiehlt „solange Arbeitsbedingungen bestehen + Verjährung (30 Jahre bei Berufskrankheit)“ — Werkszeit hält daher 30 Jahre ab Inaktiv-Setzung der Baustelle.
- Nachvollziehbarkeit. Jede Mutation → Audit-Log-Eintrag (
safety.unterweisung.*,safety.unfall.*,safety.psa.*,safety.gb.*) mit Hash-Chain auskern/08-audit-log. - Verfahrensdokumentation. Textbaustein in
gobd-verfahrensdoku.mdmit Modul-Abschnitt „Arbeitssicherheit“.
10.2 ArbZG
Abschnitt betitelt „10.2 ArbZG“— nicht zutreffend, weil das Feature keine Arbeitszeit erfasst. Die „Dauer der Unterweisung“ zählt arbeitsrechtlich zwar als Arbeitszeit (BAG 6 AZR 519/98), wird aber über die normale Zeiterfassung (kern/01-zeiterfassung) mit der Zeitart „Schulung“ erfasst — nicht im Safety-Modul selbst.
10.3 VOB/B
Abschnitt betitelt „10.3 VOB/B“— nicht zutreffend, weil der Unterweisungsnachweis kein Bauvertragsartefakt ist. Lose Kopplung: In der VOB-Abrechnung (handwerk/04-rechnung-vob) kann ein SiFa-Stunden-Satz als Nebenleistung auftauchen, das bleibt aber außerhalb dieses Feinkonzepts.
10.4 DSGVO
Abschnitt betitelt „10.4 DSGVO“- Art. 5 Datenminimierung. Der Unfall-Datensatz enthält besondere Kategorien personenbezogener Daten nach Art. 9 Abs. 1 (Gesundheitsdaten). Werkszeit speichert ausschließlich die für §193 SGB VII und F1000 geforderten Felder. Kein Diagnose-Feld, keine Krankenkassen-Nummer, kein Arzt-Name im Hauptflow (kommt erst im BG-Prozess nach Kenntnisnahme).
- Art. 6 + Art. 9 Rechtsgrundlage. Art. 9 Abs. 2 lit. b DSGVO (Arbeitsrecht) i. V. m. § 26 BDSG — Erforderlich zur Erfüllung der arbeitsschutzrechtlichen Pflichten des Verantwortlichen. Für Ersthelfer-Dokumentation zusätzlich Art. 9 Abs. 2 lit. c DSGVO (lebenswichtige Interessen).
- Technisch-organisatorische Maßnahme. Unfall-Hergangs-Text und Fotos werden mit separatem KMS-Key je Tenant verschlüsselt (
gesundheitsdatenKmsKeyId), Zugriff nur für Rollesifa,hr,adminund den Verletzten selbst sowie benannte Zeugen (RLS-Policy). Für normalen Manager: kein Zugriff auf Hergangs-Text — er sieht nur den Status-Rumpf (Person, Datum, AU-Kategorie). - Art. 17 Löschung. DSGVO-Löschung wird nicht physisch ausgeführt vor GoBD-10-Jahres-Ende (Unterweisung) bzw. 30 Jahre (Gefährdungsbeurteilung). Stattdessen: Maskierung — personenbezogene Identifikatoren (Name, User-ID, Foto) werden durch Hash-Pseudonyme ersetzt, während Struktur (Datum, Themenbezug, Hash-Chain) erhalten bleibt. Begründung: Art. 17 Abs. 3 lit. b DSGVO (rechtliche Pflicht zur Aufbewahrung).
- Art. 20 Datenexport. Mitarbeiter kann eigene Unterweisungsnachweise und PSA-Checks als ZIP (JSON + Signatur-Bytes + Video-Verweis) herunterladen. Unfall-Akten nur soweit Person Betroffene/r ist.
- Art. 30 Verarbeitungsverzeichnis. Separater Eintrag „Unfall- und Gesundheitsdaten“, mit ausdrücklicher Kennzeichnung Art. 9 und TOM-Referenz (KMS-Separation, RLS, Audit).
- Art. 35 DSFA. Pflicht bei Unfall-Modul nach DSK-Positivliste (Gesundheitsdaten + Beschäftigten-Kontext). Werkszeit liefert DSFA-Template out-of-box, das der Kunde auf sein Verfahren anpasst.
10.5 BFSG / WCAG 2.2 AA
Abschnitt betitelt „10.5 BFSG / WCAG 2.2 AA“— teilweise zutreffend. Die Unterweisungsplayer-Komponente ist ESS-naher Pflichtflow (jeder Mitarbeiter muss sie bedienen). Entsprechend:
- Video mit Untertiteln als Pflicht (VTT-Spur hochladen), Tastatur-Steuerbarkeit, Fokus-Ring sichtbar.
- Quiz in Screenreader-tauglicher Radio-Group-Semantik, Fehler-Meldungen
aria-live="assertive". - Signatur-Pad hat alternative Text-Eingabe-Fallback („Wenn Touch-Signatur nicht möglich: Namen eingeben + PIN aus E-Mail“) für Assistive-Tech-Benutzer.
- Kontrast: primäre CTA Orange
#FF6B1Aauf Anthrazit#1A1F2B= 5.2:1, Pass AA.
10.6 BetrVG §87(1)6
Abschnitt betitelt „10.6 BetrVG §87(1)6“Das Modul berührt mittelbare Leistungskontrolle in zwei Punkten:
- Video-Seek-Heatmap + Quiz-Antwort-Detail. Daraus ließen sich individuelle Leistungs-Profile ableiten. Default: deaktiviert. Aktivierung nur über Admin-UI mit BR-Beschluss-Upload. Ohne BR-Beschluss wird nur das aggregierte
quiz_score_pctgespeichert,quiz_antworten_jsonbleibtnull. - PSA-Verweigerungs-Log. Ist zwar arbeitsschutzrechtlich zwingend (Arbeitgeber muss reagieren), aber Häufung von Verweigerungen einer Person → Persönlichkeits-Profil. Konsequenz: Sichtbarkeit im Manager-Dashboard nur aggregiert; individuelle Auswertung nur über SiFa-Rolle + begründeten Zugriff (Zugriff wird audit-geloggt als
safety.psa.details_viewed).
Audit-Eintrag bei Aktivierung der erweiterten Auswertung: safety.feature.br_freigabe_detail_auswertung.activated mit BR-Beschluss-ID, Datum, Uploader-User.
10.7 Weitere Spezial-Compliance
Abschnitt betitelt „10.7 Weitere Spezial-Compliance“- DGUV Vorschrift 1 §4 (Grundsätze der Prävention). Jährliche Unterweisung + arbeitsplatzspezifisch → erfüllt durch Kombination
unterweisungs_themen.zielProfileCodesundintervallMonate. Fristüberwachung überunterweisungs_fristen_viewund Push-Scheduler. - DGUV Vorschrift 1 §26 (Ersthelfer). Quote 10 % berechnet im Live-KPI, Unterdeckung triggert Webhook + SiFa-Push.
- DGUV Information 211-005. Mitgelieferter Themen-Katalog folgt der Themen-Matrix (Absturz, Elektro, Gefahrstoff, Leitern/Tritte, Gerüst, Lärm, Hautschutz, Brandschutz, Erste Hilfe, Lagerung, Hebezeuge, Handwerkzeuge, Maschinen, Verkehrssicherheit, Witterung, Hygiene, Hautschutz, Lärm, Staub, Schweißen, PSA, Hebezeug, Gabelstapler, Abbruch).
- DGUV Vorschrift 2. SiFa-Bestellung (F-W-06) erzeugt das Bestellungsformular im DGUV-Standard-Layout.
- §193 SGB VII + §8 Abs. 1 SGB VII. Unfall-Meldefrist: 3 Werktage ab Kenntnisnahme, bei Tod: sofort. Berechnung erfolgt über
meldefrist-Feld mit Feiertags-Library (de-NW,de-BY, …). - PSA-BV. PSA-Bereitstellungs-Pflicht des Arbeitgebers wird nicht direkt im Modul abgebildet (Inventar-Thematik in V2 Autolager), der PSA-Benutzungs-Nachweis dagegen schon.
- BG BAU F1000. PDF-Layout wird jährlich aktualisiert (Wartungs-ADR für jährlichen Schema-Check). Direkt-Submit über BG-BAU-API wird geprüft (Schnittstelle steht 2026 offiziell bereit, aber erfordert Vereinbarung) — solange das nicht vorhanden ist, PDF-Upload durch den Nutzer ins BG-Serviceportal.
11. Edge-Cases
Abschnitt betitelt „11. Edge-Cases“| # | Szenario | Erwartetes Verhalten |
|---|---|---|
| EC-01 | Mitarbeiter überspringt Video-Teile, versucht direkt Quiz aufzurufen. | Quiz-Endpoint prüft serverseitig video_watched_pct ≥ 80. Wenn nicht: 409 Conflict mit code: video_incomplete, Client zeigt Hinweis „Bitte Video weiter ansehen (noch 12 % fehlen)“. |
| EC-02 | Unterweisung mit abgelaufener Frist wird angefangen. | Erlaubt — das System zählt rückwirkend als überfällig bis Abschluss. Dienstplanung-Gate bleibt aktiv, bis gueltigBis in Zukunft liegt. Push-Eskalation an Manager stoppt bei Status gestartet. |
| EC-03 | Unfall-Erfassung offline, Wiederverbindung erst nach 3 Werktagen. | Outbox-Eintrag wird mit unfallAt-Zeitstempel eingereicht (nicht now()). Server berechnet meldefrist aus unfallAt. Wenn Frist beim Sync bereits verletzt: Banner „Meldefrist überschritten — bitte mit BG telefonisch abklären“ + Audit-Flag frist_ueberschritten. Das schützt den Mitarbeiter vor Falschdatierung; die juristische Verantwortung bleibt beim Arbeitgeber. |
| EC-04 | PSA-Check verweigert, Polier übersteuert per Override. | Override wird eingetragen als separater psa_checks-Datensatz mit Status bedingt_mit_freigabe + freigabe_durch_user_id. Audit-Eintrag. Stempelung wird freigegeben. Manager- und SiFa-Dashboard zeigen Override gelb markiert. |
| EC-05 | Mitarbeiter in Unterweisung, ArbZG 10h-Grenze erreicht. | Unterweisung ist Arbeitszeit → kern/01-zeiterfassung warnt gemäß §3 ArbZG. Unterweisung kann trotzdem abgeschlossen werden (Gesundheitsrisiko-gering), aber Zeit-Eintrag „Unterweisung“ wird mit ArbZG-Marker in den Manager-Review gelegt. |
| EC-06 | Multi-Tenant-Bleed-Versuch (SiFa aus Tenant A ruft Unfall aus Tenant B per ID.) | API antwortet 404 Not Found (nicht 403, damit Existenz nicht offenbart wird). Audit-Log in Tenant A mit safety.access_denied, keine Spur in Tenant B. RLS-Test ist Pflicht in CI. |
| EC-07 | Unterweisung wird doppelt signiert (Netz-Retry.) | Idempotency-Key fängt ab, Server antwortet 200 OK + bestehender Nachweis. Keine Doppel-Zeile. |
| EC-08 | Ersthelferin Frau Brehm hat eigenen Unfall. | Zirkel-Fall: Sie kann sich nicht selbst als Ersthelfer eintragen. Mobile-Flow zeigt im Dropdown „Ersthelfer“ alle anderen bestellten Ersthelfer des Tenants. Fallback: Externer Rettungsdienst als Freitext. |
| EC-09 | Mitarbeiter wird während laufender Unterweisung demotet / entlassen. | Status wird bei nächstem Login-Check auf abgebrochen gesetzt, laufender Nachweis bleibt im Archiv unvollständig. Kein Block für andere User. |
| EC-10 | BG-BAU-Serviceportal down beim Submit. | Submit-Endpoint antwortet 503 Upstream Unavailable. Status bleibt pdf_generiert. PDF-Download bleibt verfügbar. Retry-Scheduler versucht alle 30 min für 24 h, danach Push an SiFa „Manueller Upload notwendig“. |
| EC-11 | Ehemaliger Mitarbeiter fordert DSGVO-Löschung seines Unfall-Datensatzes. | Maskierungs-Flow (siehe §10.4). Hergangs-Text bleibt (gerichtsrelevant), aber Personenbezug wird durch Pseudonym ersetzt. Antwort gem. Art. 17 Abs. 3 lit. b mit Verweis auf SGB VII / §147 AO. |
| EC-12 | Sprache nicht verfügbar (Rumäne bekommt deutsche Unterweisung.) | Banner „Keine Übersetzung verfügbar — SiFa kontaktieren“. Signatur wird mit Flag sprache_nicht_muttersprache markiert. SiFa-Dashboard zeigt Warnung, weil BAG-Rechtsprechung die Unterweisung ggf. als unwirksam einstuft. |
12. Akzeptanzkriterien (Gherkin)
Abschnitt betitelt „12. Akzeptanzkriterien (Gherkin)“Funktionalität: Arbeitssicherheit — Unterweisung, PSA-Check, Unfallmeldung
Hintergrund: Angenommen ein Tenant "musterbetrieb-maler" mit aktivem Modul-Gate "module.handwerk.arbeitssicherheit" Und ein Mitarbeiter "Mehmet Yılmaz" mit Rolle "Mitarbeiter" und Tätigkeits-Profil "maler_helfer_leiter" Und ein SiFa "Thomas Schmidt" mit Rolle "SiFa" und Scope "all" Und das Datum ist 2026-04-18
Szenario: Happy Path — Jahresunterweisung Absturzsicherung Leitern Angenommen für "Mehmet Yılmaz" ist die Unterweisung "DGUV-211-005.ABSTURZ" fällig am 18.04.2026 Wenn Mehmet die Mobile-App öffnet und auf "Unterweisung starten" tippt Und das 6:42 min Video zu mindestens 80 % anschaut Und die 4 Quiz-Fragen mit ≥ 75 % richtig beantwortet Und auf dem Touch-Signatur-Pad unterschreibt Dann wird ein Eintrag in "unterweisungs_nachweise" erzeugt mit Status "signiert" Und "gueltig_bis" = 2027-04-18 Und "hash_self" ist SHA-256 der kanonisierten Zeile mit Vorgänger "hash_prev" Und ein Audit-Log-Eintrag der Art "safety.unterweisung.signed" wird erzeugt Und die Fälligkeits-Ampel im SiFa-Dashboard wechselt von 🔴 auf 🟢
Szenario: Grenzfall 1 — Frist überschritten und Mitarbeiter eingeplant → Block Angenommen "Mehmet Yılmaz" hat keine gültige Unterweisung "DGUV-211-005.ABSTURZ" Und Manager "Sabine Maier" versucht, Mehmet in eine Dachdecker-Schicht am 20.04.2026 einzuplanen Wenn Sabine im Dienstplan-Editor den Slot zuweist Dann antwortet die API `/v1/kern/dienstplanung/shifts` mit 422 Und die Fehlermeldung enthält "unterweisung_abgelaufen: DGUV-211-005.ABSTURZ seit 18.04.2026" Und der Slot wird nicht gespeichert Und es gibt einen Audit-Eintrag "planung.block.unterweisungsfrist" Und Sabine kann mit Override und Pflicht-Begründung trotzdem planen Und der Override wird als "planung.override.unterweisungsfrist" auditiert
Szenario: Grenzfall 2 — Arbeitsunfall mit >3 Tagen AU → BG-Meldung auto-triggered Angenommen Polier "Frank Demir" erfasst um 20.04.2026 11:50 Uhr einen Unfall für "Hannes Krüger" Und er wählt Verletzung "Sturz, Fraktur Knöchel rechts" Und die erwartete AU-Kategorie "> 3 Tage — meldepflichtig" Wenn der Unfall im Backend ankommt Dann wird das Feld "meldepflichtig" auf true gesetzt Und "meldefrist" wird auf den 3. Werktag nach 20.04. gesetzt (23.04.2026 23:59 unter Berücksichtigung der BY-Feiertage) Und ein Webhook "safety.unfall.erfasst" wird gefeuert Und ein Countdown-Banner erscheint auf dem SiFa-Dashboard Und 48 h vor Fristablauf wird `safety.unfall.meldefrist_droht` gefeuert Und ein Audit-Log-Eintrag der Art "safety.unfall.erfasst" mit Hash-Chain-Verknüpfung wird erzeugt
Szenario: Grenzfall 3 — PSA-Check verweigert → Stempel blockiert Angenommen "Mehmet Yılmaz" steht am 20.04.2026 um 06:58 Uhr auf der Baustelle "Lehrer Allee 7" Und er öffnet den PSA-Check für Profil "maler_helfer_leiter" Und er wählt "Warnweste — fehlt, im Bus vergessen" Wenn er auf den Start-Stempel-Button tippt Dann wird der Stempel-Button mit roter Border und Sperr-Icon angezeigt Und die API `/v1/kern/zeiterfassung/stempel` antwortet 412 "psa_incomplete" Und ein Audit-Eintrag "safety.psa.denied" wird erzeugt Und der Polier erhält einen Push mit "Mehmet Y.: Warnweste fehlt" Und erst nach Override des Poliers oder Behebung wird die Stempelung freigegeben
Szenario: Grenzfall 4 — Multi-Tenant-Isolation Unfall-Akte Angenommen ein zweiter Tenant "shk-gebruder-schmidt" mit eigenem Unfall #2026-0017 Wenn SiFa Thomas aus Tenant A per ID "unfall_id_aus_b" die Unfall-Detail-API aufruft Dann antwortet die API mit 404 (nicht 403, um Existenz nicht zu offenbaren) Und es entsteht ein Audit-Eintrag "safety.access_denied" in Tenant A Und KEIN Audit-Eintrag in Tenant B Und der Hergangs-Text aus Tenant B taucht in keinem Log/Trace/Response-Body auf13. Test-Cases
Abschnitt betitelt „13. Test-Cases“13.1 Unit-Tests (Dart + TypeScript)
Abschnitt betitelt „13.1 Unit-Tests (Dart + TypeScript)“- U-01
calculateMeldefrist(unfallAt, bundesland) → timestamp— Property-based gegen 3-Werktage-Regel inkl. Feiertage BY/NW/BW/HE (Schnittstelle:date-holidays). - U-02
computeUnterweisungsFaelligkeit(user, thema) → {status, gueltig_bis}— deckt alle Zustandsübergänge ab inkl. „nie absolviert“ vs. „abgelaufen“. - U-03
validateVideoCompletion(segments_watched) → pct— Property-based: Ergebnis zwischen 0 und 100, monoton steigend. - U-04
isMeldepflichtig(erwartete_au, letal) → bool— Wahrheitstabelle über alle 8 Kombinationen. - U-05
canonicalizeRowForHash(row) → bytes— Hash-Stabilität gegen Feld-Reihenfolgen-Permutation.
13.2 Widget-/Component-Tests (Flutter)
Abschnitt betitelt „13.2 Widget-/Component-Tests (Flutter)“- W-01 Quiz-Komponente disabled state, wenn
videoWatchedPct < 80. Golden-Test inde-DE+ Dark. - W-02 Signatur-Pad blockiert Submit bei leerer Canvas. Alternative „PIN-Pad öffnen“ reagiert auf Tap.
- W-03 Körperteil-Diagramm setzt tap-Punkt in 1 px Genauigkeit; Screenreader liest „Knöchel rechts ausgewählt“.
- W-04 PSA-Check-Liste — jedes Item hat 3-State-RadioGroup mit
aria-required. - W-05 Unfall-Meldefrist-Banner ändert Farbe bei
<48h,<24h,<6hvor Frist; Golden-Tests je State.
13.3 Integrations-Tests (Backend, Drizzle In-Memory)
Abschnitt betitelt „13.3 Integrations-Tests (Backend, Drizzle In-Memory)“- I-01 Multi-Tenant-Isolation. Zwei Tenants mit jeweils Unterweisungen + Unfällen. Cross-Read-Versuch → 404, Audit in eigenem Tenant.
- I-02 RLS-Scope
own. MA sieht eigene Nachweise, nicht die des Kollegen. - I-03 Outbox-Idempotenz. Doppelter POST
/unfaellemit gleichem Idempotency-Key →200+ existierender Datensatz, keine neue Row. - I-04 Hash-Chain-Konsistenz. Einfügen von 100 Unterweisungsnachweisen in gemischter Reihenfolge;
verify_chain(tenant_id, thema_id)musstrueliefern. - I-05 Gesundheitsdaten-RLS. Normaler Manager ohne
sifa-Rolle bekommt beim Unfall-Read nur Stub-Felder;hergangist im Response-Body maskiert.
13.4 E2E-Tests (Patrol iOS/Android, Playwright Web)
Abschnitt betitelt „13.4 E2E-Tests (Patrol iOS/Android, Playwright Web)“- E-01 Happy Path Unterweisung Mehmet Yılmaz auf iOS + Android + Chromium + Firefox + WebKit, inkl. Video-Heartbeat-Timing.
- E-02 Offline-Erfassung eines Unfalls: Simulation
network off → onnach 6 h; Meldefrist bleibt korrekt berechnet. - E-03 PSA-Gate blockiert Stempelung; Override durch Polier gibt frei; beide Events im Audit-Log.
- E-04 Visuelle Regression: SiFa-Dashboard mit 🟢🟡🔴-Ampel auf de-DE Light+Dark.
- E-05 Accessibility: axe-core auf
/safety/unterweisung/:idohne Critical; VoiceOver iOS liest Quiz-Fragen inkl. richtiger Antwort-Feedback.
13.5 Compliance-Tests (apps/api/test/compliance/)
Abschnitt betitelt „13.5 Compliance-Tests (apps/api/test/compliance/)“- C-01 Hash-Chain-Integrität: Mutation einer
hergang-Zeile via SQL-Injection-Simulation lässt Chain-Verify fehlschlagen → Detection. - C-02 F1000-PDF-Validator: erzeugtes PDF wird gegen BG-BAU-Schema (XFA-Struktur) validiert, alle Pflichtfelder gesetzt.
- C-03 DSFA-Template-Generator:
safety-dsfa.pdfenthält die 9 Kriterien der DSK-Positivliste. - C-04 §193-SGB-VII-Fristberechnung: Property-based Test mit Feiertags-Matrix (BY, NW, HE, SN) gegen 200 Stichproben-Daten.
- C-05 DGUV V1 §26 Quoten-Check: Synthetischer Tenant mit 80 MA und 7 Ersthelfern → 8,75 % → Webhook wird gefeuert.
13.6 Flakiness-Schutz
Abschnitt betitelt „13.6 Flakiness-Schutz“20× lokaler Re-Run der neuen E2E-Tests grün. Particular Aufmerksamkeit: Video-Heartbeat-Timing (reale Zeitstempel-Drift wird in CI durch Fake-Clock ersetzt).
14. Nicht-Ziele
Abschnitt betitelt „14. Nicht-Ziele“| Nicht-Ziel | Begründung |
|---|---|
| eigenes Learning-Management-System (LMS) mit SCORM-Authoring | Werkszeit ist kein Trainings-Produkt. Wer SCORM-Pakete selbst bauen will, nutzt bestehende LMS-Tools (Moodle, rexx, Tutory) und lädt hier nur MP4 + Quiz-JSON hoch. Steht bereits als Nicht-Ziel in FUNKTIONSUMFANG.md §10. |
| automatische Verblurring von Gesichtern auf Unfall-Fotos | Das ist ein KI-Feature mit nicht-trivialer False-Positive-Quote (übersehene Gesichter oder zu aggressiv verpixelte Verletzungsstellen können BG-Beweiswert mindern). Überlassen wir dem Kunden via externer KI-Workflow, bis ein Referenzkunde das konkret fordert. |
| medizinische Diagnose-Unterstützung / Triage-Vorschläge | Kein Medizin-Produkt, kein MDR-konformes Risiko-Management vorgesehen. Ersthelfer macht, was er im DGUV-Kurs gelernt hat; die App dokumentiert nur. |
| Vollständige Integration Unfall → D-Arzt-Bericht | D-Arzt-Prozess läuft zwischen Arzt und BG, nicht über den Arbeitgeber-Kanal. Werkszeit liefert der BG, was dem Arbeitgeber obliegt (F1000). |
| Automatische Feiertags-Regelungen für Schweiz/Österreich | Phase 1 DE-only (FU §10). Bei DE-Tenant mit Schweizer Baustelle gilt Arbeitsort-Recht; aktuell manueller Override. |
| SiFa-Bestellung an externen Dienstleister mit eSignatur (QES) | EES-Signatur reicht für die Bestellung nach ASiG §5 in der Praxis (Einvernehmen + Bestätigung). QES wäre Overkill, wie in FU §10 allgemein begründet. |
| Automatische Erzeugung einer Unterweisung aus LLM-Kontext | Juristisch heikel — eine nicht-validierte Maschinen-Unterweisung erfüllt DGUV V1 §4 nicht zwingend. Kein Referenzkunde fordert das. |
| Integration in BG-BAU ASi-Portal (Meldung ohne F1000-PDF-Export) | Nicht-öffentliche API, Vertrag mit BG BAU nötig. Bei Nachfrage: V2-Roadmap. Bis dahin: PDF + Upload-Link. |
15. Risiken & offene Annahmen
Abschnitt betitelt „15. Risiken & offene Annahmen“| Risiko / Annahme | Impact | Wahrscheinlichkeit | Gegenmaßnahme |
|---|---|---|---|
| BG-BAU F1000-Schema ändert sich (BG aktualisiert das Formular 2026 oder 2027) | hoch (Tenant kann nicht mehr melden) | mittel | Jährlicher Schema-Check-ADR, Form als strukturiertes JSON → PDF-Layer, damit nur Template-Datei tauscht. Contract-Test gegen aktuelle BG-BAU-PDF im CI. |
| Video-Fortschritts-Heartbeat lässt sich clientseitig fälschen (MA-Skript feuert Fake-Progress-Calls) | mittel | niedrig (wenig Anreiz, hoher Aufwand für MA) | Server-seitige Plausibilitätsprüfung: Heartbeats müssen monoton steigen, Delta pro Sekunde ≤1.2× Echtzeit, Gesamtzeit ≥ Video-Länge × 0.8. Anomalie → Audit-Flag unterweisung.heartbeat_anomalie. |
| DSFA wird bei Roll-out nicht durchgeführt | hoch (Aufsichtsbehörde-Risiko) | mittel | DSFA-Template als Bestandteil des Onboardings, Status „DSFA durchgeführt ja/nein“ ist Pflichtfeld zum Aktivieren des Unfall-Moduls (Soft-Gate, dokumentiert). |
| Annahme: 80 % Video-Mindest-Watch-Quote ist DGUV-konform | hoch | mittel | Nicht explizit vorgeschrieben; DGUV V1 §4 ist inhaltlich („angemessen, verständlich“). 80 % ist Branchenstandard (vergleichbar mit SCORM „completion“). Dokumentieren in Verfahrensdoku. Alternative: Arbeitgeber kann den Schwellwert konfigurieren (Default 80 %). |
| Mehrsprachige Unterweisung — Übersetzungs-Qualität liegt beim Kunden | mittel | hoch | Kein Auto-Übersetzen. SiFa lädt geprüfte Version pro Sprache hoch. Warn-Banner „keine Übersetzung verfügbar“ ist Pflicht. |
| Performance der Foto-Unfall-Pipeline (12 Fotos × 4 MB = 48 MB Upload aus LTE-Loch) | mittel | mittel | Resumable S3-Multipart + Background-Upload mit Foreground-Service auf Android; iOS BGTaskScheduler. 6 Stunden Retry-Fenster. |
| Manager sieht Gesundheitsdaten — Rollen-Fehler in RLS | hoch (DSGVO Art. 9 Verletzung) | niedrig | Pflicht-CI-Test mit 12 Rollen-Kombinationen gegen gleichen Unfall-Datensatz; Regression bricht Deploy. |
16. Abhängigkeiten
Abschnitt betitelt „16. Abhängigkeiten“- Vorbedingung:
kern/03-projekte-baustellen(für Baustellen-Auswahl),kern/08-audit-log(für Hash-Chain-Audit),kern/09-foto-upload-pipeline,kern/11-dsgvo-toolkit(KMS-Separation Gesundheitsdaten). - Schnittstelle zu:
kern/01-zeiterfassung— PSA-Check-Gate beim Stempel (check_psa_before_stempel: truein Tenant-Config).kern/03-dienstplanung— Unterweisungs-Fälligkeit blockiert Zuweisung (Cross-Link zu §4.11 Qualifikations-Gate).handwerk/01-bautagebuch— PSA-Check ist eigener Eintragstyp dort.handwerk/11-fuehrerschein-zertifikate— gemeinsame Ampel- und Push-Erinnerungs-Infrastruktur.
- Wird konsumiert von:
kern/07-reporting— Monatsabschluss Arbeitsschutz (Quote, Unfälle, AU-Tage).kern/05-rechnung— SiFa-Stunden als Nebenleistung in VOB-Abrechnung (bei externem SiFa-Vertrag).
17. Referenzkunde-Slot
Abschnitt betitelt „17. Referenzkunde-Slot“Status: TBD — zu klären mit Sales + Produkt-Owner vor Sprint-Einstieg.
DOR §1.1.1 verlangt namentliche Dokumentation eines zahlenden Design-Partners.
Kandidaten-Profile:
- SHK-Gebrüder-Schmidt (NRW, 80 MA) — Sales-Call 2026-02: „BG-Meldung ist unser Horror, wir verpassen die 3-Tage-Frist regelmäßig, der SiFa will aus der Excel-Hölle raus.“
- Musterbetrieb Maler (Bayern, 25 MA) — Interview 2026-03: „Ich hätte gern die Jahresunterweisung auf dem Handy, sonst kommen die Leute nicht zum Termin.“
- Dachdecker Siedlung e. G. (Hessen, 45 MA, erhöhter Absturzrisiko-Kontext) — mögliche Eignung für Dachdecker-spezifische PSA-Profile und Gefährdungsbeurteilung.
Validierungs-Fragen für das Erst-Gespräch:
- Wie oft haben Sie in den letzten 24 Monaten einen Unfall an die BG gemeldet? Innerhalb der 3-Werktage-Frist?
- Wie pflegen Sie heute den Unterweisungs-Nachweis? (Excel, Ordner, nichts?)
- Haben Sie einen bestellten SiFa (intern/extern)? Wer pflegt die Gefährdungsbeurteilungen?
- Welche PSA-Profile unterscheiden Sie heute?
- Würden Sie 30 Tage gegen Preis-Lock-In im Beta-Modus testen? Wir bauen Ihren
BG BAU-F1000-Flow prioritär.
18. Senior-Berater-Empfehlung
Abschnitt betitelt „18. Senior-Berater-Empfehlung“Build-Sequenz (innerhalb des Features):
- Datenmodell + RLS + Multi-Tenant-Test zuerst. Besonders Gesundheitsdaten-KMS-Separation muss stehen, bevor eine einzige Zeile Unfall-Code geschrieben wird.
- Unterweisungs-Player MVP (Video-Stream + Quiz + Signatur) — das ist der Kern-Nutzen und liefert sofort Wert für den Design-Partner.
- PSA-Check + Gate in Zeiterfassung — konkreter operativer Win, „Der Monteur ohne Warnweste wird heute gesperrt“.
- SiFa-Dashboard Web + Push-Scheduler — damit der SiFa den Abschluss-Blick hat.
- Unfall-Erfassung + F1000-PDF-Generator — schwerster Teil, nicht am Anfang.
- F1000-Direkt-Submit an BG BAU — erst wenn API-Vertrag steht.
- Mehrsprachige Unterweisung — auf Referenzkunde warten.
Risiko-Reihenfolge (was zuerst absichern, wenn Zeitnot):
- Multi-Tenant-Isolation + Gesundheitsdaten-RLS sind nicht verhandelbar.
- Hash-Chain + Append-only müssen von Tag 1 stehen — Nachrüsten ist nahezu unmöglich.
- Video-Heartbeat-Anti-Skip kann V1.5b sein (als Verfahrensdoku-Maßnahme anfangs akzeptabel).
- Mehrsprachigkeit, KI-Gefährdungsvorschlag: klar V2.
Stop-the-Bus-Triggers:
- Gesundheitsdaten im Response-Body eines Non-SiFa-Users — sofort Incident, Pen-Test und Rotation KMS-Key.
- F1000-PDF wird von BG-BAU-Portal abgelehnt: Schema-Check, hotfix, ADR nachziehen.
- Hash-Chain-Bruch → Ermittlung ob Datenleck oder Schema-Migrations-Bug; kein Deploy bis geklärt.
- DSFA ist nicht durchgeführt im Tenant, aber Unfall-Modul wird aktiviert → Soft-Block, Schreiben an Tenant-Admin.
Was uns 2027 dankbar macht:
- Eine Audit-Hash-Chain auf allen Safety-Tabellen ab Tag 1 — bei der ersten BG-Prüfung oder Aufsichtsbehörde-Anfrage liefern wir in Sekunden nachprüfbare Unveränderlichkeits-Belege statt „Bitte warten Sie, wir exportieren erst unsere Excel-Listen“.
- Ein klar separierter KMS-Key für Gesundheitsdaten — wenn eines Tages ein Tenant eine Datenlöschung fordert, löschen wir den Key und damit alle Gesundheitsdaten kryptografisch, ohne dass wir hoffnungsvoll in 14 Tabellen suchen müssen.
- Das PSA-Gate zwingt uns, von Anfang an zwischen „Info-Toast“ und „harter Block“ klar zu unterscheiden. Diese Disziplin zahlt sich in jedem späteren Compliance-Feature aus.
Letzte Aktualisierung: 2026-04-19. Nächster Review-Termin: nach Festlegung des Referenzkunden und DSFA-Freigabe.