Files
erp_naurua/docs/CONCEPT.md

14 KiB

Concept

Vision

ERP Naurua bildet den operativen Kern fuer Einkauf, Lager und Auftragsabwicklung mit voller Nachvollziehbarkeit von Kontakten, Bestellungen und Chargen.

Fachliches Zielbild

ERP Naurua dient als zentraler operativer Kern fuer einen Heilpilzhandel mit zwei Verkaufskanaelen: Online-Shop (Wix) und Direktverkauf (z. B. Marktstand). Online-Bestelldaten kommen ueber eine Integrationsschicht (n8n Webhook), Direktverkaeufe werden im ERP manuell als Tages-/Sammelerfassung gebucht. Das System ist intern fuer Lager, Chargen, MHD sowie Rueckverfolgung verantwortlich. Die Kundinnen und Kunden werden im gemeinsamen Kontaktmodell verwaltet (Kunde/Lieferant als Rollen); Direktverkaeufe duerfen ohne individuellen Kundenkontakt erfasst werden. Bestellungen werden mit Chargenbewegungen verknuepft, sodass jede Entnahme auf Charge und Lagerort zurueckfuehrbar ist.

Das Zielbild ist modular erweiterbar: Rechnungswesen, Versandautomatisierung und Beratung werden als Module angefuegt, ohne das Kernmodell zu zerbrechen. Die Prioritaet in Schritt 1 liegt auf Datenqualitaet, Rueckverfolgbarkeit und klaren, auditierbaren Bewegungen.

Scope

Der erste Umsetzungsschritt umfasst ausschliesslich die Module, die mit (1) markiert wurden:

  1. Lagerverwaltung mit Chargen, MHD, Zu- und Abgaengen
  2. Bestellerfassung mit Chargenrueckverfolgung
  3. Kontakt-Angaben inkl. Liefer- und Kundenangaben

Non-Goals

Nicht Bestandteil von Schritt 1:

  1. Kreditoren- und Debitoren-Stammdaten
  2. Rechnungseingang (inkl. OCR)
  3. Rechnungspruefung und Freigabe-Workflows
  4. Automatische Zuordnung von Rechnungen zu Bestellungen/Lieferungen/Leistungen
  5. Operative Nachverfolgung von Rechnungsvorgaengen

Principles

  1. Traceability first: Jede Warenbewegung und jede Bestellung muss auf Charge rueckfuehrbar sein; bei Direktverkauf ist ein Laufkundenfall ohne Kontakt zulaessig.
  2. Daten vor UI-Komfort: Zuerst robuste Datenmodelle und Prozesse, danach Optimierungen.
  3. Erweiterbarkeit: Schritt-1-Modelle muessen spaetere Finanz- und Rechnungsprozesse aufnehmen koennen.
  4. Einfache Integrationsfaehigkeit: Importfaehigkeit fuer externe Bestelldaten ist von Beginn an mitzudenken.
  5. Kanaltrennung: Online- und Direktverkaeufe muessen technisch eindeutig unterscheidbar sein.

Users And Roles

  1. Einkauf/Disposition: Erfasst und verwaltet Bestellungen.
  2. Lager/Logistik: Pflegt Chargen, MHD sowie Warenzu- und -abgaenge.
  3. Administration/Backoffice: Verwalten von Kunden- und Lieferkontakten.

Domain Overview

Schritt 1 basiert auf drei Kern-Domaenen:

  1. Kontakte: Kunden und Lieferanten mit abrechnungs- und lieferrelevanten Angaben.
  2. Bestellungen: Bestellungskopf und Positionen aus Online-Import und Direktverkauf, gekoppelt an betroffene Chargen; Kontaktzuordnung ist fuer Direktverkauf optional.
  3. Lager/Chargen: Bestandsfuehrung je Produkt/Charge inkl. MHD und Bewegungen.

Kernaussage: Eine Bestellung kann mehrere Positionen enthalten; jede Position kann einer oder mehreren Chargen zugeordnet werden; jede Charge hat Bewegungen und MHD-Status.

System Overview

Schritt-1-Systemkomponenten:

  1. Kontaktmodul (CRUD, Basisspeicherung, optionale Felder fuer spaetere Erweiterung)
  2. Bestellmodul (Bestellungskopf, Positionen, Upsert ueber externe Bestellnummer)
  3. Artikel-Mapping (externe Shop-Artikel -> interne verkaufbare Artikel -> lagergefuehrte Produkte)
  4. Lagermodul (Chargenstamm, MHD, Bewegungsjournal, aktueller Bestand)
  5. Import-Schnittstelle fuer initiale Bestelldaten (n8n Webhook JSON)
  6. Direktverkaufs-Erfassung (Tages-/Sammelverkauf ohne Kundenregistrierung)

