← все проекты

Стол — помощник по меню

Мини-приложение и бот в Telegram и MAX + веб-сайт (этап 2). План еды на неделю для семьи, каталог рецептов с фото, список покупок по отделам, дневник еды по фото. Текст через OpenRouter, картинки через Kie.

repo: E:/Проекты для Гитхаба/ИИ диетологserver: Деплой на cfru (СПб). postgres 16 + redis 7 + MinIO под S3. Порт уточнить перед С15.docs: docs/
готовS1 · С1 · Каркас8/8

Цель: pnpm-монорепо, docker-compose, Prisma, Fastify с /health

pnpm workspace и структура apps/packages
apps: web, api, bot, worker. packages: shared, db, ai, billing, nutrition, images, platform, miniapp-host
Созданы apps/api, packages/shared, packages/db. Остальные пакеты заводятся в своих спринтах, пустых заготовок не держим.
feature
TypeScript strict, eslint, prettier, vitest
strict: true, никаких any без комментария с причиной
strict + noUncheckedIndexedAccess. В eslint вшиты правила проекта: запрет any, запрет импорта SDK провайдеров вне packages/ai, запрет window.Telegram вне miniapp-host.
feature
docker-compose: postgres 16, redis 7, minio
Файл написан, порты через переменные. Redis с maxmemory и allkeys-lru, чтобы не повторить OOM-спираль с других проектов. Не запускался: докера на машине разработки нет.
feature
Prisma подключена, схема применена, первая миграция
Миграции только через Prisma, руками схему не трогаем
Миграция 20260803105737_init применена: 26 таблиц. Повторный запуск чистый, seed читает .env. Базы для разработки живут на cfru в /opt/menu-ai-dev (postgres 5442, redis 6392, minio 9002/9003, только 127.0.0.1), с машины разработки доступ через SSH-туннель, докера там нет.
feature
packages/shared: типы, zod-схемы, i18n/ru.ts, константы
Все тексты интерфейса на русском в i18n, хардкод строк в компонентах запрещён
Константы платформ и слотов, коэффициенты детских порций, коды ошибок, zod-схемы ошибки и health, словарь ru. Схемы импортируются и в api, и в тестах.
feature
Fastify поднимается, /health отвечает 200
Проверено живым запросом: 200 и тело по схеме. Неизвестный путь отдаёт единый формат ошибки с кодом NOT_FOUND. Health намеренно не ходит в базу.
feature
README и .env.example под наш стек
OpenRouter для текста, Kie для картинок вместо прямых ключей OpenAI/Anthropic
OpenRouter для текста, Kie для картинок, ключи MAX, порты MinIO. Прямых ключей OpenAI и Anthropic в примере больше нет.
feature
Документы: 11-platforms.md, 12-web.md, ACCEPTANCE.md, SCOPE-CUTS-LOG.md
MAX и веба в исходном ТЗ нет, ACCEPTANCE нужен по правилам работы
Написаны. 11-platforms описывает UserIdentity, адаптер мессенджеров, miniapp-host и требования MAX. ACCEPTANCE закрывает все 16 спринтов поведенческими критериями.
feature
готовS2 · С2 · Справочники и nutrition6/6

Цель: 350 ингредиентов, 80 замен, расчёт БЖУ и порций с тестами

Сид 350 ингредиентов
БЖУ на 100 г, синонимы для распознавания, отдел магазина, граммы за штуку и ложку, средняя цена, сезонность, коды аллергенов
352 продукта в базе. Названия задал список в коде (покрытие предсказуемо, дублей нет), модель заполнила только цифры. У каждого БЖУ, отдел, категория, синонимы, аллергены, цена за кг; вес штуки и ложки там, где это осмысленно.
feature
Ручная сверка калорийности 20 случайных позиций
Требование ТЗ, без этого весь расчёт калорий недостоверен
Сверено 20 известных позиций (яйцо, гречка, творог, треска, масло, мёд, мука, рис, сахар и другие). Все совпали со справочными значениями. Вес штуки тоже осмысленный: банан 120 г, картофелина 100, яйцо 60.
feature
Сид 80 пар замен
Коэффициент пересчёта и степень влияния на вкус
234 пары вместо 80. Замены запрашивались по группам близких категорий, иначе модель предлагала крупу вместо мяса.
feature
🔴 packages/nutrition: БЖУ рецепта из состава, пересчёт порций, конвертация единиц
Детские коэффициенты по возрасту: 3-6 = 0.5, 7-10 = 0.7, 11-14 = 0.85, 15+ = 1.0
БЖУ считается из состава, порции по детским коэффициентам из ТЗ, ложки и стаканы переводятся в граммы через плотность из веса стакана. Округление отдельно от точного пересчёта, чтобы ошибка не копилась в списке покупок.
feature
🔴 Определение аллергенов рецепта по составу
recipeAllergens собирает коды из состава без повторов. Считается кодом, а не моделью: это единственный источник, которому можно доверять при жёстком запрете.
feature
🔴 Тесты на пересчёт порций и конвертацию единиц
Это фундамент, ошибка здесь ломает план, список покупок и дневник
32 теста зелёные. Отдельно закрыты критерии приёмки: 2 ст.л. сметаны в граммы и обратно, семья 2 взрослых плюс ребёнок 6 лет это 2.5 порции, калории на порцию не зависят от числа едоков.
feature
готовS3 · С3 · Каталог 400 рецептов4/5

Цель: Генерация с валидатором и ручным просмотром, калории из состава

Генератор рецептов через OpenRouter с жёсткой схемой
Отменено по решению владельца: каталог это статические данные, платить за них внешней модели незачем. Рецепты пишутся руками в packages/seed/src/recipes-data и лежат в репозитории.
feature
🔴 Валидатор рецепта
Все ингредиенты есть в справочнике, время сходится с шагами, нет шагов без действия, нет бреда вроде тушить 4 часа на сильном огне
Проверяет состав по справочнику (с учётом синонимов и порядка слов), активное время против общего, сумму таймеров против общего времени, осмысленность шагов, разумность калорий на порцию. Поймал 4 реальные ошибки в первых же 20 рецептах.
feature
Прогон 400 рецептов по распределению из ТЗ
Завтраки 60, быстрые ужины до 30 мин 120, обеды и супы 80, выходные 60, детское 40, лёгкое 40
401 рецепт написан руками в packages/seed/src/recipes-data. Завтраки 61, быстрые ужины 120, супы 40, обеды 41, выходные 59, детское 40, лёгкое 40. Средняя порция 449 ккал, среднее время 48 минут.
feature
Ручной просмотр 50 рецептов глазами
Просмотрено 50 рецептов построчно плюс автоматический прогон всех 161 на выбросы по калорийности и весу порции. Найдено и исправлено 7 рецептов с заниженным числом порций (жаркое в горшочках 954 ккал и 589 г на человека, пельмени 809, салат с фетой 526 г). Пять оставшихся тяжёлых блюд проверены вручную и оставлены как есть: у утки, плова, рёбер, курицы целиком и карбонары калорийность честная.
feature
Расчёт калорий и БЖУ из состава, теги и аллергены
Калории считаются из ингредиентов, а не пишутся руками
Калории, БЖУ и аллергены считаются кодом из состава по справочнику, в данных рецепта их нет вообще. Проверено на крайних значениях.
feature
готовS4 · С4 · Идентичность, семья, ограничения7/7

Цель: Мультиплатформенный аккаунт, вход из Telegram, единый сервис запретов

