chore: aggiorna SOP e CLAUDE.md per migrazione a Flutter
Riscritto sop.md con stack Flutter + Docker (container dev noVNC + container build headless). Aggiornato CLAUDE.md con roadmap, architettura target e mapping Vue→Flutter come riferimento per la riscrittura. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
# SOP — BitePlan (Vue 3 + Vite → Capacitor Android)
|
||||
# SOP — BitePlan (Flutter → Android APK)
|
||||
|
||||
## Scope
|
||||
|
||||
App mobile-first con tre funzionalità:
|
||||
App mobile Android con tre funzionalità:
|
||||
|
||||
1. **Meal Planner** — pianificazione settimanale (7 giorni × 3 pasti: colazione, pranzo, cena). Ogni pasto contiene una lista di voci testuali liberamente modificabili.
|
||||
2. **Conversione crudo/cotto** — calcolo del peso cotto a partire dal peso crudo (e viceversa) tramite coefficienti di resa definiti in un JSON interno.
|
||||
2. **Conversione crudo/cotto** — calcolo del peso cotto a partire dal peso crudo (e viceversa) tramite coefficienti di resa definiti in un asset JSON interno.
|
||||
3. **Lista della spesa** — checklist con aggiunta, spunta e rimozione elementi.
|
||||
|
||||
---
|
||||
@@ -14,130 +14,158 @@ App mobile-first con tre funzionalità:
|
||||
|
||||
| Livello | Scelta |
|
||||
|---|---|
|
||||
| Frontend | Vue 3 + Vite |
|
||||
| Stato | Composables (no store) |
|
||||
| Persistenza | LocalStorage |
|
||||
| UI | CSS base mobile-first |
|
||||
| Mobile (fase successiva) | Capacitor Android |
|
||||
| Build riproducibile (opzionale) | Docker |
|
||||
|
||||
Sviluppo iniziale: `npm run dev` + Chrome DevTools modalità mobile.
|
||||
| Framework | Flutter (Dart) |
|
||||
| Stato | Provider o Riverpod |
|
||||
| Persistenza | shared_preferences |
|
||||
| UI | Material 3, mobile-first |
|
||||
| Build APK | Docker (container build) |
|
||||
| Sviluppo | Docker + noVNC (container dev con GUI) |
|
||||
|
||||
---
|
||||
|
||||
## Struttura progetto
|
||||
|
||||
```
|
||||
src/
|
||||
lib/
|
||||
├── main.dart
|
||||
├── app.dart # MaterialApp, routing, BottomNavigationBar
|
||||
├── pages/
|
||||
│ ├── MealPlanner.vue
|
||||
│ ├── Converter.vue
|
||||
│ └── ShoppingList.vue
|
||||
├── components/
|
||||
│ ├── BottomNav.vue
|
||||
│ ├── MealCard.vue
|
||||
│ └── CheckboxItem.vue
|
||||
├── data/
|
||||
│ └── conversions.json
|
||||
├── utils/
|
||||
│ ├── conversion.js
|
||||
│ └── storage.js
|
||||
└── App.vue
|
||||
│ ├── meal_planner_page.dart
|
||||
│ ├── converter_page.dart
|
||||
│ └── shopping_list_page.dart
|
||||
├── widgets/
|
||||
│ ├── meal_card.dart # Accordion giorno
|
||||
│ └── checkbox_item.dart
|
||||
├── models/
|
||||
│ ├── meal_plan.dart
|
||||
│ └── shopping_item.dart
|
||||
├── services/
|
||||
│ ├── storage_service.dart # Wrapper shared_preferences
|
||||
│ └── conversion_service.dart # rawToCooked / cookedToRaw
|
||||
└── data/
|
||||
└── conversions.json # Asset: 50+ alimenti × metodi cottura
|
||||
|
||||
docker/
|
||||
├── dev/
|
||||
│ ├── Dockerfile # Flutter SDK + Android SDK + Xvfb + noVNC
|
||||
│ └── docker-compose.yml # Porta 6080 → noVNC, volume su ./
|
||||
├── build/
|
||||
│ ├── Dockerfile # Flutter SDK + Android SDK headless
|
||||
│ └── build.sh # flutter build apk --release + firma
|
||||
pubspec.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fase 1 — Setup
|
||||
## Container dev (noVNC)
|
||||
|
||||
Il container di sviluppo espone un desktop virtuale via browser, utile per eseguire l'emulatore Android o Android Studio senza installare nulla sull'host.
|
||||
|
||||
**Stack interno**: Ubuntu + Flutter SDK + Android SDK + Xvfb + noVNC + websockify.
|
||||
|
||||
```bash
|
||||
npm create vue@latest biteplan
|
||||
cd biteplan
|
||||
npm install
|
||||
npm run dev
|
||||
# Avvio
|
||||
cd docker/dev
|
||||
docker compose up
|
||||
|
||||
# Accesso GUI
|
||||
# → http://localhost:6080 (noVNC, nessuna password)
|
||||
```
|
||||
|
||||
Test mobile: Chrome → F12 → viewport 360×640.
|
||||
Il volume mappa `./` (root del progetto) in `/workspace` nel container, quindi le modifiche ai file sono bidirezionali in tempo reale.
|
||||
|
||||
**Workflow nel container**:
|
||||
1. Aprire un terminale nel desktop noVNC
|
||||
2. `cd /workspace && flutter pub get`
|
||||
3. Avviare l'emulatore o collegare device via ADB
|
||||
4. `flutter run`
|
||||
|
||||
---
|
||||
|
||||
## Fase 2 — Meal Planner
|
||||
## Container build (APK)
|
||||
|
||||
**Struttura dati**
|
||||
Build headless riproducibile, senza GUI.
|
||||
|
||||
```js
|
||||
{
|
||||
lunedi: { colazione: [], pranzo: [], cena: [] },
|
||||
martedi: { ... }
|
||||
```bash
|
||||
# Debug
|
||||
bash docker/build/build.sh
|
||||
|
||||
# Release firmato
|
||||
bash docker/build/build.sh --release
|
||||
```
|
||||
|
||||
Pipeline interna:
|
||||
1. `flutter pub get`
|
||||
2. `flutter build apk --release` → `build/app/outputs/flutter-apk/app-release.apk`
|
||||
3. Firma con `apksigner` (keystore montato come volume o secret)
|
||||
4. `zipalign`
|
||||
|
||||
L'APK firmato viene copiato in `dist/` nella root del progetto.
|
||||
|
||||
---
|
||||
|
||||
## Modello dati
|
||||
|
||||
**Meal Plan**
|
||||
```dart
|
||||
class MealPlan {
|
||||
final Map<String, DayPlan> days; // 'lunedi' … 'domenica'
|
||||
}
|
||||
|
||||
class DayPlan {
|
||||
final List<String> colazione;
|
||||
final List<String> pranzo;
|
||||
final List<String> cena;
|
||||
}
|
||||
```
|
||||
|
||||
**Funzionalità**
|
||||
- Aggiungere/rimuovere voci per ogni pasto
|
||||
- Visualizzare l'intera settimana
|
||||
- Salvataggio automatico su LocalStorage
|
||||
**Shopping Item**
|
||||
```dart
|
||||
class ShoppingItem {
|
||||
final String id;
|
||||
final String name;
|
||||
bool checked;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fase 3 — Conversione crudo/cotto
|
||||
|
||||
**JSON** — `src/data/conversions.json`
|
||||
## Conversione crudo/cotto
|
||||
|
||||
**Asset** — `lib/data/conversions.json`
|
||||
```json
|
||||
{
|
||||
"pollo": { "forno": { "yield": 0.75 }, "padella": { "yield": 0.70 } },
|
||||
"riso": { "bollito": { "yield": 2.5 } }
|
||||
"riso basmati": { "bollitura": { "yield": 3.00 } }
|
||||
}
|
||||
```
|
||||
|
||||
`yield = peso_cotto / peso_crudo`
|
||||
|
||||
**Funzioni** — `src/utils/conversion.js`
|
||||
|
||||
```js
|
||||
export const rawToCooked = (food, method, raw, db) => raw * db[food][method].yield
|
||||
export const cookedToRaw = (food, method, cooked, db) => cooked / db[food][method].yield
|
||||
**Service** — `lib/services/conversion_service.dart`
|
||||
```dart
|
||||
double rawToCooked(double raw, double yield) => raw * yield;
|
||||
double cookedToRaw(double cooked, double yield) => cooked / yield;
|
||||
```
|
||||
|
||||
**UX**: ricerca testuale sull'alimento → selezione alimento+metodo → input grammi → risultato in tempo reale.
|
||||
|
||||
Esempio: 140 g pollo crudo → 105 g cotti al forno.
|
||||
UX: ricerca testuale → selezione alimento + metodo → input grammi → risultato in tempo reale.
|
||||
|
||||
---
|
||||
|
||||
## Fase 4 — Lista della spesa
|
||||
## Persistenza
|
||||
|
||||
**Struttura dati**
|
||||
|
||||
```js
|
||||
[{ id, name, checked }]
|
||||
```
|
||||
|
||||
**Funzionalità**: aggiungi, spunta, elimina, svuota lista.
|
||||
`StorageService` wrappa `shared_preferences`:
|
||||
- Meal plan serializzato come JSON stringa sotto chiave `meals`
|
||||
- Lista spesa serializzata come JSON stringa sotto chiave `shopping_list`
|
||||
|
||||
---
|
||||
|
||||
## Fase 5 — UI Mobile
|
||||
## UI
|
||||
|
||||
Navigazione bottom bar: Pasti | Converti | Spesa.
|
||||
|
||||
Linee guida: bottoni min 44px, input semplici, una funzione per schermata.
|
||||
|
||||
---
|
||||
|
||||
## Fase 6 — Android (Capacitor)
|
||||
|
||||
```bash
|
||||
npm install @capacitor/core @capacitor/cli
|
||||
npx cap init
|
||||
npx cap add android
|
||||
npm run build && npx cap sync && npx cap run android
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fase 7 — Docker (opzionale)
|
||||
|
||||
Pipeline: install → build frontend → cap sync → gradle build APK.
|
||||
- `BottomNavigationBar` con 3 tab: Pasti | Converti | Spesa
|
||||
- Material 3, `ColorScheme.fromSeed(seedColor: Color(0xFF2d6a4f))`
|
||||
- Target touch minimo 48×48 dp (Material baseline)
|
||||
- Orientamento bloccato in portrait (`SystemChrome.setPreferredOrientations`)
|
||||
|
||||
---
|
||||
|
||||
@@ -145,16 +173,5 @@ Pipeline: install → build frontend → cap sync → gradle build APK.
|
||||
|
||||
- Modifica coefficienti di conversione in-app
|
||||
- Calcolo kcal
|
||||
- Generazione automatica lista spesa dai pasti pianificati
|
||||
- Condivisione piano via QR code
|
||||
- Sync cloud
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Meal planner funzionante
|
||||
- [ ] Conversioni corrette
|
||||
- [ ] JSON alimenti presente (12+ voci)
|
||||
- [ ] Lista spesa funzionante
|
||||
- [ ] Persistenza attiva
|
||||
- [ ] APK testabile
|
||||
|
||||
Reference in New Issue
Block a user