Веб-приложение для столовой: как описать блюда, ингредиенты и аллергены, собрать редактор меню и получить выгрузку списка закупок без лишней ручной работы.

Когда меню живет в таблицах и переписках, одна и та же задача распадается на куски: состав блюд хранится в одном месте, раскладка по граммам - в другом, аллергены - в голове у повара или в примечаниях, а закупки пересчитываются вручную перед каждой неделей.
Обычно столовой (а также кафе при офисе, школе или небольшом производстве) нужно закрыть четыре вещи: быстро собрать меню на день или неделю, не забыть про аллергены, держать точную раскладку ингредиентов на порцию и получать понятный план закупок под выбранное меню.
Таблиц часто не хватает не потому, что они плохие, а потому что они не защищают от типовых ошибок. Файл легко копируют и правят параллельно, версии расходятся, формулы ломаются, а замена одного ингредиента тянет за собой цепочку ручных пересчетов. Частая история: блюдо поменяли, а закупку не пересчитали. Или пересчитали, но забыли обновить аллерген (например, соус с горчицей или следы орехов в полуфабрикате).
Веб-приложение для столовой решает это как систему, а не как набор документов: вы выбираете блюда в меню, приложение подтягивает состав и аллергены, умножает раскладку на количество порций и собирает итоговый список закупок.
На выходе остаются два рабочих инструмента: редактор меню (блюда, порции, заметные отметки по аллергенам) и выгрузка закупок, где ингредиенты уже суммированы по периоду и приведены к нужным единицам (кг, л, штуки).
Дальше все держится на данных. Если один раз аккуратно описать связку «блюдо/ингредиент/аллерген/раскладка», меню и закупки собираются без постоянной ручной сверки.
Чтобы приложение умело показывать меню, отмечать аллергены и считать закупки, сначала договоритесь о словаре.
Блюдо - то, что видит гость и что попадает в план питания. Обычно у блюда есть название, категория (суп, гарнир, напиток), выход порции (например, 250 г) и способ приготовления (варка, запекание). Это помогает сортировать меню и правильно считать объем на день.
Ингредиент - продукт из кладовой, который закупают и списывают. Важно сразу задать единицу учета (кг, л, шт) и потери (например, чистка овощей). Поставщика можно хранить отдельно, если планируете сравнивать цены.
Аллерген - справочник для маркировки меню. Обычно хватает кода (например, A01) и названия (молоко, яйца, глютен). Дополнительно полезно определить правило отображения: показывать всегда, показывать только если есть, или скрывать во внутреннем учете.
Раскладка - нормы: сколько каждого ингредиента нужно на порцию или на 100 г блюда. Раскладка делает блюдо «считаемым». Без нее закупки будут «на глаз».
Связи лучше держать явными, чтобы пересчеты не превращались в лотерею:
Пример: «Омлет 200 г» состоит из яиц и молока. Яйца несут аллерген «яйцо», молоко - «молоко». Когда вы ставите 60 порций на завтрак, раскладка умножается на 60, а аллергены появляются в карточке блюда и в меню.
Если вы хотите, чтобы меню не только выглядело аккуратно, но и давало точный список закупок, важнее всего договориться о данных. Расширять модель можно потом, а базовые правила лучше не менять каждую неделю.
Для расчета закупок нужны четыре опорные сущности (блюдо, ингредиент, аллерген, раскладка) и несколько обязательных полей:
Один типичный источник ошибок: у салата выход 150 г, а в раскладке майонез указан в миллилитрах, при этом пересчета нет. Лучше сразу решить, что у каждого ингредиента есть одна базовая единица, а перевод хранится как правило.
Чтобы не путаться между г, кг, мл, л и шт, заведите справочник единиц и правила конвертации. Отдельно зафиксируйте, как округляете итоговую закупку: вверх до упаковки (сметана по 1 кг), до шага (крупы до 0,1 кг) и с учетом потерь (очистка, ужарка) коэффициентом. Плотность имеет смысл хранить только там, где без нее не обойтись (например, масло: мл в г).
Из справочников чаще всего окупаются категории блюд (супы, гарниры), группы ингредиентов (молочка, бакалея) и единый список аллергенов. Статусы тоже важны: архив не должен попадать в закупки, а черновик - в печать меню.
Самый надежный способ не ошибиться с аллергенами - считать их из состава блюда. Для этого у блюда хранится раскладка: список строк, где каждая строка описывает один ингредиент и норму на порцию (например, «молоко 3.2% - 50 мл», «мука пшеничная - 20 г»). Вы меняете ингредиент или норму, и дальше все пересчитывается.
Аллергены удобнее хранить на уровне ингредиента. У ингредиента есть список аллергенов, а блюдо наследует их через раскладку. Тогда «сыр» и «молоко» автоматически дадут «молоко», а «пшеничная мука» - «глютен». Ручной труд уменьшается, а правила становятся едиными для всего меню.
В реальной кухне бывают исключения, поэтому полезны ручные корректировки на уровне блюда: «добавить аллерген» и «исключить аллерген». Пример: полуфабрикат с пометкой «следы орехов» - добавляете вручную. Или ингредиент «соус терияки» отмечен как содержащий глютен, но для конкретной позиции вы используете безглютеновую версию - исключаете, но с обязательным комментарием.
Чтобы аллергены и закупки не «плыли» из-за ошибок в раскладке, добавьте простые проверки: у каждой строки должна быть единица измерения, норма должна быть больше нуля, ингредиент выбирается из справочника (не текстом), а при ручном исключении аллергена система должна предупреждать.
И обязательно храните историю изменений: кто и когда правил раскладку и почему. Это помогает разбирать претензии («вчера было без молока»), восстанавливать прошлую версию и отвечать проверяющим.
Чтобы приложение не превратилось в новую «таблицу на максималках», начинайте не с экранов, а с данных.
Рабочий порядок для небольшой столовой на 50-200 порций в день:
Пример: в понедельник вы ставите «Куриный суп» на 80 порций и «Пюре» на 60. Если в раскладке супа есть сельдерей, он появится в отметках аллергенов автоматически. Если вместо молока в пюре переходите на сливки, молочный аллерген останется, но обновится состав и закупка.
Редактор меню должен помогать делать две вещи: быстро собрать меню на период и не терять детали, от которых зависят аллергены и закупки. Обычно хватает двух экранов: «Меню» и «Блюдо».
Меню удобно показывать сеткой: дни недели, внутри каждого дня - приемы пищи (завтрак, обед, ужин), а в строках - выбранные блюда. Рядом стоит показывать порции на день и заметный маркер, если в блюде есть аллерген из списка, который вы решили подсвечивать.
Чтобы экран не превращался в хаос, достаточно нескольких действий рядом с днем или приемом пищи: добавить блюдо, скопировать со вчера, очистить, поменять местами.
В карточке блюда лучше держать в одном месте все, что влияет на расчеты: состав, нормы, аллергены и короткие комментарии для персонала. Аллергены логичнее показывать как список, который заполняется автоматически из ингредиентов, а рядом оставить поле комментария (например, «возможны следы орехов»).
Когда блюд становится много, начинают экономить время фильтры: по категории, по аллергену, по ингредиенту.
Стартовать можно с импорта из таблицы, а дальше редактировать в интерфейсе. И сразу продумайте версии: снимок меню или раскладки перед изменениями, чтобы можно было откатиться, если после правок «поехали» закупки.
Расчет закупок должен быть простым и объяснимым: меню на период + порции + раскладка. Тогда результат получается одинаковым каждый раз.
Входные данные: выбранные блюда и план порций (при необходимости отдельно по приемам пищи). Дальше формула одна: норма на порцию x количество порций.
Обычно достаточно такого порядка:
Потери лучше считать явно. Например, для очищаемых овощей задайте коэффициент 1,15 (15% отходов) и умножайте потребность на него. Для округления задайте упаковку: мука по 2 кг, молоко по 1 л, яйца по 10 шт. Тогда итог будет не «13,2 яйца», а «20 шт», а остаток уйдет в склад.
Пример: на неделю запланировали 120 порций супа. В раскладке: картофель 100 г и морковь 20 г на порцию. Итого картофель 12 кг, морковь 2,4 кг. Если морковь с потерями 15%, получится 2,76 кг. При фасовке по 1 кг закупка будет 3 кг.
Удобная выгрузка - это таблица, где каждая строка один ингредиент: категория, количество к закупке с единицами, брутто и нетто (если учитываете потери), упаковка и число упаковок, примечание (замена, бренд, требования).
Столовая готовит на 120 порций в день. Меню планируют на 5 дней, по 2-3 блюда в день: суп, горячее, салат. Задача простая: один раз описать блюда и состав, а дальше правки в меню автоматически меняют список закупок.
В понедельник стоят: куриный суп, гречка с котлетой, салат из капусты. Во вторник: борщ, макароны с курицей, салат из огурцов. Общий ингредиент, который встречается почти каждый день, это лук: он есть в супах, поджарке и салатах.
Аллерген тоже может «прятаться» в разных местах. Например, «глютен» появляется и в панировочных сухарях для котлет, и в макаронах, и в хлебе к обеду (если вы ведете его как отдельную позицию).
Чтобы было наглядно, в раскладке котлеты на 1 порцию задано: 90 г фарша, 15 г лука, 10 г хлеба, 5 г молока, 8 г сухарей. На 120 порций это уже 1,8 кг лука только на котлеты, плюс лук в суп и в салаты.
В среду вы решили вместо панировочных сухарей использовать рисовую муку (по поставке или чтобы снизить глютен). Вы меняете один ингредиент в составе блюда, и дальше пересчет идет по цепочке: сухари становятся нулем, рисовая мука появляется с нужным весом, по аллергенам у блюда пропадает «глютен» (если он был только в сухарях), а закупка лука, мяса и молока не меняется.
Такой сценарий и нужен в приложении: вы правите меню, а система сразу показывает, что купить и какие аллергены выходят в раздачу.
Первая ошибка - единицы измерения. Когда часть позиций в граммах, часть в килограммах, а что-то в штуках без правил перевода, итоговый план закупок начинает врать. Договоритесь: у ингредиента есть базовая единица, а упаковка и пересчет хранятся отдельными полями.
Вторая боль - аллергены, записанные текстом внутри блюда. Сегодня заменили соус, аллерген поменялся, а карточка блюда осталась прежней. Надежнее привязать аллергены к ингредиентам и наследовать их через раскладку.
Третья ошибка - игнорировать потери и выход порции. Если в раскладке 120 г сырого мяса, а на тарелке 90 г готового, закупка без учета потерь будет меньше нужного. Даже грубый коэффициент выхода лучше, чем ноль.
Четвертая - правки без версии. Сегодня изменили норму соли, завтра снова, а потом нужно понять, почему закупка на прошлой неделе была другой. Делайте версии раскладок по датам или хотя бы снимки.
Пятая - суммирование по разным названиям одного и того же ингредиента: «Молоко 2,5%», «молоко пастеризованное», «молоко» превращаются в три строки закупки. Решение - один справочник ингредиентов с уникальным кодом и нормализованным названием, а синонимы и привязку к поставщику держать отдельно.
Перед тем как отдавать меню поварам и бухгалтерии, проверьте базовые вещи. Именно на них чаще всего «едет» расчет закупок и маркировка аллергенов:
Перед запуском сделайте проверку «на здравый смысл»: возьмите один день и одно популярное блюдо (например, «котлета с гарниром»), пересчитайте закупку вручную и сравните с выгрузкой. Если сходится без подгонки, значит модель данных и формулы настроены правильно. Дальше ошибки будут чаще в данных: не та единица, забыли выход порции, пропустили строку в раскладке.
Начните с малого: один цех или одна линия раздачи, минимальные справочники (ингредиенты с единицами, аллергены, блюда и раскладки), затем 10-20 самых ходовых блюд. Этого хватает, чтобы быстро увидеть ошибки в данных и понять, как людям удобнее работать.
Проверяйте прототип на реальных пользователях: повару важен состав и выход, закупщику - список закупок, технологу - аллергены. Возьмите меню на 2-3 дня и попробуйте прожить с ним как с рабочим: выгрузить закупку, внести замену ингредиента, проверить, что все пересчиталось.
Если вы собираете такое приложение через TakProsto (takprosto.ai), удобно сначала описать сущности и экраны в режиме планирования, а затем уже собирать формы и расчет. Дальше можно подключить хостинг, свой домен и пользоваться системой ежедневно без ручного копирования таблиц.
Начните с описания данных: ингредиенты с базовой единицей учета, список аллергенов, блюда с выходом порции и раскладка «ингредиент → норма на порцию». Когда эта связка заполнена, меню и закупки считаются автоматически и перестают зависеть от ручных пересчетов.
Держите аллерген на уровне ингредиента и наследуйте его в блюдо через раскладку. Тогда замена ингредиента сразу обновит и маркировку в меню, и закупку, без ручного редактирования каждой карточки блюда.
Выберите одну базовую единицу для каждого ингредиента и приводите все нормы к ней при расчете. Если в раскладке встречаются разные единицы, добавьте правило конвертации (например, мл в г через плотность только там, где это нужно), иначе закупка начнет «плыть» на смешанных граммах и миллилитрах.
Заведите коэффициент потерь (или выхода) на ингредиент или на конкретную операцию и применяйте его к расчету потребности. Даже простой коэффициент вроде 1,15 для очищаемых овощей обычно дает заметно более точную закупку, чем расчеты «в нетто» без поправок.
Храните нормы в одном понятном формате, чаще всего «на 1 порцию», и фиксируйте выход порции у блюда. Так легче объяснить расчет и проверить его руками на одном блюде, а при изменении числа порций пересчет работает без дополнительных допущений.
Сделайте в блюде ручные корректировки «добавить» и «исключить» аллерген, но требуйте комментарий к такой правке. Это помогает обрабатывать случаи вроде «следы орехов» в полуфабрикате или замену на безглютеновую версию, не ломая общий принцип наследования через ингредиенты.
Введите статусы вроде «черновик», «активно», «архив» и используйте их в расчетах и печати. В закупки и меню должны попадать только активные позиции, иначе легко случайно посчитать закупку по старому рецепту или показать гостям тестовое блюдо.
Минимум — храните историю изменений: кто, когда и что поменял в раскладке и почему. Практичнее всего делать снимок версии перед правками, чтобы можно было быстро откатиться, если после замены ингредиента или нормы внезапно изменились закупки на весь период.
Дайте ингредиенту уникальный код и одно нормализованное имя в справочнике, а варианты названий храните как синонимы. Тогда «молоко 2,5%» и «молоко пастеризованное» не разъедутся в две строки закупки, и суммирование по периоду будет корректным.
Считайте итог, а потом применяйте правило округления до упаковки или шага закупки, который вы реально покупаете. Если яйца идут по 10 шт, а сметана по 1 кг, итог должен показывать понятное количество упаковок, иначе людям все равно придется «додумывать» и править вручную.