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:
- Lagerverwaltung mit Chargen, MHD, Zu- und Abgaengen
- Bestellerfassung mit Chargenrueckverfolgung
- Kontakt-Angaben inkl. Liefer- und Kundenangaben
Non-Goals
Nicht Bestandteil von Schritt 1:
- Kreditoren- und Debitoren-Stammdaten
- Rechnungseingang (inkl. OCR)
- Rechnungspruefung und Freigabe-Workflows
- Automatische Zuordnung von Rechnungen zu Bestellungen/Lieferungen/Leistungen
- Operative Nachverfolgung von Rechnungsvorgaengen
Principles
- Traceability first: Jede Warenbewegung und jede Bestellung muss auf Charge rueckfuehrbar sein; bei Direktverkauf ist ein Laufkundenfall ohne Kontakt zulaessig.
- Daten vor UI-Komfort: Zuerst robuste Datenmodelle und Prozesse, danach Optimierungen.
- Erweiterbarkeit: Schritt-1-Modelle muessen spaetere Finanz- und Rechnungsprozesse aufnehmen koennen.
- Einfache Integrationsfaehigkeit: Importfaehigkeit fuer externe Bestelldaten ist von Beginn an mitzudenken.
- Kanaltrennung: Online- und Direktverkaeufe muessen technisch eindeutig unterscheidbar sein.
Users And Roles
- Einkauf/Disposition: Erfasst und verwaltet Bestellungen.
- Lager/Logistik: Pflegt Chargen, MHD sowie Warenzu- und -abgaenge.
- Administration/Backoffice: Verwalten von Kunden- und Lieferkontakten.
Domain Overview
Schritt 1 basiert auf drei Kern-Domaenen:
- Kontakte: Kunden und Lieferanten mit abrechnungs- und lieferrelevanten Angaben.
- Bestellungen: Bestellungskopf und Positionen aus Online-Import und Direktverkauf, gekoppelt an betroffene Chargen; Kontaktzuordnung ist fuer Direktverkauf optional.
- 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:
- Kontaktmodul (CRUD, Basisspeicherung, optionale Felder fuer spaetere Erweiterung)
- Bestellmodul (Bestellungskopf, Positionen, Upsert ueber externe Bestellnummer)
- Artikel-Mapping (externe Shop-Artikel -> interne verkaufbare Artikel -> lagergefuehrte Produkte)
- Lagermodul (Chargenstamm, MHD, Bewegungsjournal, aktueller Bestand)
- Import-Schnittstelle fuer initiale Bestelldaten (n8n Webhook JSON)
- 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/
party- Zweck: Kunde oder Lieferant (Rollenmodell).
- Kernfelder:
id,type(customer/supplier/both),name,email,phone,status.
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.
contact- Zweck: Ansprechpartner oder zusaetzliche Kontaktpunkte.
- Kernfelder:
id,party_id,first_name,last_name,email,phone.
product- Zweck: Lagergefuehrtes Produkt (Bestandsfuehrung, Charge, MHD).
- Kernfelder:
id,sku,name,status,uom.
sellable_item- Zweck: Verkaufbarer Shop-Artikel (kann Bundle sein).
- Kernfelder:
id,item_code,display_name,status.
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.
sellable_item_component- Zweck: Stueckliste je Shop-Artikel auf lagergefuehrte Produkte.
- Kernfelder:
id,sellable_item_id,product_id,qty_per_item.
warehouse- Zweck: Lagerstandort auf hoher Ebene.
- Kernfelder:
id,name,code.
location- Zweck: Lagerorte innerhalb eines Lagers.
- Kernfelder:
id,warehouse_id,code,name,type(storage/receiving/dispatch).
stock_lot
- Zweck: Charge/Batch mit MHD.
- Kernfelder:
id,product_id,lot_number,mfg_date,expiry_date,status,sellout_date,warning_state.
payment_methodundshipping_method
- Zweck: Normalisierte interne Werte fuer Zahlungs- und Lieferart.
- Kernfelder:
id,code,label,is_active.
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.
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.
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.
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.
audit_log
- Zweck: Standardisierte Historisierung von Importen und Aenderungen.
- Kernfelder:
id,entity_name,entity_id,action,changed_at,before_data,after_data.
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)
- Ein Kontakt (
party) kann mehrere Adressen und Kontakte besitzen. - Eine Bestellung kann einem Kontakt zugeordnet sein (
sales_order.party_id), bei Direktverkauf istNULLzulaessig. - Eine Bestellung besteht aus mehreren Positionen (
sales_order_line). - Jede Position referenziert genau einen verkaufbaren Artikel (
sellable_item), nicht direkt ein Lagerprodukt. - Ein verkaufbarer Artikel kann aus mehreren lagergefuehrten Produkten bestehen (
sellable_item_component). - Chargen (
stock_lot) gehoeren zu genau einem lagergefuehrten Produkt (product). - Lagerbewegungen (
stock_move) referenzieren Produkt und Charge und bewegen Menge von einem Lagerort zum anderen. - Rueckverfolgung erfolgt ueber
sales_order_line_lot_allocationund kann je Position ueber mehrere Chargen gesplittet werden. sales_order.external_refist eindeutig; fuer Online-Import ist es der Upsert-Schluessel, fuer Direktverkauf wird es im ERP mitDIR--Praefix erzeugt.- Outbound-Ereignisse werden ueber
outbound_webhook_eventidempotent publiziert.
Data And Integrations
Minimale Kernobjekte fuer Schritt 1:
- Kontakt
- Adresse (Rechnungsadresse, Lieferadresse)
- Bestellung
- Bestellposition
- Verkaufbarer Artikel (
sellable_item) - Lagerprodukt (
product) - Artikel-Mapping (
external_item_alias) - Artikel-Stueckliste (
sellable_item_component) - Charge
- Lagerbewegung (Zugang/Abgang)
- Bestellpositions-zu-Chargen-Zuordnung (
sales_order_line_lot_allocation) - Verkaufsquelle im Auftrag (
sales_order.order_source:wix|direct)
Zuordnung zum Beispiel-Datensatz:
BestellungNr,Zahlungsstatus, Summenfelder -> BestellungVorname_*,Nachname_*,EmailKunde-> Kontakt*_RgAdr,*_LfAdr-> AdresselineItems[*]-> Bestellposition mit Rohdaten (raw_external_article_number,raw_external_title)lineItems[*]+ Alias-Mapping -> interner Artikel (sellable_item)- Artikel-Stueckliste -> benoetigte Lagerprodukte pro Position
- Kommissionierung/Abgang -> Chargenzuordnung in
sales_order_line_lot_allocation
Webhook-Regeln fuer Schritt 1 (Online-Shop):
- Upsert erfolgt ueber
sales_order.external_ref = BestellungNr. - Zahlungsstatus aus Online-Bestellung wird intern standardmaessig als
paidgespeichert. - Rechnungsadresse darf leer sein; Lieferadresse wird normal erfasst.
- Adressen speichern Klarname (
country_name) und ISO-Code (country_iso2) parallel. - Adressdaten werden nur gespeichert, nicht serverseitig validiert (Validierung erfolgt im Shop).
Direktverkauf-Regeln fuer Schritt 1:
- Direktverkaeufe werden im ERP erfasst (
sales_order.order_source = direct) und kommen nicht ueber n8n-Webhook. - Die Bestellnummer wird im ERP erzeugt und hat den Praefix
DIR-(z. B.DIR-20260329-00017). sales_order.party_idist optional; bei Laufkundschaft wird kein individueller Kontakt angelegt.- Positionen werden als Sammelverkauf mit Mengen je Produkt erfasst.
- Der brutto Gesamtpreis kann auf Flaschenebene verteilt werden (Durchschnittspreis = Gesamtpreis / Gesamtmenge).
- Zahlungsart wird explizit gespeichert (z. B.
twint,cash,paypal,bank_transfer).
Lagerregeln fuer Schritt 1:
- Pro Produkt existiert operativ genau eine
current-Charge und genau eineopen-Charge. opendarf nicht fehlen; sie ist der direkte Ueberlauf fuer den naechsten operativen Entnahmefall.- Statusfluss fuer Chargen:
open -> current -> closed. - Bei Erreichen von
qty_net <= 0auf dercurrent-Charge erfolgt automatischer Wechsel auf die vorhandeneopen-Charge. - Nach dem Wechsel wird automatisch wieder eine neue
open-Charge erzeugt (lot_number bleibt initial leer bis manuell gesetzt). - Negative Chargenbestaende sind nicht zulaessig.
- Chargensalden (
in/out/net) werden aus Bewegungen berechnet. - Jede Verkaufsbewegung muss einer Charge zugeordnet sein (kein chargenloser Abgang).
- Verkaufsbuchung erfolgt standardmaessig gegen die
current-Charge. - Korrekturen bleiben durch editierbare Datensaetze und/oder Korrekturbewegungen moeglich.
- Abverkaufdatum wird systemintern berechnet; Warnstatus wird fuer UI bereitgestellt (ohne E-Mail-Prozess in Phase 1).
Milestones
Schritt 1 wird in drei Modulpakete umgesetzt:
- M1 Kontaktmodul: Datenmodell, API/Service, Basisspeicherung
- M2 Bestellmodul: Bestellung + Positionen + optionale Kontaktverknuepfung + Upsert
- 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:
- Eine Bestellung kann mit Kunden-/Lieferkontakt oder als Direktverkauf ohne Kontakt erfasst werden.
- Positionen koennen einer oder mehreren Chargen zugeordnet werden.
- Lagerzugaenge/-abgaenge aktualisieren Bestand pro Charge konsistent.
- Rueckverfolgung Bestellung <-> Charge <-> Lagerbewegung ist technisch vorhanden.
Entscheidungen Fuer Umsetzung
- Eindeutige Bestellidentifikation ueber
sales_order.external_ref(Shop:BestellungNr, Direktverkauf:DIR-...); Dateneingang via Upsert. - Rechnungsadresse ist optional (
NULLzulaessig), Lieferadresse wird separat gespeichert. - Interne Normalisierung von Zahlungs- und Liefermethoden ueber Mapping-Tabellen.
- Land wird als Klarname und ISO-Code gespeichert.
- Initial keine serverseitige Adressvalidierung.
- Keine Buchhaltungs-/Rechnungsfunktion in Schritt 1.
- Chargenrueckverfolgung wird ueber explizite Bestellpositions-Allokation aufgebaut.
- Lagerbetrieb mit genau einer aktiven und einer vorbereiteten Charge pro Produkt (
current+open). - Storno-Fall wird im Modell vorbereitet (Status
cancelled+ Freigabe von Reservierungen). - Chargennummer fuer neu vorbereitete Charge wird initial manuell durch Mitarbeitende gesetzt.
- Abverkaufprognose und Warnlogik werden in die ERP-Datenbank uebernommen; E-Mail-Erinnerungen sind in Phase 1 deaktiviert.