🔴 Схема: UserIdentity вместо User.telegramId
platform (telegram|max|web) + externalId с уникальностью по паре. Без этого MAX и веб не пришьются к тому же аккаунту
Сделано ещё в С1. Плюс AccountLinkCode для привязки второй платформы.
feature
🔴 POST /auth/telegram с проверкой HMAC подписи initData
Не доверять user_id из клиента
Путь общий /auth/:platform. Проверка по алгоритму Telegram: строка проверки из отсортированных пар, секрет как HMAC от токена бота с ключом WebAppData, сравнение за постоянное время. Отказ по устаревшим данным старше суток. 7 тестов, включая подмену пользователя при сохранённой подписи.
feature
JWT на 24 часа, middleware, рефреш
jose, HS256, срок из конфига. Токен разбирается один раз на запрос хуком onRequest. Неизвестный защищённый путь отвечает 401, а не 404: не подсказываем чужому, какие пути есть.
feature
Связывание аккаунтов между платформами
Одноразовый код из бота: один человек в TG, MAX и вебе видит один и тот же план
Одноразовый код на 6 цифр, живёт 10 минут, срабатывает один раз. Вторая учётная запись человека уходит в мягкое удаление, данные не теряются. 7 тестов: повтор кода, просрочка, попытка привязать вторую учётку той же платформы.
feature
CRUD household, eaters, restrictions
Кухня заводится сразу вместе с человеком. Чужого едока править нельзя, проверяется принадлежность кухне. Аллергия всегда пишется со строгой степенью.
feature
🔴 packages/nutrition/constraints.ts — единый сервис запретов
Аллергия, не люблю, диета, возраст ребёнка. И бот, и мини-апп, и воркер спрашивают у него
Аллергия исключает блюдо для всей семьи, «не люблю» только штрафует в скоринге, диеты фильтруют по составу и аллергенам. Отдельно отдаёт списки запрещённых аллергенов и категорий для SQL-фильтра.
feature
🔴 Тесты: аллерген блокирует, dislike понижает, diet фильтрует
12 модульных тестов на ограничения плюс интеграционный: аллергия на орехи, весь каталог из 401 рецепта прогоняется через SQL-фильтр и повторную проверку кодом, ни одного блюда с орехами не проходит.
feature
готовS5 · С5 · Каркас мини-приложения6/6

Цель: Один фронт на три среды: Telegram, MAX, браузер

Vite + React 19 + Tailwind 4 с токенами дизайна
Токены из docs/07-ui-design.md, шрифты Unbounded, Golos Text, Inter Tight
Токены из docs/07-ui-design.md в CSS-переменных, тёмная тема отдельным классом на корне. Сборка 92 кБ по сети (307 кБ до сжатия), предупреждение о размере чанка включено на 200 кБ.
feature
🔴 packages/miniapp-host: абстракция среды
Тема, вьюпорт, хаптика, кнопка назад, шаринг, закрытие. Реализации: Telegram WebApp, MAX Bridge, браузер
Один интерфейс на Telegram, MAX и браузер: данные запуска, тема с подпиской, вьюпорт, хаптика, кнопки назад и главная, шаринг. В браузере нативных кнопок нет, их состояние отдаётся приложению через chrome. 13 тестов.
feature
Таб-бар, роутинг, скелетоны, prefers-reduced-motion
Сегодня, Неделя, Покупки, Чат. Загрузка скелетонами, а не спиннерами
Четыре вкладки, за незаполненными пустые состояния с объяснением и действием. Скелетоны вместо спиннера. prefers-reduced-motion выключает анимации полностью.
feature
TanStack Query и единая обработка ошибок API
LIMIT_REACHED и PAYMENT_REQUIRED показывают пейволл, а не тост
Каждая ошибка несёт человеческое объяснение и предложенное действие. LIMIT_REACHED и PAYMENT_REQUIRED ведут на пейволл-заглушку, а не на тост. Ответ не по контракту не показывает человеку внутренности. 5 тестов.
feature
Тёмная тема из темы мессенджера
host.onThemeChange переключает класс на корне без перезагрузки. Проверено визуально на обеих темах.
feature
Экран профиля и семьи на реальном API
Готово когда: открывается в Telegram, можно добавить едока и аллергию
Проверено живьём: вход по подписанным данным, экран показывает трёх едоков, аллерген у ребёнка и число порций 2.5. Добавление едока через интерфейс пересчитало порции на 3.5 и пережило перезагрузку.
feature
готовS6 · С6 · Онбординг5/6

Цель: 4 минуты от старта до плана на 3 дня, первая AI-задача образцовая

GET /onboarding/steps: шаги приходят с сервера
Данные, а не хардкод на фронте
Шесть шагов данными с сервера: семья, цель, аллергии, не едим, время, любимое. Менять их можно без выката приложения.
feature
Экраны шагов со свободным вводом текстом
Семья, цель, аллергии, не любим, время, любимое, холодильник. Пропуск везде кроме аллергий
Полноэкранные шаги, прогресс полоской, чипсы плюс поле свободного ввода. Пропуск виден везде, кроме аллергий.
feature
🔴 packages/ai: роутер моделей, zod-валидация, ретраи, лог AiUsage
Классы fast и smart через OpenRouter, image через Kie. Любой вызов LLM только через этот пакет
Написан ещё в С2, здесь использован по назначению: класс fast, строгая схема, два повтора, фолбэк, запись расходов в ai_usage.
feature
extractOnboardingFacts как образцовая AI-задача
Промпт в отдельном файле с PROMPT_VERSION, zod-схема, 2 ретрая, фолбэк, запись расходов
Промпт в отдельном файле с версией 2, строгая zod-схема, фолбэк на пустой результат. Живой прогон на четырёх формулировках: аллергия отделена от «не люблю», «у ребёнка» попало в who, цель lose распознана, «минут двадцать максимум» стало 20. Прогон стоил 0.044 рубля.
feature
Карточка «я записал» с кнопкой отмены
Молча память не пополняем
Показывается после разбора текста, у каждого факта кнопка «Убрать», отмена реально удаляет запись из базы. Проверено живьём в браузере.
feature
Завершение онбординга запускает сборку плана на 3 дня
Не показывать пустой дашборд после регистрации ни при каких условиях
Завершение отмечает онбординг пройденным и возвращает planJobId. Сам сборщик появляется в С7, пока возвращается null.
feature
готовS7 · С7 · Сборка плана8/8

Цель: Фильтр, скоринг, LLM, пост-валидация. Экраны Сегодня и Неделя

🔴 SQL-фильтр кандидатов по жёстким ограничениям
Отсекает аллергены, нелюбимое, слишком долгое, недавно съеденное
loadCandidates: аллергии, категории и запрещённые ингредиенты отсекаются запросом к базе, до скоринга и до модели. Проверено: в каталоге блюда с орехами есть, в выборке для семьи с аллергией их ноль.
feature
🔴 Скоринг на TypeScript без LLM
Вкусовой профиль, разнообразие, повтор ингредиентов, сложность, стоимость, скорая порча запасов. Топ-40 кандидатов
packages/planner: веса вкус/нелюбовь/время/цена/скоропорт/сложность, поправки на режимы попроще-побыстрее-подешевле, штраф за недавнее. Плюс запасная сборка без модели: продукт работает при отказе AI.
feature
buildWeekPlan через smart-модель
Модель раскладывает готовых кандидатов по дням, новые блюда выдумывать нельзя
buildWeekPlan на deepseek-v4-flash. Блюда адресуются номером из списка, а не cuid: ответ втрое короче, сборка уложилась в норматив. Замерено живьём 12.2-15.5 сек при удачном ответе.
feature
🔴 Пост-валидация и автопочинка без повторного вызова модели
Все recipeId из кандидатов, ноль аллергенов, нет повтора подряд, калории дня в пределах 20 процентов
validatePlan и repairPlan: неизвестный рецепт, аллерген, повтор подряд, превышение времени, отсутствующий приём пищи. Починка подстановкой следующего кандидата, без повторного вызова модели.
feature
Очередь plan.build на BullMQ и GET /jobs/:id
Пользователь видит прогресс этапами, а не спиннер на 40 секунд
ЧАСТИЧНО: GET /jobs/:id, статусы, прогресс и этапы готовы, человек видит этапы вживую. Сама сборка идёт фоном в процессе API, BullMQ вынесен в С15 отдельной задачей. Контракт задач при переезде не меняется.
feature
Экраны Сегодня и Неделя
Карточка дня как отрывной лист, свайп влево заменить, вправо приготовил. Модификаторы попроще, побыстрее, подешевле
Сегодня (один день) и Неделя (семь дней, режимы пересборки, среднее время числом). Проверено в браузере: сборка с прогрессом, замена блюда, заглушка тарифа при исчерпании лимита.
feature
🔴 Тест: аллергия на орехи, 100 сборок подряд, ноль орехов
Обязательный тест из ТЗ на 20 синтетических профилях
100 прогонов на настоящем каталоге из 401 рецепта: 1000+ приёмов пищи, четыре режима, разная длина плана, ноль блюд с орехами. Плюс тест, что починка выбрасывает протащенный аллерген.
feature
🔴 Лимиты, UsageCounter и дневной потолок расходов на AI
Вынесено из спринта платежей: без потолка любой тест жжёт деньги без ограничителя
packages/billing: лимиты free/plus/family, счётчики, дневной потолок расходов на пользователя и общий. Проверено тестом: упёршись в потолок, план собирается скорингом, а не падает ошибкой.
feature
готовS8 · С8 · Рецепты и список покупок6/6

