Files
food-ai/client
dbastrikin a225f6c47a refactor: migrate ingredient aliases/categories to dedicated tables, drop spoonacular_id
- migration 012: create ingredient_categories + ingredient_category_translations
  tables (7 slugs, Russian names); add ingredient_aliases (ingredient_id, lang,
  alias) with GIN trigram index; migrate aliases JSONB from ingredient_mappings
  and ingredient_translations; drop aliases columns and spoonacular_id; add
  UNIQUE (canonical_name) as conflict key
- ingredient/model: remove SpoonacularID, add CategoryName for localized display
- ingredient/repository: conflict on canonical_name; GetByID/Search join category
  translations and aliases lateral; new UpsertAliases (pgx batch),
  UpsertCategoryTranslation; remove GetBySpoonacularID; split scan helpers into
  scanMappingWrite / scanMappingRead
- gemini/recognition: add IngredientTranslation type; IngredientClassification
  now carries Translations []IngredientTranslation instead of CanonicalNameRu;
  update ClassifyIngredient prompt to English with structured translations array
- recognition/handler: update ingredientRepo interface; saveClassification uses
  UpsertAliases and iterates Translations
- recipe/model: remove SpoonacularID from RecipeIngredient
- integration tests: remove SpoonacularID fixtures, replace GetBySpoonacularID
  tests with GetByID, add UpsertAliases and UpsertCategoryTranslation tests
- Flutter: remove canonicalNameRu from IngredientMapping, add categoryName;
  displayName returns server-resolved canonicalName; regenerate .g.dart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 14:40:07 +02:00
..

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

  1. Создайте проект в Firebase Console
  2. Включите Authentication → Sign-in method: Email/Password и Google

Android

  1. Project Settings (⚙️) → Your apps → иконка Android (🤖)
  2. Package name: com.foodai.food_ai
  3. Скачать google-services.json → положить в android/app/:
cp ~/Downloads/google-services.json android/app/google-services.json

iOS

  1. Project Settings (⚙️) → Your apps → иконка iOS (``)
  2. Bundle ID: com.foodai.foodAi
  3. Скачать GoogleService-Info.plist → добавить через Xcode в группу Runner:
open ios/Runner.xcworkspace
# Перетащить GoogleService-Info.plist в группу Runner в навигаторе Xcode

Web

  1. Project Settings (⚙️) → Your apps → иконка Web (</>)
  2. Nickname: FoodAI Web
  3. Скопировать полученный firebaseConfig в web/index.html, заменив YOUR_* placeholder'ы
  4. Убедиться, что localhost есть в списке авторизованных доменов: Authentication → SettingsAuthorized 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.