Files
food-ai/docs/plans/Summary.md
dbastrikin e57ff8e06c feat: implement Iteration 1 — AI recipe recommendations
Backend:
- Add Groq LLM client (llama-3.3-70b) for recipe generation with JSON
  retry strategy (retries only on parse errors, not API errors)
- Add Pexels client for parallel photo search per recipe
- Add saved_recipes table (migration 004) with JSONB fields
- Add GET /recommendations endpoint (profile-aware prompt building)
- Add POST/GET/GET{id}/DELETE /saved-recipes CRUD endpoints
- Wire gemini, pexels, recommendation, savedrecipe packages in main.go

Flutter:
- Add Recipe, SavedRecipe models with json_serializable
- Add RecipeService (getRecommendations, getSavedRecipes, save, delete)
- Add RecommendationsNotifier and SavedRecipesNotifier (Riverpod)
- Add RecommendationsScreen with skeleton loading and refresh FAB
- Add RecipeDetailScreen (SliverAppBar, nutrition tooltip, steps with timer)
- Add SavedRecipesScreen with Dismissible swipe-to-delete and empty state
- Update RecipesScreen to TabBar (Recommendations / Saved)
- Add /recipe-detail route outside ShellRoute (no bottom nav)
- Extend ApiClient with getList() and deleteVoid()

Project:
- Add CLAUDE.md with English-only rule for comments and commit messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 22:43:29 +02:00