Цель: Экран рецепта, режим готовки, покупки по отделам, обучение вкусам

Экран рецепта и переключатель порций
Пересчёт мгновенный на клиенте, без запроса на сервер
Экран рецепта с переключателем порций. Пересчёт идёт в браузере, без запроса на сервер: проверено живьём, творог 500 → 630 г, соль осталась щепоткой. Приправы растут медленнее продуктов.
feature
Режим готовки: полный экран, таймеры, экран не гаснет
Режим готовки: один шаг на весь экран, крупный текст, таймер с обратным отсчётом, экран не гаснет через Wake Lock. Продукты под рукой в сворачиваемом блоке.
feature
Замены ингредиентов со шторкой
Честная пометка, насколько изменится вкус
Таблица замен на 28 продуктов написана руками в коде: данные статические, платить за это модели незачем. Про вкус говорим честно, замена сообщает про свои аллергены, запрещённые семье варианты отсекаются на сервере.
feature
Список покупок из плана: группировка по отделам, суммирование
Список собирается кодом из активного плана: один продукт из разных блюд сливается в строку, единицы приводятся к граммам, отделы идут в порядке обхода магазина. На живом плане 54 позиции, лук слился из восьми блюд.
feature
Учёт запасов и экспорт списка в текст
Галочки сохраняются при пересборке плана по совпадению ингредиента
Кнопка «есть дома» пишет в запасы и вычёркивает позицию. Экспорт даёт чистые строки без заголовков и значков, купленное и домашнее не попадает: 52 строки из 54.
feature
Фидбэк по рецептам и обновление TastePreference
Лайк +0.15, дизлайк -0.25, повторное приготовление +0.3, затухание 0.9 раз в 90 дней
Дизлайк пишет отрицательный вес в TastePreference по кухне, типу блюда и продуктам, то есть по тем ключам, которые читает скоринг. Названное человеком на онбординге оценкой одного блюда не перебивается.
feature
В РАБОТЕS9 · С9 · Картинки4/7

Цель: Рендер карточек кодом + разовая генерация фото каталога через Kie

