Files
HamHam/docs/IMPORT.md

94 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Importformat HamHam v1
## Ablauf
Administration → Importieren → JSON/XML auswählen → Datei hochladen oder Text einfügen → Vorschau prüfen → Import bestätigen. Maximal 2 MB und 100 Rezepte pro Vorgang. Kein Datensatz wird gespeichert, solange die Vorschau läuft. Ein Fehler oder Duplikat blockiert die gesamte Übernahme.
Titel werden für die Duplikatprüfung mit NFKC normalisiert, getrimmt und ohne Groß-/Kleinschreibung verglichen. Vorhandene IDs gelten ebenfalls als Duplikat. Import überschreibt keine bestehenden Rezepte. Zum Bearbeiten den Editor verwenden; zum Anlegen einer Variante eine neue ID bzw. keine ID und einen eigenen Titel verwenden.
JSON-Dateien haben diese Hülle:
```json
{
"version": 1,
"recipes": [{ "title": "Mein Rezept", "servings": 2, "ingredients": [], "steps": [] }]
}
```
Die leeren Arrays im obigen Strukturdiagramm müssen mit mindestens einer gültigen Zutat und einem Schritt befüllt werden. Ein vollständig gültiges Beispiel steht in `public/examples/pljeskavica.json`. Das verbindliche maschinenlesbare Schema liegt in `public/examples/hamham.schema.json` (JSON Schema 2020-12).
## Felder
Pflicht: `title` (2–180 Zeichen), `servings` (positiv), `ingredients` (1–200), `steps` (1–100).
Optional: `id` (UUID), `subtitle`, `description`, `image`, `images`, `categories`, `tags`, `cuisine`, `difficulty` (`Einfach`, `Mittel`, `Anspruchsvoll`), `prepMinutes`, `cookMinutes`, `restMinutes`, `tips`, `storage`, `nutrition`, `published`, `createdAt`, `updatedAt` (UTC ISO-8601). Gesamtzeit wird aus den drei Zeitfeldern berechnet. `published` ist standardmäßig `false`. Nährwerte gelten pro Originalportion; `nutrition` ist `null` oder `{ "kcal": 500, "protein": 25, "carbs": 60, "fat": 18 }`.
Zutat:
```json
{
"id": "huhn",
"name": "Hühnerbrust",
"amount": 400,
"unit": "g",
"section": "Hauptgericht",
"note": "ohne Haut",
"optional": false
}
```
`amount`: positive JSON-Zahl oder `null`. Dezimalpunkt verwenden, keine Zeichenketten wie `"1/2"`, `"400 g"` oder `"1,5"`. Für eine halbe Zitrone `0.5` und `Stück` verwenden. Bei Salz nach Geschmack `amount: null`, `unit: ""`, `note: "nach Geschmack"`.
Einheiten: `g`, `kg`, `ml`, `l`, `Stück`, `TL`, `EL`, `Prise`, `Bund`, `""`. Umrechnung: 1 kg = 1000 g, 1 l = 1000 ml, 1 TL = 5 ml, 1 EL = 15 ml. Masse wird nie ohne Dichteannahme in Volumen umgerechnet. IDs sind innerhalb des Rezepts eindeutig, bestehen aus Buchstaben, Ziffern, `_` oder `-`, maximal 80 Zeichen.
Schritt:
```json
{
"id": "anbraten",
"title": "Goldbraun anbraten",
"text": "- {{huhn}} in Würfel schneiden.\n- In der heißen Pfanne anbraten.",
"ingredients": ["huhn"],
"images": [],
"timers": [{ "id": "bratzeit", "label": "Hühnerbrust braten", "seconds": 480 }]
}
```
`{{huhn}}` wird zu **Menge + Einheit + Zutatenname + Hinweis** aufgelöst. Diese Referenz bleibt beim Skalieren konsistent. Keine konkreten skalierbaren Mengen als Freitext wiederholen. Temperaturen und Zeiten bleiben normaler Text. `ingredients` enthält die in diesem Schritt benötigten Zutaten-IDs. Timer-IDs müssen im gesamten Rezept eindeutig sein; ein Timer dauert 1–172800 Sekunden. Zeiten werden nicht mit Portionen skaliert.
Schritttexte unterstützen Absätze bzw. Zeilenumbrüche (`\n`, `\n\n`), Aufzählungen mit `- `, `* ` oder `• ` und nummerierte Listen mit `1. ` bzw. `1) `. Die Darstellung funktioniert in Rezeptansicht, Kochmodus und Vorschau. Lange ältere Texte ohne Zeilenumbrüche werden für die Anzeige nach jeweils zwei Sätzen gegliedert; der gespeicherte Text bleibt erhalten. Zutatenreferenzen werden hervorgehoben. HTML und weitere Markdown-Formatierung sind nicht vorgesehen.
## Bilder
Bildfelder akzeptieren lokale Pfade (`/media/<uuid>.webp` oder mitgelieferte `/images/<name>.jpg|webp|svg`) und vollständige externe **HTTPS-URLs** bis 2048 Zeichen ohne Zugangsdaten. Queryparameter sind erlaubt, z. B. für Bild-CDNs. HTTP, eingebettete Base64-/Data-URLs und Webseiten statt direkter Bildadressen sind nicht geeignet.
- `recipe.image`: ein Titelbild oder `""`.
- `recipe.images`: Galerie mit bis zu 20 Bildadressen, Standard `[]`.
- `recipe.steps[].images`: bis zu 10 Bildadressen pro Schritt, Standard `[]`. Bestehende Rezepte ohne dieses Feld bleiben kompatibel.
Lokale Bilder können im Editor hochgeladen werden. HTTPS-Adressen können für Titelbild, Galerie und Schrittbilder im Editor eingetragen oder über JSON/XML importiert werden. Externe Bilder lädt der Browser direkt mit `referrerPolicy="no-referrer"`; HamHam lädt sie nicht auf den Server herunter. Bei nicht erreichbaren oder vom Anbieter blockierten Bildern erscheint ein Platzhalter. Externe Bilder sind daher nicht Bestandteil des lokalen Bild-Backups. ChatGPT soll nur bereitgestellte oder überprüfte Bildadressen verwenden und die Bildfelder andernfalls leer lassen.
JSON/XML-Exporte enthalten Bildreferenzen, keine Binärdaten. Für einen Umzug das Bildvolume mitnehmen; für ein vollständiges Backup zusätzlich die Datenbank sichern. Metadaten, Zutaten, Schritte, Timer, Zeitstempel und IDs bleiben beim Export erhalten.
## XML
Das vollständige Beispiel ist `public/examples/pljeskavica.xml`. UTF-8, Wurzel `<hamham version="1">`, darunter `<recipes><recipe>…</recipe></recipes>`. Rezeptfelder entsprechen JSON. Array-Container:
| JSON | XML |
| ---------------- | ----------------------------------------------------------------- |
| recipes | `<recipes><recipe>…</recipe></recipes>` |
| ingredients | `<ingredients><ingredient>…</ingredient></ingredients>` |
| steps | `<steps><step>…</step></steps>` |
| timers | `<timers><timer>…</timer></timers>` |
| categories | `<categories><category>Vegetarisch</category></categories>` |
| tags | `<tags><tag>Schnell</tag></tags>` |
| images | `<images><image>/media/…webp</image></images>` |
| step.ingredients | `<ingredients><ref>huhn</ref></ingredients>` |
| step.images | `<images><image>https://example.org/schritt.jpg</image></images>` |
Leere Menge: `<amount/>`. Keine Nährwerte: `<nutrition/>`. Boolean: `true`/`false`. Texte standardkonform escapen (`&amp;`, `&lt;` etc.). DOCTYPE und Entity-Deklarationen sind verboten, es werden keine externen Ressourcen aufgelöst. Nach dem XML-Parsing gilt dieselbe Zod-Validierung wie bei JSON.
## Versionsstrategie
Die Hülle `version: 1` ist verbindlich. Inkompatible Änderungen bekommen eine neue Version mit expliziter Konvertierung. Unbekannte Versionen werden abgewiesen. Optionale Felder erhalten dokumentierte Standardwerte. HTML-Inhalte werden nicht übernommen.