# FoodAI — План реализации ## Обзор итераций | # | Итерация | Цель | Зависит от | |---|----------|------|------------| | 0 | Фундамент | Go-проект, БД, авторизация, Flutter-каркас | — | | 1 | Справочник ингредиентов и рецепты | Наполнение БД рецептами, маппинг ингредиентов | 0 | | 2 | Управление продуктами | CRUD продуктов, сроки хранения | 0 | | 3 | AI-ядро | Очереди, Gemini-адаптер, rate limiter, budget guard | 0 | | 4 | AI-распознавание | OCR чека, фото продуктов, фото блюд | 2, 3 | | 5 | Каталог рецептов | Поиск, фильтры, «из моих продуктов», замены | 1, 2 | | 6 | Планирование меню | Меню на неделю, AI-генерация, список покупок | 3, 5 | | 7 | Дневник питания | Записи, порции, трекер воды, калории | 5 | | 8 | Режим готовки | Пошаговая готовка, таймеры | 5 | | 9 | Рекомендации и статистика | Рекомендации на главной, графики, тренды | 6, 7 | | 10 | Полировка | Онбординг, пустые состояния, уведомления, отзывы | 9 | ## Карта зависимостей ``` ┌──────────────┐ │ 0. Фундамент │ └──────┬───────┘ │ ┌────────────────┼────────────────┐ │ │ │ ▼ ▼ ▼ ┌────────────────┐ ┌───────────┐ ┌────────────────┐ │ 1. Справочник │ │ 2. Продук-│ │ 3. AI-ядро │ │ ингредиентов │ │ ты │ │ (очереди, │ │ + рецепты │ │ │ │ Gemini) │ └───────┬────────┘ └─────┬─────┘ └───────┬────────┘ │ │ │ │ ┌────┴────┐ │ │ │ │ │ │ │ ┌────┴──────────┘ │ │ │ │ ▼ ▼ │ ┌──────────────────┐ │ │ 4. AI-распозна- │ │ │ вание │ │ └──────────────────┘ │ │ └─────┬─────┘ │ ▼ ┌────────────────┐ │ 5. Каталог │ │ рецептов │ └───────┬────────┘ │ ┌──────────┼──────────┐ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 6. Меню │ │ 7. Днев- │ │ 8. Режим │ │ + список │ │ ник пита-│ │ готовки │ │ покупок │ │ ния │ │ │ └─────┬────┘ └─────┬────┘ └──────────┘ │ │ └──────┬─────┘ │ ▼ ┌────────────────┐ │ 9. Рекоменда- │ │ ции + стат-ка │ └───────┬────────┘ │ ▼ ┌────────────────┐ │ 10. Полировка │ └────────────────┘ ``` **Параллельная разработка:** итерации 1, 2, 3 могут выполняться параллельно. Итерации 6, 7, 8 — тоже параллельно после завершения 5. --- ## Итерация 0: Фундамент > **Детальный план:** [Iteration_0.md](./Iteration_0.md) **Цель:** развернуть скелет проекта, базу данных, авторизацию и каркас мобильного приложения. После итерации можно зарегистрироваться, войти и увидеть пустые экраны. **Зависимости:** нет. ### User Stories #### Backend | ID | Story | Описание | |----|-------|----------| | 0.1 | Инициализация Go-проекта | Структура проекта (cmd/, internal/, pkg/), go.mod, конфигурация (envconfig), логгер (slog), graceful shutdown | | 0.2 | PostgreSQL + миграции | Подключение к PostgreSQL (pgx), система миграций (goose или golang-migrate). Начальная миграция: таблица `users` | | 0.3 | HTTP-сервер + роутер | HTTP-сервер (net/http или chi), middleware (CORS, request ID, logging, recovery), healthcheck endpoint | | 0.4 | Firebase Auth интеграция | Firebase Admin SDK. Middleware для верификации Firebase idToken. Выдача собственного JWT. Эндпоинты: `POST /auth/login`, `POST /auth/refresh`, `POST /auth/logout` | | 0.5 | Таблица users | Миграция: users (id, firebase_uid, email, name, avatar_url, параметры тела, цель, preferences JSONB, plan, created_at). CRUD-сервис | | 0.6 | Docker Compose | docker-compose.yml: PostgreSQL, приложение. Makefile с основными командами (migrate, run, test) | #### Flutter | ID | Story | Описание | |----|-------|----------| | 0.7 | Инициализация Flutter-проекта | Создание проекта, структура (features/, core/, shared/), подключение основных пакетов (dio, riverpod/bloc, go_router) | | 0.8 | Firebase Auth во Flutter | Пакеты firebase_auth, google_sign_in, sign_in_with_apple. Экраны: вход (email + Google + Apple), регистрация. Хранение JWT в secure storage | | 0.9 | Навигация и каркас экранов | Bottom Tab Bar (5 вкладок), пустые заглушки для каждого экрана, роутинг | | 0.10 | API-клиент | Dio-клиент с interceptors: JWT-токен, refresh, error handling. Базовые модели (User) | ### Результат итерации - Можно зарегистрироваться через email / Google / Apple - Войти в приложение и увидеть 5 вкладок с заглушками - Backend отвечает на healthcheck и auth-запросы - БД содержит таблицу users с данными зарегистрированных пользователей --- ## Итерация 1: Справочник ингредиентов и рецепты **Цель:** наполнить БД каноническими ингредиентами и рецептами из Spoonacular. Это фундамент для всех фичей, связанных с рецептами, поиском и маппингом продуктов. **Зависимости:** итерация 0. ### User Stories | ID | Story | Описание | |----|-------|----------| | 1.1 | Таблица ingredient_mappings | Миграция: id, canonical_name, spoonacular_id, aliases (JSONB), category, default_unit, нутриенты на 100г, storage_days. Индексы: GIN по aliases, UNIQUE по spoonacular_id | | 1.2 | Импорт ингредиентов из Spoonacular | CLI-команда / джоб: запрос Spoonacular Ingredient API → сохранение ~1000 базовых ингредиентов в ingredient_mappings | | 1.3 | Таблица recipes | Миграция: id, source, spoonacular_id, title, description, cuisine, difficulty, prep_time_min, калории, БЖУ, servings, image_url, ingredients (JSONB), steps (JSONB), tags (JSONB), avg_rating, review_count, created_by. Индексы: GIN по ingredients, full-text по title | | 1.4 | Импорт рецептов из Spoonacular | CLI-команда / джоб: импорт 5 000–10 000 популярных рецептов. Маппинг ингредиентов рецепта на ingredient_mappings через spoonacular_id | | 1.5 | Перевод рецептов | Batch-джоб: перевод title, description, steps через Gemini Flash-Lite. Результат сохраняется в БД (поля title_ru, description_ru или отдельная таблица переводов) | | 1.6 | Базовая локализация aliases | Перевод aliases топ-200 ингредиентов на русский. Batch через Gemini или ручной маппинг | ### Результат итерации - БД содержит ~1 000 ингредиентов с русскими алиасами и нутриентами - БД содержит 5 000–10 000 рецептов с переводами, ингредиентами, шагами, нутриентами - Каждый ингредиент рецепта связан с ingredient_mappings через spoonacular_id --- ## Итерация 2: Управление продуктами **Цель:** пользователь может вести список своих продуктов вручную — добавлять, редактировать, удалять, отслеживать сроки. **Зависимости:** итерация 0. ### User Stories #### Backend | ID | Story | Описание | |----|-------|----------| | 2.1 | Таблица products | Миграция: id, user_id, mapping_id (FK nullable), name, quantity, unit (ENUM), category, storage_days, added_at, expires_at (computed). Индексы по user_id, expires_at | | 2.2 | Products CRUD API | `GET /products` (фильтры: category, expiring), `POST /products`, `PUT /products/{id}`, `DELETE /products/{id}`, `DELETE /products` (очистить все) | | 2.3 | Частичное использование | `PATCH /products/{id}/consume` — уменьшить количество. Если количество = 0, предложить удаление | | 2.4 | Массовое добавление | `POST /products/batch` — добавление нескольких продуктов за раз (после распознавания). Обработка дубликатов: проверка по mapping_id, предложение объединить | | 2.5 | Дефолтные сроки хранения | `GET /products/storage-defaults`, `PUT /products/storage-defaults`. Хранение в user preferences (JSONB в таблице users) | | 2.6 | Fuzzy matching при добавлении | При добавлении продукта — поиск по ingredient_mappings.aliases. Если найдено — автозаполнение: mapping_id, category, unit, storage_days, нутриенты | #### Flutter | ID | Story | Описание | |----|-------|----------| | 2.7 | Экран «Мои продукты» | Список продуктов по категориям, поиск, chip-фильтры, badge «осталось X дней» | | 2.8 | Добавление/редактирование продукта | Форма: название, количество, единица, категория, период хранения. Выпадающее меню добавления (+) | | 2.9 | Частичное использование | Модалка «Сколько осталось?» при свайпе или тапе | | 2.10 | Очистить и перезаполнить | Контекстное меню (···) → подтверждение → очистка | | 2.11 | Настройки сроков хранения | Экран из Профиля: список категорий с редактируемыми днями | | 2.12 | Пустое состояние | Иллюстрация + CTA «Сфотографируйте продукты или сканируйте чек» | ### Результат итерации - Пользователь может вручную добавить продукты, указать количество и сроки - Видит «осталось X дней» для каждого продукта - Может частично использовать продукт, удалить, очистить всё - При добавлении — автоматический подбор категории, единицы, срока через fuzzy match --- ## Итерация 3: AI-ядро **Цель:** построить инфраструктуру для AI-запросов: очереди, rate limiter, budget guard, адаптер Gemini. После итерации можно отправлять AI-запросы через API с контролем расхода. **Зависимости:** итерация 0. ### User Stories | ID | Story | Описание | |----|-------|----------| | 3.1 | AI Service интерфейсы | Go-интерфейсы: FoodRecognizer, RecipeGenerator, MenuPlanner, NutritionEstimator. Структуры запросов и ответов | | 3.2 | Gemini-адаптер | Реализация интерфейсов через Gemini API (google/generative-ai-go). Structured JSON output. Обработка ошибок, retries | | 3.3 | Таблица ai_tasks | Миграция: id, user_id, task_type, status, priority, input/output_tokens, estimated_cost, queue/process_time_ms, created_at, completed_at. Индексы по user_id, status, created_at | | 3.4 | Priority Queue Manager | Две очереди (chan в Go): paid (N воркеров), free (1 воркер). Распределение RPM между очередями. Горутины-воркеры | | 3.5 | Rate Limiter (per-user) | Token bucket на горутинах. Конфигурируемые лимиты по тарифу (free: 20 req/час, paid: 100 req/час). HTTP 429 при превышении | | 3.6 | Budget Guard | Подсчёт дневных затрат по ai_tasks. Пороги: 80% → warn, 100% → free stop, 120% → all stop. Счётчик сбрасывается в полночь | | 3.7 | AI API эндпоинты (заглушки) | `POST /ai/recognize-receipt`, `/ai/recognize-products`, `/ai/recognize-dish`, `/ai/suggest-recipes`, `/ai/generate-menu`, `/ai/substitute`. Возвращают task_id (HTTP 202). `GET /ai/tasks/{id}` для polling | | 3.8 | Логирование и мониторинг | Каждый AI-запрос логируется в ai_tasks с токенами и стоимостью. Эндпоинт `/admin/ai-stats` для просмотра затрат | ### Результат итерации - AI-запросы проходят через очередь с приоритетами - Paid-пользователи обслуживаются быстрее - Расход бюджета контролируется, при превышении — graceful degradation - Все запросы логируются с точной стоимостью - API эндпоинты принимают запросы и возвращают результат через polling --- ## Итерация 4: AI-распознавание **Цель:** пользователь может фотографировать чеки, продукты и блюда — AI распознаёт и предлагает результат для корректировки. **Зависимости:** итерации 2 (продукты), 3 (AI-ядро). ### User Stories #### Backend | ID | Story | Описание | |----|-------|----------| | 4.1 | OCR чека | Реализация FoodRecognizer.RecognizeReceipt: фото → Gemini Flash (vision) → structured JSON (name, quantity, unit, category, price, confidence). Маппинг результатов на ingredient_mappings | | 4.2 | Распознавание продуктов (фото) | FoodRecognizer.RecognizeProducts: фото → Gemini Flash → JSON. Поддержка мультифото (объединение результатов, дедупликация). Маппинг на ingredient_mappings | | 4.3 | Распознавание блюда | FoodRecognizer.RecognizeDish: фото → Gemini Flash → dish_name, weight, calories, БЖУ, confidence. Full-text search по recipes.title для привязки к рецепту из БД | | 4.4 | Авто-маппинг нераспознанных | Если fuzzy match по aliases не нашёл ингредиент → разовый запрос к Gemini: определить canonical_name → сохранить в ingredient_mappings. Следующий запрос с таким же продуктом — без AI | | 4.5 | Загрузка фото | Эндпоинт для multipart upload фото. Сохранение в S3. Передача URL в AI-задачу | #### Flutter | ID | Story | Описание | |----|-------|----------| | 4.6 | Экран камеры (чек) | Видоискатель, кнопка съёмки, выбор из галереи. Отправка на backend | | 4.7 | Экран камеры (еда) | Переключатель «Готовое блюдо» / «Продукты». Съёмка, отправка | | 4.8 | Экран загрузки AI | Анимация «Распознаём...» с индикатором. Polling по task_id | | 4.9 | Экран корректировки (чек/фото продуктов) | Список распознанных продуктов. Инлайн-редактирование: название, количество, единица, категория, срок хранения. Чекбоксы, удаление, добавление вручную, «Сделать ещё фото». Предупреждения о дубликатах. CTA «Добавить в мои продукты» | | 4.10 | Экран результата (фото блюда) | Фото, название, калории, БЖУ. Подтверждение / корректировка. Слайдер порции. Выбор приёма пищи. CTA «Записать в дневник» | | 4.11 | Обработка ошибок AI | Экран «Не удалось распознать» → «Переснять» / «Ввести вручную» | ### Результат итерации - Пользователь фотографирует чек → получает список продуктов → корректирует → добавляет в запасы - Фотографирует холодильник (несколько фото) → то же - Фотографирует блюдо → видит калории и БЖУ → может записать в дневник - Нераспознанные ингредиенты автоматически добавляются в справочник --- ## Итерация 5: Каталог рецептов **Цель:** пользователь может просматривать, искать и фильтровать рецепты. Видит, какие ингредиенты есть в запасах, а каких не хватает. Может добавить рецепт в избранное. **Зависимости:** итерации 1 (рецепты в БД), 2 (продукты для проверки наличия). ### User Stories #### Backend | ID | Story | Описание | |----|-------|----------| | 5.1 | Поиск и фильтрация рецептов | `GET /recipes` — фильтры: cuisine, difficulty, prep_time, calories_max, meal_type, diet_tags. Full-text search по title. Пагинация (cursor-based) | | 5.2 | «Из моих продуктов» | Фильтр: сопоставление ingredients[].mapping_id с products.mapping_id пользователя. Ранжирование по доле совпадения. На каждом рецепте: «Есть всё ✓» / «-N прод.» | | 5.3 | Карточка рецепта с наличием | `GET /recipes/{id}` — рецепт + для каждого ингредиента: есть ✅ / нет ❌ / замена 🔄. Итог: «Всё есть» / «Не хватает N» | | 5.4 | Замены ингредиентов | При ❌ — поиск замены: сначала в таблице ingredient_substitutions, затем (если нет) — запрос к Gemini, результат кешируется | | 5.5 | Избранное | `POST /recipes/{id}/favorite`, `DELETE /recipes/{id}/favorite`. Таблица favorites (user_id, recipe_id). `GET /recipes?favorite=true` | | 5.6 | Дозапрос Spoonacular | Если в локальной БД мало результатов по фильтрам — запрос к Spoonacular API (findByIngredients, complexSearch). Новые рецепты сохраняются в БД | #### Flutter | ID | Story | Описание | |----|-------|----------| | 5.7 | Экран каталога рецептов | Сетка 2 колонки, поиск, chip-фильтры, кнопка «Из моих продуктов», панель фильтров (bottom sheet), бесконечный скролл | | 5.8 | Карточка рецепта | Фото, рейтинг, метаинформация (время/сложность/кухня), калории/БЖУ, регулятор порций, список ингредиентов с ✅/❌/🔄, описание. CTA «Начать готовить», «Добавить в меню» | | 5.9 | Замены ингредиентов | Строка «→ Замена: пармезан (есть)» под ингредиентом с 🔄 | | 5.10 | Кнопка «Добавить в список покупок» | Недостающие ингредиенты → формирование позиций для списка покупок | ### Результат итерации - Пользователь ищет рецепты, фильтрует по кухне/сложности/времени/калориям - Видит, что можно приготовить из имеющихся продуктов - Для каждого рецепта — отметки наличия ингредиентов и предложения замен - Может добавить рецепт в избранное --- ## Итерация 6: Планирование меню **Цель:** пользователь может составлять меню на неделю — вручную или через AI-генерацию. Формируется список покупок. **Зависимости:** итерации 3 (AI-ядро для генерации), 5 (каталог рецептов). ### User Stories #### Backend | ID | Story | Описание | |----|-------|----------| | 6.1 | Таблицы menu_plans и menu_items | Миграции. menu_plans: id, user_id, week_start, template_name. menu_items: id, menu_plan_id, day_of_week, meal_type, recipe_id, servings | | 6.2 | Menu CRUD | `GET /menu?week=`, `POST /menu/items`, `PUT /menu/items/{id}`, `DELETE /menu/items/{id}`. Подсчёт калорий за день/неделю | | 6.3 | AI-генерация меню | `POST /ai/generate-menu`: backend отбирает кандидатов из БД (SQL по фильтрам + наличие ингредиентов) → формирует промпт с recipe_id → Gemini ранжирует → backend сохраняет menu_items | | 6.4 | Шаблоны меню | `POST /menu/templates` (сохранить), `GET /menu/templates` (список), `POST /menu/from-template/{id}` (применить). История прошлых меню | | 6.5 | Таблица shopping_lists | Миграция: id, user_id, menu_plan_id, items (JSONB). Автогенерация из меню: ингредиенты рецептов − имеющиеся продукты = список | | 6.6 | Shopping list API | `GET /shopping-list`, `POST /shopping-list/generate`, `PUT /shopping-list/items/{idx}`, `PATCH /shopping-list/items/{idx}/check`, `POST /shopping-list/items` (ручная позиция) | #### Flutter | ID | Story | Описание | |----|-------|----------| | 6.7 | Экран меню | Понедельный календарь, слоты по приёмам пищи, калорийность за день, drag-and-drop, контекстное меню (···), пустые слоты с подсказками | | 6.8 | Добавление блюда в слот | Модалка выбора дня + приёма пищи. Переход в каталог рецептов для выбора | | 6.9 | AI-генерация | Кнопка ⚡ → экран параметров (период, кухня, сложность, из моих продуктов, калории) → генерация → отображение результата с возможностью заменить отдельные блюда | | 6.10 | Шаблоны и история | Выпадающее меню: сохранить как шаблон, загрузить из шаблона, из истории | | 6.11 | Экран списка покупок | Список по категориям, чекбоксы, свайп-удаление, ручное добавление, итого, «Поделиться», «Пересчитать из меню» | | 6.12 | Переходный экран «Составить меню?» | После добавления продуктов (чек/фото) → предложение сгенерировать меню с выбором параметров | ### Результат итерации - Пользователь составляет меню на неделю — вручную или AI-генерацией - AI подбирает рецепты из нашей БД с учётом продуктов, калорий, предпочтений - Формируется список покупок (автоматически из меню − запасы) - Можно сохранять шаблоны и повторять удачные меню - После сканирования чека — плавный переход к генерации меню --- ## Итерация 7: Дневник питания **Цель:** пользователь ведёт учёт съеденного — записывает приёмы пищи, отслеживает калории и БЖУ, регулирует порции. **Зависимости:** итерация 5 (рецепты для добавления из каталога). ### User Stories #### Backend | ID | Story | Описание | |----|-------|----------| | 7.1 | Таблица meal_diary | Миграция: id, user_id, date, meal_type, recipe_id (nullable), name, portions, calories, protein, fat, carbs, source (menu/photo/manual/recipe), created_at | | 7.2 | Diary CRUD | `GET /diary?date=`, `POST /diary`, `PUT /diary/{id}`, `DELETE /diary/{id}`. Подсчёт итогов дня (калории, БЖУ) | | 7.3 | Из меню в дневник | При отметке «съедено» на главном экране → автосоздание записи в дневнике. Списание ингредиентов из продуктов | | 7.4 | Трекер воды | Таблица water_tracker (user_id, date, glasses). `GET /stats/water?date=`, `PUT /stats/water` | | 7.5 | База продуктов для быстрого поиска | Endpoint для поиска по ingredient_mappings: `GET /ingredients/search?q=банан` → название + нутриенты на порцию. Для перекусов без рецепта | #### Flutter | ID | Story | Описание | |----|-------|----------| | 7.6 | Экран дневника питания | Навигация по дням, круговой прогресс калорий, прогресс-бары БЖУ, приёмы пищи, порции, «+ Добавить» | | 7.7 | Модалка добавления | Варианты: сфотографировать, из меню, из каталога, из избранного, быстрый поиск продукта, вручную | | 7.8 | Указание порции | Слайдер 0.5x–3x при добавлении из рецепта. Пересчёт калорий/БЖУ | | 7.9 | Быстрый поиск продукта | Поле поиска → результаты из ingredient_mappings → тап → добавить в дневник с указанием количества | | 7.10 | Трекер воды | Ряд стаканов внизу дневника, тап = +1/-1 | | 7.11 | Главный экран — карточка калорий | Круговой прогресс, тап → переход в дневник | | 7.12 | Главный экран — «Сегодня в меню» | Список из menu_items на сегодня с чекбоксами «съедено» | ### Результат итерации - Пользователь записывает приёмы пищи: из меню, каталога, фото или вручную - Регулирует порции, видит калории и БЖУ за день - На главном экране — прогресс калорий и чекбоксы «съедено» - Трекер воды --- ## Итерация 8: Режим готовки **Цель:** пользователь готовит блюдо по пошаговой инструкции с таймерами. После завершения — запись в дневник и оценка. **Зависимости:** итерация 5 (карточка рецепта для запуска). ### User Stories | ID | Story | Описание | |----|-------|----------| | 8.1 | Экран пошаговой готовки | Фото шага, заголовок, описание (крупный шрифт), навигация «Назад»/«Далее», свайп, точечный индикатор прогресса | | 8.2 | Таймеры | Кнопка «Запустить таймер» на шагах с timer_seconds. Обратный отсчёт. Пауза, стоп. Несколько таймеров параллельно | | 8.3 | Панель активных таймеров | Фиксирована внизу. Показывает все запущенные таймеры с оставшимся временем | | 8.4 | Уведомления таймера | Push-уведомление + звук при завершении таймера. Модалка «Готово!» | | 8.5 | Keep screen on | Экран не гаснет в режиме готовки (wakelock) | | 8.6 | Закрытие с подтверждением | Кнопка ✕ → «Прервать готовку?» | | 8.7 | Экран завершения | «Приятного аппетита!» → «Записать в дневник» (с выбором порций), «Оценить рецепт», «Поделиться фото». Автосписание ингредиентов из запасов | ### Результат итерации - Пользователь готовит по шагам с фото и описанием - Запускает таймеры (параллельно), получает уведомления - По завершении — запись в дневник, оценка рецепта, списание продуктов --- ## Итерация 9: Рекомендации и статистика **Цель:** приложение проактивно рекомендует рецепты. Пользователь видит аналитику своего питания. **Зависимости:** итерации 6 (меню), 7 (дневник — данные для статистики). ### User Stories #### Рекомендации | ID | Story | Описание | |----|-------|----------| | 9.1 | Рекомендации на главном экране | Карусель «Рекомендуем приготовить». Алгоритм: (1) рецепты из продуктов с истекающим сроком, (2) полное совпадение ингредиентов, (3) предпочтения кухни. Endpoint: `GET /recipes/recommended` | | 9.2 | «Готовили недавно» | Секция на главном экране и в каталоге. Endpoint: `GET /recipes/recent` — последние 5 приготовленных (из meal_diary с source=recipe) | | 9.3 | Секция «Для вас» в каталоге | Персональные рекомендации на основе: оценок, предпочтений кухонь, истории. Endpoint: `GET /recipes/recommended?section=personal` | | 9.4 | Подсказки в пустых слотах меню | При пустом слоте меню — рекомендация на основе оставшихся калорий + продукты с истекающим сроком | #### Статистика | ID | Story | Описание | |----|-------|----------| | 9.5 | Endpoint статистики | `GET /stats?period=week|month|3months` — калории/БЖУ по дням, средние, тренды, самые частые блюда. Агрегация по meal_diary | | 9.6 | Экран статистики | Переключатель периода, столбчатая диаграмма калорий, stacked bar БЖУ, тренды (↑↓→), топ блюд | | 9.7 | Переход из главного экрана | Тап по прогресс-бару калорий → дневник или статистика | ### Результат итерации - На главном экране — рекомендации (приоритет на истекающие продукты) и «Готовили недавно» - В каталоге — секция «Для вас» - В меню — умные подсказки в пустых слотах - Графики калорий и БЖУ за неделю/месяц/3 месяца --- ## Итерация 10: Полировка **Цель:** довести приложение до продуктового качества — онбординг, пустые состояния, уведомления, отзывы, переходные экраны. **Зависимости:** итерация 9. ### User Stories #### Онбординг | ID | Story | Описание | |----|-------|----------| | 10.1 | Экраны онбординга | 5 шагов: приветствие (свайп-карточки), параметры тела, цель + расчёт нормы, ограничения + предпочтения кухонь, предложение добавить продукты | | 10.2 | Сохранение данных онбординга | `PUT /profile` с параметрами из онбординга. Сохранение предпочтений кухонь в preferences | | 10.3 | Флаг прохождения онбординга | Показывать только при первом входе. Флаг в secure storage | #### Пустые состояния и ошибки | ID | Story | Описание | |----|-------|----------| | 10.4 | Пустые состояния всех экранов | Иллюстрация + текст + CTA для: продуктов, меню, дневника, статистики, рецептов (избранные) | | 10.5 | Состояния ошибок | Нет сети (баннер + оффлайн-данные), ошибка AI (переснять / ввести вручную), ошибка сервера (повторить) | | 10.6 | Toast с отменой | При удалении записи из дневника, продукта — toast «Удалено» + кнопка «Отменить» (5 сек) | #### Уведомления | ID | Story | Описание | |----|-------|----------| | 10.7 | Push-уведомления (FCM) | Интеграция Firebase Cloud Messaging. Flutter: запрос разрешений, обработка | | 10.8 | Уведомления о сроках продуктов | Backend: cron-джоб утром → push «Молоко — осталось 1 день. Использовать в рецепте?» | | 10.9 | Напоминания о приёмах пищи | По расписанию (настраиваемое): «Время обеда! В меню: ...» | | 10.10 | Вечернее напоминание о воде | «Вы выпили 5 из 8 стаканов воды сегодня» | #### Отзывы | ID | Story | Описание | |----|-------|----------| | 10.11 | Таблица reviews | Миграция: id, user_id, recipe_id, rating, text, photo_url, created_at. Пересчёт avg_rating, review_count в recipes | | 10.12 | API отзывов | `GET /recipes/{id}/reviews` (пагинация), `POST /recipes/{id}/reviews` | | 10.13 | UI отзывов | Секция в карточке рецепта, модалка написания отзыва (звёзды + текст + фото), полный список отзывов | #### Профиль | ID | Story | Описание | |----|-------|----------| | 10.14 | Экран профиля | Аватар, параметры, цель, ограничения, предпочтения кухонь, ссылки (статистика, избранное, отзывы, сроки хранения, настройки) | | 10.15 | Настройки приложения | Экран: уведомления (вкл/выкл по типам), тема (светлая/тёмная/системная), норма воды, язык | ### Результат итерации - Новый пользователь проходит онбординг и сразу получает персонализированный опыт - Все экраны имеют осмысленные пустые состояния - Ошибки обрабатываются gracefully - Push-уведомления о сроках, приёмах пищи, воде - Можно оставлять отзывы к рецептам - Полноценный профиль с настройками --- ## Итоги по объёму | Итерация | Backend stories | Flutter stories | Всего | |----------|----------------|-----------------|-------| | 0. Фундамент | 6 | 4 | 10 | | 1. Ингредиенты + рецепты | 6 | 0 | 6 | | 2. Продукты | 6 | 6 | 12 | | 3. AI-ядро | 8 | 0 | 8 | | 4. AI-распознавание | 5 | 6 | 11 | | 5. Каталог рецептов | 6 | 4 | 10 | | 6. Меню + покупки | 6 | 6 | 12 | | 7. Дневник питания | 5 | 7 | 12 | | 8. Режим готовки | 0 | 7 | 7 | | 9. Рекомендации + стат-ка | 4 | 3 | 7 | | 10. Полировка | 5 | 10 | 15 | | **Итого** | **57** | **53** | **110** | ## Приоритеты для MVP Минимально жизнеспособный продукт — итерации **0–6**: - Авторизация, продукты, AI-распознавание, рецепты, меню, список покупок - Позволяет пройти основной пользовательский сценарий: купил продукты → сфотографировал чек → получил меню → составил список покупок - **68 stories** из 110 (62%) Итерации 7–10 — расширение до полного продукта.