Files
ApiCore/docs/pruefung-2026-09.md
T
2026-10-01 18:44:20 +02:00

14 KiB
Raw Blame History

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
Ein-/Auswinterung & Verluste Winterverluste je Volk und Stand nachvollziehbar Nur Volksstatus, kein Bezug zum Winter, keine Ursache Mittel WinterCheck je Volk/Winter/Saison, Verlustkategorien nach COLOSS, Übersicht mit Verlustrate; nicht ausgewinterte Völker zählen nie als überlebt AT + MP
E2E-Tests Grün 23 rot (1 Produktfehler, 3 veraltete Tests) – behoben AT

Prüfungen (letzter Lauf)

  • Backend: Typecheck, ESLint, 550 Unit-Tests, 211 E2E-Tests (isolierte Postgres 17), nest build – grün.
  • Frontend: Typecheck, ESLint, 48 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 nicht überarbeitet – erledigt im Oktober 2026, siehe „AuDHD-Anpassung aller Seiten“.

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).

Überwinterung (Ein-/Auswinterung & Verluste)

  • Seite „Überwinterung“ (Betrieb): je Winter (2026 = Winter 2026/27) eine Einwinterung und eine Auswinterung pro Volk. „Als Nächstes“ nennt die noch nicht eingewinterten Völker; „Auswintern“ erscheint erst nach der Einwinterung oder ab Januar.
  • Verlustursachen: die drei Kategorien des COLOSS-Monitorings (tot/leer, unlösbares Königinnenproblem, Naturereignis). Keine Diagnose-Liste – vermutete Gründe gehören in die Notiz.
  • Verlustrate = verloren / eingewintert (wie COLOSS). Solange Völker nicht ausgewintert sind, heißt sie „vorläufig“; ohne jede Auswinterung wird „–“ statt „0 %“ angezeigt.
  • „Volk als abgestorben kennzeichnen“ setzt den Status nur auf ausdrücklichen Wunsch (Häkchen, vorbelegt), in derselben Transaktion und mit Audit-Eintrag.
  • Rechte winter-checks:read/create/update: per Migration an Imker und Mitarbeiter wie Durchsichten, Nur-Lesen-Rollen nur lesen. Einträge sind im Backup enthalten.
  • Quelle Verlustkategorien: COLOSS-Monitoring (z. B. Gray et al. 2020, J. Apic. Res., doi:10.1080/00218839.2020.1797272).

API-Sicherheit (Oktober 2026)

Audit des gesamten Backends nach OWASP API Top 10 / ASVS L2 (25 Befunde), alle umgesetzt außer den zwei in ARCHITECTURE.md §9 begründeten Restpunkten. Verifikation: AT (Unit + E2E gegen Postgres 17).

Befund Schwere Commit
MFA-Zwischen-Token galt als Access-Token (MFA-Bypass) Kritisch e0bd7b2
users:update konnte Admin-Konten übernehmen Hoch c4a11b4
SSO-Konto über unverifizierten E-Mail-Claim gewählt Hoch a25265b
Backup-Import überschreibt Benutzer; Export enthält Hashes/Secrets; Pfad-Traversal im Import Hoch bd592ad
Backup-Pfad/Zeitplan frei wählbar Mittel ebeb499
Webhooks: DNS-Rebinding, kein Timeout, Signatur ohne Zeitstempel Mittel 79d20ee
TOTP-Replay, keine Kontosperre, MFA-Aus nur mit Passwort, Timing-Enumeration Mittel 5c666fe
Refresh-Rotation nicht atomar, keine Höchstdauer Mittel 2de93bc
Throttler nach Auth, Proxy-Vertrauen fest, Cache/CSP, Logs mit Query Mittel 9ae1d96
API-Schlüssel ohne IP-Bindung, Scope über eigene Rechte hinaus Mittel f1dc0de
CSV-Formel-Injection Mittel 61e3247
Passwortregel 8 Zeichen, kein Leak-Abgleich Mittel 0ba8996
Suche umgeht Leserechte Niedrig–Mittel eafe925
Öffentliche Chargen-Seite, SSO-Callback-URL, Logout-Limit, 4xx-Mapping Niedrig 0899576
SSO-/MFA-Token mehrfach nutzbar; Rechte-Cache je Replika Niedrig–Mittel 45efb08

Neue Umgebungsvariablen: BACKUP_ENCRYPTION_KEY, BACKUP_ROOT, SESSION_MAX_AGE, TRUST_PROXY, PASSWORD_BREACH_CHECK (siehe .env.example).

Betrieb nach dem Update: Alle Benutzer melden sich einmal neu an (Access-Tokens ohne Audience gelten nicht mehr). Webhook-Empfänger prüfen die neue Signatur (X-ApiCore-Timestamp.X-ApiCore-Delivery.Body). Im Wabenhain-Schlüssel die Server-IP als erlaubte Adresse eintragen.

AuDHD-Anpassung aller Seiten (Oktober 2026)

Ziel: weniger gleichzeitig zu merken, keine Sackgassen, ein klarer nächster Schritt, handschuhtauglich. Verifikation: AT (111 Frontend-Tests, je Formular eine Spec) + CR; MP (Browser) für die neuen Seiten noch offen.

Gemeinsame Bausteine (src/components/form/*, query-state.tsx, detail-header.tsx, empty-state.tsx):

Regel Umsetzung
Was ist Pflicht? Field zeigt „Pflicht“/„optional“, Fehler direkt am Feld, Fokus aufs erste Problem
Nicht zu viel auf einmal FormSection: nummerierte Schritte, seltene Felder eingeklappt mit Anzahl
Unterbrechung kostet nichts useFormDraft: Entwurf je Benutzer auf dem Gerät, wird ausdrücklich angeboten, beim Abmelden gelöscht
Antippen statt Tippen RatingScale (1–5 als Tasten mit benannten Enden), ToggleChip (Ja/Nein), Auswahl-Tasten statt Freitext
Keine Sackgasse QueryState: Laden → Fehler mit „Erneut versuchen“ → leer mit nächstem Schritt → Daten
Ein Hauptschritt DetailHeader: Überschrift, Zurück, Status als Symbol + Wort, eine Hauptaktion, Rest unter „Mehr“
Handschuhe Felder 44 px, Tasten ≥ 40 px auf dem Handy, Speichern bleibt in Daumenreichweite, Zifferntastatur bei Zahlen
Bewegung Verschieben/Zoomen nur bei Bewegungsstufe „Voll“; Dialoge scrollen im Bildschirm
Riskantes Rückfrage mit Klartext (Vereinigen, Zähler, Vorlagen, Zuordnungen), Rückgängig beim Etiketten-Designer

Seiten: alle 14 Erfassungsformulare, Listen, Detailseiten (Volk, Stand, Königin, Honigcharge, Ernte, Schleuderung, Abfüllung, Ausrüstung), Bearbeiten-Dialoge am Volk, Kalender (Tagesliste auf dem Handy), Statistik, Überwinterung, Lager, Suche, Verwaltung (Benutzer, Audit-Log, Automatisierung, Backup).

Nebenbei behoben: Fütterungsstatistik addierte Liter und Kilogramm (jetzt je Einheit), Kalender ordnete späte Einträge dem Folgetag zu (UTC), Zeichenfarbe der Königin wurde aus der ersten Ziffer geraten.

Offen: Prüfung im Browser (Desktop + Handy) der neuen Seiten; Bearbeiten-Dialoge außerhalb des Volks (Honigcharge, Ernte, Abfüllung, Produkt) haben Zifferntastatur, aber noch nicht das volle Formular-Kit.