Karte 14 Schritt 1: geraet_instanz-Tabelle (additiv)
CI / backend-tests (push) Successful in 1m13s
CI / frontend-build (push) Successful in 23s

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
This commit is contained in:
2026-09-04 20:45:04 +02:00
co-authored by Claude Sonnet 5
parent 4c87bf2d84
commit d61aabadf3
8 changed files with 353 additions and 1 deletions
+1
View File
@@ -17,6 +17,7 @@ Status: entstanden aus Klärungsrunde vor Prompt 01. Jede Karte = ein entschiede
| 11 | [Systemumfang: generisches Ressourcenmanagement](11_systemumfang_ressourcenmanagement.md) | entschieden, grundlegend | Prompt 06, 07 |
| 12 | [Eskalation offener Fehlbestände](12_eskalation.md) | Roadmap, Datenmodell-Vorbereitung nötig | Prompt 03, 24 |
| 13 | [Hauptserver mit Satelliten-Servern](13_satelliten_server.md) | entschieden, Betrieb Roadmap, Datenmodell-Vorbereitung nötig | Prompt 17, 19, 20 |
| 14 | [Prüf- und wartungspflichtige Geräte](14_pruef_wartungspflicht.md) | Datenmodell entschieden, Umsetzung offen (geraet_instanz-Tabelle nötig) | Prompt 06, 10, 24 |
Nächster Schritt: Prompt `01_anforderungsanalyse` unter Berücksichtigung aller entschiedenen Karten bearbeiten.
+98
View File
@@ -0,0 +1,98 @@
# 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'`:
```sql
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.seriennummer` entfällt (Migration: bestehende Werte nach
`geraet_instanz` überführen, dann Spalte droppen).
- Ist-Menge bei `geraet_sn` wird nicht mehr als Zahl geführt/eingegeben, sondern
als Anzahl der `geraet_instanz`-Zeilen mit `status='einsatzbereit'` berechnet.
- `objektposition`: neues Feld `pruefintervall_monate` (int, nullable)
**individuell überschreibbar** je Objektposition (wie `sollmenge_override`),
Vorlage/Material kann einen Standard vorgeben, einzelne Objektposition kann
abweichen (z. B. älteres Gerät mit kürzerer Frist).
- `naechste_pruefung` je `geraet_instanz` wird 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_sn` bekommt 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)
1. Migration: `geraet_instanz`-Tabelle, `objektposition.pruefintervall_monate`,
Daten-Migration bestehender `seriennummer`-Werte, danach Spalte droppen.
2. Backend: `geraet_instanz`-Model + Service (CRUD, Status ändern inkl.
optionaler Fehlbestand-Erzeugung, Ist-Menge-Berechnung für `geraet_sn`).
3. Backend: Eskalation um Prüf-Fälligkeit erweitern.
4. Frontend: neue Instanz-Listen-UI für `geraet_sn` in der Kontroll-Erfassung
(`PositionCard.tsx`/`KontrollPage.tsx`), Scan-Integration (Karte 10) für
SN-Eingabe wiederverwenden.
5. Frontend: Admin-Pflege der Geräte-Instanzen (analog `ObjektPositionenPanel`).