# Katalog

> Lieferanten, Produkte und eigene Zubereitungen: die Referenzlisten, auf die der Rest der Datensätze zeigt.

Source: https://developers.backresto.com/de/docs/catalogue

Der Katalog ist das, wovon ein Restaurant eine Liste führt, statt es zu messen:
wer liefert, was durch die Tür kommt und was die Küche selbst macht. Nichts hier
ist eine Kontrolle oder eine Messung. Das sind die Zeilen, die alles andere
benennt, sie sind also meist das Erste, was Sie laden, und das Letzte, was sich
ändert.

| Collection | Scope | Was ein Datensatz ist |
| --- | --- | --- |
| `suppliers` | `suppliers:read` | Ein Unternehmen, das liefert, und wie man es erreicht. |
| `products` | `products:read` | Etwas, das das Restaurant annimmt und verwendet, mit Namen. |
| `preparations` | `preparations:read` | Etwas, das die Küche macht, mit Haltbarkeit und Allergenen. |

Alle drei teilen sich den [Snapshot-Umschlag](https://developers.backresto.com/de/docs/collections): `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` und der Rest stehen neben dem
`data`, das unten beschrieben ist.

## `suppliers`

Ein Datensatz pro Lieferant, den das Restaurant eingetragen hat, ganz gleich, ob
zuletzt etwas von ihm gekommen ist.

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `name` | string, **Pflicht** | Der Lieferant, so wie das Restaurant ihn nennt. Freitext, kein Handelsregister. |
| `isDeleted` | boolean, **Pflicht** | Das eigene Flag der App für ausgemusterte Einträge. Nicht das `deleted` des Umschlags. Siehe unten. |
| `contactMethods` | object[] | Wie man ihn erreicht. Jeder Eintrag ist `{ "type": string, "value": string }`. |
| `accountNumber` | string \| null | Die Kundennummer des Restaurants bei diesem Lieferanten, sofern eine eingetragen wurde. |

```json
{
  "id": "1f3c2a76-5b94-4b0e-9c1a-6d8f0a2e7b31",
  "collection": "suppliers",
  "deleted": false,
  "capturedAt": "1789431600214",
  "receivedAt": "1789431604771",
  "sequence": "412",
  "data": {
    "name": "Metro Nanterre",
    "isDeleted": false,
    "contactMethods": [
      { "type": "phone", "value": "+33 1 41 20 30 40" },
      { "type": "email", "value": "commandes@example.test" }
    ],
    "accountNumber": "FR-884213"
  }
}
```

**`contactMethods[].type` ist kein Enum.** Das Schema sagt string und hört auf,
und die Werte oben sind eine Veranschaulichung, keine Liste. Sehen Sie beim
Verzweigen immer einen Standardfall vor und zeigen Sie den `value`, wie auch
immer der `type` geschrieben ist.

Eine [Lieferung](https://developers.backresto.com/de/docs/deliveries) verweist über `supplierDeliveriesId` auf
ihren Lieferanten, die `id` eines Datensatzes in dieser Collection. Der Name, die
Kundennummer und die Telefonnummer stehen alle hier.

## `products`

Was das Restaurant annimmt und verwendet. Der Datensatz ist so dünn, wie er
aussieht.

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `name` | string, **Pflicht** | Das Produkt, so wie das Restaurant es benannt hat. |
| `isDeleted` | boolean, **Pflicht** | Das Flag der App für ausgemusterte Einträge. Siehe unten. |

```json
{
  "id": "6b0d4ea2-91c7-4f3d-a0be-2c5f7d1e8a44",
  "collection": "products",
  "deleted": false,
  "capturedAt": "1789431980551",
  "receivedAt": "1789432001903",
  "sequence": "413",
  "data": {
    "name": "Beurre doux 250 g",
    "isDeleted": false
  }
}
```

Das ist der ganze Datensatz: keine Referenz, keine Kategorie, keine Einheit,
kein Lieferant. Wenn Ihr Modell etwas davon braucht, halten Sie es selbst, mit
der `id` des Umschlags als Schlüssel.

**Nichts sonst zeigt über eine Kennung auf ein Produkt.** Eine Lieferung erfasst
das Gemessene als `temperatureRecords[].product`, Freitext, während der
Kontrolle getippt (siehe [Lieferungen](https://developers.backresto.com/de/docs/deliveries)). Das mit dieser Liste
abzugleichen ist String-Abgleich auf Ihrer Seite, und „Beurre doux 250 g“ ist
nicht „beurre doux“. Tun Sie es, wenn es sein muss, aber geben Sie das Ergebnis
nicht als Join aus.

## `preparations`

Etwas, das im Haus gemacht wird, statt angenommen zu werden: eine Sauce, ein
Fond, eine Terrine.

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `name` | string, **Pflicht** | Die Zubereitung, so wie die Küche sie nennt. |
| `lifespan` | number, **Pflicht** | Wie lange sie hält. Eine nackte Zahl. |
| `allergens` | string[] | Was sie enthält. Freie Strings, keine geschlossene Menge. |
| `isDeleted` | boolean, **Pflicht** | Das Flag der App für ausgemusterte Einträge. Siehe unten. |

```json
{
  "id": "c47e8b13-0a52-4d96-8f1b-73ae2905cd6f",
  "collection": "preparations",
  "deleted": false,
  "capturedAt": "1789455120087",
  "receivedAt": "1789455133642",
  "sequence": "418",
  "data": {
    "name": "Sauce béarnaise",
    "lifespan": 3,
    "allergens": ["oeuf", "lait"],
    "isDeleted": false
  }
}
```

**`lifespan` trägt keine Einheit.** Das Schema gibt Ihnen eine Zahl und nichts,
womit Sie sie deuten könnten. Drucken Sie nicht „3 Tage“, weil drei nach Tagen
aussieht. Klären Sie, was die App für das Restaurant damit meint, das Sie
lesen, und schreiben Sie es klar dazu, wenn Sie es nicht klären können.

**`allergens` ist eine Liste von Strings, keine Liste aus einer Verordnung.**
Die Einträge kommen aus der App, in der Sprache des Restaurants. Bilden Sie sie
nicht auf die vierzehn benannten Allergene ab, ohne zu prüfen, was die Strings
tatsächlich sagen, und behandeln Sie ein leeres Array nicht als bestandene
Allergenprüfung: Es heißt auch, dass niemand es ausgefüllt hat.

## `isDeleted` ist nicht `deleted`

Jede Collection auf dieser Seite trägt beides, sie bedeuten Verschiedenes, und
wer nur auf eines davon filtert, bekommt eine falsche Liste.

- **`deleted`, auf dem Umschlag**, ist der Tombstone der Schattenkopie. `true`
  heißt, dass der Datensatz in der App gelöscht wurde und `data` weg ist. So
  erfahren Sie, dass etwas verschwunden ist. [Die Seite zum
  Umschlag](https://developers.backresto.com/de/docs/collections) hat die Regeln.
- **`isDeleted`, innerhalb von `data`**, ist das eigene Soft-Delete-Flag der App
  auf dieser Zeile. Der Datensatz ist weiterhin da, hat weiterhin seinen Namen
  und kommt weiterhin mit `deleted: false` an. Das Restaurant hat ihn
  ausgemustert: Es bietet ihn in Auswahllisten nicht mehr an und hat ihn
  behalten, damit alte Datensätze sich weiterhin auflösen lassen.

Filtern Sie also auf beides. Werten Sie nur `deleted` aus, dann füllt sich Ihre
Lieferantenliste mit Lieferanten, die das Restaurant vor zwei Jahren fallen
gelassen hat. Werten Sie nur `isDeleted` aus, dann behalten Sie Zeilen, die ganz
gelöscht wurden, denn ein Tombstone hat kein `data`, aus dem sich das Flag lesen
ließe.

Behalten Sie die ausgemusterten Zeilen trotzdem, statt sie wegzuwerfen. Eine
Lieferung vom vergangenen März verweist weiterhin auf einen Lieferanten, der
heute `isDeleted: true` ist, und diese Kennung in einen Namen aufzulösen ist der
ganze Grund, aus dem
Sie diese Liste halten.

## Den Katalog lesen

Diese drei sind klein, ändern sich langsam und werden von fast allem anderen
gebraucht; das macht sie zum billigen Teil eines Abgleichs und zu dem Teil, bei
dem man leicht unauffällig danebenliegt.

- **Durchlaufen Sie sie zuerst, behalten Sie sie, frischen Sie sie nach Plan
  auf.** Der ganze Katalog eines Restaurants sind bei `limit=100` eine Handvoll
  Seiten. Halten Sie ihn in Ihrem eigenen Speicher, mit der `id` des Umschlags
  als Schlüssel, und lösen Sie Namen von dort auf, statt pro Datensatz
  abzurufen.
- **Namen ändern sich, Kennungen nicht.** `name` ist Freitext, den das
  Restaurant während des Betriebs bearbeitet. Speichern Sie die `id` als Ihren
  Schlüssel und behandeln Sie den Namen als Beschriftung, die Sie auffrischen,
  und niemals als etwas, worüber Sie verbinden.
- **Auch hier ist Abwesenheit mehrdeutig.** Ein Lieferant, der nicht auftaucht,
  wurde vielleicht nie eingetragen oder hat uns noch nicht erreicht. Lesen Sie
  [die Anmerkung dazu](https://developers.backresto.com/de/docs/collections), bevor Sie eine Anzahl melden.
