Files
erp_naurua/docs/SPEC_PHASE1_COMPONENTS.md

265 lines
8.9 KiB
Markdown

# Phase 1 Component Specification
## Dokumentstatus
1. Typ: `operational`
2. Zweck: verbindliche Umsetzungs-Spezifikation fuer Schritt 1 Komponenten
3. Normative Referenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/CONCEPT.md`
4. Abgeleitete Referenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/SCHEMA_PHASE1.sql`
5. Prozessreferenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/docs/PROCESS_PHASE1.md`
6. Implementierungsreferenz: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua/db/migrations/`
## Scope
Diese Spezifikation deckt alle Schritt-1-Komponenten ab:
1. Bestellerfassung
2. Kontakt- und Adressdaten
3. Artikel-Mapping und Stuecklisten
4. Lagerverwaltung mit Chargen, MHD, Zu-/Abgaengen
5. Chargenrueckverfolgung
6. Teil-/Vollstorno
7. Inbound/Outbound Webhooks
8. Audit und technische Guardrails
## Globale Invarianten
1. `sales_order.external_ref` ist eindeutig und dient als Upsert-Schluessel (Shop: `BestellungNr`, Direktverkauf: `DIR-...`).
2. Datensaetze werden nicht geloescht; Statusaenderungen und Audit-Trail werden verwendet.
3. Verkaufsbewegungen sind immer chargengebunden.
4. Negativbestand ist unzulaessig.
5. Pro Produkt existieren exakt eine `current`-Charge und eine `open`-Charge.
6. `open` darf nie fehlen.
7. Zahlungsstatus aus Shop wird intern auf `paid` normalisiert.
8. Direktverkaeufe haben `order_source = direct` und `external_ref` mit `DIR-`-Praefix.
## Komponente 1: Bestellerfassung
### Ziel
Persistente Erfassung von Bestellungen aus Shop und Direktverkauf inkl. Positionen, Summen und Import-/Erfassungsdaten.
### Eingangsquelle
1. n8n Inbound Webhook mit Shop-JSON (`order_source = wix`)
2. Manuelle ERP-Erfassung fuer Direktverkauf (`order_source = direct`)
### Datenregeln
1. Upsert auf `sales_order.external_ref` fuer Shop-Bestellungen.
2. Direktbestellungen erhalten ERP-interne Nummern mit `DIR-`-Praefix.
3. `order_status` initial `imported`.
4. Summenfelder werden direkt gespeichert (`amount_net`, `amount_shipping`, `amount_tax`, `amount_discount`, `total_amount`).
5. `webhook_payload` wird fuer Shop-Rohdaten gespeichert (Nachvollziehbarkeit).
6. Fuer Direktverkauf darf `party_id` leer sein (Laufkundschaft).
### Fehlerverhalten
1. Bei fehlender `BestellungNr`: Import ablehnen, Audit-Log `import_rejected`.
2. Bei unbekanntem Artikelfehler: Bestellung speichern, Position mit Rohdaten speichern, Mapping-Luecke markieren.
### Akzeptanzkriterien
1. Wiederholter Import derselben `BestellungNr` erzeugt kein Duplikat.
2. Direktbestellungen sind ueber den `DIR-`-Praefix eindeutig erkennbar.
3. Positionsdaten bleiben stabil und auditierbar.
## Komponente 2: Kontakt- und Adressdaten
### Ziel
Speicherung von Kundenkontakt, Lieferadresse und optionaler Rechnungsadresse.
### Datenregeln
1. Rechnungsadresse darf vollstaendig `NULL` sein.
2. Lieferadresse wird als eigener Datensatz gespeichert.
3. Land wird immer doppelt gespeichert: `country_name` + `country_iso2`.
4. Keine serverseitige Adressvalidierung in Phase 1.
5. Ausnahmefaelle bei Name/Firma werden unveraendert uebernommen.
6. Bei Direktverkauf ist keine Kontakt-/Adressanlage erforderlich.
### Akzeptanzkriterien
1. Bestellung kann ohne Rechnungsadresse gespeichert werden.
2. Liefer- und Rechnungsadresse sind getrennt auswertbar.
## Komponente 3: Artikel-Mapping und Stuecklisten
### Ziel
Stabile Entkopplung von Shop-Artikeln und lagergefuehrten Produkten.
### Datenmodell
1. `sellable_item`: verkaufbarer Artikel (auch Bundles).
2. `external_item_alias`: Mapping Shop-Artikelnummer/Titel -> `sellable_item`.
3. `sellable_item_component`: Stueckliste `sellable_item` -> `product` mit Menge.
### Aufloesungsreihenfolge
1. Match ueber `external_article_number`.
2. Fallback ueber normalisierten Titel.
3. Wenn beides fehlschlaegt: Position als unmapped speichern und auditieren.
### Akzeptanzkriterien
1. Bundle-Artikel koennen auf mehrere Lagerprodukte aufgeloest werden.
2. Ohne Mapping bleibt Bestellung dennoch erfassbar.
## Komponente 4: Lagerverwaltung und Chargen
### Ziel
Konsistente Bestandsfuehrung je Charge inklusive Auto-Wechsel.
### Statusmodell Charge
1. `open`: vorbereitete Charge
2. `current`: aktive Entnahmecharge
3. `closed`: abgeschlossene Charge
### Lebenszyklus
1. `open -> current -> closed`
2. Wenn `current` auf `qty_net <= 0` faellt:
1. alte `current` wird `closed`
2. vorhandene `open` wird `current`
3. neue `open` wird auto-angelegt
### Feldregeln
1. `lot_number` bei `open` darf leer sein.
2. `lot_number` fuer `current/closed` ist Pflicht.
3. Chargennummer ist pro Produkt eindeutig.
4. Chargensalden werden aus `stock_move` berechnet (`v_stock_lot_balance`).
5. Abverkaufprognose pro aktueller Charge wird im System gepflegt (`sellout_date`, `warning_state`).
### Korrekturregeln
1. Korrekturen erfolgen ueber `adjustment`-Bewegungen.
2. Keine direkten Netto-Setzungen als Betriebsprozess.
### Akzeptanzkriterien
1. Nach jeder Entnahme bleibt die Invariante `1x current + 1x open` erhalten.
2. Negativbestand wird technisch verhindert.
3. Warnstatus fuer UI ist ohne E-Mail nutzbar (`none`, `due_60d`, `due_now`).
## Komponente 5: Chargenrueckverfolgung
### Ziel
Lueckenlose Rueckverfolgung Bestellung -> Position -> Produkt -> Charge -> Lagerbewegung.
### Datenregeln
1. Jede Entnahme schreibt `stock_move` (`move_type = out`) mit `lot_id`.
2. Pro Entnahme wird `sales_order_line_lot_allocation` geschrieben.
3. `allocation_status` in Phase 1 standardmaessig `allocated`.
### Akzeptanzkriterien
1. Fuer jede ausgelieferte Position ist die verwendete Charge abfragbar.
2. Rueckverfolgung funktioniert auch nach Teilstorno.
## Komponente 6: Storno (Teil/Voll)
### Ziel
Revisionssicheres Storno ohne physisches Loeschen.
### Datenregeln
1. Teil- und Vollstorno sind erlaubt.
2. `sales_order_line.qty_cancelled` wird fortgeschrieben.
3. `line_status`: `allocated`, `partially_cancelled`, `cancelled`.
4. Bei Storno von bereits `allocated` Mengen erfolgt Gegenbuchung als `adjustment in` auf dieselbe Charge.
5. Bestellung bleibt erhalten; Statuswechsel statt Delete.
### Akzeptanzkriterien
1. Historische Ursprungs- und Korrekturbewegungen bleiben sichtbar.
2. Vollstorno setzt `sales_order.order_status = cancelled`.
## Komponente 7: Webhooks
### Inbound (n8n -> ERP)
1. Transport: JSON via HTTP.
2. Idempotenzschluessel: `BestellungNr`.
3. Verarbeitung: Upsert Bestellung, Kontakt, Positionen, Lagerabgang, Audit.
4. Quelle wird als `order_source = wix` gespeichert.
### Direkt (ERP intern)
1. Transport: manuelle Erfassung in ERP-Maske.
2. Nummernlogik: ERP erzeugt `external_ref` mit `DIR-`-Praefix.
3. Verarbeitung: Bestellung (optional ohne Kontakt), Positionen, Lagerabgang, Audit.
### Outbound (ERP -> n8n)
1. Transport: Queue-basierter POST ueber `outbound_webhook_event`.
2. Events Phase 1:
1. `order.imported`
2. `order.cancelled.partial`
3. `order.cancelled.full`
4. `lot.auto_switched`
3. Signatur: `X-ERP-Signature` (HMAC-SHA256).
4. Zustellung: Retry mit Backoff; final `dead_letter`.
### Akzeptanzkriterien
1. Event-Zustellung ist idempotent (`event_key` eindeutig).
2. Fehlgeschlagene Events sind operativ auffindbar.
3. Outbound-Payload enthaelt die Quelle (`order_source`), damit `wix` und `direct` getrennt auswertbar sind.
## Komponente 8: Audit und Betriebssicherheit
### Audit
1. Jede fachliche Aenderung schreibt `audit_log`.
2. Pflichtfelder: `entity_name`, `entity_id`, `action`, `changed_at`.
3. Vorher/Nachher-Daten werden als JSON gespeichert, wenn verfuegbar.
### Guardrails
1. Check-Constraints fuer Statuswerte.
2. Check-Constraints fuer Mengenbereiche.
3. Unique-Constraints fuer kritische Eindeutigkeiten.
4. Outbox-Statusmaschine fuer robuste externe Zustellung.
## Komponenten-Matrix
1. `Bestellerfassung`
Zustandsquelle: `sales_order`, `sales_order_line`
Hauptereignisse: `order.imported`, `order.cancelled.*`
2. `Kontakt/Adressen`
Zustandsquelle: `party`, `contact`, `address`
Hauptereignisse: `order.imported`
3. `Artikel-Mapping`
Zustandsquelle: `sellable_item`, `external_item_alias`, `sellable_item_component`
Hauptereignisse: `order.imported`
4. `Lagerverwaltung`
Zustandsquelle: `stock_lot`, `stock_move`, `v_stock_lot_balance`
Hauptereignisse: `order.imported`, `lot.auto_switched`, `order.cancelled.*`
5. `Rueckverfolgung`
Zustandsquelle: `sales_order_line_lot_allocation`
Hauptereignisse: alle Abgaenge und Stornos
6. `Outbound-Integration`
Zustandsquelle: `outbound_webhook_event`
Hauptereignisse: alle publizierten Domain-Events
## Nicht in Phase 1
1. Rechnungswesen, Buchungssaetze, OCR-Verarbeitung.
2. Automatisierte Preis-/Steuerneuberechnung.
3. Vollautomatische Chargennummerngenerierung nach Produktklasse.
## Change Governance
1. Konzeptaenderungen zuerst in `CONCEPT.md`.
2. Prozess- und Betriebsablauf in `PROCESS_PHASE1.md`.
3. Technische Ableitung in `SCHEMA_PHASE1.sql`.
4. Diese Spezifikation synchronisiert alle Komponenten auf Umsetzungsniveau.