Files
calorie-counter/docs/PLAN-AND-REQUIREMENTS.md
Andris Enins 12820632e7
Some checks failed
CI / Build & test backend (push) Failing after 14m56s
feat: Phase 4 — 9 new features (v1.1)
REQ-MOB-010: BarcodeScreen.tsx — barcode scanner via react-native-camera
REQ-VIZ-001: WeeklyCalorieChart.tsx — 7-day bar chart on History screen
REQ-VIZ-002: Streak tracker — GET /meals/streak + HomeScreen badge
REQ-UX-001: Quick-add calories — POST /meals/quick-add + QuickAddScreen
REQ-UX-002: Food favourites — UserFoodMemory.favourite + toggle endpoint + FoodRow star
REQ-UX-003: GoalBanner.tsx — in-app slide-in when daily target hit
REQ-EXP-001: ExportController — GET /export/meals CSV download
REQ-WTR-001: Water tracking — WaterEntry entity + POST/GET /water + DailyDetails widget
REQ-UX-004: Daily logging reminder — HomeScreen after-18:00 banner

Also: Flyway V2 (favourite), V3 (water_entries), V4 (source constraints)
Traceability, CHANGELOG, PLAN updated after each feature
2026-05-19 02:11:23 +03:00

399 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Calorie Counter App — Plan & Requirements
**Version**: 1.1
**Date**: 2026-05-19
**Status**: Phase 4 in progress
---
## 1. Product Vision
> "The easiest way to track calories with minimal effort and acceptable accuracy, using AI + smart defaults."
**Core principle**: Consistent estimation beats absolute precision. Users should trust the app enough to use it daily — not abandon it because it demands too much.
**KPI**: Log a meal in under 10 seconds.
---
## 2. Target Users
**Primary**: Busy professionals who eat a mix of home-cooked, restaurant, and packaged food. They want low friction, not lab-grade accuracy.
---
## 3. MVP Feature Scope
### IN scope
| Feature | Description |
|---|---|
| Manual food search | Search food DB, select portion, add to day |
| Barcode scan | Scan product → auto-fill nutrition |
| Photo logging (AI assist) | Snap photo → AI suggests items + portions → user confirms/edits |
| Daily calorie tracking | Consumed vs. target, remaining calories |
| Macro tracking | Protein / carbs / fat (optional display) |
| User profile | Age, weight, height, goal → auto-calculated daily target (BMR) |
| History view | Calorie totals per day |
| Repeat last meal | One-tap shortcut on home screen |
| AI correction loop | User edits AI result → stored to improve future suggestions |
### OUT of scope (MVP)
- Social features
- Meal plans
- Wearable integrations
- Deep health analytics
- Custom ML model training
---
## 4. Differentiation Strategy
Three features that separate this from MyFitnessPal etc:
1. **Confidence-aware calories** — show `500 kcal ± 80 kcal (confidence 85%)` instead of a false-precision single number
2. **Personal food memory** — app learns your typical portions, pre-fills next time
3. **AI correction loop** — every manual correction improves future suggestions, building a personalised model layer over time
---
## 5. Technical Architecture
### Stack decision
| Layer | Technology |
|---|---|
| Mobile | React Native |
| Backend | Spring Boot (Java)|
| Database | PostgreSQL |
| Food DB | Open Food Facts API (free, open) |
| AI service | OpenAI Vision API (MVP) → custom fine-tuned model (later) |
| Auth | JWT-based auth |
### Architecture diagram
```
Mobile App (React Native)
REST API
Backend (Spring Boot / FastAPI)
┌────────────────────────────────┐
│ Food DB (OpenFoodFacts cache) │
│ AI Service (Vision API) │
│ User Data (Postgres) │
└────────────────────────────────┘
```
**Key design decision**: Cache food DB locally for performance. Normalize all food entries to a common schema regardless of source (OpenFoodFacts / barcode / AI / manual).
---
## 6. Data Model
### User
```json
{
"id": "uuid",
"email": "string",
"createdAt": "timestamp",
"profile": {
"age": 30,
"weightKg": 80,
"heightCm": 180,
"goal": "lose | maintain | gain",
"dailyCaloriesTarget": 2200
}
}
```
### FoodItem (normalised DB)
```json
{
"id": "uuid",
"name": "Chicken breast",
"source": "openfoodfacts | custom | ai",
"caloriesPer100g": 165,
"macros": {
"proteinG": 31,
"fatG": 3.6,
"carbsG": 0
}
}
```
### MealEntry
```json
{
"id": "uuid",
"userId": "uuid",
"date": "2026-05-16",
"mealType": "breakfast | lunch | dinner | snack",
"items": [
{
"foodItemId": "uuid",
"quantityGrams": 200,
"calories": 330
}
],
"source": "manual | barcode | photo",
"confidence": 0.82
}
```
### PhotoAnalysis (AI audit trail)
```json
{
"id": "uuid",
"userId": "uuid",
"imageUrl": "string",
"detectedItems": [
{ "name": "rice", "estimatedGrams": 150, "confidence": 0.76 }
],
"userCorrections": [
{ "name": "rice", "correctedGrams": 180 }
]
}
```
### UserFoodMemory (personalisation layer)
```json
{
"userId": "uuid",
"foodName": "coffee with milk",
"avgPortionGrams": 250,
"lastUsed": "timestamp"
}
```
---
## 7. API Design
### Auth
```
POST /auth/register
POST /auth/login
```
### User
```
GET /user/profile
PUT /user/profile
```
### Food
```
GET /foods?query=chicken
GET /foods/barcode/{code}
```
### Meals
```
POST /meals
GET /meals/daily?date=YYYY-MM-DD
GET /meals/{id}
PUT /meals/{id}
DELETE /meals/{id}
```
`GET /meals/daily` response:
```json
{
"totalCalories": 1800,
"target": 2200,
"remaining": 400,
"meals": [...]
}
```
### AI
```
POST /ai/analyze-meal ← multipart image upload
POST /ai/correction ← submit user correction
```
`POST /ai/analyze-meal` response:
```json
{
"analysisId": "uuid",
"suggestions": [
{ "name": "pasta", "grams": 250, "confidence": 0.78 }
]
}
```
---
## 8. UI / UX Requirements
### Screen map
```
Bottom Nav: [ Home ] [ History ] [ Profile ]
FAB: [ + Add Meal ] (accessible from Home)
```
### Screens
| Screen | Key elements |
|---|---|
| Home | Calorie progress card, meal list (Breakfast/Lunch/Dinner), repeat shortcut, FAB |
| Add Meal (bottom sheet) | Photo / Search / Barcode options |
| Camera | Full-screen preview, capture button |
| AI Result | Detected items with portions + confidence %, Edit and Confirm CTAs |
| Edit Meal | Per-item sliders (0500g), real-time calorie total, Save button |
| Manual Search | Search input, results list with kcal/100g, portion selector |
| Daily Details | Calorie total, macro breakdown, meal list |
| History | Per-day calorie totals (scrollable list) |
| Profile | Weight / height / goal / daily target, Edit button |
### Critical UX rules (non-negotiable)
1. **Always require user confirmation** before saving AI-detected meals — never auto-save
2. **1-tap access** to Add Meal from Home screen
3. **Sliders over number inputs** for portion adjustment — faster, fewer errors
4. **Calories update in real-time** while adjusting portions
5. **Confidence score visible** on AI suggestions (supports honest accuracy framing)
### Accessibility
- All interactive elements keyboard/touch accessible
- Minimum touch target 48×48px
- Contrast ratio ≥ 4.5:1 (WCAG 2.2 AA)
- `alt` text on all food images / icons
---
## 9. Design System (summary)
### Colours
| Token | Value |
|---|---|
| Primary/Green | `#22C55E` |
| Primary/Dark | `#16A34A` |
| Error/Red | `#EF4444` |
| Warning/Yellow | `#F59E0B` |
| Gray/900 (text) | `#0F172A` |
| Background | `#FFFFFF` |
| Background/Muted | `#F8FAFC` |
### Typography (Inter / SF Pro)
- Heading/Large: 24px SemiBold
- Body/Large: 16px Regular
- Caption: 12px Regular
- Number/Kcal: 28px Bold
### Spacing: 8px grid (4 / 8 / 16 / 24 / 32 / 48px)
### Key components
`Button`, `MealItemRow`, `FoodRow`, `CalorieCard`, `AISuggestionCard`, `PortionSlider`, `ProgressBar`, `FAB`
---
## 10. Phased Delivery Plan
### Phase 1 — Core MVP ✅ Implemented
- [x] User auth (register / login)
- [x] User profile + BMR-based calorie target
- [x] Food search (OpenFoodFacts API)
- [x] Manual meal logging
- [x] Barcode scan backend endpoint
- [x] Daily calorie dashboard
- [x] Meal history
### Phase 2 — AI Layer ✅ Implemented
- [x] Photo capture screen
- [x] OpenAI Vision API integration (`/ai/analyze-meal`)
- [x] AI result confirmation screen
- [x] Per-item portion sliders (Edit Meal screen)
- [x] AI correction storage
### Phase 3 — Intelligence + Polish ✅ Implemented
- [x] Confidence-aware display (kcal ± range)
- [x] UserFoodMemory — personalised portion defaults
- [x] "Repeat last meal" shortcut
- [x] Macro tracking display (protein/carbs/fat)
- [x] Fine-tune AI suggestions based on user corrections
### Phase 4 — Enhanced Features (v1.1)
- [x] REQ-MOB-010: Barcode scanner mobile screen (HIGH — fix UI gap)
- [x] REQ-VIZ-001: Weekly calorie bar chart on History screen (HIGH)
- [x] REQ-VIZ-002: Streak tracker — consecutive days logged (HIGH)
- [x] REQ-UX-001: Quick-add calories without food search (MEDIUM)
- [x] REQ-UX-002: Food favourites — star items in search (MEDIUM)
- [x] REQ-UX-003: Goal achievement in-app notification (MEDIUM)
- [x] REQ-EXP-001: Data export as CSV (LOW)
- [x] REQ-WTR-001: Water intake tracking (LOW)
- [x] REQ-UX-004: Daily logging reminder banner (LOW)
---
## 11. Phase 4 Requirement Details
### REQ-MOB-010 — Barcode Scanner Screen (HIGH)
**Gap**: Backend and API client for barcode lookup exist; mobile UI omits the scan option.
- New `BarcodeScreen.tsx` using `react-native-camera` (already installed) — full-screen camera with barcode overlay
- Add "Scan Barcode" as third option in HomeScreen bottom sheet
- On successful scan → call `GET /foods/barcode/{code}` → navigate to portion selector → log meal
### REQ-VIZ-001 — Weekly Calorie Chart (HIGH)
- New `WeeklyCalorieChart` component: proportional-height bar chart for last 7 days (pure RN `View`, no extra deps)
- Rendered at top of History screen above the daily list
- Each bar shows day-of-week label + kcal value; target line drawn at user's daily goal
- Color-coded: green = at/under goal, amber = over goal
### REQ-VIZ-002 — Streak Tracker (HIGH)
- Backend: `GET /meals/streak` → returns `{ currentStreak: N, longestStreak: N }`
- Counts consecutive calendar days (ending today) where at least one meal was logged
- Mobile: streak badge on Home screen below CalorieCard
### REQ-UX-001 — Quick-Add Calories (MEDIUM)
- New `QuickAddScreen.tsx` — number-pad input for kcal + meal type picker
- Backend: `POST /meals/quick-add``{ date, mealType, calories, label? }` → creates system food "Quick Add" entry
- Accessible from Home bottom sheet as "⚡ Quick Add"
### REQ-UX-002 — Food Favourites (MEDIUM)
- Add `favourite` boolean column to `user_food_memories` (Flyway V3)
- Backend: `POST /foods/{id}/favourite` (toggle) → upserts UserFoodMemory with `favourite=true/false`
- Mobile: star icon on each `FoodRow`; Favourites section at top of Search screen
### REQ-UX-003 — Goal Achievement Notification (MEDIUM)
- In-app only (no native push required)
- When `remaining ≤ 0` after a meal is logged, show an in-app success banner on HomeScreen
- Banner auto-dismisses after 4 seconds
### REQ-EXP-001 — Data Export CSV (LOW)
- Backend: `GET /export/meals?from=YYYY-MM-DD&to=YYYY-MM-DD``Content-Type: text/csv`
- Columns: `date, mealType, foodName, grams, calories, source`
- Mobile: "Export Data" button in Profile screen → uses React Native `Share` API
### REQ-WTR-001 — Water Intake Tracking (LOW)
- Backend: `WaterEntry` entity + Flyway V4 migration; `POST /water`, `GET /water/daily?date=`
- Mobile: water counter widget on DailyDetails screen (+250ml / +500ml quick buttons, reset)
### REQ-UX-004 — Daily Logging Reminder (LOW)
- In-app banner (no native push)
- If it is after 18:00 local time and `totalCalories === 0` for today, show a reminder banner on HomeScreen
- Dismissible; does not re-appear once dismissed in the same session
---
## 12. Open Questions (to resolve before development)
1. **Backend language**: Spring Boot (Java — familiar) or FastAPI (Python — easier AI integration)?
2. **Auth provider**: Self-managed JWT, Firebase Auth, or Auth0?
3. **Database**: Postgres (more control) or Firestore (faster to start)?
4. **Image storage**: Firebase Storage or S3 for photo uploads?
5. **AI provider**: OpenAI Vision API only, or also evaluate Google Vision / custom model from day 1?
6. **Platforms**: iOS only, Android only, or both from day 1?
7. **Confidence display**: Show to users always, or only when below a threshold (e.g. < 80%)?