Grobmodell (Schema) Schritt 1

Die folgenden Entitaeten bilden das Zielschema fuer Schritt 1. Felder sind als grobe Vorschlaege zu verstehen und werden in der Detailphase konkretisiert.

Der Entwurf des SQL-Schemas liegt unter: /Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/SCHEMA_PHASE1.sql

Die ausfuehrbaren Migrationen liegen unter: /Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/db/migrations/

  1. party
    • Zweck: Kunde oder Lieferant (Rollenmodell).
    • Kernfelder: id, type (customer/supplier/both), name, email, phone, status.
  2. address
    • Zweck: Liefer- und Rechnungsadressen pro Kontakt.
    • Kernfelder: id, party_id, type (billing/shipping), street, house_number, zip, city, state_code, country_name, country_iso2.
  3. contact
    • Zweck: Ansprechpartner oder zusaetzliche Kontaktpunkte.
    • Kernfelder: id, party_id, first_name, last_name, email, phone.
  4. product
    • Zweck: Lagergefuehrtes Produkt (Bestandsfuehrung, Charge, MHD).
    • Kernfelder: id, sku, name, status, uom.
  5. sellable_item
    • Zweck: Verkaufbarer Shop-Artikel (kann Bundle sein).
    • Kernfelder: id, item_code, display_name, status.
  6. external_item_alias
    • Zweck: Mapping von externen Webshop-Artikeldaten auf interne Artikel.
    • Kernfelder: id, source_system, external_article_number, external_title, title_normalized, sellable_item_id.
  7. sellable_item_component
    • Zweck: Stueckliste je Shop-Artikel auf lagergefuehrte Produkte.
    • Kernfelder: id, sellable_item_id, product_id, qty_per_item.
  8. warehouse
    • Zweck: Lagerstandort auf hoher Ebene.
    • Kernfelder: id, name, code.
  9. location
    • Zweck: Lagerorte innerhalb eines Lagers.
    • Kernfelder: id, warehouse_id, code, name, type (storage/receiving/dispatch).
  10. stock_lot
  • Zweck: Charge/Batch mit MHD.
  • Kernfelder: id, product_id, lot_number, mfg_date, expiry_date, status, sellout_date, warning_state.
  1. payment_method und shipping_method
  • Zweck: Normalisierte interne Werte fuer Zahlungs- und Lieferart.
  • Kernfelder: id, code, label, is_active.
  1. sales_order
  • Zweck: Bestellungskopf (Online-Shop und Direktverkauf).
  • Kernfelder: id, external_ref (unique), order_source, party_id (optional bei Direktverkauf), order_date, order_status, payment_status, Summenfelder, webhook_payload.
  1. sales_order_line
  • Zweck: Bestellpositionen.
  • Kernfelder: id, sales_order_id, line_no, sellable_item_id, raw_external_article_number, raw_external_title, qty, unit_price.
  1. stock_move
  • Zweck: Zu- und Abgaenge sowie Umlagerungen.
  • Kernfelder: id, product_id, lot_id, from_location_id, to_location_id, qty, move_type, move_date.
  1. sales_order_line_lot_allocation
  • Zweck: Explizite Zuordnung Bestellposition <-> Charge (Rueckverfolgung).
  • Kernfelder: id, sales_order_line_id, product_id, lot_id, qty, stock_move_id.
  1. audit_log
  • Zweck: Standardisierte Historisierung von Importen und Aenderungen.
  • Kernfelder: id, entity_name, entity_id, action, changed_at, before_data, after_data.
  1. outbound_webhook_event
  • Zweck: Outbox-Queue fuer robuste ERP -> n8n Zustellung.
  • Kernfelder: id, event_type, event_key, aggregate_type, aggregate_id, payload, status, attempt_count.

Skizze (ERD)

