# tapinomahub Commerce: Standard und Formate

Status: Konzeptvorschau. Alle Namen dieses öffentlichen Modells gehören tapinomahub und bleiben unabhängig von angebundenen Kanälen und Übertragungswegen stabil.

## Kanonische Fachobjekte

| Objekt | Zweck | Wichtige Identität |
| --- | --- | --- |
| `catalogItem` | beschreibbarer, nicht physischer Artikel | `catalogItemId` |
| `stockItem` | konkrete Verkaufseinheit an einem Lagerort | `stockItemId` |
| `offer` | Veröffentlichung eines Lagerstücks in einem Verkaufskonto | `offerId` |
| `salesOrder` | normalisierter Auftrag | `salesOrderId` plus unveränderliche Eingangsreferenz |
| `shipment` | Versand von Auftragspositionen | `shipmentId` |
| `cancellation` | Voll- oder Teilstorno | `cancellationId` |
| `return` | physische Rückgabe und Prüfung | `returnId` |
| `refund` | finanzielle Voll- oder Teilerstattung | `refundId` |
| `invoice` | unveränderlicher Rechnungsbeleg mit Steuer- und Summenaufschlüsselung | `invoiceId` |
| `creditNote` | referenzierte Voll- oder Teilkorrektur eines Rechnungsbelegs | `creditNoteId` |
| `feeStatement` | Beteiligung, Rabatt und Korrektur | `feeStatementId` |
| `reconciliation` | Soll-Ist-Abgleich mit Vollständigkeitsgrenze | `reconciliationId` |

Ein `catalogItem` kann mehrere konkrete `stockItem`-Objekte beschreiben. Ein `stockItem` kann in mehreren `offer`-Objekten erscheinen, bleibt aber genau eine physische Verkaufseinheit. Jedes `offer` gehört über genau eine `connectionId` zu genau einer Verbindung; dieselbe physische Einheit auf einer zweiten Verbindung erhält ein eigenes `offer`. Ein `salesOrder` referenziert Angebot und Lagerstück auf Positionsebene.

Der erste sichere Pilot modelliert nur einzelne physische Verkaufseinheiten mit einer Auftragsmenge von eins. Bundles und Mengen größer eins sind P1 und bleiben gesperrt, bis Komponenten, Reservierungswirkung, Teilauflösung und Rückabwicklung normativ modelliert und getestet sind.

## Gemeinsame Regeln

- Kennungen sind opake tapinomahub-Werte und werden nie aus Titeln oder externen Kennungen zusammengesetzt.
- Datumswerte sind UTC-Zeitpunkte im ISO-8601-Format.
- Geld verwendet `{ amountMinor, currency }`; `amountMinor` ist ganzzahlig.
- Raten verwenden Basispunkte; `800` entspricht 8 %, `600` entspricht 6 %.
- Jede Mutation verlangt einen Idempotenzschlüssel.
- Revisionierte Änderungen verlangen die erwartete Revision; Konflikte liefern einen stabilen fachlichen Fehler.
- Listen verwenden Cursor-Paginierung.
- Unbekannte Adapterdaten erscheinen weder als frei erfundene Felder noch als ungefilterte Fehlermeldung.

## REST/JSON

REST/JSON steuert Einzelobjekte, Einrichtung, Transfers, Zustandsänderungen und Ereignisabholung. Bulk-Übertragungen werden als asynchroner `catalogTransfer` angelegt:

```text
queued → validating → preview_ready → approved → applying → completed
                   ↘ rejected                    ↘ failed
```

Die Vorschau ist ein eigenes unveränderliches Ergebnis. Eine Freigabe referenziert genau diese Revision; nach einer Datenänderung muss neu validiert werden.

## Katalog-XML

Das XML besitzt einen eigenen tapinomahub-Namensraum und kennt keine kanalabhängigen Tags. Das folgende Snapshot-Beispiel verwendet durchgängig kanonische IDs:

```xml
<commerceTransfer
  xmlns="urn:tapinomahub:commerce:catalog:0.2.0-preview.2"
  transferId="018f3f12-7a64-4ec7-8f41-4f856f155d10"
  contractVersion="0.2.0-preview.2"
  lifecycle="preview"
  mode="snapshot"
  sequence="42"
  createdAt="2026-09-12T12:00:00Z">
  <scope
    connectionId="2e049f1d-171f-45fc-b79c-c78b621fb2de"
    marketAreaReference="mkt_example_de01"
    completeness="full" />
  <counts catalogItems="1" stockItems="1" inventoryBalances="1" offers="1" />
  <catalogItems>
    <catalogItem
      catalogItemId="e5fd89e5-46b1-4e1f-80d4-f1f1acdf8ab6"
      merchantSku="EXAMPLE-001"
      condition="used"
      revision="rev_00000001">
      <title>Neutrales Beispielteil</title>
    </catalogItem>
  </catalogItems>
  <stockItems>
    <stockItem
      stockItemId="95bd7078-6a58-42a1-b60b-36374c639987"
      catalogItemId="e5fd89e5-46b1-4e1f-80d4-f1f1acdf8ab6"
      merchantSku="EXAMPLE-001"
      locationKey="warehouse-01"
      condition="used"
      revision="rev_00000001" />
  </stockItems>
  <inventoryBalances>
    <inventoryBalance
      stockItemId="95bd7078-6a58-42a1-b60b-36374c639987"
      physicalQuantity="1"
      safetyStockQuantity="0"
      revision="rev_00000001" />
  </inventoryBalances>
  <offers>
    <offer
      offerId="6195cb42-700e-40e4-b92f-b5c50aa9aac2"
      stockItemId="95bd7078-6a58-42a1-b60b-36374c639987"
      connectionId="2e049f1d-171f-45fc-b79c-c78b621fb2de"
      pricingPolicyId="2d4e6112-842d-483d-9c7a-76cff6c7561d"
      publicationState="ready"
      revision="rev_00000001">
      <price amountMinor="10000" currency="EUR" />
    </offer>
  </offers>
</commerceTransfer>
```

