GET /api/v1/shop-sync returns exactly the data ApiCore releases to the shop: harvest facts, article master data and bottlings with their harvest ids. Every query uses an explicit select, so notes, colonies, treatments and fields added to the models later never leave ApiCore unless deliberately added to the allowlist. - New permission shop-sync:read (granted to ADMIN automatically, to no other role): the shop's service account needs nothing else, in particular no access to harvest or extraction records with notes. - contractVersion 1; only breaking changes bump it. - Always the full set: small volume, and a full comparison heals missed runs by itself. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
7.0 KiB
7.0 KiB
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 |
| E2E-Tests | Grün | 23 rot (1 Produktfehler, 3 veraltete Tests) | – | behoben | AT |
Prüfungen (letzter Lauf)
- Backend: Typecheck, ESLint, 524 Unit-Tests, 185 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
Zuständigkeit pro Feld im Sync– erledigt.Eigene, versionierte Sync-Schnittstelle– erledigt:GET /api/v1/shop-sync(Vertragsversion 1, Feld-Allowlist, Berechtigungshop-sync:read). Bewusst ohne „geändert seit“: kleine Datenmenge, Voll-Abgleich heilt verpasste Läufe selbst. Wabenhain nutzt sie seit5642f0c, mit Rückfall auf die alten Endpunkte bei HTTP 404.- Nur-Lese-API-Schlüssel statt Passwort-Login des Service-Kontos.
- Ende-zu-Ende-Test beider Systeme gegen Test-Instanzen.
- Merge/Push.
Offen / Entscheidungen
- 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.
- Service-Konto statt API-Schlüssel: Wabenhain meldet sich mit E-Mail/Passwort an. Ein eigener, nur lesender API-Token-Mechanismus in ApiCore wäre sicherer – bewusst nicht ohne Absprache gebaut.
- Status „blockiert“ existiert im Aufgabenmodell nicht. Nicht ergänzt (Schemaänderung + fachliche Definition nötig).
- Produktbeschreibung aus ApiCore wird in Wabenhain übernommen und auf der öffentlichen Herkunftsseite gezeigt – gilt damit als öffentlich. Falls sie intern gemeint ist: klären.
- Automatische Vorschläge haben standardmäßig keinen Termin (keine erfundene Frist);
je Regel über
config.dueInDayseinstellbar. - Übrige Formulare/Seiten wurden nicht einzeln überarbeitet (Fokus: Heute, Aufgaben, Profil).