feat(core): add secure recipe APIs, precise scaling and versioned imports
This commit is contained in:
commit
5d71d32e20
31 files changed
+6293
No files matched your search
@@ -0,0 +1,349 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "number",
|
||||
"const": 1
|
||||
},
|
||||
"recipes": {
|
||||
"minItems": 1,
|
||||
"maxItems": 100,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 2,
|
||||
"maxLength": 180
|
||||
},
|
||||
"subtitle": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
},
|
||||
"description": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 4000
|
||||
},
|
||||
"image": {
|
||||
"default": "",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^\\/(?:media\\/[a-f0-9-]+\\.webp|images\\/[a-z0-9-]+\\.(?:webp|jpg|svg))$"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"const": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"images": {
|
||||
"default": [],
|
||||
"maxItems": 20,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^\\/(?:media\\/[a-f0-9-]+\\.webp|images\\/[a-z0-9-]+\\.(?:webp|jpg|svg))$"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"default": [],
|
||||
"maxItems": 20,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 60
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"default": [],
|
||||
"maxItems": 30,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 60
|
||||
}
|
||||
},
|
||||
"cuisine": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 80
|
||||
},
|
||||
"difficulty": {
|
||||
"default": "Einfach",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Einfach",
|
||||
"Mittel",
|
||||
"Anspruchsvoll"
|
||||
]
|
||||
},
|
||||
"prepMinutes": {
|
||||
"default": 0,
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 10080
|
||||
},
|
||||
"cookMinutes": {
|
||||
"default": 0,
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 10080
|
||||
},
|
||||
"restMinutes": {
|
||||
"default": 0,
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 10080
|
||||
},
|
||||
"servings": {
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 10000
|
||||
},
|
||||
"ingredients": {
|
||||
"minItems": 1,
|
||||
"maxItems": 200,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9_-]{1,80}$"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 160
|
||||
},
|
||||
"amount": {
|
||||
"default": null,
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 1000000
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"g",
|
||||
"kg",
|
||||
"ml",
|
||||
"l",
|
||||
"Stück",
|
||||
"TL",
|
||||
"EL",
|
||||
"Prise",
|
||||
"Bund",
|
||||
""
|
||||
]
|
||||
},
|
||||
"section": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 80
|
||||
},
|
||||
"note": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
},
|
||||
"optional": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"amount",
|
||||
"unit",
|
||||
"section",
|
||||
"note",
|
||||
"optional"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"steps": {
|
||||
"minItems": 1,
|
||||
"maxItems": 100,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9_-]{1,80}$"
|
||||
},
|
||||
"title": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 160
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 6000
|
||||
},
|
||||
"ingredients": {
|
||||
"default": [],
|
||||
"maxItems": 100,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9_-]{1,80}$"
|
||||
}
|
||||
},
|
||||
"timers": {
|
||||
"default": [],
|
||||
"maxItems": 10,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9_-]{1,80}$"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 100
|
||||
},
|
||||
"seconds": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 172800
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"label",
|
||||
"seconds"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"text",
|
||||
"ingredients",
|
||||
"timers"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"tips": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 6000
|
||||
},
|
||||
"storage": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
"maxLength": 3000
|
||||
},
|
||||
"nutrition": {
|
||||
"default": null,
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kcal": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"protein": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"carbs": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"fat": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kcal",
|
||||
"protein",
|
||||
"carbs",
|
||||
"fat"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"published": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"image",
|
||||
"images",
|
||||
"categories",
|
||||
"tags",
|
||||
"cuisine",
|
||||
"difficulty",
|
||||
"prepMinutes",
|
||||
"cookMinutes",
|
||||
"restMinutes",
|
||||
"servings",
|
||||
"ingredients",
|
||||
"steps",
|
||||
"tips",
|
||||
"storage",
|
||||
"nutrition",
|
||||
"published"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"version",
|
||||
"recipes"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
{
|
||||
"version": 1,
|
||||
"recipes": [
|
||||
{
|
||||
"id": "10000000-0000-4000-8000-000000000001",
|
||||
"title": "Grüne Pesto-Pasta",
|
||||
"subtitle": "Ein Teller Sommer, ganz ohne Eile.",
|
||||
"description": "Frisches Basilikum, geröstete Pinienkerne und ein Hauch Zitrone. Unsere liebste Pasta für Tage, an denen es einfach gut sein soll.",
|
||||
"image": "/images/kitchen.jpg",
|
||||
"images": [],
|
||||
"categories": [
|
||||
"Alltagsküche",
|
||||
"Vegetarisch"
|
||||
],
|
||||
"tags": [
|
||||
"Schnell",
|
||||
"Familienliebling"
|
||||
],
|
||||
"cuisine": "Italien",
|
||||
"difficulty": "Einfach",
|
||||
"prepMinutes": 10,
|
||||
"cookMinutes": 12,
|
||||
"restMinutes": 0,
|
||||
"servings": 2,
|
||||
"ingredients": [
|
||||
{
|
||||
"id": "pasta",
|
||||
"name": "Pasta",
|
||||
"amount": 200,
|
||||
"unit": "g",
|
||||
"section": "Für die Pasta",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "basilikum",
|
||||
"name": "Basilikum",
|
||||
"amount": 40,
|
||||
"unit": "g",
|
||||
"section": "Für das Pesto",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "kerne",
|
||||
"name": "Pinienkerne",
|
||||
"amount": 30,
|
||||
"unit": "g",
|
||||
"section": "Für das Pesto",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "oel",
|
||||
"name": "Olivenöl",
|
||||
"amount": 60,
|
||||
"unit": "ml",
|
||||
"section": "Für das Pesto",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "kaese",
|
||||
"name": "Hartkäse mit mikrobiellem Lab",
|
||||
"amount": 40,
|
||||
"unit": "g",
|
||||
"section": "Für das Pesto",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "zitrone",
|
||||
"name": "Bio-Zitrone",
|
||||
"amount": 0.5,
|
||||
"unit": "Stück",
|
||||
"section": "Zum Abschmecken",
|
||||
"note": "",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "salz",
|
||||
"name": "Salz",
|
||||
"amount": null,
|
||||
"unit": "",
|
||||
"section": "Zum Abschmecken",
|
||||
"note": "nach Geschmack",
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"id": "vorbereiten",
|
||||
"title": "Ein bisschen Vorbereitung",
|
||||
"text": "{{basilikum}} waschen und trocken schütteln. {{kaese}} fein reiben. Einen großen Topf Salzwasser aufsetzen.",
|
||||
"ingredients": [
|
||||
"basilikum",
|
||||
"kaese",
|
||||
"salz"
|
||||
],
|
||||
"timers": []
|
||||
},
|
||||
{
|
||||
"id": "pesto",
|
||||
"title": "Das Pesto zum Leuchten bringen",
|
||||
"text": "{{kerne}} in einer trockenen Pfanne goldbraun rösten. Mit Basilikum und {{oel}} fein mixen, anschließend den geriebenen Käse unterheben.",
|
||||
"ingredients": [
|
||||
"kerne",
|
||||
"basilikum",
|
||||
"oel",
|
||||
"kaese"
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"id": "roesten",
|
||||
"label": "Pinienkerne rösten",
|
||||
"seconds": 180
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "kochen",
|
||||
"title": "Pasta trifft Pesto",
|
||||
"text": "{{pasta}} nach Packungsangabe bissfest kochen. Vor dem Abgießen etwas Kochwasser auffangen. Pasta mit dem Pesto vermengen und mit Kochwasser geschmeidig rühren.",
|
||||
"ingredients": [
|
||||
"pasta"
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"id": "nudeln",
|
||||
"label": "Pasta kochen",
|
||||
"seconds": 600
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "geniessen",
|
||||
"title": "Der schönste Moment",
|
||||
"text": "Mit dem Saft von {{zitrone}} und Salz abschmecken. Auf warme Teller verteilen und sofort genießen.",
|
||||
"ingredients": [
|
||||
"zitrone",
|
||||
"salz"
|
||||
],
|
||||
"timers": []
|
||||
}
|
||||
],
|
||||
"tips": "Pesto nicht stark erhitzen: So bleibt es leuchtend grün. Ein Schuss stärkehaltiges Nudelwasser macht die Sauce wunderbar cremig.",
|
||||
"storage": "Pesto in einem sauberen Glas mit einer dünnen Ölschicht bedecken und im Kühlschrank innerhalb von zwei Tagen verbrauchen.",
|
||||
"nutrition": {
|
||||
"kcal": 780,
|
||||
"protein": 22,
|
||||
"carbs": 79,
|
||||
"fat": 42
|
||||
},
|
||||
"published": true
|
||||
},
|
||||
{
|
||||
"id": "10000000-0000-4000-8000-000000000002",
|
||||
"title": "Bunte Garten-Bowl",
|
||||
"subtitle": "Knackig, frisch und voller guter Dinge.",
|
||||
"description": "Eine großzügige Schüssel Gemüse, cremige Kichererbsen und ein zitroniges Tahini-Dressing. Genau richtig für einen frischen Start.",
|
||||
"image": "/images/garden.jpg",
|
||||
"images": [],
|
||||
"categories": [
|
||||
"Vegetarisch"
|
||||
],
|
||||
"tags": [
|
||||
"Meal Prep"
|
||||
],
|
||||
"cuisine": "Mediterran",
|
||||
"difficulty": "Einfach",
|
||||
"prepMinutes": 20,
|
||||
"cookMinutes": 10,
|
||||
"restMinutes": 0,
|
||||
"servings": 2,
|
||||
"ingredients": [
|
||||
{
|
||||
"id": "kichererbsen",
|
||||
"name": "Kichererbsen, gekocht",
|
||||
"amount": 240,
|
||||
"unit": "g",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "salat",
|
||||
"name": "Blattsalat",
|
||||
"amount": 100,
|
||||
"unit": "g",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "tomaten",
|
||||
"name": "Cherrytomaten",
|
||||
"amount": 200,
|
||||
"unit": "g",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "gurke",
|
||||
"name": "Gurke",
|
||||
"amount": 0.5,
|
||||
"unit": "Stück",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "tahini",
|
||||
"name": "Tahini",
|
||||
"amount": 2,
|
||||
"unit": "EL",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "zitrone",
|
||||
"name": "Zitronensaft",
|
||||
"amount": 2,
|
||||
"unit": "EL",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "wasser",
|
||||
"name": "Wasser",
|
||||
"amount": 3,
|
||||
"unit": "EL",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "salz",
|
||||
"name": "Salz",
|
||||
"amount": null,
|
||||
"unit": "",
|
||||
"section": "",
|
||||
"note": "nach Geschmack",
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"id": "gemuese",
|
||||
"title": "Bunt vorbereiten",
|
||||
"text": "{{salat}} waschen und trocknen. {{tomaten}} halbieren und {{gurke}} in Scheiben schneiden.",
|
||||
"ingredients": [
|
||||
"salat",
|
||||
"tomaten",
|
||||
"gurke"
|
||||
],
|
||||
"timers": []
|
||||
},
|
||||
{
|
||||
"id": "roesten",
|
||||
"title": "Kichererbsen rösten",
|
||||
"text": "{{kichererbsen}} abtropfen lassen und in einer beschichteten Pfanne zehn Minuten rösten. Regelmäßig umrühren.",
|
||||
"ingredients": [
|
||||
"kichererbsen"
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"id": "roesten",
|
||||
"label": "Kichererbsen rösten",
|
||||
"seconds": 600
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dressing",
|
||||
"title": "Alles kommt zusammen",
|
||||
"text": "{{tahini}} mit {{zitrone}}, {{wasser}} und Salz verrühren. Gemüse und Kichererbsen anrichten und das Dressing darübergeben.",
|
||||
"ingredients": [
|
||||
"tahini",
|
||||
"zitrone",
|
||||
"wasser",
|
||||
"salz"
|
||||
],
|
||||
"timers": []
|
||||
}
|
||||
],
|
||||
"tips": "Das Dressing separat aufbewahren, wenn die Bowl für morgen ist.",
|
||||
"storage": "Gekühlt einen Tag haltbar. Salat und Dressing getrennt lagern.",
|
||||
"nutrition": null,
|
||||
"published": true
|
||||
},
|
||||
{
|
||||
"id": "10000000-0000-4000-8000-000000000003",
|
||||
"title": "Wärmende Gemüsesuppe",
|
||||
"subtitle": "Ein Löffel Gemütlichkeit.",
|
||||
"description": "Saisongemüse, weiße Bohnen und aromatische Kräuter machen aus wenigen Zutaten ein wohliges Essen für die ganze Familie.",
|
||||
"image": "/images/soup.jpg",
|
||||
"images": [],
|
||||
"categories": [
|
||||
"Alltagsküche"
|
||||
],
|
||||
"tags": [
|
||||
"Familienliebling",
|
||||
"Meal Prep"
|
||||
],
|
||||
"cuisine": "",
|
||||
"difficulty": "Einfach",
|
||||
"prepMinutes": 15,
|
||||
"cookMinutes": 30,
|
||||
"restMinutes": 0,
|
||||
"servings": 4,
|
||||
"ingredients": [
|
||||
{
|
||||
"id": "karotten",
|
||||
"name": "Karotten",
|
||||
"amount": 300,
|
||||
"unit": "g",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "kartoffeln",
|
||||
"name": "Kartoffeln",
|
||||
"amount": 400,
|
||||
"unit": "g",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "bohnen",
|
||||
"name": "Weiße Bohnen, gekocht",
|
||||
"amount": 240,
|
||||
"unit": "g",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "bruehe",
|
||||
"name": "Gemüsebrühe",
|
||||
"amount": 1,
|
||||
"unit": "l",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "zwiebel",
|
||||
"name": "Zwiebel",
|
||||
"amount": 1,
|
||||
"unit": "Stück",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "oel",
|
||||
"name": "Olivenöl",
|
||||
"amount": 1,
|
||||
"unit": "EL",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "kraeuter",
|
||||
"name": "Petersilie",
|
||||
"amount": 0.5,
|
||||
"unit": "Bund",
|
||||
"section": "",
|
||||
"note": "",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"id": "schneiden",
|
||||
"title": "Alles klein schneiden",
|
||||
"text": "{{karotten}}, {{kartoffeln}} und {{zwiebel}} schälen und würfeln.",
|
||||
"ingredients": [
|
||||
"karotten",
|
||||
"kartoffeln",
|
||||
"zwiebel"
|
||||
],
|
||||
"timers": []
|
||||
},
|
||||
{
|
||||
"id": "kochen",
|
||||
"title": "Zeit für Wärme",
|
||||
"text": "Zwiebel in {{oel}} glasig dünsten. Karotten und Kartoffeln dazugeben, mit {{bruehe}} aufgießen und zugedeckt etwa 25 Minuten sanft kochen, bis das Gemüse weich ist.",
|
||||
"ingredients": [
|
||||
"oel",
|
||||
"bruehe"
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"id": "suppe",
|
||||
"label": "Gemüse weich kochen",
|
||||
"seconds": 1500
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "abschmecken",
|
||||
"title": "Der letzte Schliff",
|
||||
"text": "{{bohnen}} dazugeben und fünf Minuten erwärmen. Abschmecken und mit {{kraeuter}} bestreuen.",
|
||||
"ingredients": [
|
||||
"bohnen",
|
||||
"kraeuter"
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"id": "bohnen",
|
||||
"label": "Bohnen erwärmen",
|
||||
"seconds": 300
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tips": "",
|
||||
"storage": "Rasch abkühlen und im Kühlschrank maximal zwei Tage lagern. Portionsweise bis zu drei Monate einfrieren.",
|
||||
"nutrition": null,
|
||||
"published": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"version": 1,
|
||||
"recipes": [
|
||||
{
|
||||
"title": "Serbische Pljeskavica",
|
||||
"subtitle": "Saftig gegrillt, mit Ajvar und frischen Zwiebeln",
|
||||
"description": "Ein Klassiker vom Balkan: würzige Faschierte-Laibchen, außen kräftig geröstet und innen saftig. Dazu passen Lepinja, Ajvar und ein knackiger Salat.",
|
||||
"image": "",
|
||||
"images": [],
|
||||
"categories": [
|
||||
"Für Gäste"
|
||||
],
|
||||
"tags": [
|
||||
"Grillen",
|
||||
"Familienliebling"
|
||||
],
|
||||
"cuisine": "Serbien",
|
||||
"difficulty": "Einfach",
|
||||
"prepMinutes": 20,
|
||||
"cookMinutes": 12,
|
||||
"restMinutes": 60,
|
||||
"servings": 4,
|
||||
"ingredients": [
|
||||
{
|
||||
"id": "fleisch",
|
||||
"name": "Rinderfaschiertes",
|
||||
"amount": 800,
|
||||
"unit": "g",
|
||||
"section": "Pljeskavica",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "zwiebel",
|
||||
"name": "Zwiebel",
|
||||
"amount": 1,
|
||||
"unit": "Stück",
|
||||
"section": "Pljeskavica",
|
||||
"note": "sehr fein gewürfelt",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "paprika",
|
||||
"name": "Paprikapulver edelsüß",
|
||||
"amount": 2,
|
||||
"unit": "TL",
|
||||
"section": "Pljeskavica",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "salz",
|
||||
"name": "Salz",
|
||||
"amount": 10,
|
||||
"unit": "g",
|
||||
"section": "Pljeskavica",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "pfeffer",
|
||||
"name": "Schwarzer Pfeffer",
|
||||
"amount": null,
|
||||
"unit": "",
|
||||
"section": "Pljeskavica",
|
||||
"note": "nach Geschmack",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "wasser",
|
||||
"name": "Mineralwasser",
|
||||
"amount": 60,
|
||||
"unit": "ml",
|
||||
"section": "Pljeskavica",
|
||||
"note": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"id": "ajvar",
|
||||
"name": "Ajvar",
|
||||
"amount": 120,
|
||||
"unit": "g",
|
||||
"section": "Zum Servieren",
|
||||
"note": "",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "brot",
|
||||
"name": "Lepinja",
|
||||
"amount": 4,
|
||||
"unit": "Stück",
|
||||
"section": "Zum Servieren",
|
||||
"note": "",
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"id": "mischen",
|
||||
"title": "Die Mischung vorbereiten",
|
||||
"text": "{{fleisch}}, {{zwiebel}}, {{paprika}}, {{salz}} und {{wasser}} gründlich verkneten. Mit {{pfeffer}} abschmecken.",
|
||||
"ingredients": [
|
||||
"fleisch",
|
||||
"zwiebel",
|
||||
"paprika",
|
||||
"salz",
|
||||
"wasser",
|
||||
"pfeffer"
|
||||
],
|
||||
"timers": []
|
||||
},
|
||||
{
|
||||
"id": "ruhen",
|
||||
"title": "Geschmack entwickeln lassen",
|
||||
"text": "Die Masse zugedeckt mindestens eine Stunde im Kühlschrank ruhen lassen.",
|
||||
"ingredients": [],
|
||||
"timers": [
|
||||
{
|
||||
"id": "ruhezeit",
|
||||
"label": "Im Kühlschrank ruhen",
|
||||
"seconds": 3600
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "formen",
|
||||
"title": "Flache Laibchen formen",
|
||||
"text": "Mit angefeuchteten Händen je Portion ein etwa 1,5 cm dickes Laibchen formen. In die Mitte eine leichte Mulde drücken.",
|
||||
"ingredients": [],
|
||||
"timers": []
|
||||
},
|
||||
{
|
||||
"id": "grillen",
|
||||
"title": "Kräftig grillen",
|
||||
"text": "Grill oder Grillpfanne vorheizen. Laibchen von beiden Seiten je etwa fünf bis sechs Minuten braten. Faschiertes vollständig durchgaren: im Kern mindestens 70 °C für zwei Minuten erreichen.",
|
||||
"ingredients": [],
|
||||
"timers": [
|
||||
{
|
||||
"id": "erste-seite",
|
||||
"label": "Erste Seite",
|
||||
"seconds": 360
|
||||
},
|
||||
{
|
||||
"id": "zweite-seite",
|
||||
"label": "Zweite Seite",
|
||||
"seconds": 360
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "servieren",
|
||||
"title": "Ab an den Tisch",
|
||||
"text": "In {{brot}} mit {{ajvar}} servieren. Nach Wunsch frische Zwiebelringe dazu reichen.",
|
||||
"ingredients": [
|
||||
"brot",
|
||||
"ajvar"
|
||||
],
|
||||
"timers": []
|
||||
}
|
||||
],
|
||||
"tips": "Nicht während des Bratens flachdrücken – so bleibt die Pljeskavica saftig. Für Schärfe etwas Chiliflocken zur Masse geben.",
|
||||
"storage": "Reste rasch abkühlen, abgedeckt im Kühlschrank aufbewahren und innerhalb von zwei Tagen verbrauchen. Vor dem Essen gründlich erhitzen.",
|
||||
"nutrition": null,
|
||||
"published": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hamham version="1">
|
||||
<recipes>
|
||||
<recipe>
|
||||
<title>Serbische Pljeskavica</title>
|
||||
<subtitle>Saftig gegrillt, mit Ajvar und frischen Zwiebeln</subtitle>
|
||||
<description>Ein Klassiker vom Balkan: würzige Faschierte-Laibchen, außen kräftig geröstet und innen saftig. Dazu passen Lepinja, Ajvar und ein knackiger Salat.</description>
|
||||
<image></image>
|
||||
<images></images>
|
||||
<categories>
|
||||
<category>Für Gäste</category>
|
||||
</categories>
|
||||
<tags>
|
||||
<tag>Grillen</tag>
|
||||
<tag>Familienliebling</tag>
|
||||
</tags>
|
||||
<cuisine>Serbien</cuisine>
|
||||
<difficulty>Einfach</difficulty>
|
||||
<prepMinutes>20</prepMinutes>
|
||||
<cookMinutes>12</cookMinutes>
|
||||
<restMinutes>60</restMinutes>
|
||||
<servings>4</servings>
|
||||
<ingredients>
|
||||
<ingredient>
|
||||
<id>fleisch</id>
|
||||
<name>Rinderfaschiertes</name>
|
||||
<amount>800</amount>
|
||||
<unit>g</unit>
|
||||
<section>Pljeskavica</section>
|
||||
<note></note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>zwiebel</id>
|
||||
<name>Zwiebel</name>
|
||||
<amount>1</amount>
|
||||
<unit>Stück</unit>
|
||||
<section>Pljeskavica</section>
|
||||
<note>sehr fein gewürfelt</note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>paprika</id>
|
||||
<name>Paprikapulver edelsüß</name>
|
||||
<amount>2</amount>
|
||||
<unit>TL</unit>
|
||||
<section>Pljeskavica</section>
|
||||
<note></note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>salz</id>
|
||||
<name>Salz</name>
|
||||
<amount>10</amount>
|
||||
<unit>g</unit>
|
||||
<section>Pljeskavica</section>
|
||||
<note></note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>pfeffer</id>
|
||||
<name>Schwarzer Pfeffer</name>
|
||||
<amount></amount>
|
||||
<unit></unit>
|
||||
<section>Pljeskavica</section>
|
||||
<note>nach Geschmack</note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>wasser</id>
|
||||
<name>Mineralwasser</name>
|
||||
<amount>60</amount>
|
||||
<unit>ml</unit>
|
||||
<section>Pljeskavica</section>
|
||||
<note></note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>ajvar</id>
|
||||
<name>Ajvar</name>
|
||||
<amount>120</amount>
|
||||
<unit>g</unit>
|
||||
<section>Zum Servieren</section>
|
||||
<note></note>
|
||||
<optional>true</optional>
|
||||
</ingredient>
|
||||
<ingredient>
|
||||
<id>brot</id>
|
||||
<name>Lepinja</name>
|
||||
<amount>4</amount>
|
||||
<unit>Stück</unit>
|
||||
<section>Zum Servieren</section>
|
||||
<note></note>
|
||||
<optional>false</optional>
|
||||
</ingredient>
|
||||
</ingredients>
|
||||
<steps>
|
||||
<step>
|
||||
<id>mischen</id>
|
||||
<title>Die Mischung vorbereiten</title>
|
||||
<text>{{fleisch}}, {{zwiebel}}, {{paprika}}, {{salz}} und {{wasser}} gründlich verkneten. Mit {{pfeffer}} abschmecken.</text>
|
||||
<ingredients>
|
||||
<ref>fleisch</ref>
|
||||
<ref>zwiebel</ref>
|
||||
<ref>paprika</ref>
|
||||
<ref>salz</ref>
|
||||
<ref>wasser</ref>
|
||||
<ref>pfeffer</ref>
|
||||
</ingredients>
|
||||
<timers></timers>
|
||||
</step>
|
||||
<step>
|
||||
<id>ruhen</id>
|
||||
<title>Geschmack entwickeln lassen</title>
|
||||
<text>Die Masse zugedeckt mindestens eine Stunde im Kühlschrank ruhen lassen.</text>
|
||||
<ingredients></ingredients>
|
||||
<timers>
|
||||
<timer>
|
||||
<id>ruhezeit</id>
|
||||
<label>Im Kühlschrank ruhen</label>
|
||||
<seconds>3600</seconds>
|
||||
</timer>
|
||||
</timers>
|
||||
</step>
|
||||
<step>
|
||||
<id>formen</id>
|
||||
<title>Flache Laibchen formen</title>
|
||||
<text>Mit angefeuchteten Händen je Portion ein etwa 1,5 cm dickes Laibchen formen. In die Mitte eine leichte Mulde drücken.</text>
|
||||
<ingredients></ingredients>
|
||||
<timers></timers>
|
||||
</step>
|
||||
<step>
|
||||
<id>grillen</id>
|
||||
<title>Kräftig grillen</title>
|
||||
<text>Grill oder Grillpfanne vorheizen. Laibchen von beiden Seiten je etwa fünf bis sechs Minuten braten. Faschiertes vollständig durchgaren: im Kern mindestens 70 °C für zwei Minuten erreichen.</text>
|
||||
<ingredients></ingredients>
|
||||
<timers>
|
||||
<timer>
|
||||
<id>erste-seite</id>
|
||||
<label>Erste Seite</label>
|
||||
<seconds>360</seconds>
|
||||
</timer>
|
||||
<timer>
|
||||
<id>zweite-seite</id>
|
||||
<label>Zweite Seite</label>
|
||||
<seconds>360</seconds>
|
||||
</timer>
|
||||
</timers>
|
||||
</step>
|
||||
<step>
|
||||
<id>servieren</id>
|
||||
<title>Ab an den Tisch</title>
|
||||
<text>In {{brot}} mit {{ajvar}} servieren. Nach Wunsch frische Zwiebelringe dazu reichen.</text>
|
||||
<ingredients>
|
||||
<ref>brot</ref>
|
||||
<ref>ajvar</ref>
|
||||
</ingredients>
|
||||
<timers></timers>
|
||||
</step>
|
||||
</steps>
|
||||
<tips>Nicht während des Bratens flachdrücken – so bleibt die Pljeskavica saftig. Für Schärfe etwas Chiliflocken zur Masse geben.</tips>
|
||||
<storage>Reste rasch abkühlen, abgedeckt im Kühlschrank aufbewahren und innerhalb von zwei Tagen verbrauchen. Vor dem Essen gründlich erhitzen.</storage>
|
||||
<nutrition></nutrition>
|
||||
<published>false</published>
|
||||
</recipe>
|
||||
</recipes>
|
||||
</hamham>
|
||||
Reference in new issue
Block a user