Das maschinenlesbare [`commerce-transfer-0.2.0-preview.2.xsd`](./schema/commerce-transfer-0.2.0-preview.2.xsd) legt Pflichtfelder, optionale Felder, Datentypen, Kardinalitäten und erlaubte Werte fest. Es ist ausdrücklich eine nicht operative Vorschau; eine spätere Produktionsfreigabe verlangt weiterhin Roundtrip- und Negativtests.

### Snapshot

- beschreibt den vollständigen vereinbarten Scope;
- enthält erwartete Datensatzanzahlen und eine Prüfsumme;
- wird vollständig validiert und danach atomar umgeschaltet;
- löscht fehlende Datensätze nur, wenn der Scope ausdrücklich `full` ist.

### Delta

- nennt Vorgänger- und Zielsequenz;
- unterscheidet `upsert` und `delete` explizit;
- darf erst nach lückenloser Sequenzprüfung angewendet werden;
- ein erneutes Delta mit derselben Transfer-ID ist fachlich idempotent.

## CSV-Paket

CSV ist ein ZIP-Paket und kein einzelnes loses Tabellenblatt:

```text
manifest.json
catalog_items.csv
identifiers.csv
compatibility.csv
media.csv
attributes.csv
stock_items.csv
inventory.csv
offers.csv
```

`manifest.json` enthält Vertragsversion, Preview-Lifecycle, Modus, Sequenz, Scope, CSV-Dialekt, Dateinamen, Zeilen- und Byteanzahlen sowie Prüfsummen. Jede CSV-Datei besitzt genau eine Kopfzeile und verwendet stabile IDs für Beziehungen. Ein `offer` enthält genau eine `connectionId`. Mehrfachwerte werden in Beziehungstabellen abgebildet, nicht als uneindeutige Listen in einer Zelle.

Die maschinenlesbaren Verträge sind:

- [`csv-columns-0.2.0-preview.2.json`](./schema/csv-columns-0.2.0-preview.2.json) für Dateien, Spalten, Schlüssel, Referenzen sowie Pflicht- und optionale Werte;
- [`csv-manifest-0.2.0-preview.2.schema.json`](./schema/csv-manifest-0.2.0-preview.2.schema.json) für die Manifestvalidierung;
- [`manifest.example.json`](./schema/manifest.example.json) als neutrales, nicht produktives Beispiel.

CSV wird in UTF-8 geschrieben. Der Dialekt verwendet eine Kopfzeile, Komma als Trennzeichen, doppelte Anführungszeichen mit Verdopplung als Escape und CRLF als Datensatztrenner nach RFC-4180-Art. Leser dürfen LF akzeptieren. Optionale Werte werden als leeres Feld dargestellt; leere Pflichtwerte, zusätzliche Spalten, fehlende Kopfspalten und Leerzeilen werden abgelehnt.

CSV dient Katalog- und Bestandsübertragungen sowie unveränderlichen Exporten. Zeitkritische Auftrags-, Reservierungs- und Erstattungsänderungen laufen primär über REST und Ereignisse.

## Verlustfreier Roundtrip

Die Freigabe setzt für jedes kanonische Feld folgende automatisierte Prüfung voraus:

```text
JSON → XML → JSON
JSON → CSV-Paket → JSON
XML → JSON → XML (kanonisiert)
CSV-Paket → JSON → CSV-Paket (kanonisiert)
```

Reihenfolge, Whitespace und Dateiaufteilung dürfen kanonisiert werden; fachliche Werte, Identitäten, Null-Semantik und Geldbeträge müssen identisch bleiben. Ein Adapter darf Daten nur verlieren, wenn seine Fähigkeitsmatrix dies vor dem Transfer sichtbar als nicht unterstützt ausweist und der Verkäufer die Konsequenz bestätigt.

## Versionierung

- additive kompatible Felder: neue Minor-Version;
- semantische Änderung, Entfernung oder engerer Enum: neue Major-Version;
- jeder Transfer nennt die verwendete Vertragsversion;
- mindestens eine angekündigte Übergangsphase und ein maschinenlesbarer Migrationshinweis;
- Adapterversion und öffentlicher Standard werden getrennt geführt.
