- Treatment records supplier, purchase proof and prescribing vet, and keeps the apiary the colony stood at on the treatment day. - Holder name and address in site settings (never in public output; regression test in public.service.spec). - treatment-log.pdf: one sheet per apiary, identical treatments grouped, missing mandatory fields printed as FEHLT, uncertain locations marked. - Shared PDF table helpers extracted from the record card. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
93 lines
9.0 KiB
Markdown
93 lines
9.0 KiB
Markdown
# Prüfung & Verbesserung ApiCore / Wabenhain – Arbeitsstand September 2026
|
||
|
||
Branch in ApiCore: `improve/integrity-sync-audhd` (nicht gemergt, nicht gepusht).
|
||
Wabenhain: Commits direkt auf `main` (nicht gepusht).
|
||
|
||
Verifikationsstufen: **CR** = durch Codeprüfung beurteilt, **AT** = automatisiert getestet,
|
||
**MP** = manuell im Browser geprüft (Desktop 1366 px + Mobil 390 px), **NV** = nicht verifiziert.
|
||
|
||
## Prüfmatrix
|
||
|
||
| Funktion | Erwartetes Verhalten | Befund (vorher) | Prio | Umsetzung | Status |
|
||
|---|---|---|---|---|---|
|
||
| Abfüllung bucht Honigmenge | Menge nie doppelt/zu viel abgebucht | Menge außerhalb der Transaktion gelesen, Absolutwert geschrieben → parallele Abfüllungen überbuchen, Abzug geht verloren | Kritisch | Bedingtes `UPDATE … WHERE amount >= x` in Transaktion; Korrektur/Löschen per Increment | AT |
|
||
| Lagerentnahme | Kein negativer Bestand | Ausgang ohne Bestandsprüfung | Hoch | Bedingtes Decrement, 400 bei Unterdeckung | AT |
|
||
| Völker umsetzen/teilen/vereinigen | Lebende Völker bearbeitbar | Nur Status `ACTIVE` erlaubt – schwache/weisellose Völker gesperrt (Vereinigung weiselloser Völker unmöglich) | Hoch | Nur Endzustände (aufgelöst, verkauft, tot, vereinigt) sperren; Selbst-Vereinigung + doppeltes Auflösen abgelehnt | AT |
|
||
| Königin umweiseln | Wechsel A → B möglich, Historie korrekt | Altes Volk behielt `currentQueenId` → Unique-Konflikt; Zuweisung an aufgelöste Völker möglich | Hoch | Altes Volk gibt Königin frei (→ weisellos), weiselloses Volk mit Königin → aktiv | AT |
|
||
| Aufgabe erledigen | Idempotent, Status/Zeit konsistent | Doppelklick verschob `completedAt`, Webhook doppelt; Wiedereröffnen behielt `completedAt` | Mittel | Zweites Erledigen = No-op; `completedAt` folgt Status | AT |
|
||
| Wiederkehrende Aufgaben | Fällige Aufgabe mit Termin | Erzeugte Aufgaben ohne Fälligkeit; verpasste Wochen einzeln nachgeholt | Mittel | Fälligkeit = Termin; verpasste Termine ergeben EINE Erinnerung | AT |
|
||
| Automatisierungen | Eine offene Aufgabe je Regel und Objekt | Jede Auslösung (z. B. jede Entnahme unter Mindestbestand) erzeugte neue Aufgabe + Warnung | Hoch | Kennzeichnung `sourceAutomationTrigger`, Duplikatsperre; optional `config.dueInDays` | AT |
|
||
| Varroa-Schwelle | Vergleich nur in gleicher Einheit | Probenzählwerte (Puderzucker/Auswaschen) und Brettzählung ohne Zeitraum gegen „Milben/Tag“ verglichen | Hoch | Nur natürlicher Milbenfall mit Tagesrate | AT |
|
||
| Offline-Warteschlange | Wiederholung erzeugt keine Duplikate | Verlorene Antwort → erneutes Senden → doppelte Durchsicht/Ernte + Automatik-Aufgabe | Hoch | `Idempotency-Key` (Opt-in je Endpunkt), Schlüssel im Queue-Eintrag | AT |
|
||
| Start mehrerer Replikas | Beide Pods starten | Berechtigungs-Sync auf leerer DB: Unique-Fehler, Pod-Absturz | Mittel | `createMany … skipDuplicates` | AT |
|
||
| Eingabeplausibilität | Serverseitige Grenzen | Skalen 1–5 nur im UI; doppelte Völker in Ernte → 500; Netto > Brutto möglich | Mittel | DTO-Grenzen, `ArrayUnique`, Gewichtsprüfung | AT |
|
||
| Wabenhain: Ernte-Beschreibung | Keine internen Daten öffentlich | Interne ApiCore-Ernte-Notizen in Shoptext kopiert | Hoch (Sicherheit) | Notizen nicht mehr übernommen | AT |
|
||
| Wabenhain: Entwürfe | Admin-Korrekturen bleiben | Jeder Sync überschrieb unveröffentlichte Entwürfe | Hoch | Im Admin bearbeitete Entwürfe (Audit-Log) geschützt, gemeldet | CR |
|
||
| Wabenhain: Abruf | Kein Hängen, Fehler ≠ leere Liste | Kein Timeout | Mittel | 20-s-Timeout; Tests: Fehler/Strukturfehler brechen ab | AT |
|
||
| Wabenhain: Sichtbarkeit | Letzter Lauf erkennbar | Nur direkt nach Klick | Niedrig | „Letzter vollständiger Lauf“ im Panel | CR |
|
||
| Start-/Heute-Ansicht | Nächster Schritt klar | Kennzahlen-Kacheln statt Aufgaben | Hoch (UX) | „Als Nächstes“ + „Außerdem heute“, Rückgängig | AT (Logik) + MP |
|
||
| Bewegung | Einstellbar, System respektiert | Nur `motion-safe`-Klassen | Mittel | Voll/Dezent/Aus je Gerät | MP |
|
||
| Etiketten-Schnittmarken | Anlegekante für Papierschneider | Keine Marken, Zuschnitt nach Augenmaß | Mittel | Haarlinien-Marken im Blattrand an jeder Schnittkante, je Vorlage abschaltbar | AT + MP |
|
||
| Folge-Kontrollen | Nachkontrolle nach Maßnahme | Keine | Mittel | Regeln „Nach Behandlung/Fütterung“, standardmäßig aus, Frist „Fällig nach (Tagen)“ | AT |
|
||
| Stockkarte je Volk | Vollständige Historie als PDF | Nur Jahresbericht | Mittel | `colony-record-card.pdf`, optional je Jahr | AT + MP |
|
||
| Bestandsbuch Tierarzneimittel | Pflichtangaben Art. 108 VO (EU) 2019/6 | Lieferant, Erwerbsbeleg, Tierarzt, Standort am Behandlungstag, Halter fehlten | Hoch (Recht) | Felder ergänzt, Stand je Behandlung gespeichert, PDF je Stand, fehlende Pflichtangaben als „FEHLT“ | AT + MP |
|
||
| E2E-Tests | Grün | 23 rot (1 Produktfehler, 3 veraltete Tests) | – | behoben | AT |
|
||
|
||
## Prüfungen (letzter Lauf)
|
||
|
||
- Backend: Typecheck, ESLint, 539 Unit-Tests, 203 E2E-Tests (isolierte Postgres 17), `nest build` – grün.
|
||
- Frontend: Typecheck, ESLint, 44 Tests, `next build` – grün. Design-Detektor (impeccable): 0 Befunde.
|
||
- Wabenhain: Typecheck, ESLint (geänderte Dateien), 538 Tests – grün.
|
||
- Manuell (Browser, lokale Demo-Daten): Login, Heute-Ansicht Desktop/Mobil, Abhaken in Liste und
|
||
„Als Nächstes“, Rückgängig (stellt vorherigen Status her), Profil-Bewegung „Aus“ wirkt, Aufgabenliste mobil.
|
||
|
||
## Zuständigkeit (Quelle der Wahrheit)
|
||
|
||
ApiCore und Wabenhain bleiben getrennte Pakete; Verbindung nur über die HTTP-API von ApiCore.
|
||
|
||
| Information | Maßgeblich | Sync-Verhalten (Wabenhain) |
|
||
|---|---|---|
|
||
| Stand, Völker, Durchsichten, Behandlungen, interne Notizen | ApiCore | wird nicht übertragen |
|
||
| Ernte: Datum, Jahr | ApiCore | bei jedem Lauf aktualisiert |
|
||
| Ernte: Sorte, Ort, Text | Wabenhain | nur Vorbelegung unbearbeiteter Entwürfe |
|
||
| Charge: Losnummer, Abfülldatum, MHD, abgefüllte Gläser | ApiCore | bei jedem Lauf aktualisiert (Zuordnung über ApiCore-ID) |
|
||
| Charge: Shop-Bestand, Bilder, Ernte-Zuordnung | Wabenhain | nie geändert; Bestand > Abfüllmenge wird gemeldet |
|
||
| Produkt: Name, Text, Gewicht, Preis, Bilder, Sichtbarkeit | Wabenhain | nur beim ersten Anlegen vorbelegt |
|
||
| Bestellungen, Kunden, Bewertungen | Wabenhain | nie Richtung ApiCore |
|
||
|
||
Umgesetzt in Wabenhain `d38f430` (AT: Entscheidungslogik; CR: DB-Ablauf der Server-Action).
|
||
|
||
## Nächste Schritte
|
||
|
||
1. ~~Zuständigkeit pro Feld im Sync~~ – erledigt.
|
||
2. ~~Eigene, versionierte Sync-Schnittstelle~~ – erledigt: `GET /api/v1/shop-sync` (Vertragsversion 1, Feld-Allowlist, Berechtigung `shop-sync:read`). Bewusst ohne „geändert seit“: kleine Datenmenge, Voll-Abgleich heilt verpasste Läufe selbst. Wabenhain nutzt sie seit `5642f0c`; seit `3bc0693` ausschließlich (kein Rückfall auf andere Endpunkte).
|
||
3. ~~Nur-Lese-API-Schlüssel~~ – erledigt: Verwaltung → Automatisierung → API-Schlüssel. Nur Hash gespeichert, Klartext einmalig angezeigt, Scope nur `shop-sync:read`, widerrufbar, optional befristet, „zuletzt benutzt“ sichtbar. Wabenhain liest nur noch `APICORE_API_KEY`; der Passwort-Login ist entfernt (`3bc0693`).
|
||
4. Ende-zu-Ende-Test beider Systeme gegen Test-Instanzen.
|
||
5. Merge/Push.
|
||
|
||
## Offen / Entscheidungen
|
||
|
||
1. **Wabenhain-Sync gegen echtes ApiCore** nicht Ende zu Ende getestet (keine Zugangsdaten/Testinstanz
|
||
verbunden). Mapping, Client und Schutzlogik sind unit-getestet bzw. per Code geprüft.
|
||
2. ~~Service-Konto statt API-Schlüssel~~ – erledigt: nur noch API-Schlüssel mit Scope `shop-sync:read`.
|
||
3. **Status „blockiert“** existiert im Aufgabenmodell nicht. Nicht ergänzt (Schemaänderung + fachliche Definition nötig).
|
||
4. **Produktbeschreibung** aus ApiCore wird in Wabenhain übernommen und auf der öffentlichen
|
||
Herkunftsseite gezeigt – gilt damit als öffentlich. Falls sie intern gemeint ist: klären.
|
||
5. Automatische Vorschläge haben standardmäßig **keinen Termin** (keine erfundene Frist);
|
||
je Regel über `config.dueInDays` einstellbar.
|
||
6. Übrige Formulare/Seiten wurden nicht einzeln überarbeitet (Fokus: Heute, Aufgaben, Profil).
|
||
|
||
## Bestandsbuch (Tierarzneimittel)
|
||
|
||
Grundlage: Art. 108 VO (EU) 2019/6, abgeglichen mit dem Muster-Formblatt des Veterinäramts Kassel
|
||
(Stand März 2026) und der FAQ des LGL Bayern. Gilt für jedes Tierarzneimittel, auch freiverkäufliche Säuren;
|
||
Aufbewahrung 5 Jahre.
|
||
|
||
- Export: Stand → „Bestandsbuch {Jahr}“ (`/export/treatment-log.pdf?year=&apiaryId=`), ein Blatt je Stand.
|
||
- Gleiche Behandlungen mehrerer Völker (Mittel, Charge, Menge, Zeitraum, Bezug) stehen in einer Zeile.
|
||
- Standort am Behandlungstag: seit dieser Version mit der Behandlung gespeichert (`Treatment.apiaryId`).
|
||
Für ältere Einträge aus der Umsetz-Historie abgeleitet; ist das unsicher, markiert `*` die Zeile.
|
||
- Fehlende Pflichtangaben erscheinen als „FEHLT“ statt leer – das Blatt sieht nie vollständiger aus, als es ist.
|
||
- Name und Anschrift des Halters: Verwaltung → Automatisierung → Stammdaten & Web. Erscheinen nur im
|
||
Bestandsbuch; die öffentliche Chargen-Seite gibt sie nachweislich nicht aus (Test in `public.service.spec.ts`).
|