feat(apicore-sync): field-level ownership between ApiCore and the shop

ApiCore stays the source of truth for beekeeping facts, Wabenhain for
everything sales-related; both remain separate packages talking only over
ApiCore's HTTP API.

- Batches: lot number, fill date, best-before date and filled jar count
  now follow ApiCore on every run (before: created once, corrections never
  arrived). remainingGlasses - the shop's own stock - is never written; if
  it exceeds a corrected fill quantity, the run reports it instead of
  silently adjusting.
- Batches are matched by the new Batch.apicoreBottlingId instead of the lot
  number, so correcting a lot number in ApiCore no longer creates a second
  batch. Existing synced batches are adopted once via their lot number.
- Harvests: date and year always follow ApiCore, also when published or
  edited; type, location and text stay as maintained in the admin.
- Products stay entirely shop-owned after creation (weight drives the
  legally required unit price, so it is never changed automatically).
- Admin panel: batch update count and stock-conflict notice; intro text
  states which system owns which fields.

Migration is additive (nullable unique column).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-09-27 20:14:35 +02:00
1 parent 45ca0ea745
commit d38f4303ff
9 files changed
+272 -42

No files matched your search

@@ -0,0 +1,13 @@
-- Herkunftsschluessel fuer den ApiCore-Chargen-Sync: ID der Abfuellung
-- (BottlingBatch). Bisher wurde eine Charge nur ueber die Losnummer (code)
-- wiedererkannt — wird die Losnummer in ApiCore korrigiert, entstand beim
-- naechsten Lauf eine zweite Charge. Nullable: manuell angelegte Chargen
-- haben keine Herkunft in ApiCore, bestehende Zeilen bleiben gueltig. Schon
-- synchronisierte Chargen erhalten die ID beim naechsten Lauf ueber ihre
-- Losnummer.
-- AlterTable
ALTER TABLE "batches" ADD COLUMN "apicoreBottlingId" TEXT;
-- CreateIndex
CREATE UNIQUE INDEX "batches_apicoreBottlingId_key" ON "batches"("apicoreBottlingId");