objektposition.seriennummer war ein Einzelfeld, konnte nur EIN Gerät pro Materialtyp/Objekt abbilden (z.B. 2 Pulsoxymeter im selben Rucksack nicht darstellbar). Neue Tabelle geraet_instanz erlaubt beliebig viele Exemplare pro Position (Seriennummer, Prüfdatum, nächste Prüfung, Status). Zusätzlich objektposition.pruefintervall_monate (individuell überschreibbar). Bewusst additiv: seriennummer-Spalte bleibt vorerst stehen (Service/ Endpunkte/Frontend hängen noch daran), bestehende Werte werden per INSERT...SELECT nach geraet_instanz kopiert. Drop + Umbau der abhängigen Schichten folgt in Umsetzungsschritt 2 (siehe arbeitskarten/14_...). Migration von postgres-expert gegengeprüft (ON CONFLICT DO NOTHING als Sicherheitsnetz, DROP TYPE IF EXISTS ergänzt), Tests decken Mehrfach- Instanzen, UNIQUE-Constraint je Position, gleiche SN an verschiedenen Positionen und pruefintervall_monate ab. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
5.2 KiB
Karte 14 – Prüf- und wartungspflichtige Geräte
Status: Konzeptphase, Datenmodell entschieden (2026-09-04), Umsetzung offen
Entscheidung
Das Portal deckt nicht nur Bestandskontrolle (Soll/Ist-Mengen, Verbrauchsmaterial- Nachschub) ab, sondern auch gesetzlich/betrieblich prüf- und wartungspflichtige Geräte (z. B. Feuerlöscher, Defibrillatoren, Leitern, Atemschutzgeräte, Pulsoxymeter) mit wiederkehrenden Prüfintervallen und Fristen. Das ist fachlich etwas anderes als Ablaufdatum (einmaliges festes Datum) oder Charge (Identifikation) – hier geht es um einen wiederkehrenden Prüfzyklus mit Ergebnis pro Durchgang, UND um mehrere Geräte-Exemplare desselben Materials im selben Objekt.
Kernproblem im aktuellen Datenmodell
objektposition.seriennummer ist ein Einzelfeld – kann nur EIN Gerät pro
Materialtyp pro Objekt erfassen. Bei z. B. 2 Pulsoxymetern im selben Rucksack
gibt es keine Möglichkeit, beide Seriennummern zu speichern. Das ist ein echtes
Datenmodell-Defizit, kein UI-Problem – erfordert eine neue Entität.
Datenmodell (entschieden)
Neue Tabelle geraet_instanz ersetzt objektposition.seriennummer für
materialtyp='geraet_sn':
CREATE TABLE geraet_instanz (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
objektposition_id UUID NOT NULL REFERENCES objektposition(id),
seriennummer TEXT NOT NULL,
pruefdatum DATE, -- letzte Prüfung
naechste_pruefung DATE, -- fällige Prüfung
status TEXT NOT NULL DEFAULT 'einsatzbereit', -- einsatzbereit / defekt / in_reparatur
bemerkung TEXT,
UNIQUE (objektposition_id, seriennummer)
);
objektposition.seriennummerentfällt (Migration: bestehende Werte nachgeraet_instanzüberführen, dann Spalte droppen).- Ist-Menge bei
geraet_snwird nicht mehr als Zahl geführt/eingegeben, sondern als Anzahl dergeraet_instanz-Zeilen mitstatus='einsatzbereit'berechnet. objektposition: neues Feldpruefintervall_monate(int, nullable) – individuell überschreibbar je Objektposition (wiesollmenge_override), Vorlage/Material kann einen Standard vorgeben, einzelne Objektposition kann abweichen (z. B. älteres Gerät mit kürzerer Frist).naechste_pruefungjegeraet_instanzwird nach jeder erfassten Prüfung neu berechnet (pruefdatum + pruefintervall_monate).
"Nicht bestanden" / defekt → Fehlbestand (entschieden)
Pro Gerät entscheidbar, nicht global fix. Beim Setzen von
status='defekt' oder status='in_reparatur' an einer geraet_instanz wird
im selben Dialog gefragt/entschieden, ob daraus ein Fehlbestand entsteht (nutzt
die bestehende Fehlbestand-/Eskalations-Infrastruktur weiter, kein Parallel-
Konzept). Die ganze bestehende Fehlbestand-Logik (Kette Fehlbestand →
Nachfüllung/Mindermenge → Historie) wird dabei mitgenutzt, nicht neu gebaut –
ein "defektes Gerät" ist fachlich einfach ein Fehlbestand mit Fehlmenge=1 an
dieser Position.
Erfassungs-UI für geraet_sn (komplett neu, kein Mengenfeld mehr)
Statt Mengenfeld + "Passt"-Button: Instanz-Liste pro Position.
┌─────────────────────────────────────────┐
│ Pulsoxymeter Modell X (Soll: 2) │
├─────────────────────────────────────────┤
│ ✓ SN-001 [Prüfdatum: 2025-03-15] [OK] │
│ ✓ SN-002 [Prüfdatum: 2025-06-22] [OK] │
│ + Gerät hinzufügen (SN scannen/eingeben) │
└─────────────────────────────────────────┘
Buttons pro Instanz:
- OK – Gerät ist da, einsatzbereit.
- Fehlt/Defekt – Dialog: Grund (fehlt/defekt/in Reparatur), Bemerkung → Instanz-Status ändern, bei "fehlt"/"defekt" optional Fehlbestand erzeugen (siehe oben, pro Gerät entscheidbar).
materialtyp='ablauf_charge' und 'standard' bleiben unverändert (Mengenfeld
- Passt-Button wie bisher) – nur
geraet_snbekommt diese neue Erfassungsart.
Eskalation bei überfälliger Prüfung
Bestehende Zwei-Stufen-Mechanik (app/services/eskalation.py) um eine zweite
Datenquelle erweitern: überfällige geraet_instanz.naechste_pruefung statt
fehlbestand.entstanden_am. Eigene Konfigurationszeile/-spalten, damit
Prüf-Fristen unabhängig von Fehlbestand-Fristen einstellbar sind (TÜV-Fristen
unterscheiden sich je nach Gerätetyp).
Umsetzungsschritte (grobe Reihenfolge)
- Migration:
geraet_instanz-Tabelle,objektposition.pruefintervall_monate, Daten-Migration bestehenderseriennummer-Werte, danach Spalte droppen. - Backend:
geraet_instanz-Model + Service (CRUD, Status ändern inkl. optionaler Fehlbestand-Erzeugung, Ist-Menge-Berechnung fürgeraet_sn). - Backend: Eskalation um Prüf-Fälligkeit erweitern.
- Frontend: neue Instanz-Listen-UI für
geraet_snin der Kontroll-Erfassung (PositionCard.tsx/KontrollPage.tsx), Scan-Integration (Karte 10) für SN-Eingabe wiederverwenden. - Frontend: Admin-Pflege der Geräte-Instanzen (analog
ObjektPositionenPanel).