Inserts a new PlanProductsSheet as step 1 of the planning flow. Users see their current products as a multi-select checklist (all selected by default) before choosing the planning mode and dates. - Empty state explains the benefit and offers "Add products" CTA while always allowing "Plan without products" to skip - Selected product IDs flow through PlanMenuSheet → PlanDatePickerSheet → MenuService.generateForDates → backend - Backend: added ProductIDs field to generate-menu request body; uses ListForPromptByIDs when set, ListForPrompt otherwise - Backend: added Repository.ListForPromptByIDs (filtered SQL query) - All 12 ARB locale files updated with planProducts* keys 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.