Files
erp_naurua/docs/konzepte/phase1-technisches-konzept.md
T

10 KiB

Phase 1: DEV-Ist-Stand Tabellen- und Prozesskonzept

Stand: 2026-06-02 Status: Verbindlicher DEV-Ist-Stand fuer Phase 1

1. Uebersicht

Dieses Dokument beschreibt die technische Wahrheit des aktuellen DEV-Standes auf Basis von:

  • docs/CONCEPT.md
  • docs/SCHEMA_PHASE1.sql
  • docs/PROCESS_PHASE1.md
  • db/migrations/0001_phase1_core.sql bis db/migrations/0006_phase1_otc_products.sql
  • order-import.php
  • n8n/exports/current/*.json

Wichtige Einordnung:

  • SCHEMA_PHASE1.sql bleibt ein Draft und ist nicht identisch mit der live DB.
  • Die live DB hat 18 Base Tables und 1 View.
  • Die Forecast-Erweiterung aus 0003_phase1_inventory_forecast.sql ist im live Schema nicht aktiv.
  • Die Doku unten trennt deshalb zwischen implementiertem Ist-Stand und nicht gefundenen Zielbild-Teilen.

Tabellen:

  • party
  • address
  • contact
  • product
  • sellable_item
  • external_item_alias
  • sellable_item_component
  • warehouse
  • location
  • stock_lot
  • payment_method
  • shipping_method
  • sales_order
  • sales_order_line
  • stock_move
  • sales_order_line_lot_allocation
  • audit_log
  • outbound_webhook_event

View:

  • v_stock_lot_balance

Prozesse:

  • n8n.bestell-eingang-online-shop
  • order-import.php
  • db.trigger.sales_order
  • db.trigger.sales_order_line
  • db.trigger.stock_move
  • db.trigger.product
  • n8n.adressetikette-erstellen
  • Outbox-Ablage ueber outbound_webhook_event

2. Zweck

Dieses Dokument beschreibt die aktuelle DB- und Prozesswahrheit fuer Phase 1 auf dem DEV-Stand.

Es ist eine technische Uebersicht fuer Analyse, Umsetzung und Review.

Nicht Bestandteil dieses Dokuments sind:

  • API-Details
  • UI-Details
  • Migrations-Rollout-Planung
  • offene Zielbilddiskussionen ausserhalb des aktuellen DEV-Standes

3. Normatives Datenmodell

3.1 party

Zweck:

  • gemeinsamer Kontaktstamm fuer Kunden und Lieferanten

Ist-Stand:

  • type ist customer, supplier oder both
  • status ist active oder inactive
  • email wird fuer Match/Upsert genutzt

3.2 address

Zweck:

  • Rechnungs- und Lieferadressen pro party

Ist-Stand:

  • type ist billing oder shipping
  • raw_payload speichert die Rohdaten des Eingangsdokuments

3.3 contact

Zweck:

  • zusaetzliche Ansprechpartnerdaten pro party

Ist-Stand:

  • keine weitere Prozesslogik im Code gefunden

3.4 product

Zweck:

  • lagergefuehrtes Produkt mit Bestand und Charge

Ist-Stand:

  • sku ist eindeutig
  • beim Insert erzeugt der Trigger trg_product_bootstrap_lots sofort eine current- und eine open-Charge

3.5 sellable_item

Zweck:

  • verkaufbarer Shop-Artikel

Ist-Stand:

  • Bestellungen referenzieren zuerst sellable_item
  • der Import kann neue sellable_item-Datensaetze automatisch erzeugen

3.6 external_item_alias

Zweck:

  • Mapping externer Shop-Daten auf sellable_item

Ist-Stand:

  • source_system = 'wix'
  • Aufloesung ueber Artikelnummer, normalisierten Titel oder Originaltitel

3.7 sellable_item_component

Zweck:

  • Stueckliste eines sellable_item auf lagergefuehrte Produkte

Ist-Stand:

  • qty_per_item > 0
  • wird vom Import und von Seed-Skripten gepflegt

3.8 warehouse

Zweck:

  • oberer Lagerstandort

Ist-Stand:

  • im Seed ist ein Hauptlager vorgesehen

3.9 location

Zweck:

  • konkreter Lagerort innerhalb eines warehouse

Ist-Stand:

  • type ist storage, receiving, dispatch oder adjustment

3.10 stock_lot

Zweck:

  • Charge eines Produkts

Ist-Stand:

  • status ist open, current oder closed
  • pro Produkt sind current und open per Unique Index abgesichert
  • die live DB hat keine sellout_date- oder warning_state-Spalten
  • die Sicht v_stock_lot_balance ist die Bestandswahrheit

3.11 payment_method

Zweck:

  • normalisierte Zahlungsart

Ist-Stand:

  • Seed-Werte im DEV: card, twint, bank_transfer, cash, paypal

3.12 shipping_method

Zweck:

  • normalisierte Versandart

Ist-Stand:

  • Seed-Werte im DEV: post_standard, pickup

3.13 sales_order

Zweck:

  • Bestellkopf fuer Online-Import und Direktverkauf

Ist-Stand:

  • external_ref ist eindeutig
  • order_source ist wix oder direct
  • party_id ist nullable
  • payment_status ist faktisch auf paid beschraenkt
  • shipping_date existiert im live Schema und wird per Trigger berechnet, falls leer

3.14 sales_order_line

Zweck:

  • Bestellposition

Ist-Stand:

  • qty_cancelled und line_status werden per Trigger synchronisiert
  • sellable_item_id kann NULL sein

3.15 stock_move

Zweck:

  • Bewegungsjournal fuer Zu- und Abgaenge

Ist-Stand:

  • move_type ist in, out, transfer oder adjustment
  • Bewegungen werden vor Insert/Update gegen Negativbestand validiert

3.16 sales_order_line_lot_allocation

Zweck:

  • explizite Rueckverfolgung zwischen Bestellposition und Charge

Ist-Stand:

  • allocation_status ist reserved, allocated, released oder cancelled
  • im Import wird allocated verwendet

3.17 audit_log

Zweck:

  • technische Historisierung

Ist-Stand:

  • im Schema vorhanden
  • im geprüften PHP- und n8n-Flow nicht als zentraler Pflichtpfad sichtbar

3.18 outbound_webhook_event

Zweck:

  • Outbox fuer ERP-Events

Ist-Stand:

  • Spalten: event_type, event_key, aggregate_type, aggregate_id, payload, status, attempt_count, next_attempt_at, last_attempt_at, last_error, created_at, sent_at
  • fn_enqueue_event(...) schreibt idempotent in diese Tabelle
  • ein Dispatcher/Worker fuer die Auslieferung wurde im geprüften DEV-Baum nicht gefunden

3.19 v_stock_lot_balance

Zweck:

  • berechneter Chargensaldo

Ist-Stand:

  • die Sicht ermittelt qty_in, qty_out und qty_net
  • sie ist die Grundlage fuer Bestandspruefung und Auto-Switch

4. Normatives Prozessmodell

Alle Prozesse gehoeren fachlich zur Phase-1-Bestell-, Lager- und Integrationslogik.

4.1 n8n.bestell-eingang-online-shop

Fachliche Aufgabe:

  • E-Mail auf Neue Bestellung erkennen
  • Payload in ERP-JSON umformen
  • JSON per HTTP POST an order-import.php senden

Liest:

  • IMAP-Eingang
  • n8n-Extraktionslogik

Schreibt:

  • keine DB direkt

Fachliche Wirkung:

  • n8n ist hier nur die Integrationshuelle fuer den ERP-Import

4.2 order-import.php

Fachliche Aufgabe:

  • eingehende Bestelldaten idempotent in die ERP-DB schreiben
  • Kontakte, Adressen, Bestellkopf, Positionen und Chargenrueckverfolgung aufbauen
  • bei Reimport vorhandene Allokationen zurueckbuchen
  • nach Commit die Label- und Excel-Flows direkt anstossen

Liest:

  • .env
  • eingehendes Webhook-JSON
  • party, address, sales_order, sales_order_line
  • external_item_alias
  • sellable_item_component
  • stock_lot
  • v_stock_lot_balance

Schreibt:

  • party
  • address
  • sales_order
  • sales_order_line
  • sellable_item
  • external_item_alias
  • sellable_item_component
  • warehouse
  • location
  • stock_lot
  • stock_move
  • sales_order_line_lot_allocation

Fachliche Wirkung:

  • die Bestellung wird im ERP gespeichert und mit Lagerbewegung verknuepft
  • vorhandene Allokationen derselben external_ref werden vor dem Neuimport rueckwaerts gebucht
  • nach erfolgreichem Commit werden Label- und Excel-N8N-Flows direkt per HTTP ausgelöst

4.3 db.trigger.sales_order

Fachliche Aufgabe:

  • shipping_date aus order_date ableiten
  • order.imported und order.cancelled.full in die Outbox schreiben
  • direct-Bestellungen automatisch mit DIR-... Nummer versehen

Liest:

  • sales_order
  • fn_next_business_day(timestamp)

Schreibt:

  • sales_order.shipping_date
  • outbound_webhook_event

Fachliche Wirkung:

  • fehlendes shipping_date wird auf den naechsten Werktag gesetzt
  • neue Auftraege und Vollstornos werden als Event in die Outbox gelegt
  • direkte Auftraege erhalten bei leerer Nummer automatisch einen DIR-...-Ref

4.4 db.trigger.sales_order_line

Fachliche Aufgabe:

  • line_status aus qty_cancelled ableiten
  • Partial-Cancel-Event enqueuen

Liest:

  • sales_order_line

Schreibt:

  • sales_order_line.line_status
  • outbound_webhook_event

Fachliche Wirkung:

  • allocated, partially_cancelled und cancelled werden deterministisch gesetzt
  • ein Wechsel auf partially_cancelled erzeugt ein order.cancelled.partial-Event

4.5 db.trigger.stock_move

Fachliche Aufgabe:

  • Negativbestand verhindern
  • Chargenwechsel bei leerer current-Charge ausloesen

Liest:

  • stock_move
  • stock_lot
  • v_stock_lot_balance

Schreibt:

  • stock_lot
  • outbound_webhook_event

Fachliche Wirkung:

  • out-Bewegungen sind nur auf current-Chargen erlaubt
  • bei qty_net <= 0 wird die naechste open-Charge current
  • danach wird wieder eine neue open-Charge angelegt

4.6 db.trigger.product

Fachliche Aufgabe:

  • neue Produkte sofort chargenfaehig machen

Liest:

  • product

Schreibt:

  • stock_lot

Fachliche Wirkung:

  • jedes neue Produkt bekommt direkt eine current- und eine open-Charge

4.7 n8n.adressetikette-erstellen

Fachliche Aufgabe:

  • Lieferadresse entgegennehmen
  • Felder normalisieren
  • HTML/CSS in PDF/PNG umsetzen
  • Ergebnis per SFTP hochladen

Liest:

  • Webhook-Input
  • Gotenberg / pdf2png / SFTP-Ziele

Schreibt:

  • keine ERP-DB

Fachliche Wirkung:

  • eigenstaendiger Ausgabekanal fuer Versandetiketten

4.8 Outbox-Ablage ueber outbound_webhook_event

Fachliche Aufgabe:

  • Eventdaten fuer spaetere Auslieferung sammeln

Liest:

  • fn_enqueue_event

Schreibt:

  • outbound_webhook_event

Fachliche Wirkung:

  • Queue wird im geprüften DEV-Stand befuellt
  • ein dazugehoeriger Dispatcher/Worker wurde im Code nicht gefunden

5. Technische Einbettung

Die reale Phase-1-Logik bildet einen kleinen operativen Kern mit vier Schwerpunkten:

  1. Kontakt- und Adressstamm
  2. Bestellimport via n8n -> PHP -> DB
  3. Chargen- und Lagerbewegung mit Trigger-Logik
  4. Label-Generierung als separater n8n-Ausgang

Wichtige Abweichungen zum alten Zielbild:

  • Sellout-Forecast ist im live Schema nicht aktiv.
  • Ein Dispatcher fuer outbound_webhook_event wurde im geprüften DEV-Baum nicht gefunden.
  • Eine separate Direct-Sale-Eingabestrecke wurde im geprüften DEV-Baum nicht gefunden; vorhanden ist nur die DB-/Trigger-Unterstuetzung fuer order_source = direct.

6. Kurzfazit

Die aktuelle technische Wahrheit von Phase 1 ist auf Nachvollziehbarkeit und direkte Integrationspfade ausgerichtet:

  • Bestellungen werden idempotent gespeichert
  • Lagerbestand wird ueber Chargen und Bewegungen abgebildet
  • Rueckverfolgung erfolgt ueber explizite Allokationen
  • n8n importiert und erzeugt Labels direkt
  • Outbox-Events werden geschrieben, aber ein Dispatcher ist im geprüften DEV-Stand nicht vorhanden