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
150 lines
15 KiB
Markdown
150 lines
15 KiB
Markdown
# 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:** U1–U14 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.
|
||
|
||
- S1–S17 = exakt die Testfälle 1–17 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:** S1–S17 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 1–6) 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:** 2–3 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)
|
||
- 1–2 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 1–3 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]]
|