Describe ProfileService, profileProvider, ProfileScreen sections (avatar, body params, goal/activity, daily calories, logout), EditProfileSheet, and HomeScreen name integration. No new backend endpoints needed — GET/PUT /profile already exist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
21 KiB
FoodAI — План реализации
Обзор итераций
| # | Итерация | Цель | Зависит от |
|---|---|---|---|
| 0 | Фундамент | Go-проект, БД, авторизация, Flutter-каркас | — |
| 1 | AI-рекомендации рецептов | GPT генерирует рецепты, Pexels фото, сохранение рецептов | 0 |
| 2 | Управление продуктами | CRUD продуктов, сроки хранения, ingredient_mappings | 0 |
| 3 | Распознавание продуктов | OCR чека, фото продуктов, фото блюд (GPT-4o Vision) | 1, 2 |
| 4 | Планирование меню | Меню на неделю, AI-генерация, список покупок, дневник | 1, 2 |
| 5 | Главный экран | Дашборд: калории, план на сегодня, истекающие продукты, рекомендации | 1, 2, 4 |
| 6 | Профиль | Просмотр и редактирование профиля, норма калорий, выход из аккаунта | 0 |
Дальнейшие итерации определяются приоритетами после MVP. Функциональность из TODO.md (дневник статистики, режим готовки, полировка) — следующий горизонт.
Карта зависимостей
┌──────────────┐
│ 0. Фундамент │
└──────┬───────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌────────────────────┐ ┌──────────────────┐
│ 1. AI-рекомендации │ │ 2. Продукты │
│ (Gemini+Pexels) │ │ + ingredient_ │
│ saved_recipes │ │ mappings │
└──────────┬─────────┘ └────────┬─────────┘
│ │
└────────────┬────────────┘
│
┌──────────┴──────────┐
│ │
▼ ▼
┌────────────────────┐ ┌─────────────────────┐
│ 3. Распознавание │ │ 4. Планирование │
│ продуктов │ │ меню │
│ (GPT-4o Vision) │ │ (GPT+Pexels) │
└────────────────────┘ └──────────┬──────────┘
│
▼
┌─────────────────────┐
│ 5. Главный экран │
│ (дашборд) │
└─────────────────────┘
┌─────────────────────┐
│ 6. Профиль │ (зависит только от 0)
│ (просмотр + │
│ редактирование) │
└─────────────────────┘
Параллельная разработка: итерации 1 и 2 могут выполняться параллельно. Итерации 3 и 4 — тоже параллельно после завершения 1 и 2. Итерация 5 — после 4.
Итерация 0: Фундамент
Детальный план: 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
Цель: реализовать ключевую функцию — персонализированные рецепты, сгенерированные 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
Цель: пользователь может вести список своих продуктов вручную — добавлять через автодополнение (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
Цель: пользователь фотографирует чек, холодильник или блюдо — 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: 1–3 фото → параллельные 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
Цель: пользователь получает полное меню на неделю от 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 | GPT генерирует 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-агрегация без AI), GET, PATCH check |
Flutter
| ID | Story | Описание |
|---|---|---|
| 4.6 | MenuScreen | 7-дневный вид, skeleton на генерацию, кнопка «Сгенерировать» |
| 4.7 | Замена рецепта | Тап «Изменить» → выбор из saved_recipes или перегенерация |
| 4.8 | ShoppingListScreen | Список по категориям, чекбоксы, «Поделиться» |
| 4.9 | DiaryScreen | Записи за день, «+ Добавить» |
Результат итерации
- Пользователь получает меню на неделю одним запросом к GPT
- Все рецепты меню сохраняются в saved_recipes
- Из меню автоматически формируется список покупок (то, чего нет в запасах)
- Ведётся дневник питания
Итерация 5: Главный экран
Детальный план: Iteration_5.md
Цель: дашборд — сводка на сегодня, прогресс калорий, плановые приёмы пищи, предупреждение об истекающих продуктах, рекомендации рецептов.
Зависимости: итерации 1, 2, 4.
User Stories
Backend
| ID | Story | Описание |
|---|---|---|
| 5.1 | GET /home/summary | Агрегирует: план на сегодня, калории дневника, истекающие продукты, последние рекомендации |
Flutter
| ID | Story | Описание |
|---|---|---|
| 5.2 | HomeScreen | Приветствие, кольцо калорий, план на сегодня, быстрые действия, баннер истекающих, блок рекомендаций |
| 5.3 | homeProvider | StateNotifier, обновление после scan/menu-генерации |
Результат итерации
- Открываешь приложение — сразу видишь баланс калорий и план на день
- Предупреждение если продукты скоро истекут
- Рекомендации без нового AI-вызова (из ранее сохранённых)
Итерация 6: Профиль
Детальный план: Iteration_6.md
Цель: заменить заглушку вкладки «Профиль» полноценным экраном — просмотр данных, редактирование параметров тела и целей, отображение расчётной нормы калорий, выход из аккаунта.
Зависимости: итерация 0.
User Stories
Backend
Новых эндпоинтов не требуется — GET /profile и PUT /profile реализованы в итерации 0.
Flutter
| ID | Story | Описание |
|---|---|---|
| 6.1 | ProfileService | getProfile() → GET /profile, updateProfile() → PUT /profile |
| 6.2 | profileProvider | StateNotifier<AsyncValue<User>>, методы load() и update() |
| 6.3 | ProfileScreen | Секции: аватар+имя, параметры тела, цель+активность, норма калорий, кнопка выхода |
| 6.4 | EditProfileSheet | Modal bottom sheet с формой редактирования всех параметров |
| 6.5 | HomeScreen — имя | Приветствие берёт имя из profileProvider вместо захардкоженного |
Результат итерации
- Пользователь видит своё имя, email, параметры тела и цели
- Может обновить параметры — норма калорий пересчитывается автоматически сервером
- Может выйти из аккаунта с подтверждением
- Приветствие на главном экране показывает реальное имя пользователя
Итоги
| Итерация | Цель | Ключевые API |
|---|---|---|
| 0. Фундамент | Auth, профиль, каркас | Firebase |
| 1. AI-рекомендации | Рецепты + сохранение | GPT-4o-mini, Pexels |
| 2. Продукты | CRUD запасов, ingredient_mappings | — |
| 3. Распознавание | OCR чека, фото продуктов/блюда | GPT-4o Vision |
| 4. Меню | Недельное меню, список покупок | GPT-4o-mini, Pexels |
| 5. Главный экран | Дашборд: калории, план, истекающие, рекомендации | — |
| 6. Профиль | Параметры тела, цель, норма калорий, выход | — |
MVP: итерации 0–2 (авторизация + рекомендации + продукты) — пользователь получает персонализированные рецепты.
Полный продукт: итерации 0–4 — полный цикл: сфотографировал чек → получил меню → список покупок → дневник питания.