245 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FoodAI — План реализации
## Обзор итераций
| # | Итерация | Цель | Зависит от |
|---|----------|------|------------|
| 0 | Фундамент | Go-проект, БД, авторизация, Flutter-каркас | — |
| 1 | AI-рекомендации рецептов | Gemini генерирует рецепты, Pexels фото, сохранение рецептов | 0 |
| 2 | Управление продуктами | CRUD продуктов, сроки хранения, ingredient_mappings | 0 |
| 3 | Распознавание продуктов | OCR чека, фото продуктов, фото блюд (Gemini Vision) | 1, 2 |
| 4 | Планирование меню | Меню на неделю, AI-генерация, список покупок, дневник | 1, 2 |
Дальнейшие итерации определяются приоритетами после MVP. Функциональность из TODO.md (дневник статистики, режим готовки, полировка) — следующий горизонт.
## Карта зависимостей
```
┌──────────────┐
│ 0. Фундамент │
└──────┬───────┘
┌────────────┴────────────┐
│ │
▼ ▼
┌────────────────────┐ ┌──────────────────┐
│ 1. AI-рекомендации │ │ 2. Продукты │
│ (Gemini+Pexels) │ │ + ingredient_ │
│ saved_recipes │ │ mappings │
└──────────┬─────────┘ └────────┬─────────┘
│ │
└────────────┬────────────┘
┌──────────┴──────────┐
│ │
▼ ▼
┌────────────────────┐ ┌─────────────────────┐
│ 3. Распознавание │ │ 4. Планирование │
│ продуктов │ │ меню │
│ (Gemini Vision) │ │ (Gemini+Pexels) │
└────────────────────┘ └─────────────────────┘
```
**Параллельная разработка:** итерации 1 и 2 могут выполняться параллельно. Итерации 3 и 4 — тоже параллельно после завершения 1 и 2.
---
## Итерация 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: AI-рекомендации рецептов
> **Детальный план:** [Iteration_1.md](./Iteration_1.md)
**Цель:** реализовать ключевую функцию — персонализированные рецепты, сгенерированные Gemini, с фотографиями из Pexels и возможностью сохранять понравившиеся.
**Зависимости:** итерация 0.
### User Stories
#### Backend
| ID | Story | Описание |
|----|-------|----------|
| 1.1 | Gemini-клиент | Пакет internal/gemini. Интерфейс RecipeGenerator. GenerateRecipes(prompt) → []Recipe. Retry на невалидный JSON |
| 1.2 | Pexels-клиент | Пакет internal/pexels. SearchPhoto(query) → image_url. Параллельные запросы |
| 1.3 | Таблица saved_recipes | Миграция: id, user_id, title, description, cuisine, difficulty, prep/cook_time_min, servings, image_url, ingredients (JSONB), steps (JSONB), tags (JSONB), nutrition (JSONB), source, saved_at |
| 1.4 | GET /recommendations | Формирует промпт из профиля пользователя → Gemini → Pexels → ответ с image_url |
| 1.5 | CRUD saved_recipes | POST /saved-recipes, GET /saved-recipes, GET /saved-recipes/{id}, DELETE /saved-recipes/{id} |
#### Flutter
| ID | Story | Описание |
|----|-------|----------|
| 1.6 | RecommendationsScreen | Список карточек, skeleton-загрузка, кнопка 🔄 для перегенерации |
| 1.7 | RecipeDetailScreen | Фото, КБЖУ≈, ингредиенты, шаги, кнопка сохранить |
| 1.8 | SavedRecipesScreen | Список с удалением, пустое состояние |
### Результат итерации
- Пользователь открывает вкладку «Рецепты» и видит 5 персонализированных рецептов с фото
- Может сохранить рецепт, просмотреть детали, удалить из сохранённых
- КБЖУ помечены «≈» как приблизительные
---
## Итерация 2: Управление продуктами
> **Детальный план:** [Iteration_2.md](./Iteration_2.md)
**Цель:** пользователь может вести список своих продуктов вручную — добавлять через автодополнение (ingredient_mappings), редактировать, удалять, отслеживать сроки. Рекомендации становятся персонализированными: Gemini учитывает имеющиеся продукты.
**Зависимости:** итерация 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: Распознавание продуктов
> **Детальный план:** [Iteration_3.md](./Iteration_3.md)
**Цель:** пользователь фотографирует чек, холодильник или блюдо — Gemini Vision распознаёт продукты и помогает заполнить список запасов.
**Зависимости:** итерации 1, 2.
### User Stories
#### Backend
| ID | Story | Описание |
|----|-------|----------|
| 3.1 | OCR чека | POST /ai/recognize-receipt: фото → Gemini Flash (vision) → JSON (name, qty, unit, confidence). Fuzzy match по ingredient_mappings |
| 3.2 | Фото продуктов | POST /ai/recognize-products: 13 фото → параллельные Gemini-запросы → дедупликация → JSON |
| 3.3 | Распознавание блюда | POST /ai/recognize-dish: фото → Gemini → {dish_name, weight_g, КБЖУ≈, confidence} |
| 3.4 | Авто-маппинг | Нераспознанный продукт → Gemini классифицирует → сохраняет в ingredient_mappings |
| 3.5 | S3 / multipart | Загрузка фото: multipart или presigned URL |
#### Flutter
| ID | Story | Описание |
|----|-------|----------|
| 3.6 | ScanScreen | Выбор режима: чек / продукты / блюдо. Камера + галерея |
| 3.7 | Экран подтверждения | Список с инлайн-редактированием, удалением, «Добавить ещё фото», CTA «В запасы» |
| 3.8 | Экран результата блюда | Фото, КБЖУ≈, кнопки «В дневник» / «Открыть рецепт» |
### Результат итерации
- Сфотографировал чек → список продуктов → подтвердил → добавил в запасы
- Сфотографировал холодильник → то же
- Сфотографировал блюдо → КБЖУ≈ → можно добавить в дневник
---
## Итерация 4: Планирование меню
> **Детальный план:** [Iteration_4.md](./Iteration_4.md)
**Цель:** пользователь получает полное меню на неделю от Gemini с учётом продуктов, целей и предпочтений. Автоматически формируется список покупок.
**Зависимости:** итерации 1, 2.
### User Stories
#### Backend
| ID | Story | Описание |
|----|-------|----------|
| 4.1 | Таблицы menu_plans, menu_items | Миграции. menu_items → saved_recipes |
| 4.2 | Таблица meal_diary | Миграция. Записи приёмов пищи |
| 4.3 | POST /ai/generate-menu | Gemini генерирует 21 рецепт, Pexels параллельно, сохранение в БД |
| 4.4 | Menu CRUD | GET /menu?week=, PUT /menu/items/{id}, DELETE /menu/items/{id} |
| 4.5 | Shopping list | POST /shopping-list/generate (SQL-агрегация без Gemini), GET, PATCH check |
#### Flutter
| ID | Story | Описание |
|----|-------|----------|
| 4.6 | MenuScreen | 7-дневный вид, skeleton на генерацию, кнопка «Сгенерировать» |
| 4.7 | Замена рецепта | Тап «Изменить» → выбор из saved_recipes или перегенерация |
| 4.8 | ShoppingListScreen | Список по категориям, чекбоксы, «Поделиться» |
| 4.9 | DiaryScreen | Записи за день, «+ Добавить» |
### Результат итерации
- Пользователь получает меню на неделю одним запросом к Gemini
- Все рецепты меню сохраняются в saved_recipes
- Из меню автоматически формируется список покупок (то, чего нет в запасах)
- Ведётся дневник питания
---
## Итоги
| Итерация | Цель | Ключевые API |
|----------|------|-------------|
| 0. Фундамент | Auth, профиль, каркас | Firebase |
| 1. AI-рекомендации | Рецепты + сохранение | Gemini, Pexels |
| 2. Продукты | CRUD запасов, ingredient_mappings | — |
| 3. Распознавание | OCR чека, фото продуктов/блюда | Gemini Vision |
| 4. Меню | Недельное меню, список покупок | Gemini, Pexels |
**MVP:** итерации 02 (авторизация + рекомендации + продукты) — пользователь получает персонализированные рецепты.
**Полный продукт:** итерации 04 — полный цикл: сфотографировал чек → получил меню → список покупок → дневник питания.