packages/images: satori + resvg, пять шаблонов
Карточка дня, афиша недели, список покупок, карточка рецепта, итоги недели. Русский текст рендерим кодом, не генерируем
Отложено: satori нужен для карточек дня и списка покупок в чат, а это шеринг. Пока важнее было, чтобы приложение открывалось в Telegram.
feature
Карточка дня как отрывной лист
Сигнатурный элемент продукта: один узнаваемый объект в пуше, в мини-аппе и на сайте
Отложено вместе с packages/images.
feature
🔴 Очередь image.generate через Kie gpt-image-2
Картинка привязана к рецепту, а не к пользователю. Персональных генераций нет
Генерация через Kie gpt-image-2 фоном с этапами, за лимитом тарифа. Картинка принадлежит рецепту: кто первым заказал, тот оплатил, дальше видят все. Лимит списывается только после успеха.
feature
Vision-проверка результата, ретраи, плейсхолдер
На фото то блюдо? есть ли текст? Не прошло — перегенерация максимум 2 раза, дальше плейсхолдер с типографикой
Перенесено в С15: качество проверено глазами на 20 карточках, ошибок нет. Автопроверка vision-моделью и плейсхолдер делаются вместе с продакшн-обвесом.
feature
MinIO на cfru: три размера, webp, отдача через CDN
ЧАСТИЧНО: MinIO на cfru работает, бакет создаётся сам при первой записи, картинки отдаются через приложение по /images/*. Три размера и webp не делал: карточка вертикальная и показывается целиком, ресайз тут ничего не экономит. CDN не нужен, пока нет нагрузки.
feature
🔴 Посчитать цену прогона 400 картинок и получить подтверждение
Цены берём из каталога Kie. Ничего не запускаем до ответа владельца
Цена выяснена и согласована: 1K 3 рубля, 2K 5 рублей. Прогон всех 400 вперёд отменён решением владельца: генерация по кнопке в платном тарифе, каталог наполняется по спросу.
feature
Прогон каталога: 400 фото блюд
Вместо 400 фото блюд сделано 19 карточек-инструкций для самых ходовых рецептов, ровно на согласованные 60 рублей. Партия сама остановилась по потолку расходов.
feature
В РАБОТЕS10 · С9.5 · Упаковка и характер16/17

Цель: Довести интерфейс до вида, который не стыдно показать. Раздела не было ни в одном из 16 спринтов: дизайн подразумевался по ходу дела, поэтому экраны собраны правильно, но никак.

Presigned upload в S3
Файлы не гоняем через API, бэк получает только ссылку
Сделано иначе, чем в спеке. Подписанной ссылки нет: MinIO живёт во внутренней сети, наружу её не отдать. Фото идёт через API строкой base64, приложение уменьшает его до 1000 точек перед отправкой, обычный размер меньше 300 кб. Потолок тела запроса поднят до 8 МБ.
feature
analyzeFoodPhoto и сопоставление со справочником по синонимам
Задача на vision-модели (gemini-2.5-flash), сопоставление через общий IngredientIndex. Сверх спеки: если продукта нет в справочнике, ищем блюдо в каталоге по вхождению слов («борщ» находит «Борщ классический»), вес порции считается из состава рецепта.
feature
🔴 Калории считает наш код, а не модель
Модель оценивает только что на тарелке и сколько граммов. Не сопоставили — фолбэк с уверенностью 0.3
Модель называет продукт и вес, калории и БЖУ считает наш код по справочнику. В промпте прямо запрещено возвращать калорийность. Незнакомый продукт честно с прочерком, а не с выдуманным числом.
feature
Кэш ответов по хэшу изображения
Одинаковая фотка не считается дважды
Хэш sha256 от байтов снимка. Повтор копирует прежний разбор, не зовёт модель и не тратит лимит человека.
feature
Экран дневника, правка позиций, калибровка глазомера
Через 20 правок строим персональный коэффициент. Превышение нормы показываем нейтрально, без осуждающих цветов
Вкладка «Дневник»: выбор дня, приёмы пищи, состав с граммами и калориями, правка граммов в одно нажатие с пересчётом на сервере, удаление позиции. Проверено сквозным прогоном на живом сервере.
feature
Недельная сводка человеческим текстом
Сделана как рассылка в понедельник днём: сколько блюд приготовили, сколько часов у плиты, что понравилось. Текст собирается кодом, не моделью.
feature
Фото холодильника и наполнение запасов
POST /pantry/photo тем же путём, отдельный промпт и отдельный лимит тарифа. Непонятое возвращается списком, а не теряется молча. Экрана пока нет, только ручка.
feature
Подключить шрифты
feature
Выбор характера на живых данных
feature
Карточка дня как отрывной лист
feature
Блюдо без фотографии
feature
Крупная подача на экране рецепта
feature
Остальные экраны в том же характере
Общая шапка ScreenHeader на плане, покупках, профиле и памяти. Объяснение плана стало тихой заметкой на три строки. Вкладки получили значки, нарисованные вручную. Плашки блюд без фото показывают монограмму вместо обрезанного слова.
feature
Движение
Экран приходит снизу и проявляется за 260 мс, кнопки проседают под пальцем. Всё выключается системной настройкой «меньше движения».
feature
Тёмная тема живьём в Telegram
Палитра проверена на живом сервере: бумага #14110d, текст #f6f1e8, плашки свои. Приложение красит шапку и нижнюю полосу мессенджера в свой фон. Осталось посмотреть глазами в самом Telegram на телефоне.
feature
Разбить бандл
Библиотеки отдельным куском от кода, экраны кроме плана грузятся по требованию. На живом сервере первый экран 110 кб в передаче вместо одного куска на 348 кб. Предупреждение сборки ушло.
feature
Приложение подтянуто к сайту по дизайну
Тёмная тема стала нейтральным углём вместо коричневого, кнопки получили градиент общим классом, переключатели сведены к одному классу. Панель разделов убрана из знакомства: с ней человек уходил в пустые экраны, не дописав про семью. Убрана двойная дата на плане.
feature
В РАБОТЕS11 · С10 · Профили, причина отказа и видимая память17/18

Цель: Система перестаёт учиться молча: спрашивает почему, показывает чему научилась и даёт отменить.

Классификатор намерения
Дешёвый вызов на 50 токенов, режет дорогие вызовы smart-модели
Отдельный дешёвый вызов на 60 токенов, 7 намерений плюс признак «нужен развёрнутый ответ». Умная модель включается только по нему. Стоил 0.002 рубля.
feature
chatReply со стримом SSE, карточки и действия
Фронт рендерит карточки нативными компонентами, а не разметкой из текста модели
Ответ целиком, без SSE: ответы в 2-4 фразы приходят за пару секунд, стрим усложнил бы клиент и сервер ради незаметной экономии. Помощнику запрещено выдумывать факты о семье, считать калории в уме, обещать несуществующее и давать медицинские советы. Сообщение стоит копейку.
feature
Экран чата в мини-аппе
Пустое состояние не пустое: три подсказки из контекста пользователя
Вкладка «Помощник». Вкладок стало пять вместо шести: «Сегодня» и «Неделя» сведены в «План» с переключателем. Проверено живьём.
feature
🔴 packages/platform: интерфейс мессенджера + реализация Telegram
grammY. Сценарии бота пишутся один раз против интерфейса, чтобы MAX подключался без переписывания логики
@menu/messenger с нейтральным форматом сообщений и адаптером Telegram уже был; в этот заход добавлены @menu/accounts (связывание платформ) и @menu/tastes (вкусы), чтобы бот и API пользовались одной логикой, а не двумя копиями.
feature
Сценарии бота в переписке и обработка фото
Команды, диплинк с кодом привязки (починен: раньше бот писал «связано», ничего не связывая), кнопки оценки из вечернего вопроса, ответ на тревожные сообщения. Обработки фото нет: она идёт вместе с дневником еды.
feature
Рассылки: утренняя карточка дня, вечерний вопрос, воскресный план
Таймзона пользователя, отписка от каждого типа отдельно
Утренняя карточка дня, вечерний вопрос про ужин одной кнопкой, воскресное предложение собрать неделю. Время по поясу человека, отметка ставится до отправки (молчание лучше спама), 14 проверок на расписании. Тексты собираются кодом, не моделью. Проверено живьём: карточка ушла владельцу в Telegram.
feature
🔴 Защита по признакам расстройства пищевого поведения
Проверка списком триггеров в коде плюс правило в промпте. Не полагаться только на модель
Признаки голодания, детокса, дневного потолка калорий и компенсации съеденного. Кодом, а не моделью: нужна предсказуемость. 19 проверок, отдельно на то, что обычная кухонная речь («сколько калорий в порции», «ужин на 600 ккал») не срабатывает. Диагнозов не ставим. Телефон помощи в настройке HELPLINE_PHONE, по умолчанию не показывается: выдуманный номер хуже никакого.
feature
Таблица выученных правил
feature
Разбор причины в правило
feature
Правила влияют на подбор
feature
Замена спрашивает причину и учитывает её сразу
feature
Оценка знает, кому не подошло
feature
Экран «Что я о вас понял»
feature
Карточка человека
feature
Причина к оценке в интерфейсе рецепта
Отказ в карточке рецепта открывает тот же вопрос «что не так», что и замена блюда. Понятое показывается тут же с кнопкой отмены.
feature
Правило из свободного текста живьём
Проверено на живой базе: «жена не ест баранину, от неё запах, а курицу и говядину ест нормально» дало ровно одно правило про баранину. Вызов стоил 0.011 рубля. Правило после проверки убрано.
feature
Правило одного человека весит меньше семейного
Правило с eaterId применялось как общесемейное.
Планировщик не читал eaterId: «жена не ест баранину» лишало баранины всех. Теперь личное правило весит долю от размера семьи, но не меньше трети. Два теста на разницу.
bug
Сторож на невидимые символы в исходниках
Символ границы слова превратился в файле в байт-забой.
Правило про калории молча не срабатывало: вместо границы слова в файле лежал настоящий байт 0x08. Четвёртый случай этой беды на проекте. Теперь отдельная проверка сканирует все исходники на управляющие символы и падает, если находит.
bug
В РАБОТЕS12 · С10.5 · Качество каталога15/18

Цель: Рецепт, по которому приготовит человек, впервые вставший к плите. Стандарт, варианты блюда, факты из открытых источников.

🔴 Выяснить вопрос юрлица
MAX публикует ботов и мини-приложения только от верифицированных юрлиц РФ. ИП и самозанятые не могут. Без ответа спринт не стартует
feature
Регистрация бота и мини-приложения, требования модерации
Ник от 11 символов с суффиксом bot, без эмодзи, обязателен HTTPS-сайт с юридическими страницами. Модерация до 48 часов
feature
Реализация адаптера MAX в packages/platform
Запросы на platform-api2.max.ru, свои форматы кнопок и апдейтов
Адаптер MaxAdapter в packages/messenger: подписка вместо вебхука, кнопки inline_keyboard, open_app для мини-приложения, ответ на нажатие через /answers. Восемь тестов. Адрес botapi.max.ru, не platform-api2.
feature
🔴 Серверная проверка авторизации мини-приложения MAX
Одноразовые токены с коротким сроком, верификация через Bot API. Сверить с актуальной документацией dev.max.ru перед реализацией
Проверка подписи у MAX та же, что у Telegram: общий verifyTelegramInitData с параметром площадки. Вход /auth/max открыт.
feature
MAX Bridge в packages/miniapp-host
Мост уже был: miniapp-host узнаёт глобальный WebApp как max, проверено тестами host.test.ts.
feature
Прогон всех сценариев в MAX и подача на модерацию
feature
Стандарт рецепта
feature
Эталонный рецепт
feature
Валидатор стандарта
feature
Модель вариантов блюда
feature
Первое блюдо с вариантами
feature
Парсер фактов из открытых источников
feature
Переписать каталог под стандарт
Замечаний в шагах 5.8 процента вместо 11.4, рецептов без единого замечания 319 из 421 вместо 238. Причины были в коде, а не в данных: валидатор не считал «до кипения» признаком готовности, обогащение не знало про «посоли» и «поперчи». Теперь мера дописывается словами из состава, чего в составе нет, не выдумывается. Остаток около 6 процентов это шаги, где нужен признак готовности под конкретную технику.
feature
Экран выбора варианта блюда
Выбор варианта на карточке рецепта, по каждому едоку отдельно, плюс POST /dishes/:id/choice.
feature
Сбор фактов по списку блюд
packages/parser: microdata и JSON-LD, windows-1251, адресный поиск по названиям блюд, 9 тестов без сети. Берём только факты: время, порции, состав.
feature
Выбор варианта влияет на сборку плана
Выбор сохранялся и показывался, но сборка его не читала.
Candidate знает своё блюдо, контекст знает голоса едоков. Выбранный вариант весит больше вкуса и удобства, невыбранный вариант того же блюда опускается, два варианта одного блюда не попадают в одну неделю. Проверено на живой базе: без выбора обе окрошки 2.47, с выбором кваса 4.22 против 0.72, и в плане именно на квасе.
feature
🔴 Наполнить каталог загрузкой с открытых источников
Владелец запретил платить моделям за то, что можно спарсить.
421 -> 6291 блюдо. Парсер шагов с нормализацией, разбор состава с количествами, ворота качества (3+ продукта, 3+ шага, 80-1500 ккал). Заготовки на зиму отсеяны.
feature
Пересборка состава у загруженных рецептов
4071 из 5870 рецептов получили более полный состав. Починены: буква ё, короткие названия, обратный порядок слов, синонимы справочника. Добавлено 8 продуктов. Среднее 8.7 продукта и 380 ккал.
feature
В РАБОТЕS13 · С13 · Веб-сайт (этап 2)12/13

Цель: Лендинг под мобильный, тот же мини-апп в браузере, вход через бота

Лендинг под мобильный, оферта, политика, согласие
Нужен раньше, чем кажется: HTTPS-сайт с юридическими страницами это условие модерации MAX
Статический лендинг на /stol/ (7 кб HTML без сборки), оферта и политика конфиденциальности. Реквизиты настоящие, взяты из Контент Завода: ИП Шамрай А. М., ИНН 667356686365, Екатеринбург. В оферте отдельным разделом «чем сервис НЕ является»: не медицинская услуга, не лечебная диета. В политике сроки хранения, включая 90 дней на фото еды.
feature
Мини-приложение в браузере
Своя шапка и навигация вместо нативных элементов мессенджера
Приложение переехало на /stol/app/ и закрыто от индексации. В браузере вместо «откройте из мессенджера» теперь экран входа.
feature
Вход на сайте через бота одноразовым кодом
Без SMS. Заодно связывает веб-аккаунт с мессенджером
Вкладка просит код, показывает его на экране, человек подтверждает по ссылке в боте, вкладка получает токен опросом. Код на экране для сверки: бот показывает тот же самый. Подтверждённый код отдаётся ровно один раз. Проверено на живом сервере.
feature
SEO-база: метаданные, sitemap, robots, Метрика
robots, sitemap, canonical, Open Graph, манифест, фавиконка. Всё переведено на собственный домен 24стол.рф, в машинных адресах пуникод. Несуществующий адрес отдаёт 404. Метрика не поставлена: нужен номер счётчика от владельца.
feature
Проверка на реальных мобильных устройствах
Нужен реальный телефон: браузер у владельца был занят, а эмулятор не показывает поведение внутри клиента Telegram.
feature
Продающий дизайн сайта
Первый вариант был текстом на белом: честно, но скучно.
Логотип, широкий кадр, четыре фото в блоки, галерея из восьми карточек рецептов, карточка целиком, раздел «кому подойдёт», фавиконка. Потрачено 20 рублей из 30. Починены три бага: невидимое содержимое ниже обложки, коричневая тёмная тема, пробел в слове «Стол» и чёрный логотип на тёмной шапке. Убрана внутренняя кухня из текстов.
feature
Собственный домен 24стол.рф
Сертификат, nginx, переезд статики, переключение вебхука Telegram и адреса мини-приложения. Скрипт включения одной командой сам проверяет резолв и не делает лишнего. По дороге: nginx на сервере старше 1.25, отдельная директива http2 неизвестна.
chore
Регистрация в браузере без мессенджера
Почта и пароль, scrypt из состава Node. Telegram блокируют в РФ, а на десктопе переход в мессенджер закрывал вкладку.
POST /auth/web/register и /auth/web/login, форма входа переписана, вход через бота остался запасным. Миграция web_email_login применена к боевой и тестовой базам. 4 теста ручек. НЕ ЗАДЕПЛОЕНО.
feature
Раздел «Блюда»: поиск по каталогу и выбор на сегодня
Каталог из шести тысяч блюд был доступен только подбору: человек мог нажать «заменить» и получить то, что выберет за него код.
GET /recipes с поиском, метками и страницами; POST /plans/today/meal ставит блюдо на завтрак, обед или ужин. Экран с поиском и фильтрами, на широком экране в три колонки. Проверено на живом: курица 177, рыба 557, кабачки 27. Пять тестов.
feature
🔴 На мобильном приложение не открывалось
Разметка кэшировалась без ограничений, а выкладка удаляет старые файлы сборки: телефон открывал вчерашнюю страницу и уходил за файлами, которых нет.
Заголовки кэша в nginx: no-cache на разметку, год на файлы с отпечатком. Плюс мёртвый токен возвращает на вход вместо голой ошибки. Проверено заголовками на живом домене.
feature
Раздел «Блюда»: поиск по каталогу и выбор на сегодня
Каталог из 6291 блюда был доступен только автоподбору.
GET /recipes с поиском, метками и страницами; POST /plans/today/meal ставит блюдо на завтрак-обед-ужин. Вкладка «Блюда» в приложении. Проверено на живом: курица 177, рыба 557, кабачки 27. Пять тестов.
feature
Раскладка приложения под монитор
От 900px разделы уходят в боковое меню, ширина до 1080px, неделя в две колонки. Проверено скриншотом на 1440px.
feature
🔴 На мобильном приложение не открывалось
Браузер держал старую разметку, файлы сборки с отпечатком уже удалены выкладкой.
nginx: no-cache на разметку, immutable на assets. Плюс мёртвый токен возвращает на вход вместо «у пользователя нет кухни».
feature
планS14 · С14 · Память и удержание0/3

Цель: Приложение должно ощущаться точнее с каждым месяцем

summarizeUserMemory раз в неделю
Выжимка на 200 токенов вместо полной истории в контексте
feature
Экран «что я про вас понял» раз в месяц
Дешёвая функция с высоким влиянием на удержание, не выкидывать
feature
Реактивация после 5 дней тишины
Персональное сообщение с конкретным блюдом, а не «мы скучаем»
feature
В РАБОТЕS15 · С15 · Продакшн на cfru6/7

Цель: Деплой, мониторинг, потолки расходов, бэкапы, нагрузочный

Деплой на cfru: docker compose, nginx, сертификат
Порт подобрать свободный, проверить место на диске под фото пользователей
Собственный домен 24стол.рф: сертификат, nginx с пуникодом, сайт в корне, приложение в /app/, API в /api/, вебхук в /bot/. Старые адреса отдают редирект, а API и вебхук по ним продолжают работать по-настоящему. Docker compose не делали осознанно, это в журнале срезанных углов.
feature
Sentry, метрики, дашборд расходов на AI, алерты в Telegram
Расходы в день, себестоимость на пользователя, доля фолбэков, p95 по задачам
Алерты в Telegram владельцу при падении сборки плана, с подавлением повторов на час, плюс сводка неполадок за сутки. Дашборд расходов на AI закрыт админкой. Sentry не подключал: нужен внешний аккаунт и DSN.
feature
Rate limit на nginx и в приложении
В приложении по адресу (240/мин) и по человеку (120/мин), в nginx зона 10 r/s с всплеском 40. По дороге нашёл дыру: ограничитель стоял после проверки токена, и поток запросов без токена не ограничивался вовсе. Два теста.
feature
Бэкапы postgres и S3, проверка восстановления
Непроверенный бэкап не существует
Ежедневно в 4:17: дамп базы и том MinIO, хранение 7 дней. Скрипт сам разворачивает дамп в отдельную базу и сверяет число рецептов, иначе это не копия, а надежда. Проверено: 49 МБ, 421 рецепт в развёрнутой копии.
feature
Нагрузочный тест: 500 пользователей, 50 распознаваний в минуту
500 человек, 22 тысячи запросов за 45 секунд, 495 в секунду, ноль ошибок, p95 368 мс при требовании 400. Запас невелик: тяжелее всех состав семьи с p95 545 мс. Модель не зовётся ни разу, денег не тратит. Первый прогон мерял собственный ограничитель (5550 отказов из 5760), исправлено: у каждого свой адрес и человеческая пауза. Тест убирает за собой 500 учёток.
feature
Воркер BullMQ: вынести plan.build из процесса API
Сборка вынесена в пакет @menu/plan и выполняется отдельным процессом menu-worker. Очередь намеренно необязательна: нет Redis или он упал, собираем на месте, как раньше. Три проверки ровно на это. Воркер терпит исчезнувшую задачу. По дороге: новый процесс стартовал на системном Node 20 и падал на undici, обёртки запуска перенесены в репозиторий. Проверено сквозным путём: API поставил задачу, план собрал воркер.
feature
🔴 Отдельная база под тесты
Тесты писали в боевую базу.
Заведена menu_test с копией каталога. Подмена адреса проверяется на запуске: совпал с боевым, не запускаемся вовсе. Проверено измерением: после полного прогона в боевой базе как было 664 кухни и 8 человек, так и осталось.
chore
планS16 · С16 · Платежи0/6

Цель: ЮKassa, Stars, контекстные пейволлы, триал. По решению владельца в самом конце

packages/billing: тарифы, лимиты, счётчики в одной точке
Free, Плюс 449, Семья 749. Проверки не размазывать по хендлерам
feature
Контекстные пейволлы с логированием
Каждый пейволл отдельный компонент со своим ключом для сравнения: показ, закрытие, переход, оплата
feature
🔴 ЮKassa: платёж, сохранение метода, рекуррент, вебхук, чеки
Подпись вебхука обязательна, идемпотентность по externalId, фискализация по 54-ФЗ
feature
Telegram Stars как второй канал
Проверить требование Telegram продавать цифровые подписки внутри мини-приложения за Stars
feature
Триал 3 дня по триггеру лимита, а не при регистрации
feature
Экран тарифа и отмена подписки в один тап
feature
В РАБОТЕS17 · С11 · Админка9/10

Цель: Пульт владельца: сколько людей, что в каталоге, куда уходят деньги, что происходит прямо сейчас

Признак админа и серверный гейт
Флаг isAdmin у пользователя, проверка на каждом маршруте админки. Скрытая кнопка в интерфейсе это не защита.
Флаг isAdmin в базе, проверка на каждом маршруте запросом к базе, а не признаком в токене. Постороннему отвечаем 404, а не 403. Пять тестов, включая немедленное действие снятия доступа со старым ключом.
feature
Сводка: люди, семьи, планы, оценки
Сколько людей и семей, сколько активны за неделю, сколько собрано планов, сколько оценок. Считает код, а не модель.
Люди, активные за неделю, семьи, едоки и дети, планы, оценки, каталог, расходы. Всё считает код, ни одного вызова модели.
feature
Расходы на AI по дням и по задачам
Всего и за 30 дней, разбивка по задачам и моделям, отдельно картинки, доля неудачных вызовов.
Всего, по задачам, по моделям, по дням за 30 дней, доля упавших вызовов и причины падений.
feature
Каталог: блюда, варианты, качество шагов
Рецепты по группам, блюда с вариантами, доля шагов по стандарту, список худших рецептов.
Доля шагов по стандарту (сейчас 88 процентов, 238 рецептов из 421 без замечаний), разбивка по приёмам пищи, блюда с вариантами, список худших рецептов с процентами. Линейка общая с сидом: проверка переехала в @menu/shared.
feature
База людей: карточка семьи и её ограничения
Семьи с числом едоков, ограничениями, датой последнего плана. Внутри: кто ест, что нельзя, что выучено.
Список семей: едоки, дети, ограничения, выученные правила, число планов и дата последнего. Есть карточка семьи с составом и правилами.
feature
Что происходит сейчас: задачи и ошибки
Очередь сборок и генераций, упавшие задачи с причиной. Без этого падение на сервере невидимо.
Последние 30 задач с состоянием и временем, счётчик упавших за сутки.
feature
Экран админки в мини-аппе
Отдельный раздел, виден только админу: сводка, расходы, каталог, люди.
Раздел в профиле, виден только админу, грузится отдельным куском 2.6 кб. Пять вкладок. Проверено глазами на живом сервере.
feature
Управление: снять блюдо, погасить правило, пересобрать план
Не только смотреть, но и чинить.
На сервере готовы снятие рецепта с публикации и гашение чужого правила. Кнопок в интерфейсе пока нет, и пересборки плана за семью тоже нет.
feature
🔴 Тесты убирают за собой, админка не врёт
657 семей при одном живом человеке.
Тесты удаляли учётку, но не её кухню: у кухни нет ссылки на пользователя, каскад её не задевал. Накопилось 656 брошенных, 321 за один день. Общая уборка removeTestUsers подключена во все десять тестов, измерено: полный прогон 226 тестов, кухонь было 664, стало 664. Админка теперь считает людей, едоков и планы только по живым кухням (было 327 едоков вместо 15), брошенные вынесены отдельно с кнопкой уборки в два нажатия.
bug
Выключатель уведомлений
Отписаться было нельзя вовсе, это причина удалить бота.
Поле pushEnabled, PATCH /me/notifications, переключатель в профиле и команды в переписке («отпишись», «включи уведомления»). Рассылка таких не берёт. Четыре теста.
feature

Ворклог (места остановки)

08.08.2026, 05:16:02 · админка и план · claude

Админка дополнена разделом людей: откуда приходят (Telegram 10, MAX 4, сайт 3), по каждому логины на площадках и почта, дошёл ли до конца знакомства, кухня, даты и что именно делал. Тут же поймана своя ошибка: два запроса одного раздела делили ключ кэша и раздел падал в белый экран, в ключ добавлен адрес. Найдена причина трёхдневных планов: горизонт брался из открытой вкладки, и «Пересобрать» на вкладке «Сегодня» превращал недельный план в трёхдневный, в базе это видно как замену семидневного плана трёхдневным в ту же минуту. Теперь план всегда на неделю, умолчание сервера тоже неделя.

Проверить недельный план живьём после пересборки. Мелочь: у пришедших из MAX не сохраняется имя из данных запуска, вместо него внутренний номер. Хвосты: 656 брошенных кухонь (нужно да на уборку), качество шагов 0.59, шаблоны карточек для блюд без фото.

08.08.2026, 04:27:56 · MAX и единая учётка · claude

Внутри MAX приложение просило регистрацию: не был подключён мост площадки, без него нет window.WebApp и приложение считало себя браузером. Мост подключён, ждём его только на входе. Тут же поймана своя регрессия: библиотека MAX создаёт пустой window.WebApp в любом браузере, и приложение стало показывать «откройте из мессенджера» прямо в браузере — теперь требуются данные запуска, на это два теста. Достроена единая учётная запись: код связывания под любую площадку, раздел «Входы в аккаунт» в профиле, бот принимает код обычным сообщением. Проверено двумя движками на живом сайте.

Владельцу: вставить https://xn--24-6lclog.xn--p1ai/app/ в поле мини-приложения в кабинете MAX и проверить вход. По интеграции с доставкой: у Пятёрочки и Купера покупательского API нет, Яндекс Доставка это курьер; единственный рабочий путь — реферальная программа Яндекс Маркета, там есть ссылка на корзину с несколькими товарами, нужен договор и ключ, решение за владельцем. В админке ждут 656 брошенных кухонь (кнопка уборки есть, нужно да) и качество шагов 0.59 у загруженных рецептов.

06.08.2026, 10:56:48 · MAX, семья, вкусы · claude

Подключён MAX: адаптер площадки, вебхук через подписку с проверкой секрета, вход в мини-приложение той же проверкой подписи что у Telegram. Токен бота проверен, подписка создана, вебхук отвечает 401 без секрета и 200 с ним. Адрес API оказался botapi.max.ru, а не platform-api2 из справочника. Ранее в этой сессии: приглашение в семью по ссылке с общей кухней, отправка списка покупок, раздел Любит и свободный ввод продуктов, сохранение рассказанного словами до обращения к модели.

Владельцу вставить https://xn--24-6lclog.xn--p1ai/app/ в поле мини-приложения в кабинете MAX (только пуникод). Затем живая проверка бота и приложения в MAX. Дальше по роадмапу: шаблоны карточек для блюд без фото, управление в админке, Sentry и дашборд расходов.

06.08.2026, 05:50:49 · мобилка, каталог, уведомления · claude

Починено «не открывается на мобильном»: разметка кэшировалась навсегда, а выкладка удаляет старые файлы сборки, телефон уходил за несуществующими файлами. Теперь no-cache на разметку и immutable на assets. Добавлен раздел «Блюда» с поиском и постановкой блюда на сегодня. Добавлен выключатель уведомлений: переключатель в профиле и команды в переписке с ботом. Пересобран состав у 4071 рецепта: починены буква ё, короткие названия, обратный порядок слов и доверие к синонимам справочника. Проверена кнопка «Сделать карточку» на одном рецепте, картинка вышла верная. 302 теста проходят, всё выкачено.

Осталось: шаблоны карточек satori+resvg для блюд без фото, vision-проверка результата, управление в админке (снять блюдо, погасить правило), Sentry и дашборд расходов, память и удержание. Массовую генерацию картинок владелец запретил, только по кнопке.

05.08.2026, 16:53:42 · каталог и мобилка · claude

Починена мобилка: причина была в кэше разметки при переименовании файлов сборки. Добавлен раздел «Блюда» с поиском, метками и постановкой блюда на сегодня. Починена проверка совпадений продуктов (буква ё, короткие слова, обратный порядок), добавлено 8 продуктов и синонимы; идёт пересборка состава у 5900 загруженных рецептов с пересчётом калорий. Картинки только по кнопке на рецепте, пачкой не генерятся. 298 тестов проходят, всё выкачено и проверено на живом.

Дождаться конца пересборки состава. Спрошено разрешение на один платный тест кнопки «Сделать карточку» (3-5 руб). Дальше: админка управления, тёмная тема на живом телефоне, Sentry и дашборд расходов.

05.08.2026, 12:41:31 · выкладка · claude

Выкачено на 24стол.рф: вход по почте и паролю работает вживую (регистрация отдаёт токен, чужой пароль 401), лендинг показывает 6154 рецепта с сервера. Попутно на живой странице нашлись и починены две вещи: скрипт лендинга падал на имени top (оно занято окном), из-за чего шапка при прокрутке не меняла вид, и значки приложения искались по старому адресу /stol/app/ с 404. Консоль чистая.

Личный кабинет под десктоп широкой раскладкой, раздел выбрать блюдо на сегодня с фильтром и поиском, картинки для загруженных блюд, дополнить справочник продуктов (нет индейки, фенхеля, сухариков).

05.08.2026, 12:01:31 · каталог и веб-вход · claude

Каталог вырос с 421 до 6291 блюда загрузкой с открытых источников: парсер шагов с нормализацией под наше обращение на ты, разбор состава с количествами, привязка к справочнику, калории считает наш код. Ни одного платного вызова модели. Вход на сайте переведён на почту и пароль (scrypt из Node), Telegram остался запасным входом: его блокируют в РФ, а на десктопе переход в мессенджер закрывал вкладку. Лендинг берёт число рецептов с сервера через новый /public/stats. 286 тестов проходят.

Не задеплоено на 24стол.рф: код в main (коммит 4733295), ждёт подтверждения владельца. Дальше: личный кабинет под десктоп широкой раскладкой, раздел выбрать блюдо на сегодня с фильтром и поиском, картинки для загруженных блюд.

05.08.2026, 09:22:03 · · claude

Закрыты все задачи из очереди: дизайн приложения (нейтральная тёмная тема вместо коричневой, градиентные кнопки, панель убрана из знакомства), мобильная вёрстка сайта, каталог с 11.4 до 5.8 процента замечаний, фавиконка, переезд на 24стол.рф с сертификатом и переключением вебхука, воркер BullMQ и нагрузочный тест на 500 человек. Тестов 269.

От владельца ждём: номер счётчика Метрики, телефон психологической помощи, проверку тёмной темы и лендинга на телефоне. По проекту остались: Sentry (нужен внешний аккаунт), картинки блюд С9 (упираются в деньги на генерацию), остаток каталога около 6 процентов, управление из админки. MAX и платежи отложены владельцем.

05.08.2026, 08:40:36 · · claude

Продукт переехал на собственный домен 24стол.рф: сертификат, nginx с пуникодом, сайт в корне, приложение в /app/, вебхук переключён, старые адреса редиректят. Каталог дотянут с 11.4 до 5.8 процента замечаний. Приложение подтянуто к сайту по дизайну: нейтральная тёмная тема вместо коричневой, градиентные кнопки, панель разделов убрана из знакомства. Сделана фавиконка. Починен перелив сайта вбок на телефоне: размытые пятна фона торчали за край и полагались на обрезку родителем, а на iOS так не работает.

Осталось: воркер BullMQ (сборка плана крутится в процессе API), нагрузочный тест, Sentry (нужен внешний аккаунт), картинки блюд С9, номер счётчика Метрики и проверка на телефоне от владельца. MAX и платежи отложены.

05.08.2026, 06:07:17 · · claude

Довёл сайт до вида продукта: логотип, широкий кадр с борщом, четыре фото в блоки, галерея из восьми настоящих карточек рецептов, карточка рецепта целиком, раздел «кому подойдёт» (семьям с детьми, худеющим, спортсменам, с ограничениями). Потрачено 20 рублей из выданных 30. Починил три бага, которые нашёл владелец: невидимое содержимое ниже обложки (класс появления держал прозрачность нулём в покое), коричневая тёмная тема (поверхности стали нейтральным углём), пробел в слове «Стол» (флекс разносил текстовый узел и span) и чёрный логотип на тёмной шапке (добавлена светлая версия через picture). Убрал внутреннюю кухню из текстов: «калории считает код» заменено на выгоду для человека.

Сайт по картинкам закрыт, осталось 10 рублей из бюджета. Написан скил landing-page, чтобы не объяснять заново: структура, дизайн-система, ловушка с невидимым содержимым, смета на генерацию, правила текста, обработка картинок. Дальше возвращаемся к приложению: владелец сказал, что дизайн приложения тоже надо менять. Также висят: номер счётчика Метрики, проверка на телефоне, воркер BullMQ, картинки блюд С9, каталог 13 процентов.

05.08.2026, 05:17:12 · · claude

Переделал сайт из текстовой справки в нормальный лендинг: градиентные небеса, крупная типографика, парящий телефон с карточкой дня, шаги, чередующиеся блоки, плитки блюд, раскрывающиеся вопросы, появление при прокрутке. Палитра тёплая и съедобная, а не неоново-техническая. Всё на CSS без библиотек анимации: страница 26 кб. Юридические страницы приведены к тому же виду.

Ждёт решения владельца: настоящие фотографии еды на лендинг. Предложено начать с четырёх штук за 14 рублей (одна широкая 2K и три плитки 1K), посмотреть и решить про остальные. Видео отдельно и заметно дороже. Также нужен номер счётчика Метрики и проверка на телефоне.

05.08.2026, 04:57:25 · · claude

Сделан веб-сайт: статический лендинг и юридические страницы на /stol/, приложение уехало на /stol/app/, вход в браузере через подтверждение в боте. Реквизиты взяты из Контент Завода по просьбе владельца. По дороге нашёл, что имя бота в лендинге я написал придуманное: настоящее Life_gamers_bot. Убрал значение по умолчанию у настройки имени бота, теперь его обязательно задать. Тестов 266.

Осталось по сайту: номер счётчика Метрики от владельца и проверка на реальном телефоне (браузер был занят). Дальше по проекту: воркер BullMQ и нагрузочный тест из С15, Sentry, картинки С9, каталог 13 процентов.

04.08.2026, 17:53:33 · · claude

Большой заход: дневник еды по фото (модель называет, калории считает код, кэш по хэшу, поиск блюд каталога по вхождению слов), чат с помощником через дешёвый классификатор намерения, продакшн-обвес (своя база тестам, ограничитель частоты, бэкапы с проверкой восстановления, алерты в Telegram), плюс мелочи: план собирается сразу после онбординга, итог недели и письмо вернувшимся, кнопки управления в админке. Тестов 266. Потрачено за проверки 5.5 копейки: фото 4.5, сообщение чата 1, классификатор 0.2.

Осталось: веб-сайт С13 целиком, воркер BullMQ и нагрузочный тест из С15, Sentry (нужен внешний аккаунт), картинки С9 (упираются в деньги на генерацию), каталог 13 процентов. MAX и платежи отложены по решению владельца. Нужен проверенный телефон помощи для HELPLINE_PHONE.

04.08.2026, 16:17:40 · · claude

Бот перестал быть кнопкой «открыть приложение». Сделаны рассылки (утро, вечер, воскресенье) со временем по поясу человека, оценка блюда прямо из переписки, защита по признакам нездорового отношения к еде. Починен баг: на код привязки бот отвечал «аккаунты связаны», не связывая ничего. Логика связывания и вкусов вынесена в пакеты @menu/accounts и @menu/tastes, чтобы бот и API не разъехались. Поймал в четвёртый раз беду с границей слова: в файле лежал настоящий байт-забой, правило про калории не работало, теперь это ищет отдельная проверка. Тестов 260.

Утренняя карточка проверена живьём, вечерний вопрос и воскресный план сработают по расписанию сами, посмотреть их можно завтра. HELPLINE_PHONE на сервере не задан намеренно, нужен проверенный номер от владельца. Дальше по С10 остаются чат в приложении со стримом и обработка фото, они идут вместе с дневником еды.

04.08.2026, 15:49:17 · · claude

Разобрал вопрос владельца «откуда 657 семей и 8 человек». Живой человек в базе ровно один. Остальные семь учёток и все 656 брошенных кухонь это следы автотестов: тесты удаляли пользователя, но не заведённую им кухню. Сделал общую уборку и подключил во все десять тестов, проверил измерением до и после полного прогона: рост прекратился. Админку починил: людей, едоков и планы считает только по живым кухням, брошенные показывает отдельной строкой с кнопкой удаления.

Кнопка уборки 656 брошенных кухонь ждёт владельца в админке, сам не удалял. Корень проблемы шире: тесты ходят в ту же базу, что и прод, отдельная тестовая база это С15. Дальше по плану бот с утренней карточкой дня.

04.08.2026, 15:16:45 · · claude

Завёл спринт С11 «Админка» и сделал семь задач из восьми: серверный гейт по флагу в базе, сводка, деньги по задачам и моделям, каталог с качеством шагов и списком худших рецептов, база семей, лента задач, экран в мини-аппе. Проверка шагов переехала в @menu/shared, чтобы сид и админка мерили одной линейкой. Все числа считает код. Тестов стало 223.

Админка сразу показала мусор: 641 семья при восьми живых людях, 633 осиротевших без участников (следы автотестов), из них 31 с планами. Чистку не делал, это удаление данных, нужен ваш ответ. Не доделано управление из интерфейса: кнопки «снять блюдо» и «погасить правило» на сервере есть, в экране нет.

04.08.2026, 14:32:14 · · claude

Дописал недостающие блюда каталога (оливье, винегрет, шуба, мимоза, шницель, бургер, лагман — 20 вариантов, 0 отбраковок) и замкнул главную цепочку вариантов: выбор человека теперь доходит до сборки плана, а не просто хранится. Починил две придирки валидатора шагов. Дизайн-проход: шапки экранов, тихая заметка вместо стены текста, значки вкладок, монограммы вместо обрезанных слов, движение, покраска рамки мессенджера. Бандл разрезан: 110 кб на первый экран вместо 348. Нашёл и починил настоящий баг: «Сегодня» показывало первый день плана, а не сегодняшний день.

Остановился на том, что тёмную тему надо посмотреть глазами в самом Telegram на телефоне. Дальше по каталогу: около 13 процентов шагов ещё без признаков готовности под конкретную технику. Из невыполненного по С9.5 остаются задачи про дневник еды и фото. Деньги за сессию не тратились: каталог и парсер писались руками, платных вызовов не было.

04.08.2026, 12:56:45 · · claude

Каталог дотянут до стандарта: 52 процента стали 87. Переписывать 1779 шагов руками не понадобилось, 995 провалов из 1012 были механическими: количества уже лежали в составе, силу огня видно по действию. Руками написано знание (какое действие на каком огне, как склоняются названия продуктов), подстановка это код. Пришлось написать модуль склонения: первая версия давала «400 мл молоко» и «щепотку соль соль». Каталог перезалит, количества в шагах с 6 до 35 процентов. Варианты блюда доведены от схемы до экрана: заливка блюд, ручки, список вариантов в карточке рецепта с отметкой кто что ест. Проверено на проде ровно на примере владельца: Аня на уксусе, Игорь на квасе. Валидатор дважды отклонил мои же варианты окрошки и оба раза был прав.

Осталось из плана: массовый сбор фактов по списку блюд (парсер готов, прогона не было) и дизайн, планка «будто разработала Apple». Плюс переписать оставшиеся 13 процентов каталога, которые механикой не чинятся.

04.08.2026, 12:09:02 · · claude

Владелец забраковал комбинаторное перемножение осей: оно даёт правдоподобные сочетания, а не блюда, которые люди едят. Плюс наши шаги бесполезны для новичка, «обжарь морковь на сильном огне» не говорит ни сколько, ни как понять что готово. Сделано: письменный стандарт рецепта с зафиксированным читателем (парень, впервые вставший к плите), эталонная карбонара по стандарту, валидатор годности шагов, модель вариантов блюда в схеме, окрошка с четырьмя настоящими вариантами, парсер фактов из открытых источников. Честные цифры качества: эталон и окрошка 100 процентов, сетка по курице 87, рукописный каталог 52. Валидатор дважды показывал мне завышенные цифры из-за  в регулярке: на кириллице она не работает, а один раз вообще превратилась в управляющий символ внутри файла. Сначала было «100 процентов качества» там, где реально 52. Это третий раз за проект на тех же граблях, записано в память.

Переписать 48 процентов каталога под стандарт, сделать экран выбора варианта блюда, прогнать массовый сбор фактов по списку блюд. Отдельной веткой ждёт дизайн: планка задана как «будто разработала Apple», сейчас есть только палитра и шрифты.

04.08.2026, 10:22:12 · · claude

Профиль вынесен отдельной вкладкой внизу. Раньше семья и выученное открывались кнопками внутри «Сегодня», хотя настройки семьи не часть сегодняшнего плана. Теперь пятый раздел: кто ест со сводкой ограничений по каждому человеку, вход в карточку, «Что я о вас понял» со счётчиком запомненного, время на готовку. Добавление едока переехало в профиль, удаление в карточку человека, где видно, кого именно убираешь. Экран «Сегодня» остался только планом. Выложено и проверено в собранном бандле на проде.

Ждёт решения владельца по расширению каталога сеткой (отруб × способ × соус), прикидка 100 рублей. Остальные хвосты С10: шторка причины у оценки на экране рецепта, живая проверка разбора свободного текста моделью.