caterium-app/public/demo/extras-v1.json
pavlov346346-source 40b5c146c2 feat: add photos for the 34 training-catalog items that had none
The banquet menu (18 dishes) and extras/supplies/delivery items (16)
in the training catalog were seeded with photo:'', which the catalog
tiles render as a plain red placeholder square. Sourced a real photo
for each item (mostly Pexels, free license, picked and visually
reviewed one by one to avoid mismatches -- several first search hits
were wrong: a live chicken for "chicken caesar salad", a person in
frame, branded bottles/cups) and two AI-generated (banquet-caprese,
banquet-roastbeef). Converted to square 1024x1024 WebP with sharp.

Wires the paths through the actual source of truth: ops/demo/trial-
banquet-data.mjs and trial-extras-data.mjs now set photo to the real
path, then ops/demo/build-trial-*.mjs regenerated public/demo/*.json
and the matching Supabase seed-function migrations, so the client's
static JSON fetch and the server-side company-provisioning function
stay in sync.

Bumped the demo-catalog fetch's own cache-busting query string in
training-catalog.js (and its script-tag/precache version), since it's
fetched by the client with a separate version from the outer script
tags -- the same stale-cache class of bug fixed earlier this session.

Verified: all 34 referenced files resolve (200) and decode as real
1024x1024 images; confirmed via the actual rendered catalog tiles
(#tiles img[src]) that the extras category -- where the user's
red-square screenshot was taken -- now serves the real photo paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 17:00:45 +03:00

984 lines
28 KiB
JSON
Raw 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.

{
"version": 1,
"items": [
{
"id": "demo-extras-v1-salmon-caprese",
"name": "Премиум-сет «Лосось и капрезе»",
"category": 5,
"catalogSection": "Демонстрационные премиум-сеты",
"price": 3500,
"pieces": 18,
"weight": "710 г",
"photo": "demo/images/extras-salmon-caprese.webp",
"demo": true,
"composition": [
"Половина стандартного бокса: Канапе с лососем и сливочным сыром",
"Половина стандартного бокса: Канапе «Капрезе»"
],
"ingredients": [
[
"Хлеб ржаной",
0.12,
"кг"
],
[
"Лосось слабосолёный",
0.12,
"кг"
],
[
"Сыр сливочный",
0.08,
"кг"
],
[
"Огурцы",
0.042,
"кг"
],
[
"Укроп",
0.005,
"кг"
],
[
"Коробка для кейтеринга",
1,
"шт."
],
[
"Моцарелла мини",
0.18,
"кг"
],
[
"Томаты черри",
0.154,
"кг"
],
[
"Базилик",
0.011,
"кг"
],
[
"Масло оливковое",
0.02,
"кг"
],
[
"Шпажка бамбуковая",
10,
"шт."
]
],
"ttk": {
"number": "ДЕМО-П1",
"basis": "На 1 готовый премиум-сет",
"outputGrams": 710,
"pieces": 18,
"rows": [
{
"productId": "demo-v1-stock-rye",
"name": "Хлеб ржаной",
"unit": "кг",
"gross": 0.12,
"net": 0.12,
"unitCost": 220
},
{
"productId": "demo-v1-stock-salmon",
"name": "Лосось слабосолёный",
"unit": "кг",
"gross": 0.12,
"net": 0.12,
"unitCost": 2400
},
{
"productId": "demo-v1-stock-cream",
"name": "Сыр сливочный",
"unit": "кг",
"gross": 0.08,
"net": 0.08,
"unitCost": 850
},
{
"productId": "demo-v1-stock-cucumber",
"name": "Огурцы",
"unit": "кг",
"gross": 0.042,
"net": 0.036,
"unitCost": 220
},
{
"productId": "demo-v1-stock-dill",
"name": "Укроп",
"unit": "кг",
"gross": 0.005,
"net": 0.004,
"unitCost": 700
},
{
"productId": "demo-v1-stock-box",
"name": "Коробка для кейтеринга",
"unit": "шт.",
"gross": 1,
"net": 1,
"unitCost": 65
},
{
"productId": "demo-v1-stock-mozzarella",
"name": "Моцарелла мини",
"unit": "кг",
"gross": 0.18,
"net": 0.18,
"unitCost": 950
},
{
"productId": "demo-v1-stock-cherry",
"name": "Томаты черри",
"unit": "кг",
"gross": 0.154,
"net": 0.14,
"unitCost": 450
},
{
"productId": "demo-v1-stock-basil",
"name": "Базилик",
"unit": "кг",
"gross": 0.011,
"net": 0.01,
"unitCost": 1500
},
{
"productId": "demo-v1-stock-oil",
"name": "Масло оливковое",
"unit": "кг",
"gross": 0.02,
"net": 0.02,
"unitCost": 1100
},
{
"productId": "demo-v1-stock-skewer",
"name": "Шпажка бамбуковая",
"unit": "шт.",
"gross": 10,
"net": 10,
"unitCost": 2
}
],
"steps": [
"Приготовить две мини-подборки в половинном объёме по указанным нормам.",
"Канапе с лососем и сливочным сыром: Вырезать из ржаного хлеба 16 основ.",
"Канапе с лососем и сливочным сыром: Нанести сливочный сыр, добавить ломтики огурца и лосося.",
"Канапе с лососем и сливочным сыром: Украсить укропом и уложить в коробку.",
"Канапе «Капрезе»: Подготовить черри и базилик, обсушить моцареллу.",
"Канапе «Капрезе»: Собрать 20 шпажек, распределив ингредиенты поровну.",
"Канапе «Капрезе»: Добавить оливковое масло, уложить в коробку.",
"Уложить обе подборки в одну общую коробку."
],
"allergens": [
"Рыба",
"Молоко",
"Глютен"
],
"ingredientCost": 758.94,
"note": "Учебный сет и примерные цены. Все количества в таблице рассчитаны на один сет."
}
},
{
"id": "demo-extras-v1-meat-cheese",
"name": "Премиум-сет «Мясо и сыры»",
"category": 5,
"catalogSection": "Демонстрационные премиум-сеты",
"price": 3900,
"pieces": 0,
"weight": "750 г",
"photo": "demo/images/extras-meat-cheese.webp",
"demo": true,
"composition": [
"Половина стандартного бокса: Мясное ассорти с корнишонами",
"Половина стандартного бокса: Сырный бокс с виноградом и орехами"
],
"ingredients": [
[
"Салями",
0.09,
"кг"
],
[
"Ростбиф готовый",
0.11,
"кг"
],
[
"Ветчина из индейки",
0.075,
"кг"
],
[
"Корнишоны",
0.045,
"кг"
],
[
"Маслины без косточек",
0.023,
"кг"
],
[
"Горчица",
0.015,
"кг"
],
[
"Соусник",
1,
"шт."
],
[
"Коробка для кейтеринга",
1,
"шт."
],
[
"Сыр бри",
0.1,
"кг"
],
[
"Сыр гауда",
0.09,
"кг"
],
[
"Сыр с голубой плесенью",
0.06,
"кг"
],
[
"Виноград",
0.088,
"кг"
],
[
"Орех грецкий очищенный",
0.025,
"кг"
],
[
"Мёд",
0.02,
"кг"
],
[
"Крекер",
0.025,
"кг"
]
],
"ttk": {
"number": "ДЕМО-П2",
"basis": "На 1 готовый премиум-сет",
"outputGrams": 750,
"pieces": 0,
"rows": [
{
"productId": "demo-v1-stock-salami",
"name": "Салями",
"unit": "кг",
"gross": 0.09,
"net": 0.09,
"unitCost": 1400
},
{
"productId": "demo-v1-stock-beef",
"name": "Ростбиф готовый",
"unit": "кг",
"gross": 0.11,
"net": 0.11,
"unitCost": 2000
},
{
"productId": "demo-v1-stock-turkey",
"name": "Ветчина из индейки",
"unit": "кг",
"gross": 0.075,
"net": 0.075,
"unitCost": 1000
},
{
"productId": "demo-v1-stock-pickle",
"name": "Корнишоны",
"unit": "кг",
"gross": 0.045,
"net": 0.04,
"unitCost": 400
},
{
"productId": "demo-v1-stock-olive",
"name": "Маслины без косточек",
"unit": "кг",
"gross": 0.023,
"net": 0.02,
"unitCost": 650
},
{
"productId": "demo-v1-stock-mustard",
"name": "Горчица",
"unit": "кг",
"gross": 0.015,
"net": 0.015,
"unitCost": 350
},
{
"productId": "demo-v1-stock-sauce-cup",
"name": "Соусник",
"unit": "шт.",
"gross": 1,
"net": 1,
"unitCost": 7
},
{
"productId": "demo-v1-stock-box",
"name": "Коробка для кейтеринга",
"unit": "шт.",
"gross": 1,
"net": 1,
"unitCost": 65
},
{
"productId": "demo-v1-stock-brie",
"name": "Сыр бри",
"unit": "кг",
"gross": 0.1,
"net": 0.1,
"unitCost": 1600
},
{
"productId": "demo-v1-stock-gouda",
"name": "Сыр гауда",
"unit": "кг",
"gross": 0.09,
"net": 0.09,
"unitCost": 900
},
{
"productId": "demo-v1-stock-blue",
"name": "Сыр с голубой плесенью",
"unit": "кг",
"gross": 0.06,
"net": 0.06,
"unitCost": 1700
},
{
"productId": "demo-v1-stock-grape",
"name": "Виноград",
"unit": "кг",
"gross": 0.088,
"net": 0.08,
"unitCost": 420
},
{
"productId": "demo-v1-stock-walnut",
"name": "Орех грецкий очищенный",
"unit": "кг",
"gross": 0.025,
"net": 0.025,
"unitCost": 1000
},
{
"productId": "demo-v1-stock-honey",
"name": "Мёд",
"unit": "кг",
"gross": 0.02,
"net": 0.02,
"unitCost": 800
},
{
"productId": "demo-v1-stock-cracker",
"name": "Крекер",
"unit": "кг",
"gross": 0.025,
"net": 0.025,
"unitCost": 500
}
],
"steps": [
"Приготовить две мини-подборки в половинном объёме по указанным нормам.",
"Мясное ассорти с корнишонами: Нарезать готовые мясные продукты тонкими ломтиками.",
"Мясное ассорти с корнишонами: Обсушить корнишоны и маслины, переложить горчицу в соусник.",
"Мясное ассорти с корнишонами: Разложить ассорти секциями, добавить гарниры.",
"Сырный бокс с виноградом и орехами: Нарезать сыры порционными кусочками.",
"Сырный бокс с виноградом и орехами: Подготовить виноград, переложить мёд в соусник.",
"Сырный бокс с виноградом и орехами: Разложить сыры, виноград, орехи и крекер отдельными секциями.",
"Уложить обе подборки в одну общую коробку."
],
"allergens": [
"Горчица",
"Молоко",
"Орехи",
"Глютен"
],
"ingredientCost": 964.66,
"note": "Учебный сет и примерные цены. Все количества в таблице рассчитаны на один сет."
}
},
{
"id": "demo-extras-v1-mini-buffet",
"name": "Премиум-сет «Мини-фуршет»",
"category": 5,
"catalogSection": "Демонстрационные премиум-сеты",
"price": 2900,
"pieces": 22,
"weight": "820 г",
"photo": "demo/images/extras-mini-buffet.webp",
"demo": true,
"composition": [
"Половина стандартного бокса: Брускетты с томатами и базиликом",
"Половина стандартного бокса: Тарталетки с грибами и сыром"
],
"ingredients": [
[
"Багет",
0.24,
"кг"
],
[
"Томаты",
0.165,
"кг"
],
[
"Базилик",
0.013,
"кг"
],
[
"Масло оливковое",
0.028,
"кг"
],
[
"Коробка для кейтеринга",
1,
"шт."
],
[
"Тарталетки готовые",
0.1,
"кг"
],
[
"Шампиньоны",
0.22,
"кг"
],
[
"Сливки",
0.05,
"кг"
],
[
"Сыр гауда",
0.06,
"кг"
],
[
"Лук репчатый",
0.044,
"кг"
]
],
"ttk": {
"number": "ДЕМО-П3",
"basis": "На 1 готовый премиум-сет",
"outputGrams": 820,
"pieces": 22,
"rows": [
{
"productId": "demo-v1-stock-baguette",
"name": "Багет",
"unit": "кг",
"gross": 0.24,
"net": 0.24,
"unitCost": 240
},
{
"productId": "demo-v1-stock-tomato",
"name": "Томаты",
"unit": "кг",
"gross": 0.165,
"net": 0.15,
"unitCost": 260
},
{
"productId": "demo-v1-stock-basil",
"name": "Базилик",
"unit": "кг",
"gross": 0.013,
"net": 0.012,
"unitCost": 1500
},
{
"productId": "demo-v1-stock-oil",
"name": "Масло оливковое",
"unit": "кг",
"gross": 0.028,
"net": 0.028,
"unitCost": 1100
},
{
"productId": "demo-v1-stock-box",
"name": "Коробка для кейтеринга",
"unit": "шт.",
"gross": 1,
"net": 1,
"unitCost": 65
},
{
"productId": "demo-v1-stock-tartlet",
"name": "Тарталетки готовые",
"unit": "кг",
"gross": 0.1,
"net": 0.1,
"unitCost": 750
},
{
"productId": "demo-v1-stock-mushroom",
"name": "Шампиньоны",
"unit": "кг",
"gross": 0.22,
"net": 0.15,
"unitCost": 340
},
{
"productId": "demo-v1-stock-cooking-cream",
"name": "Сливки",
"unit": "кг",
"gross": 0.05,
"net": 0.05,
"unitCost": 500
},
{
"productId": "demo-v1-stock-gouda",
"name": "Сыр гауда",
"unit": "кг",
"gross": 0.06,
"net": 0.06,
"unitCost": 900
},
{
"productId": "demo-v1-stock-onion",
"name": "Лук репчатый",
"unit": "кг",
"gross": 0.044,
"net": 0.03,
"unitCost": 80
}
],
"steps": [
"Приготовить две мини-подборки в половинном объёме по указанным нормам.",
"Брускетты с томатами и базиликом: Нарезать багет на 24 одинаковых ломтика и подсушить.",
"Брускетты с томатами и базиликом: Подготовить томаты и базилик, смешать с маслом.",
"Брускетты с томатами и базиликом: Распределить начинку по ломтикам, уложить в коробку.",
"Тарталетки с грибами и сыром: Подготовить и обжарить лук с грибами на масле; в расчёте учтены потери массы.",
"Тарталетки с грибами и сыром: Добавить сливки и распределить начинку по 20 тарталеткам.",
"Тарталетки с грибами и сыром: Добавить сыр, запечь до расплавления и упаковать после охлаждения.",
"Уложить обе подборки в одну общую коробку."
],
"allergens": [
"Глютен",
"Молоко"
],
"ingredientCost": 448.12,
"note": "Учебный сет и примерные цены. Все количества в таблице рассчитаны на один сет."
}
},
{
"id": "demo-extras-v1-water",
"name": "Вода негазированная, 0,5 л",
"category": 3,
"catalogSection": "Безалкогольные напитки",
"price": 90,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-water.webp",
"composition": [
"Одна бутылка 0,5 л"
],
"ingredients": [
[
"Демо: вода негазированная 0,5 л",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-sparkling",
"name": "Вода газированная, 0,5 л",
"category": 3,
"catalogSection": "Безалкогольные напитки",
"price": 100,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-sparkling.webp",
"composition": [
"Одна бутылка 0,5 л"
],
"ingredients": [
[
"Демо: вода газированная 0,5 л",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-juice",
"name": "Яблочный сок, 1 л",
"category": 3,
"catalogSection": "Безалкогольные напитки",
"price": 220,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-juice.webp",
"composition": [
"Одна упаковка 1 л"
],
"ingredients": [
[
"Демо: сок яблочный 1 л",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-mors",
"name": "Клюквенный морс, 1 л",
"category": 3,
"catalogSection": "Безалкогольные напитки",
"price": 280,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-mors.webp",
"composition": [
"Одна бутылка готового морса 1 л"
],
"ingredients": [
[
"Демо: морс клюквенный 1 л",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-plate",
"name": "Тарелка одноразовая, 1 шт.",
"category": 1,
"catalogSection": "Одноразовая посуда",
"price": 25,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-plate.webp",
"composition": [
"Одна сервировочная тарелка"
],
"ingredients": [
[
"Демо: тарелка одноразовая",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-fork",
"name": "Вилка одноразовая, 1 шт.",
"category": 1,
"catalogSection": "Одноразовая посуда",
"price": 10,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-fork.webp",
"composition": [
"Одна вилка"
],
"ingredients": [
[
"Демо: вилка одноразовая",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-glass",
"name": "Стакан одноразовый, 250 мл",
"category": 1,
"catalogSection": "Одноразовая посуда",
"price": 15,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-glass.webp",
"composition": [
"Один стакан"
],
"ingredients": [
[
"Демо: стакан одноразовый 250 мл",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-napkin",
"name": "Салфетка сервировочная, 1 шт.",
"category": 1,
"catalogSection": "Одноразовая посуда",
"price": 10,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-napkin.webp",
"composition": [
"Одна бумажная салфетка"
],
"ingredients": [
[
"Демо: салфетка сервировочная",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-ice",
"name": "Лёд пищевой, пакет 1 кг",
"category": 2,
"catalogSection": "Для сервировки",
"price": 180,
"pieces": 1,
"weight": "1 кг",
"photo": "demo/images/extras-ice.webp",
"composition": [
"Один пакет пищевого льда, 1 кг"
],
"ingredients": [
[
"Демо: лёд пищевой",
1,
"кг"
]
],
"demo": true
},
{
"id": "demo-extras-v1-tablecloth",
"name": "Скатерть одноразовая, 1 шт.",
"category": 2,
"catalogSection": "Для сервировки",
"price": 250,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-tablecloth.webp",
"composition": [
"Одна одноразовая скатерть 120 × 180 см"
],
"ingredients": [
[
"Демо: скатерть одноразовая",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-serving-kit",
"name": "Набор для подачи: щипцы и лопатка",
"category": 2,
"catalogSection": "Для сервировки",
"price": 190,
"pieces": 1,
"weight": "",
"photo": "demo/images/extras-serving-kit.webp",
"composition": [
"Один комплект одноразовых приборов для подачи"
],
"ingredients": [
[
"Демо: набор щипцы и лопатка",
1,
"шт."
]
],
"demo": true
},
{
"id": "demo-extras-v1-delivery-city",
"name": "Доставка по городу",
"category": 4,
"catalogSection": "Учебные тарифы доставки",
"price": 600,
"pieces": 0,
"weight": "",
"photo": "demo/images/extras-delivery-city.webp",
"composition": [
"Учебный тариф за один адрес в пределах города."
],
"ingredients": [],
"demo": true
},
{
"id": "demo-extras-v1-delivery-outer",
"name": "Доставка за город",
"category": 4,
"catalogSection": "Учебные тарифы доставки",
"price": 1200,
"pieces": 0,
"weight": "",
"photo": "demo/images/extras-delivery-outer.webp",
"composition": [
"Учебный тариф за один адрес в ближайшем пригороде."
],
"ingredients": [],
"demo": true
}
],
"stock": [
{
"id": "demo-extras-v1-stock-water",
"name": "Демо: вода негазированная 0,5 л",
"cost": 35,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-grocery",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-sparkling",
"name": "Демо: вода газированная 0,5 л",
"cost": 40,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-grocery",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-juice",
"name": "Демо: сок яблочный 1 л",
"cost": 110,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-grocery",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-mors",
"name": "Демо: морс клюквенный 1 л",
"cost": 140,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-grocery",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-plate",
"name": "Демо: тарелка одноразовая",
"cost": 12,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-pack",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-fork",
"name": "Демо: вилка одноразовая",
"cost": 4,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-pack",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-glass",
"name": "Демо: стакан одноразовый 250 мл",
"cost": 6,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-pack",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-napkin",
"name": "Демо: салфетка сервировочная",
"cost": 3,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-pack",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-ice",
"name": "Демо: лёд пищевой",
"cost": 70,
"unit": "кг",
"qty": 0,
"min": 1,
"supplierId": "demo-v1-supplier-grocery",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-tablecloth",
"name": "Демо: скатерть одноразовая",
"cost": 110,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-pack",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
},
{
"id": "demo-extras-v1-stock-serving-kit",
"name": "Демо: набор щипцы и лопатка",
"cost": 85,
"unit": "шт.",
"qty": 0,
"min": 10,
"supplierId": "demo-v1-supplier-pack",
"lastPurchaseDate": "",
"lastPurchasePrice": 0
}
]
}