Add project foundation: CLAUDE.md, requirements tracking system, technical architecture docs, Firestore setup guide, device testing guide, and Stitch design mockups for Precision Vitality app. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
313 lines
11 KiB
Markdown
313 lines
11 KiB
Markdown
# Requisiti — CalorieTracker (Precision Vitality)
|
|
|
|
> Documento di riferimento per tutti i requisiti funzionali e sistemistici del progetto.
|
|
> Ultimo aggiornamento: 16/04/2026
|
|
|
|
---
|
|
|
|
## Indice Requisiti
|
|
|
|
| ID | Tipo | Priorità | Titolo | Dipendenze |
|
|
|----|------|----------|--------|------------|
|
|
| REQ-001 | SISTEMISTICO | CRITICA | Scaffolding Ionic + Capacitor | — |
|
|
| REQ-002 | SISTEMISTICO | CRITICA | Setup Firebase Firestore | REQ-001 |
|
|
| REQ-003 | EVOLUTIVO | ALTA | Home screen + FAB | REQ-002 |
|
|
| REQ-004 | EVOLUTIVO | ALTA | Modal input numerico | REQ-003 |
|
|
| REQ-005 | EVOLUTIVO | ALTA | Modal input LLM | REQ-003, REQ-006 |
|
|
| REQ-006 | EVOLUTIVO | ALTA | Servizio Claude API | REQ-001 |
|
|
| REQ-007 | EVOLUTIVO | ALTA | CRUD pasti Firestore | REQ-002 |
|
|
| REQ-008 | EVOLUTIVO | MEDIA | Statistiche giornaliere | REQ-007 |
|
|
| REQ-009 | EVOLUTIVO | MEDIA | Statistiche settimanali | REQ-007 |
|
|
| REQ-010 | EVOLUTIVO | MEDIA | Ricerca pasti | REQ-007 |
|
|
| REQ-011 | REWORK | MEDIA | Design brief Google Stitch | — |
|
|
|
|
---
|
|
|
|
## REQ-001 — Scaffolding Ionic + Capacitor
|
|
|
|
**Tipo**: SISTEMISTICO | **Priorità**: CRITICA
|
|
|
|
**Obiettivo**: Scaffolding del progetto Ionic 7+ con Capacitor 5+. Configurazione build nativa Android/iOS. Setup ambiente con struttura cartelle, linting e variabili d'ambiente.
|
|
|
|
**Stato Target**:
|
|
- Progetto Ionic Angular inizializzato con routing e tab layout (Journal, Stats, Plans, Profile)
|
|
- Capacitor configurato per Android e iOS
|
|
- Variabili ambiente: `ANTHROPIC_API_KEY`, `FIREBASE_*`
|
|
- Struttura moduli: `core/`, `shared/`, `features/home`, `features/stats`, `features/search`
|
|
- Proxy sviluppo configurato per CORS Anthropic API
|
|
|
|
**Passi Implementativi**:
|
|
1. `ionic start calorie-tracker tabs --type=angular --capacitor`
|
|
2. Aggiungere `@capacitor/android` e `@capacitor/ios`
|
|
3. Configurare `capacitor.config.ts` con appId e server URL
|
|
4. Creare struttura moduli `features/` con lazy loading
|
|
5. Aggiungere `@ionic/storage-angular` per cache locale
|
|
6. Configurare `environment.ts` e `environment.prod.ts`
|
|
7. Verificare build `ionic build` + `npx cap sync`
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] `ionic serve` avvia l'app senza errori
|
|
- [ ] `ionic build` produce `www/` senza errori
|
|
- [ ] `npx cap sync` completa senza errori
|
|
- [ ] Struttura a 4 tab visibile nel browser (Journal, Stats, Plans, Profile)
|
|
- [ ] Variabili d'ambiente lette correttamente in `environment.ts`
|
|
|
|
---
|
|
|
|
## REQ-002 — Setup Firebase Firestore
|
|
|
|
**Tipo**: SISTEMISTICO | **Priorità**: CRITICA | **Dipende da**: REQ-001
|
|
|
|
**Obiettivo**: Setup Firebase con Firestore come database. Schema dati, regole sicurezza e SDK Angular.
|
|
|
|
**Schema Firestore**:
|
|
```
|
|
users/{userId}/
|
|
meals/{mealId}/
|
|
- id: string
|
|
- timestamp: Timestamp
|
|
- calories: number
|
|
- inputType: 'manual' | 'llm'
|
|
- description?: string
|
|
- llmConfidence?: 'high' | 'medium' | 'low'
|
|
- llmExplanation?: string
|
|
- createdAt: Timestamp
|
|
```
|
|
|
|
**Regole Sicurezza**:
|
|
- Lettura/scrittura solo all'utente autenticato proprietario
|
|
- Nessun accesso cross-user
|
|
|
|
**Auth**: Anonymous auth abilitato (upgrade Google Sign-In futuro)
|
|
|
|
**Passi Implementativi**:
|
|
1. Creare Firebase project su console
|
|
2. Abilitare Firestore in modalità produzione
|
|
3. Abilitare Anonymous Authentication
|
|
4. Scaricare `google-services.json` e `GoogleService-Info.plist`
|
|
5. Installare `@angular/fire` e configurare in `app.module.ts`
|
|
6. Definire regole Firestore in `firestore.rules`
|
|
7. Creare `FirestoreService` con CRUD per collection `meals`
|
|
8. Testare lettura/scrittura da `ionic serve`
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Scrittura documento su Firestore funzionante
|
|
- [ ] Lettura documenti da Firestore funzionante
|
|
- [ ] Regole sicurezza bloccano accesso non autenticato
|
|
- [ ] `FirestoreService` espone: `addMeal()`, `getMealsByDate()`, `getMealsRange()`
|
|
- [ ] Offline persistence abilitata e testata
|
|
|
|
---
|
|
|
|
## REQ-003 — Home Screen + FAB
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: ALTA | **Dipende da**: REQ-002
|
|
|
|
**Obiettivo**: Home screen (tab Journal) con totale kcal giornaliero, lista pasti e FAB per aggiunta.
|
|
|
|
**Specifiche UI** (da design Precision Vitality):
|
|
- Header: data odierna centrata (es. "MERCOLEDÌ 16 APRILE")
|
|
- Titolo: "Il tuo progresso giornaliero"
|
|
- Numero kcal grande (56px, Lexend Bold, verde `#006b1b`)
|
|
- Label "calorie oggi"
|
|
- Barra progresso: kcal / obiettivo (default 2000)
|
|
- Sezione "Diario Alimentare": lista card pasti (ora, descrizione, kcal)
|
|
- Badge "AI" (arancione) o "M" (grigio) su ogni pasto
|
|
- FAB arancione `#FF7043` in basso a destra con icona "+"
|
|
- Empty state: "Nessun pasto registrato oggi. Inizia!"
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Totale kcal odierno visibile e aggiornato real-time
|
|
- [ ] Lista pasti del giorno visibile e scrollabile
|
|
- [ ] FAB visibile e cliccabile su tutti i device
|
|
- [ ] Empty state quando nessun pasto registrato
|
|
- [ ] Aggiornamento immediato dopo salvataggio nuovo pasto
|
|
|
|
---
|
|
|
|
## REQ-004 — Modal Input Numerico
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: ALTA | **Dipende da**: REQ-003
|
|
|
|
**Obiettivo**: Modal per inserimento diretto kcal con tastiera numerica.
|
|
|
|
**Specifiche UI** (da design):
|
|
- Titolo: "Inserisci calorie"
|
|
- Icona fulmine verde
|
|
- Motivazionale: "Ogni dato conta per il tuo obiettivo."
|
|
- Campo numerico grande (font 40px), placeholder "0", label "KCAL"
|
|
- Campo "Descrizione (opzionale)"
|
|
- Bottone "Salva" verde a tutta larghezza
|
|
- Suggerimenti veloci: 150 (Spuntino), 450 (Pranzo), 600 (Cena)
|
|
|
|
**Validazione**: valore > 0 e ≤ 9999
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Modal si apre dal FAB
|
|
- [ ] Tastiera numerica nativa su mobile
|
|
- [ ] Validazione blocca valori ≤ 0 e > 9999
|
|
- [ ] Salvataggio corretto su Firestore
|
|
- [ ] Toast conferma dopo salvataggio
|
|
- [ ] Modal si chiude e Home aggiorna totale
|
|
|
|
---
|
|
|
|
## REQ-005 — Modal Input LLM (Descrizione Pasto)
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: ALTA | **Dipende da**: REQ-003, REQ-006
|
|
|
|
**Obiettivo**: Modal per descrizione testuale del pasto con stima AI.
|
|
|
|
**Specifiche UI** (da design):
|
|
- Titolo: "Descrivi il pasto"
|
|
- Sottotitolo: "Usa il linguaggio naturale per stimare i tuoi nutrienti in pochi secondi."
|
|
- Textarea "IL TUO PASTO" con placeholder
|
|
- Bottone "Stima calorie" arancione
|
|
- Risultato: badge "ALTA PRECISIONE" / "MEDIA" / "BASSA"
|
|
- Kcal stimate in grande + breakdown (carbi, proteine, grassi)
|
|
- Campo kcal modificabile
|
|
- Bottone "Salva" verde
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Textarea accetta input testuale
|
|
- [ ] Bottone "Stima calorie" chiama API (REQ-006)
|
|
- [ ] Loading spinner durante chiamata
|
|
- [ ] Risultato kcal e badge confidence corretti
|
|
- [ ] Campo kcal modificabile dopo stima
|
|
- [ ] Salvataggio su Firestore con `inputType: 'llm'`
|
|
- [ ] Gestione errore timeout (messaggio + retry)
|
|
|
|
---
|
|
|
|
## REQ-006 — Servizio Claude API
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: ALTA | **Dipende da**: REQ-001
|
|
|
|
**Obiettivo**: Servizio Angular per stima calorica via Claude API con proxy sicuro.
|
|
|
|
**Architettura**: Firebase Cloud Function come proxy (API key mai nel bundle)
|
|
|
|
**Specifiche**:
|
|
- Model: `claude-haiku-4-5-20251001`
|
|
- Max tokens: 256
|
|
- Food dictionary incluso nel system prompt
|
|
- Parser JSON robusto (strip markdown code blocks)
|
|
- Timeout: 10 secondi
|
|
- Risposta: `{ calories, confidence, explanation }`
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Stima kcal corretta per descrizioni test
|
|
- [ ] Food dictionary nel system prompt
|
|
- [ ] API key non nel bundle app
|
|
- [ ] Parser gestisce JSON wrapped in markdown
|
|
- [ ] Timeout 10s con errore esplicito
|
|
|
|
---
|
|
|
|
## REQ-007 — CRUD Pasti Firestore
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: ALTA | **Dipende da**: REQ-002
|
|
|
|
**Obiettivo**: Servizio Angular per CRUD pasti su Firestore.
|
|
|
|
**Metodi**:
|
|
- `addMeal(data)` — scrittura con timestamp e userId
|
|
- `getMealsForDate(date)` — query filtrata per giorno (Observable)
|
|
- `getMealsInRange(from, to)` — query per range date
|
|
- `deleteMeal(mealId)` — hard delete
|
|
- `getTotalCaloriesForDate(date)` — aggregazione client-side
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] `addMeal()` scrive documento corretto
|
|
- [ ] `getMealsForDate()` restituisce solo pasti del giorno richiesto
|
|
- [ ] `getMealsInRange()` restituisce pasti nel range
|
|
- [ ] `deleteMeal()` rimuove documento
|
|
- [ ] Observable aggiorna componenti senza reload
|
|
- [ ] Funziona offline
|
|
|
|
---
|
|
|
|
## REQ-008 — Statistiche Giornaliere
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: MEDIA | **Dipende da**: REQ-007
|
|
|
|
**Obiettivo**: Vista giornaliera nel tab Stats con totale kcal, breakdown pasti e progresso obiettivo.
|
|
|
|
**Specifiche UI**:
|
|
- Tab selector: "Oggi" | "Settimana"
|
|
- Navigazione tra giorni (frecce)
|
|
- Totale kcal, barra progresso (verde/rosso)
|
|
- Lista pasti con swipe-to-delete
|
|
- Obiettivo calorico: salvato in @ionic/storage (default 2000)
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Totale kcal giornaliero corretto
|
|
- [ ] Navigazione tra giorni funzionante
|
|
- [ ] Barra progresso aggiornata real-time
|
|
- [ ] Colore cambia se obiettivo superato
|
|
- [ ] Swipe-to-delete funzionante
|
|
|
|
---
|
|
|
|
## REQ-009 — Statistiche Settimanali
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: MEDIA | **Dipende da**: REQ-007
|
|
|
|
**Obiettivo**: Grafico a barre 7 giorni con media settimanale.
|
|
|
|
**Specifiche UI** (da design):
|
|
- Periodo corrente (es. "14-20 apr") con frecce navigazione
|
|
- Grafico barre: barre verdi ≤ obiettivo, rosse > obiettivo
|
|
- Asse X: LUN, MAR, MER... (giorno corrente evidenziato)
|
|
- Legenda: "In target" (verde), "Eccesso" (rosso)
|
|
- Card "RIEPILOGO PRESTAZIONI": media kcal/giorno
|
|
- Indicatori: variazione % vs settimana precedente, giorni in target
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Grafico a barre con dati reali
|
|
- [ ] Colori corretti sopra/sotto obiettivo
|
|
- [ ] Media settimanale calcolata
|
|
- [ ] Navigazione settimane funzionante
|
|
- [ ] Tap su barra apre dettaglio giornaliero
|
|
- [ ] Grafico responsive
|
|
|
|
---
|
|
|
|
## REQ-010 — Ricerca Pasti
|
|
|
|
**Tipo**: EVOLUTIVO | **Priorità**: MEDIA | **Dipende da**: REQ-007
|
|
|
|
**Obiettivo**: Tab ricerca per trovare pasti passati per testo o intervallo date.
|
|
|
|
**Specifiche**:
|
|
- Searchbar con debounce 300ms
|
|
- Filtro date opzionale (da/a)
|
|
- Risultati: data, ora, kcal, descrizione, badge tipo
|
|
- Funzione "Ri-registra": crea nuovo pasto con stesse kcal e timestamp corrente
|
|
- Ordinamento: data DESC
|
|
- Range: ultimi 30 giorni (client-side)
|
|
|
|
**Criteri Accettazione**:
|
|
- [ ] Ricerca per testo funzionante con debounce
|
|
- [ ] Filtro date funzionante
|
|
- [ ] Badge tipo visibili
|
|
- [ ] "Ri-registra" crea nuovo documento
|
|
- [ ] Empty state "Nessun risultato"
|
|
|
|
---
|
|
|
|
## REQ-011 — Design Brief Google Stitch
|
|
|
|
**Tipo**: REWORK | **Priorità**: MEDIA
|
|
|
|
**Stato**: COMPLETATO — I mockup sono disponibili in `stitch_calorietracker_design_brief_brief/`
|
|
|
|
**Schermate generate**:
|
|
1. Home (Journal) — `home_calorietracker/`
|
|
2. Bottom sheet scelta input — `scelta_input_calorietracker/`
|
|
3. Modal input numerico — `inserisci_calorie_calorietracker/`
|
|
4. Modal descrizione LLM — `descrizione_ai_calorietracker/`
|
|
5. Statistiche settimanali — `statistiche_calorietracker/`
|
|
|
|
**Design System**: `vitality_pulse/DESIGN.md`
|