Files
MABEA/ergebnisse/testphasen.md
T
patrickandClaude Sonnet 5 f47cefcc28
CI / backend-tests (push) Successful in 53s
CI / frontend-build (push) Successful in 53s
fix(import): Spalte D ist Ablaufdatum-Hinweis, keine Artikelnummer
Nutzer-Fund: "Kompresse 10x10 / 5 / Apr 29" - Wert 47209 in Spalte D ist
Excel-Datum 2029-04-01, kein Artikelnummer. Vollständige Prüfung aller drei
Listen bestätigt: D ist überwiegend ein echtes Ablaufdatum, keine
Artikelnummer-Spalte existiert überhaupt. Material-Abgleich läuft jetzt über
den Namen; ein plausibles Datum in Spalte D klassifiziert das Material als
'ablauf_charge' statt 'standard' (Wert selbst wird nicht gespeichert - gehört
auf objektposition, nicht auf die Vorlage). Bekannte Ausreißer (Platzhalter-
wert 12754, Freitext "Jahr 2023"/"MTK 23") werden per Plausibilitätsfenster
ignoriert statt fehlzuklassifizieren.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:58:25 +02:00

15 KiB
Raw Blame History

Testphasen MABEA V1

Bezug: 22_testkonzept, 18_version_1, 02_prozess_kontrolle, 03_fehlbestandsmanagement, 04_mindermengen, 05_rollen_rechte, 17_mobile_offline, 21_api.

Grundprinzip: Tests werden phasenweise aufgebaut, parallel zur Implementierung nicht als Block am Ende. Jede Phase hat Einstiegs- und Abnahmekriterien. Der Satelliten-Betrieb (Karte 13) ist bewusst nicht Teil der V1-Testphasen, sondern eigene spätere Phase S (Roadmap).

Phase 0 Testinfrastruktur (vor erstem Feature-Code)

Ziel: Gerüst steht, bevor Logik entsteht verhindert „Tests schreiben wir später".

  • pytest + pytest-asyncio + httpx (AsyncClient für FastAPI) im Projekt
  • pytest-cov mit Regressions-Gate: --cov-fail-under=50 als Startwert in pytest.ini (Erfahrungswert: lieber niedrig starten und hochschrauben als gar kein Gate)
  • Separate Test-Datenbank (eigene PostgreSQL-Datenbank, Schema via Alembic-Migrationen aufgesetzt, nie gegen Dev-/Produktiv-DB)
  • Test-Fixtures: frische DB pro Testklasse (Transaction-Rollback oder Drop/Create), Standard-Stammdaten-Set (1 Bereich, 2 Standorte, 3 Objekttypen, ~10 Materialien aller 3 Typen, 1 Vorlage mit Positionen, 2 Objekte, 4 Benutzer = 1 je Rolle)
  • CI-Job (Gitea Actions): install → migrate → pytest → Coverage-Report; Blocker bei Rot
  • Seed-Datensatz systemknoten: objekt.zustaendiger_server_id, kontrolle.erzeugt_von_server_id, fehlbestand.erzeugt_von_server_id, historie.erzeugt_von_server_id sind NOT NULL (Prompt 20) V1 braucht daher zwingend einen Seed-Datensatz systemknoten (typ='haupt') VOR dem ersten Datensatz jeder Art, plus eine Konfigurations-Referenz im Backend (z. B. Umgebungsvariable/Settings-Wert SYSTEMKNOTEN_ID), die der Anwendungscode bei jedem Insert einsetzt. Ohne diesen Seed schlägt der allererste Insert fehl gehört in die Migrations-/Setup-Reihenfolge von Phase 0, nicht erst bei Satelliten-Umsetzung (Phase S) relevant.

Abnahmekriterium: pytest läuft grün (auch wenn erst 1 Smoke-Test existiert), CI schlägt bei Testfehler fehl.

Phase 1 Domänenlogik (Unit-Tests, keine API, keine UI)

Ziel: Die fachlichen Leitplanken sind bewiesen, bevor irgendein Endpoint existiert. Reine Python-Tests gegen den Service-Layer (Prompt 19 Punkt 2), DB über Fixtures.

