feat: implement Iteration 0 foundation (backend + Flutter client)

Backend (Go):
- Project structure with chi router, pgxpool, goose migrations
- JWT auth (access/refresh tokens) with Firebase token verification
- NoopTokenVerifier for local dev without Firebase credentials
- PostgreSQL user repository with atomic profile updates (transactions)
- Mifflin-St Jeor calorie calculation based on profile data
- REST API: POST /auth/login, /auth/refresh, /auth/logout, GET/PUT /profile, GET /health
- Middleware: auth, CORS (localhost wildcard), logging, recovery, request_id
- Unit tests (51 passing) and integration tests (testcontainers)
- Docker Compose setup with postgres healthcheck and graceful shutdown

Flutter client:
- Riverpod state management with GoRouter navigation
- Firebase Auth (email/password + Google sign-in with web popup support)
- Platform-aware API URLs (web/Android/iOS)
- Dio HTTP client with JWT auth interceptor and concurrent refresh handling
- Secure token storage
- Screens: Login, Register, Home (tabs: Menu, Recipes, Products, Profile)
- Unit tests (17 passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dbastrikin
2026-02-20 13:14:58 +02:00
commit 24219b611e
140 changed files with 13062 additions and 0 deletions

151
client/README.md Normal file
View File

@@ -0,0 +1,151 @@
# 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. Установить зависимости
```bash
flutter pub get
```
### 2. Настроить Firebase
1. Создайте проект в [Firebase Console](https://console.firebase.google.com)
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/`:
```bash
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`:
```bash
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 → **Settings****Authorized domains**
> **Важно:** не коммитить конфиг-файлы в git:
> ```bash
> echo "android/app/google-services.json" >> .gitignore
> echo "ios/Runner/GoogleService-Info.plist" >> .gitignore
> ```
### 3. Настроить URL бэкенда
Откройте `lib/core/config/app_config.dart` и укажите адрес API:
```dart
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. Сгенерировать код
```bash
flutter pub run build_runner build --delete-conflicting-outputs
```
### 5. Запустить приложение
```bash
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`.