# 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`. 11. `payment_method` und `shipping_method` - Zweck: Normalisierte interne Werte fuer Zahlungs- und Lieferart. - Kernfelder: `id`, `code`, `label`, `is_active`. 12. `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`. 13. `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`. 14. `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`. 15. `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`. 16. `audit_log` - Zweck: Standardisierte Historisierung von Importen und Aenderungen. - Kernfelder: `id`, `entity_name`, `entity_id`, `action`, `changed_at`, `before_data`, `after_data`. 17. `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) ```mermaid 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.