Kritischste Regeln zuerst (aus reihenfolge.md und Prompt 03/04):

# Test Herkunft
U1 Fehlbestand entsteht automatisch bei Ist < Soll Prompt 02.3
U2 Mindermengen-Genehmigung ändert NIEMALS Ist-Menge und setzt Fehlbestand NIEMALS auf erledigt Leitplanke, Prompt 04.1
U3 Fehlbestand → erledigt AUSSCHLIESSLICH wenn Ist = Soll (nie manuell) Prompt 03.3
U4 Sofort-Nachfüllung in Kontrolle: Fehlbestand entsteht + wird erledigt, 2 Historieneinträge Karte 07
U5 Teilnachfüllung: Status nachgefuellt_teilweise, Fehlmenge reduziert, zählt weiter als offen Prompt 03/12
U6 Genehmigung läuft bei nächster Kontrolle des Objekts automatisch ab Karte 08, Prompt 04.4
U7 Genehmigung + Behebung vor nächster Kontrolle → beides gemeinsam beendet Prompt 04.4
U8 Soll-Auflösung: Override auf Objektposition schlägt Vorlagenwert; Vorlagenänderung wirkt nur auf Positionen ohne Override Prompt 10
U9 Duplizieren: Struktur/Soll ja, Ist/SN/Chargen/Fehlbestände/Historie nein, neuer Code Prompt 09
U10 Vorlagenänderung erzeugt neue Version, alte Version bleibt lesbar (Snapshot-Historie) Prompt 08
U11 Kontrolle abschließen mit unbestätigten Positionen → Fehler Prompt 16.1
U12 Abgebrochene Kontrolle: keine Ist-Übernahme, kein Fehlbestand, Objekt bleibt unkontrolliert Prompt 16.6
U13 Überbestand (Ist > Soll): protokolliert, aber KEIN Fehlbestand Prompt 02.4
U14 Historie ist append-only: jeder fachliche Schritt erzeugt Eintrag mit wer/wann/alt→neu Prompt 13

Einstiegskriterium: Phase 0 fertig. Abnahmekriterium: U1U14 grün, Coverage Service-Layer ≥ 80 % (Domänenlogik ist der sicherheitskritische Kern).

Phase 2 API-Integrationstests (HTTP gegen Test-DB)

Ziel: Jeder Endpoint aus Prompt 21 verhält sich spezifikationsgemäß, inkl. Rollenmatrix und Fehlerfälle.

  • Auth: Login ok/falsch (401), Token abgelaufen, auth/me liefert korrekte Rollen
  • Rollenmatrix (Prompt 05): parametrisierter Test jede Rolle × jede kritische Aktion → erwarteter Status (200er/403). Das ist EIN Test mit Tabelle, deckt Matrix vollständig ab
  • Fehlerfälle aus Prompt 21.9: Genehmigung ohne Begründung → 422; Genehmigung durch Mitarbeiter → 403; Abschluss mit offenen Positionen → 409 + Liste; Code-Duplikat beim Anlegen/Duplizieren → 409
  • Idempotenz PUT Kontrollposition: derselbe PUT zweimal gesendet → identischer Endzustand, kein doppelter Fehlbestand (Vorbereitung Prompt 17)
  • Zuständigkeitsfilter (Karte 04): Verantwortlicher sieht nur Fehlbestände seines Bereichs, Administration alles
  • Objekt-Sperre (Prompt 02.8): Kontrolle auf Objekt A aktiv → zweiter Benutzer bekommt „wird kontrolliert von …", Übernahme erzeugt Historieneintrag; parallele Kontrollen auf Objekt B bleiben möglich
  • Admin-API (7a): Benutzer/Zuständigkeiten/Kontrollverantwortung anlegen, ändern, löschen

Einstiegskriterium: Phase 1 grün. Abnahmekriterium: alle Endpunkte aus Prompt 21 durch Tests abgedeckt, Gesamt-Coverage ≥ 50 % (Gate greift).

Phase 3 Prozess-Szenarien (E2E über API, komplette fachliche Ketten)