erDiagram
  PARTY ||--o{ ADDRESS : "has"
  PARTY ||--o{ CONTACT : "has"
  PARTY o|--o{ SALES_ORDER : "places_or_walkin"

  SALES_ORDER ||--o{ SALES_ORDER_LINE : "contains"
  SELLABLE_ITEM ||--o{ SALES_ORDER_LINE : "ordered_item"

  SELLABLE_ITEM ||--o{ EXTERNAL_ITEM_ALIAS : "mapped_from"
  SELLABLE_ITEM ||--o{ SELLABLE_ITEM_COMPONENT : "contains"
  PRODUCT ||--o{ SELLABLE_ITEM_COMPONENT : "component"

  WAREHOUSE ||--o{ LOCATION : "contains"
  PRODUCT ||--o{ STOCK_LOT : "has"

  PRODUCT ||--o{ STOCK_MOVE : "moves"
  STOCK_LOT ||--o{ STOCK_MOVE : "tracks"
  LOCATION ||--o{ STOCK_MOVE : "from_to"

  SALES_ORDER_LINE ||--o{ SALES_ORDER_LINE_LOT_ALLOCATION : "allocates"
  STOCK_LOT ||--o{ SALES_ORDER_LINE_LOT_ALLOCATION : "traces_to"
  PRODUCT ||--o{ SALES_ORDER_LINE_LOT_ALLOCATION : "allocated_product"

Phase-1 Beziehungen (fachlich)

  1. Ein Kontakt (party) kann mehrere Adressen und Kontakte besitzen.
  2. Eine Bestellung kann einem Kontakt zugeordnet sein (sales_order.party_id), bei Direktverkauf ist NULL zulaessig.
  3. Eine Bestellung besteht aus mehreren Positionen (sales_order_line).
  4. Jede Position referenziert genau einen verkaufbaren Artikel (sellable_item), nicht direkt ein Lagerprodukt.
  5. Ein verkaufbarer Artikel kann aus mehreren lagergefuehrten Produkten bestehen (sellable_item_component).
  6. Chargen (stock_lot) gehoeren zu genau einem lagergefuehrten Produkt (product).
  7. Lagerbewegungen (stock_move) referenzieren Produkt und Charge und bewegen Menge von einem Lagerort zum anderen.
  8. Rueckverfolgung erfolgt ueber sales_order_line_lot_allocation und kann je Position ueber mehrere Chargen gesplittet werden.
  9. sales_order.external_ref ist eindeutig; fuer Online-Import ist es der Upsert-Schluessel, fuer Direktverkauf wird es im ERP mit DIR--Praefix erzeugt.
  10. Outbound-Ereignisse werden ueber outbound_webhook_event idempotent publiziert.

Data And Integrations

Minimale Kernobjekte fuer Schritt 1:

  1. Kontakt
  2. Adresse (Rechnungsadresse, Lieferadresse)
  3. Bestellung
  4. Bestellposition
  5. Verkaufbarer Artikel (sellable_item)
  6. Lagerprodukt (product)
  7. Artikel-Mapping (external_item_alias)
  8. Artikel-Stueckliste (sellable_item_component)
  9. Charge
  10. Lagerbewegung (Zugang/Abgang)
  11. Bestellpositions-zu-Chargen-Zuordnung (sales_order_line_lot_allocation)
  12. Verkaufsquelle im Auftrag (sales_order.order_source: wix | direct)

Zuordnung zum Beispiel-Datensatz:

  1. BestellungNr, Zahlungsstatus, Summenfelder -> Bestellung
  2. Vorname_*, Nachname_*, EmailKunde -> Kontakt
  3. *_RgAdr, *_LfAdr -> Adresse
  4. lineItems[*] -> Bestellposition mit Rohdaten (raw_external_article_number, raw_external_title)
  5. lineItems[*] + Alias-Mapping -> interner Artikel (sellable_item)
  6. Artikel-Stueckliste -> benoetigte Lagerprodukte pro Position
  7. Kommissionierung/Abgang -> Chargenzuordnung in sales_order_line_lot_allocation

Webhook-Regeln fuer Schritt 1 (Online-Shop):

  1. Upsert erfolgt ueber sales_order.external_ref = BestellungNr.
  2. Zahlungsstatus aus Online-Bestellung wird intern standardmaessig als paid gespeichert.
  3. Rechnungsadresse darf leer sein; Lieferadresse wird normal erfasst.
  4. Adressen speichern Klarname (country_name) und ISO-Code (country_iso2) parallel.
  5. Adressdaten werden nur gespeichert, nicht serverseitig validiert (Validierung erfolgt im Shop).

Direktverkauf-Regeln fuer Schritt 1:

  1. Direktverkaeufe werden im ERP erfasst (sales_order.order_source = direct) und kommen nicht ueber n8n-Webhook.
  2. Die Bestellnummer wird im ERP erzeugt und hat den Praefix DIR- (z. B. DIR-20260329-00017).
  3. sales_order.party_id ist optional; bei Laufkundschaft wird kein individueller Kontakt angelegt.
  4. Positionen werden als Sammelverkauf mit Mengen je Produkt erfasst.
  5. Der brutto Gesamtpreis kann auf Flaschenebene verteilt werden (Durchschnittspreis = Gesamtpreis / Gesamtmenge).
  6. Zahlungsart wird explizit gespeichert (z. B. twint, cash, paypal, bank_transfer).

Lagerregeln fuer Schritt 1:

  1. Pro Produkt existiert operativ genau eine current-Charge und genau eine open-Charge.
  2. open darf nicht fehlen; sie ist der direkte Ueberlauf fuer den naechsten operativen Entnahmefall.
  3. Statusfluss fuer Chargen: open -> current -> closed.
  4. Bei Erreichen von qty_net <= 0 auf der current-Charge erfolgt automatischer Wechsel auf die vorhandene open-Charge.
  5. Nach dem Wechsel wird automatisch wieder eine neue open-Charge erzeugt (lot_number bleibt initial leer bis manuell gesetzt).
  6. Negative Chargenbestaende sind nicht zulaessig.
  7. Chargensalden (in/out/net) werden aus Bewegungen berechnet.
  8. Jede Verkaufsbewegung muss einer Charge zugeordnet sein (kein chargenloser Abgang).
  9. Verkaufsbuchung erfolgt standardmaessig gegen die current-Charge.
  10. Korrekturen bleiben durch editierbare Datensaetze und/oder Korrekturbewegungen moeglich.
  11. Abverkaufdatum wird systemintern berechnet; Warnstatus wird fuer UI bereitgestellt (ohne E-Mail-Prozess in Phase 1).

Milestones

Schritt 1 wird in drei Modulpakete umgesetzt:

  1. M1 Kontaktmodul: Datenmodell, API/Service, Basisspeicherung
  2. M2 Bestellmodul: Bestellung + Positionen + optionale Kontaktverknuepfung + Upsert
  3. M3 Lagermodul: Charge, MHD, Bewegungen, Bestandssicht, Rueckverfolgung zur Bestellung

Operative Ablaufdetails liegen unter: /Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/PROCESS_PHASE1.md

Komponenten-Spezifikation liegt unter: /Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/SPEC_PHASE1_COMPONENTS.md

DB-Migrationsdetails liegen unter: /Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/db/README.md

Erfolgskriterien Schritt 1:

  1. Eine Bestellung kann mit Kunden-/Lieferkontakt oder als Direktverkauf ohne Kontakt erfasst werden.
  2. Positionen koennen einer oder mehreren Chargen zugeordnet werden.
  3. Lagerzugaenge/-abgaenge aktualisieren Bestand pro Charge konsistent.
  4. Rueckverfolgung Bestellung <-> Charge <-> Lagerbewegung ist technisch vorhanden.

Entscheidungen Fuer Umsetzung

  1. Eindeutige Bestellidentifikation ueber sales_order.external_ref (Shop: BestellungNr, Direktverkauf: DIR-...); Dateneingang via Upsert.
  2. Rechnungsadresse ist optional (NULL zulaessig), Lieferadresse wird separat gespeichert.
  3. Interne Normalisierung von Zahlungs- und Liefermethoden ueber Mapping-Tabellen.
  4. Land wird als Klarname und ISO-Code gespeichert.
  5. Initial keine serverseitige Adressvalidierung.
  6. Keine Buchhaltungs-/Rechnungsfunktion in Schritt 1.
  7. Chargenrueckverfolgung wird ueber explizite Bestellpositions-Allokation aufgebaut.
  8. Lagerbetrieb mit genau einer aktiven und einer vorbereiteten Charge pro Produkt (current + open).
  9. Storno-Fall wird im Modell vorbereitet (Status cancelled + Freigabe von Reservierungen).
  10. Chargennummer fuer neu vorbereitete Charge wird initial manuell durch Mitarbeitende gesetzt.
  11. Abverkaufprognose und Warnlogik werden in die ERP-Datenbank uebernommen; E-Mail-Erinnerungen sind in Phase 1 deaktiviert.