From ca875d29c4fb822d27b8b47bcd1bfce8f1f87ffd Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Sun, 17 May 2026 23:39:00 +0200 Subject: [PATCH] docs: allinea CLAUDE.md, README e docker/README al codice reale CLAUDE.md: rimossi riferimenti a noVNC/Vue3/sop.md, aggiornata architettura reale (features/*/presentation/), rimossi file fantasma (checkbox_item.dart, conversion_service.dart), aggiunta feature guide, corretta struttura test, aggiornati comandi Docker. README.md: riscritto per Flutter (rimosso stack Vue3/Node.js), aggiunta sezione test con comandi e struttura cartelle, link docs/. docker/README.md: aggiunta sezione test completa con comandi per tutti i test, singolo file e singola feature; aggiornato flusso completo. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 128 ++++++++++++++++++++++++----------------------- README.md | 92 ++++++++++++++++++++++++---------- docker/README.md | 89 ++++++++++++++++++++++---------- 3 files changed, 195 insertions(+), 114 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 017f4af..7d75565 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,89 +4,93 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -BitePlan è un'app Android per meal planning, conversione crudo/cotto e lista della spesa. Il progetto è in **riscrittura completa da Vue 3 + Capacitor a Flutter**. Segui `sop.md` come piano di lavoro: ogni sezione del SOP corrisponde a una fase da completare in ordine. L'obiettivo finale è un APK Android buildabile via Docker. Tutta la UI e la UX sono in **italiano**. - -## Stato attuale - -Il codice Dart Flutter è stato scritto e si trova in `lib/`. Il codice Vue 3 è stato rimosso. - -**Passo successivo obbligatorio**: eseguire `flutter create .` nel container dev (noVNC) per generare lo scaffolding Android (`android/`, `ios/`, `test/`). Senza questo passo il progetto non è buildabile. - -## Roadmap (da sop.md) - -1. ✅ Struttura progetto Flutter (`lib/`, `pubspec.yaml`, `assets/data/conversions.json`) -2. ✅ `StorageService`, `ConversionService`, modelli dati -3. ✅ Tutte e 3 le pagine + widget + provider -4. ✅ `BottomNavigationBar`, portrait lock, Material 3 -5. ✅ Container dev: Docker + Xvfb + noVNC (`docker/dev/`) -6. ✅ Container build headless APK (`docker/build/`) -7. ⬜ Eseguire `flutter create .` nel container + `flutter pub get` -8. ⬜ Configurare icona con `flutter pub run flutter_launcher_icons` +BitePlan è un'app Android per meal planning, conversione crudo/cotto e lista della spesa, scritta in Flutter. Tutta la UI e la UX sono in **italiano**. L'obiettivo finale è un APK Android buildabile via Docker. ## Comandi ```bash -# Avvia container dev con GUI noVNC +# Sviluppo (web server con hot reload) cd docker/dev && docker compose up -# → http://localhost:6080/vnc.html +# → http://localhost:5173 +# Con il container attivo: docker compose attach dev → r = hot reload -# Prima volta nel container (dal terminale noVNC): -flutter create --project-name biteplan --org com.biteplan . -flutter pub get && flutter pub run flutter_launcher_icons +# Test (dalla root del progetto — richiede immagine biteplan-build) +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter pub get && flutter test" -# Sviluppo nel container: -flutter run -d linux # app desktop nella GUI -flutter run -d chrome # app web +# Test singolo file +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter test test/features/meal_planner/qr_test.dart" -# Test (nel container o con Flutter installato localmente): -flutter test # unit + widget -flutter test integration_test/ # e2e (richiede device/emulatore) - -# Build APK (headless, da host): -bash docker/build/build.sh # debug → dist/biteplan-debug.apk -bash docker/build/build.sh --release # release firmato → dist/biteplan-release.apk +# Build APK (headless, da host) +bash docker/build/build.sh # debug → dist/biteplan-debug.apk +bash docker/build/build.sh --release # release → dist/biteplan-release.apk ``` -## Architettura target (Flutter) +## Architettura ``` lib/ ├── main.dart -├── app.dart # MaterialApp, routing, BottomNavigationBar -├── pages/ -│ ├── meal_planner_page.dart -│ ├── converter_page.dart -│ └── shopping_list_page.dart -├── widgets/ -│ ├── meal_card.dart -│ └── checkbox_item.dart -├── models/ -│ ├── meal_plan.dart -│ └── shopping_item.dart -├── services/ -│ ├── storage_service.dart -│ └── conversion_service.dart -└── data/ - └── conversions.json # 50+ alimenti × metodi cottura, yield = cotto/crudo +├── app.dart # MaterialApp, NavigationBar, AppBar con bottone info +├── core/ +│ ├── constants/app_constants.dart # kDayIds, kMealSlots, kStorageKey*, kAppVersion +│ └── theme/app_theme.dart +├── shared/ +│ ├── services/storage_service.dart # wrapper SharedPreferences (load/save) +│ └── widgets/ +├── features/ +│ ├── meal_planner/ +│ │ ├── models/meal_plan.dart # MealPlan, DayPlan +│ │ ├── providers/meal_planner_provider.dart +│ │ ├── qr_codec.dart # buildQrPayload, parseMealPlanFromQr +│ │ └── presentation/ +│ │ ├── pages/meal_planner_page.dart +│ │ ├── pages/qr_scan_page.dart +│ │ └── widgets/meal_card.dart, qr_share_sheet.dart +│ ├── converter/ +│ │ ├── models/conversion_entry.dart # rawToCooked, cookedToRaw (metodi sul model) +│ │ ├── providers/converter_provider.dart +│ │ └── presentation/pages/converter_page.dart +│ ├── shopping_list/ +│ │ ├── models/shopping_item.dart # quantity per aggregazione duplicati +│ │ ├── providers/shopping_list_provider.dart +│ │ └── presentation/ +│ │ ├── pages/shopping_list_page.dart +│ │ └── widgets/shopping_item_tile.dart +│ └── guide/ +│ └── presentation/ +│ ├── pages/guide_page.dart # 3 tab: Pasti, Converti, Spesa +│ └── widgets/info_bottom_sheet.dart # aperto dal bottone info in AppBar +└── assets/data/conversions.json # 50+ alimenti × metodi cottura ``` -**Stato**: Provider o Riverpod (nessuno store esterno pesante). +**State management**: Provider (`ChangeNotifier`). **Persistenza**: `shared_preferences`, chiavi `meals` e `shopping_list` (JSON serializzato). -**Conversione**: `rawToCooked(raw, yield) = raw * yield` / `cookedToRaw(cooked, yield) = cooked / yield`. -**UI**: Material 3, seed color `Color(0xFF2d6a4f)`, touch target minimo 48×48 dp. +**Conversione**: logica in `ConversionEntry` — `rawToCooked = raw * yieldFactor`, `cookedToRaw = cooked / yieldFactor`. +**UI**: Material 3, seed color `Color(0xFF2d6a4f)`, tutto in italiano. +**QR**: payload JSON `{ "v": 1, "meals": { ... } }`, limite 2953 byte (capacità QR con error correction L). ## Testing +110 test (unit + widget). Non richiedono device fisico. + ``` test/ -├── unit/ -│ ├── models/ # DayPlan, MealPlan, ConversionEntry, ShoppingItem -│ └── providers/ # MealPlannerProvider, ShoppingListProvider -└── widget/ # MealCard, ShoppingItemTile - -integration_test/ -└── app_test.dart # navigazione, shopping list, converter, meal planner +├── helpers/pump_app.dart # estensione pumpApp per widget test +└── features/ + ├── converter/ + │ ├── models/conversion_entry_test.dart + │ └── providers/converter_provider_test.dart + ├── meal_planner/ + │ ├── models/meal_plan_test.dart + │ ├── providers/meal_planner_provider_test.dart + │ ├── widgets/meal_card_test.dart + │ └── qr_test.dart + └── shopping_list/ + ├── models/shopping_item_test.dart + ├── providers/shopping_list_provider_test.dart + └── widgets/shopping_item_tile_test.dart ``` -- **Unit/widget**: `flutter test` — non richiedono dispositivo, usano `SharedPreferences.setMockInitialValues({})` per isolare lo storage -- **Integration**: `flutter test integration_test/` — richiedono emulatore o device fisico +I test usano `SharedPreferences.setMockInitialValues({})` per isolare lo storage. diff --git a/README.md b/README.md index b93b212..7816b8e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BitePlan -App mobile-first per la gestione della dieta quotidiana — pianificazione pasti, conversione crudo/cotto e lista della spesa. +App Android per la gestione della dieta quotidiana — pianificazione pasti, conversione crudo/cotto e lista della spesa. ## Funzionalità @@ -8,15 +8,16 @@ App mobile-first per la gestione della dieta quotidiana — pianificazione pasti - Pianificazione settimanale su 7 giorni × 3 pasti (colazione, pranzo, cena) - Card accordion per giorno, giorno corrente aperto di default - Aggiunta e rimozione di voci per ogni pasto -- Generazione automatica della lista della spesa dai pasti pianificati -- Persistenza automatica su LocalStorage +- Generazione automatica della lista della spesa con aggregazione duplicati (es. "zucchine (x2)") +- Condivisione del piano via QR code tra dispositivi +- Persistenza automatica su SharedPreferences ### Convertitore crudo/cotto - Conversione bidirezionale del peso (crudo → cotto e cotto → crudo) - Ricerca alimento in tempo reale - Oltre 50 voci tra cereali, legumi, verdure, carni, pesce e uova - Fino a 4 metodi di cottura per alimento: bollitura, padella, forno, friggitrice ad aria -- Coefficienti di resa documentati con fonti (CREA, SINU, Istituto Muzzone, USDA) +- Coefficienti di resa documentati con fonti — vedi [docs/conversioni.md](docs/conversioni.md) ### Lista della spesa - Checklist con aggiunta manuale o importazione dai pasti pianificati @@ -27,36 +28,75 @@ App mobile-first per la gestione della dieta quotidiana — pianificazione pasti | Livello | Tecnologia | |---|---| -| Frontend | Vue 3 + Vite | -| Persistenza | LocalStorage | -| UI | CSS mobile-first (max 480px) | -| Mobile | Capacitor Android | -| Build APK | Docker | +| Framework | Flutter 3.x / Dart 3.x | +| State management | Provider | +| Persistenza | shared_preferences | +| QR code | qr_flutter + mobile_scanner | +| Build APK | Docker (headless) | -## Requisiti per lo sviluppo +## Sviluppo -| Strumento | Versione minima | Note | -|---|---|---| -| Node.js | >= 20.x LTS | testato con v24 | -| npm | 9.x | incluso con Node.js | -| Git | 2.x | | -| Browser | Chrome / Edge / Firefox recente | DevTools modalità mobile consigliati | - -Per la build APK Android sono necessari requisiti aggiuntivi — vedi [docker/README.md](docker/README.md). - -## Avvio in sviluppo +Il container dev avvia un web server Flutter accessibile dal browser, con hot reload. ```bash -npm install -npm run dev +cd docker/dev +docker compose up +# → http://localhost:5173 ``` -Aprire [http://localhost:5173](http://localhost:5173) in Chrome con DevTools in modalità mobile (viewport 360×640). -Da un dispositivo mobile sulla stessa rete, aprire `http://:5173`. +Con il container attivo, in un altro terminale: -## Build APK Android +```bash +docker compose attach dev +# r → hot reload | R → hot restart | q → esci +``` -Vedi [docker/README.md](docker/README.md) per i requisiti e i dettagli della pipeline. +Vedi [docker/README.md](docker/README.md) per i dettagli e la build APK. + +## Test + +La suite copre unit test e widget test. Richiede l'immagine Docker `biteplan-build` +(creata automaticamente al primo `bash docker/build/build.sh`). + +```bash +# Tutti i test (dalla root del progetto) +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter pub get && flutter test" + +# Un singolo file +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter test test/features/meal_planner/qr_test.dart" +``` + +### Struttura + +``` +test/ +├── helpers/ +│ └── pump_app.dart # estensione pumpApp per widget test +└── features/ + ├── converter/ + │ ├── models/conversion_entry_test.dart + │ └── providers/converter_provider_test.dart + ├── meal_planner/ + │ ├── models/meal_plan_test.dart + │ ├── providers/meal_planner_provider_test.dart + │ ├── widgets/meal_card_test.dart + │ └── qr_test.dart + └── shopping_list/ + ├── models/shopping_item_test.dart + ├── providers/shopping_list_provider_test.dart + └── widgets/shopping_item_tile_test.dart +``` + +## Build APK + +```bash +bash docker/build/build.sh # debug → dist/biteplan-debug.apk +bash docker/build/build.sh --release # release → dist/biteplan-release.apk +``` + +Vedi [docker/README.md](docker/README.md) per i requisiti della firma release. ## Documentazione diff --git a/docker/README.md b/docker/README.md index 68faa85..714d633 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,12 +1,13 @@ # Docker — BitePlan -Due container distinti: uno per lo sviluppo, uno per la build APK. +Due container distinti: uno per lo sviluppo con hot reload, uno per la build APK headless. +Tutti i comandi vanno eseguiti dalla **root del progetto** (`~/biteplan`), non da `docker/`. --- ## Container dev (`docker/dev/`) -Avvia un web server Flutter con hot reload accessibile dal browser. +Avvia un web server Flutter accessibile dal browser, con hot reload. ```bash cd docker/dev @@ -15,17 +16,19 @@ docker compose up Apri **http://localhost:5173** nel browser. -**Hot reload** — con il container attivo, in un altro terminale: +### Hot reload + +Con il container attivo, in un altro terminale: ```bash docker compose attach dev -# premi 'r' → hot reload | 'R' → hot restart | 'q' → esci +# r → hot reload | R → hot restart | q → esci ``` -Le modifiche ai file `.dart` sull'host sono visibili subito nel container -grazie al volume montato — basta premere `r` per ricaricare. +Le modifiche ai file `.dart` sull'host sono visibili subito nel container grazie al volume +montato — basta premere `r` per ricaricare. -> Prima esecuzione: scarica Flutter SDK (~500 MB), richiede 5-10 minuti. +> Prima esecuzione: scarica l'immagine Flutter (~500 MB), richiede 5-10 minuti. > Le successive usano la cache Docker e sono molto più rapide. --- @@ -34,16 +37,9 @@ grazie al volume montato — basta premere `r` per ricaricare. Build headless riproducibile per generare l'APK Android. -**Prerequisito**: la cartella `android/` deve esistere nel progetto. -Se non esiste, generala con Flutter installato localmente o nel container dev: - -```bash -flutter create --project-name biteplan --org com.biteplan . -``` - ### Build debug -APK firmato con il debug keystore di Android — adatto per test su dispositivo. +APK firmato con il debug keystore di Android — adatto per installazione diretta sul dispositivo. ```bash bash docker/build/build.sh @@ -63,7 +59,7 @@ keytool -genkey -v \ -keyalg RSA -keysize 2048 -validity 10000 ``` -> `docker/biteplan.jks` è in `.gitignore` — non verrà mai committato. +> `docker/biteplan.jks` è in `.gitignore` e non verrà mai committato. > Conservalo in un posto sicuro: senza di esso non puoi pubblicare aggiornamenti. **2. Esegui la build release** @@ -73,25 +69,65 @@ bash docker/build/build.sh --release # → dist/biteplan-release.apk ``` -Il keystore viene montato nel container come volume read-only e non viene -mai copiato nell'immagine Docker. +Il keystore viene montato nel container come volume read-only e non viene mai copiato +nell'immagine Docker. > Prima esecuzione: scarica Flutter SDK + Android SDK (~1-2 GB), richiede 10-15 minuti. +### Installazione sul dispositivo + +```bash +adb install dist/biteplan-debug.apk +# oppure copia manualmente dist/biteplan-release.apk via USB o Drive +``` + +--- + +## Test + +I test non richiedono il container dev — usano l'immagine `biteplan-build`, creata +automaticamente al primo `bash docker/build/build.sh`. + +```bash +# Tutti i test (110 test — unit + widget) +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter pub get && flutter test" + +# Un singolo file +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter test test/features/meal_planner/qr_test.dart" + +# Una singola feature +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter test test/features/shopping_list/" +``` + +--- + +## Prima configurazione (android/ assente) + +Se la cartella `android/` non esiste ancora, lo script `build.sh` la genera +automaticamente tramite `flutter create` all'interno del container — non è necessario +avere Flutter installato sull'host. + --- ## Flusso completo ``` +# 1. Sviluppo cd docker/dev && docker compose up - → http://localhost:5173 (sviluppo con hot reload) - ↓ -flutter create --project-name biteplan --org com.biteplan . - (una volta sola, genera android/) - ↓ -bash docker/build/build.sh # → dist/biteplan-debug.apk -bash docker/build/build.sh --release # → dist/biteplan-release.apk - ↓ +→ http://localhost:5173 (hot reload con 'r') + +# 2. Test +docker run --rm -v "$(pwd):/workspace" -w /workspace biteplan-build \ + bash -c "flutter pub get && flutter test" + +# 3. Build +bash docker/build/build.sh # → dist/biteplan-debug.apk +bash docker/build/build.sh --release # → dist/biteplan-release.apk + +# 4. Installazione adb install dist/biteplan-debug.apk ``` @@ -102,3 +138,4 @@ adb install dist/biteplan-debug.apk - App ID: `com.biteplan.biteplan` - Android target: API 34 - Il keystore non viene mai copiato nell'immagine Docker (volume read-only) +- `dist/` è in `.gitignore`