Ziel: Die 17 Testfälle aus 22_testkonzept als durchspielbare Szenarien hier wird bewiesen, dass die Einzelteile zusammenwirken.

  • S1S17 = exakt die Testfälle 117 aus Prompt 22 (Normalfall, Fehlbestand, Sofort-Nachfüllung, Nachfüllung später, Teilnachfüllung, Dauer-offen, Genehmigung, Ablauf Genehmigung ×2, Ablaufdatum, Duplizieren, Override, Vorlagenänderung mit Override, Rollenmatrix, Historie-Kette, Kurzzeit-Netzausfall, Abbruch)
  • Besonderheit S15 (Historie-Kette): komplette Kette aus Prompt 13.3 durchlaufen und Reihenfolge + Referenzen aller Historieneinträge prüfen
  • Besonderheit S16 (Netzausfall): clientseitig simuliert PUT zweimal absetzen bzw. verzögert, Server-Verhalten muss identisch sein

Einstiegskriterium: Phase 2 grün. Abnahmekriterium: S1S17 grün, zweimal reproduzierbar (kein Flaky).

Phase 4 Frontend/PWA-Tests

Ziel: Die Einsatzumfeld-Anforderungen (Prompt 11, 17) sind bewiesen.

  • Kurzzeit-Netzausfall: Eingabe wird lokal gepuffert, nach Reconnect automatisch übertragen, Abschluss blockiert solange ungesendete Positionen existieren (Prompt 17.3) Browser-Test mit Netzwerk-Throttling/Offline-Toggle (Playwright)
  • Responsivität: Kernscreens (Screen 16) auf PC + Tablet + Smartphone-Viewport bedienbar, Touch-Ziele groß genug
  • Fortschrittsanzeige + Gerätewechsel: Kontrolle auf Gerät 1 begonnen, auf Gerät 2 fortgesetzt (login-/objektgebunden, Karte 06)
  • Statusfarben/Markierungen: genehmigte Mindermenge, individuelle Abweichung, Ablaufdatum-Warnung sichtbar unterscheidbar
  • Manuelle Explorations-Session: 23 Praktiker aus dem Rettungsdienst klicken ohne Anleitung durch eine Kontrolle Beobachtung dokumentieren (UX-Fallen)

Einstiegskriterium: Phase 3 grün, PWA bedienbar auf Test-Deployment. Abnahmekriterium: Netzausfall-Test grün, keine kritischen UX-Befunde offen.

Phase 5 Pilotphase mit Echtdaten (organisatorisch, kein Code-Test)

