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

137
backend/README.md Normal file
View File

@@ -0,0 +1,137 @@
# FoodAI Backend
Go REST API с авторизацией через Firebase, JWT и PostgreSQL.
## Стек
- **Go 1.23** — язык
- **chi** — HTTP-роутер
- **pgx / pgxpool** — PostgreSQL-драйвер
- **goose** — миграции
- **golang-jwt/v5** — JWT
- **Firebase Admin SDK** — верификация токенов
## Требования
- Go 1.23+
- Docker & Docker Compose
- [goose](https://github.com/pressly/goose) (`go install github.com/pressly/goose/v3/cmd/goose@latest`)
- Файл `firebase-credentials.json` (сервисный аккаунт Firebase)
## Быстрый старт
### 1. Переменные окружения
```bash
cp .env.example .env
```
Отредактируйте `.env`:
| Переменная | Описание | По умолчанию |
|---|---|---|
| `DATABASE_URL` | DSN подключения к PostgreSQL | `postgres://food_ai:food_ai_local@localhost:5432/food_ai?sslmode=disable` |
| `FIREBASE_CREDENTIALS_FILE` | Путь к JSON-ключу сервисного аккаунта Firebase | `./firebase-credentials.json` |
| `JWT_SECRET` | Секрет для подписи JWT | — |
| `JWT_ACCESS_DURATION` | Время жизни access-токена | `15m` |
| `JWT_REFRESH_DURATION` | Время жизни refresh-токена | `720h` |
| `PORT` | Порт сервера | `8080` |
| `ALLOWED_ORIGINS` | CORS-разрешённые источники | `http://localhost:3000` |
### 2. Запуск через Docker Compose
Поднимает PostgreSQL и собирает приложение:
```bash
make docker-up
```
### 3. Запуск локально (только БД в Docker)
```bash
# Запустить только PostgreSQL
docker compose up -d postgres
# Применить миграции
make migrate-up
# Запустить сервер
make run
```
## Команды
| Команда | Описание |
|---|---|
| `make run` | Запустить сервер в режиме разработки |
| `make test` | Запустить unit-тесты |
| `make test-integration` | Запустить интеграционные тесты (требует Docker) |
| `make lint` | Проверить код через golangci-lint |
| `make docker-up` | Поднять PostgreSQL + приложение |
| `make docker-down` | Остановить контейнеры |
| `make docker-logs` | Логи приложения |
| `make migrate-up` | Применить миграции |
| `make migrate-down` | Откатить последнюю миграцию |
| `make migrate-status` | Статус миграций |
| `make migrate-create name=<name>` | Создать новую миграцию |
## API
### Публичные эндпоинты
| Метод | Путь | Описание |
|---|---|---|
| `GET` | `/health` | Проверка состояния сервера и БД |
| `POST` | `/auth/login` | Вход через Firebase ID-токен |
| `POST` | `/auth/refresh` | Обновление JWT по refresh-токену |
| `POST` | `/auth/logout` | Выход (инвалидация refresh-токена) |
### Защищённые эндпоинты (Bearer JWT)
| Метод | Путь | Описание |
|---|---|---|
| `GET` | `/profile` | Получить профиль пользователя |
| `PUT` | `/profile` | Обновить профиль пользователя |
### Примеры запросов
**Логин:**
```bash
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"firebase_token": "<FIREBASE_ID_TOKEN>"}'
```
**Получить профиль:**
```bash
curl http://localhost:8080/profile \
-H "Authorization: Bearer <ACCESS_TOKEN>"
```
**Обновить профиль:**
```bash
curl -X PUT http://localhost:8080/profile \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"height_cm": 180, "weight_kg": 75.5, "age": 28, "gender": "male", "activity": "moderate", "goal": "maintain"}'
```
## Структура проекта
```
backend/
├── cmd/server/ # Точка входа
├── internal/
│ ├── auth/ # Firebase-верификация, JWT, сервис и хэндлер авторизации
│ ├── config/ # Конфигурация через переменные окружения
│ ├── database/ # Подключение к PostgreSQL (pgxpool)
│ ├── middleware/ # RequestID, Logging, Recovery, CORS, Auth
│ ├── server/ # Роутер (chi)
│ ├── testutil/ # Вспомогательные утилиты для тестов
│ └── user/ # Модель, репозиторий, сервис, хэндлер, расчёт калорий
├── migrations/ # SQL-миграции (goose)
├── .env.example
├── docker-compose.yml
├── Dockerfile
└── Makefile
```