# Datenprodukt beschreiben

Das Datenprodukt hinter den Kontrakten mit ODPS beschreiben.

Source: https://learn.datacontract.com/de/data-product/

Deine Datenkontrakte beschreiben die *Schnittstelle* deiner Daten: Tabellen, Typen, Qualitätsregeln.
Consumer wollen mehr wissen: *Wofür sind die Daten gedacht? Wem gehören sie? Welche Versionen gibt es, und welche sollte ich nutzen?*
Das beschreibt das **Datenprodukt**, mit dem [Open Data Product Standard](https://bitol-io.github.io/open-data-product-standard/latest/) (ODPS).

**You will learn:**
- Den Unterschied zwischen Datenprodukt und Datenkontrakt verstehen
- Das Datenprodukt Orders mit ODPS 1.1 beschreiben, inklusive Typ und Output-Ports
- Die Beschreibung mit der Data Product CLI validieren

> **Datenprodukt vs. Datenkontrakt**
>
> Ein **Datenprodukt** sind Daten, die ein Team verantwortet und anderen *als Produkt* anbietet: mit Zweck, Owner, Support und Lebenszyklus.
> Es stellt seine Daten über **Output-Ports** bereit, jeder beschrieben durch einen **Datenkontrakt**.
>
> Es gibt **ein** Datenprodukt Orders, obwohl es **zwei** Kontraktversionen anbietet (`orders_v1` und `orders_v2`).
> Das Produkt ist die stabile Einheit der Verantwortung. Seine Ports und Kontrakte entwickeln sich weiter.

_Scenario: the Orders data product (output ports orders_v1 and orders_v2) is consumed by the SKU Sales data product, which the purchasing team uses._

## Das Datenprodukt erstellen

### Die Datei anlegen

Die Data Product CLI legt eine Startdatei an:

macOS / Linux:

```bash
dataproduct init orders.odps.yaml
```

Windows (PowerShell):

```powershell
dataproduct init orders.odps.yaml
```

Output:

```text
📄 data product written to orders.odps.yaml
```

Öffne `orders.odps.yaml` in deiner IDE. Sie enthält Platzhalter und auskommentierte Abschnitte.
Ersetze den oberen Teil durch die Grunddaten deines Orders-Produkts:

```yaml
apiVersion: v1.1.0
kind: DataProduct
id: orders
name: Orders
version: 1.0.0 # die Version des Datenprodukts, unabhängig von den Kontraktversionen
status: active
type: sourceAligned
domain: ecommerce
description:
  purpose: # wofür ist dieses Datenprodukt gedacht?
  limitations: # was sollten Consumer vor der Nutzung wissen?
```

Ersetze die Kommentare bei `purpose` und `limitations` durch echten Text: Was muss ein Consumer wissen, bevor er Zugriff beantragt?

> **Typen von Datenprodukten (neu in ODPS 1.1)**
>
> `type` sagt Consumern, wie ein Produkt ausgerichtet ist:
>
> - **`sourceAligned`**: stellt Daten nah an einem operativen System bereit, wie Orders
> - **`aggregate`**: kombiniert mehrere Quellen
> - **`consumerAligned`**: für einen konkreten Anwendungsfall gebaut, wie das Produkt SKU Sales in [Teil B](https://learn.datacontract.com/de/contract-first/)

### Die Output-Ports ergänzen

Ergänze pro Datenkontrakt einen **Output-Port**. Die `contractId` muss der `id` des Kontrakts entsprechen:

```yaml
outputPorts:
  - name: orders_v1
    description: Orders and line items tables in PostgreSQL (v1, superseded by v2)
    deprecated: true
    version: 1.0.0
    contractId: orders_v1
  - name: orders_v2
    description: # ...
    version: 2.0.0
    contractId: orders_v2
```

Schreib die Beschreibung für `orders_v2` selbst. Entferne den Beispiel-Port von `dataproduct init`.

`deprecated: true` (neu in ODPS 1.1) markiert den Port `orders_v1` als nicht mehr empfohlen. Er bleibt für bestehende Consumer dokumentiert, neue Consumer wählen `orders_v2`.

### Team und Support ergänzen

Ergänze `team` und `support`. Übernimm, was du in deinen Kontrakten definiert hast:

```yaml
team:
  name: order_data_team
  members:
    - username: owner@example.com
      role: Owner

support:
  - channel: "#order-data-help"
    url: https://example.slack.com/archives/order-data-help
    tool: slack
```

## Validieren

### Das Datenprodukt linten

Validiere gegen das offizielle ODPS-JSON-Schema:

macOS / Linux:

```bash
dataproduct lint orders.odps.yaml
```

Windows (PowerShell):

```powershell
dataproduct lint orders.odps.yaml
```

Output:

```text
✅ Data product is valid against ODPS v1.1.0
🟢 Data product is valid.
```

Lass es einmal fehlschlagen: Ändere `kind: DataProduct` in `kind: DataProdukt` und linte erneut:

macOS / Linux:

```bash
dataproduct lint orders.odps.yaml
```

Windows (PowerShell):

```powershell
dataproduct lint orders.odps.yaml
```

Output:

```text
❌ Check that data product is valid against ODPS v1.1.0: kind: 'DataProdukt' is not one of
['DataProduct']
🔴 Data product is invalid.
```

Die CLI nennt das falsche Feld und endet mit Exit-Code `1`. Mach es danach rückgängig.

**Solution: orders.odps.yaml**

```yaml title=orders.odps.yaml
apiVersion: v1.1.0
kind: DataProduct
id: orders
name: Orders
version: 1.0.0
status: active
type: sourceAligned
domain: ecommerce
description:
  purpose: Source-aligned data product exposing orders and line items from the e-commerce platform.
  limitations: Contains PII (customer email addresses). Access requires approval by the Order Data Team.
tags: ['orders', 'ecommerce']
outputPorts:
- name: orders_v1
  description: Orders and line items tables in PostgreSQL (v1, superseded by v2)
  deprecated: true
  version: 1.0.0
  contractId: orders_v1
- name: orders_v2
  description: Orders and line items tables in PostgreSQL, including quantity (v2)
  version: 2.0.0
  contractId: orders_v2
team:
  name: order_data_team
  members:
  - username: owner@example.com
    role: Owner
support:
- channel: "#order-data-help"
  url: https://example.slack.com/archives/order-data-help
  tool: slack
```

> **Lint vs. Test**
>
> `dataproduct lint` prüft, ob die Datei laut Standard *wohlgeformt* ist. Es verbindet sich mit keiner Datenbank.
> Ob die Daten hinter einem Output-Port ihr Versprechen halten, prüft `datacontract test` am Kontrakt.

**Quick check:** Dein Orders-Produkt veröffentlicht nächstes Jahr orders_v3. Was ändert sich in orders.odps.yaml?

- Du legst ein neues Datenprodukt orders_v3 an
- Du ergänzt einen Output-Port, der auf den Kontrakt orders_v3 verweist (correct)
- Nichts, das Datenprodukt verweist nicht auf Kontrakte
- Du ersetzt den Port orders_v2 sofort durch orders_v3

Das Datenprodukt bleibt dasselbe. Eine neue Kontraktversion wird zu einem neuen Output-Port, alte Ports werden erst deprecated und später entfernt, wenn ihre Kontrakte retired sind.

## Bonus

- `orders_v1` ist `retired`. Sollte sein als deprecated markierter Output-Port in der Produktbeschreibung bleiben oder entfernt werden? Wäge Transparenz für bestehende Consumer gegen einen aufgeräumten Katalog ab.
- ODPS 1.1 kennt wie ODCS 3.2 einen `context`-Block für KI-Agenten, auf Produkt- und Output-Port-Ebene. Ergänze `instructions`, die einem Agenten sagen, welchen Port er nutzen soll.
- Ergänze `tags` am Datenprodukt, z. B. `['orders', 'ecommerce']`, und linte erneut.