Ziel: Realitätsabgleich, bevor Papier abgeschaltet wird.

  • Testdaten aus den echten Excel-Listen (Handball Rucksack.xlsx, Rettungsrucksack.xlsx, Rucksack PAX SEG.xlsx im Repo) als initiale Vorlagen/Materialstamm importieren (Mapping siehe Abschnitt „Excel-Import-Mapping" unten)
  • 12 Wochen Parallelbetrieb: Kontrolle digital UND Papier wie bisher, danach Abgleich (findet das System alles, was Papier fand?)
  • Dedizierte Übungskontrollen mit vorher verabredeten Abweichungen („versteckte Fehlmenge") prüft, ob Mitarbeiter den digitalen Weg korrekt durchlaufen
  • E-Mail-Benachrichtigung (Karte 05) mit realem Mailserver verifizieren
  • Feedback-Runde → kleinteilige UI-Nachjustierung

Einstiegskriterium: Phase 4 grün, Echtdaten importiert, Test-Deployment erreichbar. Abnahmekriterium (Go/No-Go für V1): Parallelbetrieb ohne fachliche Diskrepanz, keine Datenverluste, Akzeptanz bei Pilotnutzern vorhanden.

Excel-Import-Mapping (Detail zu Phase 5)

Grundlage: die drei bestehenden Listen im Repo (Handball Rucksack.xlsx, Rettungsrucksack.xlsx, Rucksack PAX SEG.xlsx), Struktur laut Ausgangsanalyse (Prompt 01): Fach-Überschriftzeile, darunter Zeilen mit Artikel/Menge/Artikelnummer, teils Seriennummer-Spalte.

Mapping-Tabelle

Excel-Spalte/Struktur Ziel im Datenmodell (Prompt 06/20) Hinweis
Datei selbst (z. B. „Handball Rucksack") objekttyp.name + beladungsvorlage.name (z. B. „Rucksack Handball Standard") Ein Import-Lauf pro Datei erzeugt einen Objekttyp + eine Vorlage Version 1
Fach-Überschriftzeile (z. B. „Fach 1") vorlagenposition.fach Freitext übernehmen wie in Excel geschrieben, keine Normalisierung nötig
Artikel-Spalte material.name (neu anlegen, falls Name noch nicht im Materialstamm existiert) Abgleich über den Namen - die drei Listen haben keine echte Artikelnummer-Spalte (Korrektur, siehe unten), Tippfehler-Risiko bleibt manuelle Review-Pflicht
Menge-Spalte vorlagenposition.sollmenge Numerisch parsen, Fehleinträge (z. B. „ca. 5") vor Import manuell bereinigen
Spalte D (Excel-Zellformat: Datum) Materialtyp-Erkennung: plausibles Ablaufdatum (Jahr ~2015-2039) in dieser Zeile → material.materialtyp = 'ablauf_charge' Korrektur: ursprünglich fälschlich als Artikelnummer gemappt, siehe „Bekannte Lücken" unten. Datum selbst wird NICHT gespeichert (gehört auf objektposition, nicht auf die Vorlage - Ablaufdatum ist pro physischem Exemplar, nicht pro Soll-Position)
Seriennummer-Spalte (falls vorhanden) Materialtyp-Erkennung: Vorhandensein einer SN-Spalte bei dieser Zeile → material.materialtyp = 'geraet_sn' (hat Vorrang vor Ablaufdatum-Erkennung)
Einheit nicht in Excel vorhanden Beim Import Standardwert „Stück" setzen, danach manuell korrigieren wo nötig (z. B. „Paar", „Packung")
Kategorie/Bereich nicht in Excel vorhanden Einmalig vor Import anlegen: 1 Bereich „Rettungsdienst/KatS", grobe Kategorie „Rucksäcke" für alle drei Objekttypen

Ablauf des Imports (Vorschlag, Umsetzung Phase 5)

  1. Bereich + Kategorie einmalig anlegen (Administration, manuell oder Skript).
  2. Je Excel-Datei: Objekttyp + Beladungsvorlage Version 1 anlegen.
  3. Zeilen einlesen (stdlib zipfile/xml.etree.ElementTree wie bei der Erstanalyse, siehe Prompt 01 kein openpyxl nötig): Fach, Artikel, Menge, Ablaufdatum-Hinweis (Spalte D), optionale SN-Spalte.
  4. Je Zeile: Material anhand des Namens suchen oder neu anlegen, dann Vorlagenposition mit Sollmenge und Fach erzeugen.
  5. Konkrete Objekte (z. B. „Rucksack Handball 12", „Rucksack Handball 17") werden NICHT aus Excel importiert (Excel enthält nur die Soll-Struktur, keine konkreten Instanzen) Administration legt sie danach manuell an, je mit Code (Karte 10) und Vorlagen-Referenz.
  6. Erste Kontrolle je neu angelegtem Objekt erfasst den tatsächlichen Ist-Bestand (Objekte starten „nicht kontrolliert", analog Duplizieren-Regel Prompt 09) dies IST der Übergang vom Papier- zum Digitalbetrieb (Prompt 23).

Bekannte Lücken, vor Import zu klären

  • Einheiten pro Material sind in den Excel-Listen nicht erfasst vor Import Liste durchgehen und einmalig ergänzen (einmaliger manueller Aufwand, keine Systemfrage).
  • Import-Skript selbst ist Code (Prompt-19-Deployment-Regel gilt: bei Umsetzung nur Skript-Datei erzeugen, Ausführung gegen Test-DB erst auf Zielsystem/Test-Deployment, nicht lokal).
  • Korrektur (nach echtem Import-Lauf, vom Nutzer anhand "Kompresse 10x10 / 5 / Apr 29" bemerkt): Spalte D wurde ursprünglich fälschlich als Artikelnummer gemappt. Vollständige Prüfung aller drei Listen zeigt: D ist bei den meisten Zeilen ein echtes Excel-Datum (z. B. 47209 → 2029-04-01, angezeigt „Apr 29") - ein Ablaufdatum-Hinweis, keine Artikelnummer. Es gibt in den drei Listen keine Artikelnummer-Spalte; Material-Abgleich läuft daher über den Namen. Ausnahmen in den Rohdaten: der Wert 12754 (→ 1934-12-01) wiederholt sich identisch bei mehreren unterschiedlichen Artikeln und ist offensichtlich kein echtes Datum, sondern ein Platzhalter/Fehlwert; vereinzelt steht in Spalte D auch Freitext („Jahr 2023", „MTK 23"). Das Importskript (backend/scripts/import_excel.py) akzeptiert daher nur Werte in einem plausiblen Jahresfenster (~2015-2039) als Ablaufdatum-Hinweis und nutzt sie ausschließlich zur materialtyp-Klassifikation (ablauf_charge) - das konkrete Datum selbst wird nicht gespeichert (gehört auf objektposition, nicht auf die Vorlage).
  • Bereits mit der alten (falschen) Logik importierte Test-Daten auf dem Zielsystem enthalten fehlerhafte material.artikelnummer-Werte (die eigentlich Datums-Rohwerte waren) und teils falschen materialtyp (standard statt ablauf_charge) - Bereinigung/Neu-Import auf dem Testsystem nötig, siehe Projekt-Historie.
  • Gleiches Material kommt in einer Liste teils in mehreren Fächern vor (z. B. Verbandsmaterial in mehreren Taschen) - da vorlagenposition nur eine Zeile pro Material+Vorlage zulässt (Prompt 20-Schema), führt das Importskript solche Duplikate zusammen (Mengen addiert, Fächer als Liste), erste Erkenntnis erst beim echten Import-Lauf gegen den Zielserver, nicht vorher erkannt.

Regeln übergreifend

  • Kein Feature ohne Test: jeder Endpoint/jede Domänenregel wird erst mit Test gemerged (CI-Gate).
  • Leitplanke-Doppelschutz: U2/U3 (Mindermenge ≠ erledigt) laufen zusätzlich als Phase-3-Szenario (S7) bei Bruch dieser Regel sofortiger Release-Blocker.
  • Coverage-Hochschraubung: nach V1-Release Gate schrittweise 50 → 60 → 70 % erhöhen.
  • Testdaten niemals Produktivdaten: Pilotphase läuft auf Test-Deployment, echte Inbetriebnahme erst nach Go/No-Go.

Phase S Satelliten-Betrieb (spätere Erweiterung, NICHT V1)

Roadmap-Phase, erst nach stabiler V1. Eigener Testplan nötig, mindestens:

  • PoC mit zwei lokalen PostgreSQL-Instanzen (Docker oder zwei Datenbanken): Objekt auslagern → Kontrolle + Fehlbestand + Nachfüllung + Genehmigung am „Satelliten" → zurücksyncen → Hauptserver-Stand vollständig und ohne Duplikate
  • Sync-Fälle 13 aus Prompt 20.10 einzeln beweisen (Insert neue Zeilen, Upsert Objektpositionen, Upsert Fehlbestand/Genehmigung)
  • Bestückungsregel testen: Objekt mit offenem Fehlbestand auslagern → am Satelliten nachfüllen → zurücksyncen → genau EIN Fehlbestand, erledigt
  • Schreibzugriff am Hauptserver auf ausgelagertes Objekt → muss abgelehnt werden
  • Offene Punkte aus Karte 13 vorher entscheiden: Pre-Sync-Check laufender Kontrollen, DB-Trigger für zuletzt_geaendert_am, Bestückungs-Details

Referenzen

Bezug: 22_testkonzept, 18_version_1, 01_anforderungsanalyse, 09_duplizieren, 23_papieraloesung, 13_satelliten_server