Backend:
- Rename recognition_jobs → dish_recognition_jobs; add target_date and
target_meal_type columns to capture scan context at submission time
- Add job_id FK on meal_diary so entries are linked to their origin job
- New GET /ai/jobs endpoint returns today's unlinked jobs for the current user
- diary.Entry and CreateRequest gain job_id field; repository reads/writes it
- CORS middleware: allow Accept-Language and Cache-Control headers
- Logging middleware: implement http.Flusher on responseWriter (needed for SSE)
- Consolidate migrations into a single 001_initial_schema.sql
Flutter:
- POST /ai/recognize-dish now sends target_date and target_meal_type
- DishResultSheet accepts jobId; _addToDiary includes it in the diary payload,
saves last-used meal type to SharedPreferences, invalidates todayJobsProvider
- TodayJobsNotifier + todayJobsProvider: loads unlinked jobs via GET /ai/jobs
- Home screen shows _TodayJobsWidget (up to 3 tiles) between macros and meals;
tapping a done tile reopens DishResultSheet with the stored result
- Quick Actions row: third button "История" → /scan/history
- New RecognitionHistoryScreen: full-screen list of today's unlinked jobs
- LocalPreferences wrapper over SharedPreferences (last_used_meal_type)
- app_theme: apply Google Fonts Roboto as default font family
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove denormalized columns (name, calories, protein_g, fat_g, carbs_g)
from meal_diary. Name is now resolved via JOIN with dishes/dish_translations;
macros are computed as recipe.*_per_serving * portions at query time.
- Add dish.Repository.FindOrCreateRecipe: finds or creates a minimal recipe
stub seeded with AI-estimated macros
- recognition/handler: resolve recipe_id synchronously per candidate;
simplify enrichDishInBackground to translations-only
- diary/handler: accept dish_id OR name; always resolve recipe_id via
FindOrCreateRecipe before INSERT
- diary/entity: DishID is now non-nullable string; CreateRequest drops macros
- diary/repository: ListByDate and Create use JOIN to return computed macros
- ai/types: add RecipeID field to DishCandidate
- Update tests and wire_gen accordingly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove "Определить блюдо" from ScanScreen and the /scan/dish route.
The + button on each meal card now triggers dish recognition inline —
picks image, shows loading dialog, then presents DishResultSheet as a
modal bottom sheet. After adding to diary the sheet closes and the user
stays on home.
Also fix Navigator.pop crash: showDialog uses the root navigator by
default, so capture Navigator.of(context, rootNavigator: true) before
the async gap and use it to close the loading dialog.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace static 7-day ListView with a scrollable strip (365 days back,
today at the right edge) and a header row with:
- chevron buttons to step one day at a time
- selected date label ("Вт, 18 марта")
- "Сегодня" shortcut that appears when a past date is selected
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- Translate all recognition prompts (receipt, products, dish) from Russian to English
- Add lang parameter to Recognizer interface and pass locale.FromContext in handlers
- DishResult type uses candidates array for multi-candidate responses
Client:
- Add meal tracking: diary provider, date selector, meal type model
- DishResult parser: backward-compatible with legacy flat format and new candidates format
- DishResultScreen: sticky bottom button, full-width portion/meal-type inputs,
КБЖУ disclaimer moved under nutrition card, add date field to diary POST body
- Recognition prompts now return dish/product names in user's preferred language
- Onboarding, profile, home screen visual updates
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The home screen CaloriesCard now uses a circular ring (CustomPainter)
instead of a LinearProgressIndicator. Ring colour is determined by the
user's goal type (lose / maintain / gain) with inverted semantics for
the gain goal — red means undereating, not overeating.
Overflow beyond 100% is shown as a thinner second-lap arc in the same
warning colour. Numbers (logged kcal, goal, remaining/overage) are
displayed both inside the ring and in a stat column to the right.
Adds docs/calorie_ring_color_spec.md with the full colour threshold
specification per goal type.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add ProfileService (GET/PUT /profile), ProfileNotifier provider,
and full ProfileScreen with body-params, goal/activity, daily-calories
sections and logout confirmation. EditProfileSheet lets user update
name, height, weight, age, gender, goal and activity; backend
auto-recalculates daily_calories via Mifflin-St Jeor.
HomeScreen greeting now shows the user's real name from profileProvider.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- internal/home: GET /home/summary endpoint
- Today's meal plan from menu_plans/menu_items
- Logged calories sum from meal_diary
- Daily goal from user profile (default 2000)
- Expiring products within 3 days
- Last 3 saved recommendations (no AI call on home load)
- Wire homeHandler in server.go and main.go
Flutter:
- shared/models/home_summary.dart: HomeSummary, TodaySummary,
TodayMealPlan, ExpiringSoon, HomeRecipe
- features/home/home_service.dart + home_provider.dart
- features/home/home_screen.dart: greeting, calorie progress bar,
today's meals card, expiring banner, quick actions row,
recommendations horizontal list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>