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>
FoodAI Client
Flutter-приложение для управления питанием с поддержкой iOS, Android и Web.
Стек
- Flutter 3 / Dart 3 — фреймворк
- Riverpod — управление состоянием
- go_router — навигация с auth guard
- Dio — HTTP-клиент с автоматическим обновлением токенов
- Firebase Auth — аутентификация (email + Google)
- flutter_secure_storage — безопасное хранение токенов
- json_serializable — генерация сериализации моделей
Требования
- Flutter SDK 3.x (
flutter --version) - Dart SDK 3.9+
- Android Studio или Xcode (для запуска на симуляторе/устройстве)
- Chrome (для запуска в браузере)
- Проект Firebase с включёнными Email и Google Sign-In
Быстрый старт
1. Установить зависимости
flutter pub get
2. Настроить Firebase
- Создайте проект в Firebase Console
- Включите Authentication → Sign-in method: Email/Password и Google
Android
- Project Settings (⚙️) → Your apps → иконка Android (
🤖) - Package name:
com.foodai.food_ai - Скачать
google-services.json→ положить вandroid/app/:
cp ~/Downloads/google-services.json android/app/google-services.json
iOS
- Project Settings (⚙️) → Your apps → иконка iOS (``)
- Bundle ID:
com.foodai.foodAi - Скачать
GoogleService-Info.plist→ добавить через Xcode в группуRunner:
open ios/Runner.xcworkspace
# Перетащить GoogleService-Info.plist в группу Runner в навигаторе Xcode
Web
- Project Settings (⚙️) → Your apps → иконка Web (
</>) - Nickname:
FoodAI Web - Скопировать полученный
firebaseConfigвweb/index.html, заменивYOUR_*placeholder'ы - Убедиться, что
localhostесть в списке авторизованных доменов: Authentication → Settings → Authorized domains
Важно: не коммитить конфиг-файлы в git:
echo "android/app/google-services.json" >> .gitignore echo "ios/Runner/GoogleService-Info.plist" >> .gitignore
3. Настроить URL бэкенда
Откройте lib/core/config/app_config.dart и укажите адрес API:
static const development = AppConfig(
apiBaseUrl: 'http://10.0.2.2:9090', // Android-эмулятор → localhost:9090
// apiBaseUrl: 'http://localhost:9090', // iOS-симулятор / Web
);
static const production = AppConfig(
apiBaseUrl: 'https://api.food-ai.app',
);
Бэкенд по умолчанию поднимается на порту
9090через Docker Compose (9090:8080).
4. Сгенерировать код
flutter pub run build_runner build --delete-conflicting-outputs
5. Запустить приложение
flutter run
Команды
| Команда | Описание |
|---|---|
flutter pub get |
Установить зависимости |
flutter run |
Запустить на подключённом устройстве/симуляторе |
flutter run -d chrome |
Запустить в браузере (web) |
flutter test |
Запустить все тесты |
flutter analyze |
Статический анализ кода |
flutter build apk |
Собрать APK для Android |
flutter build ios |
Собрать для iOS |
flutter pub run build_runner build |
Сгенерировать код (json_serializable) |
flutter pub run build_runner watch |
Следить за изменениями и генерировать |
Структура проекта
client/
├── lib/
│ ├── core/
│ │ ├── api/ # ApiClient (Dio), AuthInterceptor, исключения
│ │ ├── auth/ # AuthService, AuthNotifier (Riverpod), SecureStorage
│ │ ├── config/ # AppConfig (URL бэкенда по окружению)
│ │ ├── router/ # GoRouter с auth guard и MainShell
│ │ └── theme/ # Цвета и тема Material 3
│ ├── features/
│ │ ├── auth/ # LoginScreen, RegisterScreen
│ │ ├── home/ # HomeScreen (placeholder)
│ │ ├── menu/ # MenuScreen (placeholder)
│ │ ├── products/ # ProductsScreen (placeholder)
│ │ ├── profile/ # ProfileScreen (placeholder)
│ │ └── recipes/ # RecipesScreen (placeholder)
│ ├── shared/
│ │ └── models/ # User (json_serializable + user.g.dart)
│ ├── app.dart # Корневой виджет
│ └── main.dart # Точка входа, инициализация Firebase
└── test/
├── features/auth/ # Тесты LoginScreen, RegisterScreen
└── shared/models/ # Тесты модели User
Навигация
Приложение использует go_router с guard-ом авторизации:
/login— экран входа (только для неавторизованных)/register— экран регистрации/→/home— главная (требует авторизации)/products— продукты/menu— меню дня/recipes— рецепты/profile— профиль пользователя
Неавторизованный пользователь автоматически перенаправляется на /login. После входа — на /home.