# QuantoBasta — stato dei lavori

Ultimo aggiornamento: 2026-09-29

## Cos'è

App iOS e Android che ricalcola le dosi di una ricetta, per numero di porzioni
oppure partendo dalla quantità che hai davvero di un ingrediente. Rifà una
webapp privata che sta in `../casa/app/dosatore`, usata per anni in famiglia.
Verrà pubblicata sugli store, quindi ogni utente ha il suo ricettario sul
proprio dispositivo, senza account.

Repository: `paoloalby/quantobasta`, privata. Si lavora su `main`.

## Documenti, in ordine di autorità

Per ripartire, in quest'ordine:

1. **questo file** — dove siamo e come si lavora;
2. `docs/DESIGN.md` — l'aspetto: le decisioni prese sui colori, i caratteri, i
   segni, le fotografie, e le due che restano aperte;
3. `docs/BUILD.md` — come si compila per iOS e per Android, con le due trappole
   che fanno perdere un'ora;
4. `docs/store/privacy.md` — l'informativa da pubblicare a un indirizzo web.

Archivio, da aprire solo se serve ricostruire il perché di una scelta:

- `docs/design/campionari/` — le sei pagine con cui Paolo ha scelto l'aspetto,
  con un indice che dice cosa è uscito da ognuna;
- `docs/superpowers/specs/2026-08-18-dosatore-core-design.md` — la spec
  approvata, che dice cosa fa l'app e perché;
- `docs/superpowers/plans/2026-08-18-quantobasta-pezzo-a.md` — il piano dei 23
  task con dentro il codice e i test;
- `docs/registro-pezzo-a.md` — il registro di lavorazione di quei 23 task;
- `.superpowers/sdd/progress.md` — il registro di avanzamento, non versionato.

## Le decisioni prese, e perché

- **Prima il dosatore, poi il ricettario.** Nato come dosatore puro, ora ogni
  ricetta ha anche il procedimento, e dentro l'app c'è il ricettario di Quanto
  Basta (200 ricette regionali). Niente passi numerati, niente lista della spesa.
- **Il riscalo salva la richiesta dell'utente, non il moltiplicatore.** La
  vecchia webapp salvava il risultato del calcolo, e chi correggeva una ricetta
  dopo averla riscalata si ritrovava numeri sbagliati sotto un'etichetta che
  mentiva. Qui il fattore si ricalcola sempre dalla ricetta di adesso.
- **Categorie create dall'utente**, con un'icona scelta fra trenta che diamo
  noi. Sono raggruppamenti, non etichette: una ricetta sta in una categoria
  sola o in nessuna. La schermata principale mostra le categorie.
- **Una foto per ricetta**, compressa allo scatto sotto i 300 KB. Duecento
  ricette fanno una cinquantina di megabyte, che iCloud e Drive portano. Con
  gli originali della fotocamera si arriverebbe a un giga e mezzo.
- **Italiano e inglese**, tutti e due i sistemi di misura riconosciuti, nessuna
  conversione automatica. La conversione fra volume e peso (tazze verso grammi)
  resta fuori: dipende dall'ingrediente e va fatta a parte.
- **Niente account.** Sync cloud senza account (CloudKit e Drive) è il pezzo B,
  che verrà dopo.
- **Stack**: Expo e React Native con TypeScript, SQLite locale, navigazione con
  native-stack, test con `node --test` senza framework.

## Come si lavora

Il piano si esegue con la skill `superpowers:subagent-driven-development`: un
agente fresco per ogni task, poi una revisione, poi eventuali correzioni, poi
il task successivo. Gli strumenti stanno in
`~/.claude/plugins/cache/superpowers-marketplace/superpowers/6.0.3/skills/subagent-driven-development/scripts/`:
`task-brief PIANO N` estrae il task N, `review-package BASE HEAD` prepara il
diff per il revisore.

Le revisioni non devono rileggere i test del task: devono scrivere materiale
proprio, eseguire il codice, e rompere apposta delle righe per vedere se i test
se ne accorgono. È così che sono stati trovati tutti i difetti veri.

## Comandi

```
npm test            # test del dominio e dei dati, senza framework
npm run typecheck
npm run migra       # migra le 12 ricette vere della vecchia webapp
node scripts/controlla-ricettario.mts <regione>   # le righe che il lettore non capisce
```

## Dove si lavora

Il repository di Paolo sta sul NAS, in `Server/Siti Web/_private/ - App/QuantoBasta`,
ma quella cartella è un mount SMB e **Metro non ci parte**: resta in attesa di
I/O (stato `UN`) anche dopo dieci minuti, perché deve scandire decine di
migliaia di file di `node_modules` attraverso la rete. Per dare un'idea, `npm
install` ci mette sei minuti e mezzo sul NAS e cinque secondi e mezzo in locale.

Quindi si lavora nella copia locale **`/Users/paolo/dev/quantobasta`**, si pusha
su GitHub, e il NAS si riallinea con `git pull`. La verità è GitHub, non una
delle due copie.

## Il simulatore iOS

Simulatore **iPhone 18 Pro** (iOS 27), l'app compilata in Release come in
`docs/BUILD.md`. Con Expo Go: `npx expo start --port 8081` e poi
`xcrun simctl openurl booted "exp://127.0.0.1:8081"`; `npx expo start --ios`
non funziona (AppleScript bloccato dal sandbox). Per toccare lo schermo serve
`idb` (`uvx --from fb-idb idb ui tap --udid <UDID> X Y`), perché `simctl` non
simula i tocchi. Little Snitch blocca la rete dell'app sul simulatore: quello
che scarica pagine («Da un link») si prova sul telefono.

## Dove siamo

I 23 task del primo piano sono finiti il 2026-08-31; da allora ogni lavoro ha
la sua spec in `docs/superpowers/specs/` e il suo piano in `plans/`. L'app è
sull'App Store (1.0.1) e nel test chiuso di Google Play; la 1.0.2 è dai tester.

Una regola che vale per tutte le schermate: **se una schermata prende una
decisione, quella decisione sta in un modulo puro con il suo test, e nel `.tsx` resta solo il disegno.**

Non è una preferenza di stile. I test girano con `node --test` e non sanno
caricare un `.tsx`: una ri-revisione ha mutato otto righe dentro `Elenco.tsx`,
una alla volta, e tutte e otto le mutazioni hanno lasciato i test verdi —
comprese due che riportavano indietro difetti appena corretti. La strada
battuta sarebbe installare un motore di test per componenti; è stata scartata,
perché sono dipendenze pesanti per collaudare tre `if`. Le decisioni si portano
in `src/ui/logica-*.ts`, che i test caricano già.

Quello che resta senza test è il disegno vero e proprio, e quello si collauda
nel simulatore.

### Due pannelli sugli schermi larghi (2026-09-24)

Da 700 punti di larghezza in su (tablet in verticale, iPhone Duo aperto)
le categorie e le ricette stanno a sinistra e la ricetta aperta a destra; sul
telefono non cambia niente. All'apertura torna l'ultima ricetta aperta; la
modifica si apre a tutto schermo. Piegando o aprendo il Duo si ritrovano la
stessa ricetta, le stesse dosi e lo stesso punto dello scorrimento. Le regole
stanno in `src/ui/logica-pannelli.ts`; progetto in
`docs/superpowers/specs/2026-09-24-due-pannelli-design.md`.

Collaudato sull'emulatore Pixel Tablet, anche la piega simulata con
`adb shell wm size 2560x1000` / `wm size reset` (solo la larghezza: cambiare
anche la densità fa riavviare l'app, cosa che il Duo vero non fa). Resta da
provare sul simulatore dell'iPhone Duo, che arriva con Xcode 27.1: aperto,
chiuso, e in Split View a metà schermo. L'iPad non è attivo
(`supportsTablet: false`) e l'app resta solo verticale.

### Il menù in basso (2026-09-25)

Progetto in `docs/superpowers/specs/2026-09-25-menu-in-basso-design.md`, piano
in `docs/superpowers/plans/2026-09-25-menu-in-basso.md`. La pagina di partenza
è un menù di sistema (`@react-navigation/bottom-tabs/unstable`, tab native di
react-native-screens): Ricette, Categorie, Impostazioni, e su iPhone la lente.

- **iPhone**: capsula di vetro di iOS 26/27 con i simboli di Apple; cambia vista
  e + in alto a destra; la ricerca sta nella sezione Cerca (campo di sistema
  attivo all'arrivo, Recenti in fila, risultati a tessere), non più in cima
  alle pagine. Con iOS 27 la lente resta **dentro** la capsula e il campo
  compare in alto: per staccarla serve che react-native-screens usi
  l'API `UITab`/`UISearchTab`. **Da controllare a ogni build nuova.**
- **Android**: barra Material a tre voci con etichette (icone PNG in
  `assets/menu/`), ricerca in cima e + tondo come prima; il contenuto si ferma
  sopra la barra (`SopraIlMenu`, l'area sicura di react-native-screens).
- Le differenze fra i due sistemi le decide `logica-menu.ts`; i Recenti
  `logica-ricerca.ts` (chiave `ricerca.recenti`, al massimo 10).
- La ricetta, la modifica e l'anteprima coprono il menù. Sugli schermi larghi
  una ricetta aperta dalla ricerca e l'apertura del Duo portano il menù su
  Ricette con `TabActions.jumpTo` mirato, che non tocca la pila
  (`navigate` impilava un secondo Principale sopra una Modifica aperta).

Trappola trovata al collaudo: il menù di vetro si rimpicciolisce scorrendo
solo se la lista è il primo discendente lungo `subviews[0]`: lista prima
nell'albero, testata riportata in cima con `column-reverse`,
`collapsable={false}` sulle radici. **Resta**: Gestisci categorie con tante
categorie da scorrere, VoiceOver su iPhone, l'inglese, l'iPhone Duo con Xcode
27.1.

### Versione 1.0.2 (2026-09-28)

Progetto in `docs/superpowers/specs/2026-09-28-versione-1.0.2-design.md`.

- **Impostazioni a riquadri**: Esporta, Importa, Svuota il ricettario; Tema e
  Lingua (schermata `Scelta`, spunta sulla scelta attiva); Assistenza,
  Privacy, Consiglia a un amico. Dieci segni nuovi più la spunta.
- **Svuota il ricettario**: copia di sicurezza prima, poi tombstone di tutto in
  una transazione esclusiva (`svuotaRicettario`), conferma
  con «Esporta prima una copia».
- **Importa → Sostituisci il ricettario**: secondo tasto nell'Anteprima se il
  ricettario ha già qualcosa e il file porta almeno 2 ricette vive (una sola è
  quella che manda un amico: si aggiunge e basta); nella stessa transazione dell'import
  (`importaLetto(..., { sostituisci: true })`), attivo anche con un backup più
  vecchio di quanto c'è.
- **Lente di Cerca staccata su iOS 27** con la patch a react-native-screens
  (`patches/`, vedi `docs/BUILD.md`): il campo di ricerca ora sta in basso,
  come in Foto e Podcast.

Da provare: Svuota e Sostituisci su Android; la patch in Debug, in tema scuro
e cambiando lingua a caldo; VoiceOver sulle righe nuove. Poi:

- la build 5 su un iPhone con **iOS 26**: lì la patch non entra e le schede
  si installano col percorso vecchio (`setViewControllers`), che nessuno ha
  più guardato dopo la patch;
- l'**iPad con iOS 27**, con la patch: la lente staccata e le schede `UITab`
  lì passano dalla barra in alto e dalla barra laterale, non dal menù in basso;
- su **Android**, dove finiscono i tre tasti dell'Alert di Svuota e di
  Sostituisci («Esporta prima una copia», il tasto rosso, «Annulla»): Android
  li mette in un ordine suo, e il tasto distruttivo non è rosso.

### Scrivere una ricetta (2026-09-28)

La schermata Modifica rifatta perché i tester la trovavano confusionaria.
Paolo ha scelto sul campionario `docs/design/campionari/modifica.html`; le
regole stanno in `docs/DESIGN.md`, «Scrivere una ricetta». Foto come banner in
cima, campi con etichetta, ogni ingrediente si scrive in un foglio
(`FoglioIngrediente`), molti insieme con «Incolla elenco» (`FoglioIncolla`),
sezioni con il loro menù. Le decisioni stanno in `logica-modifica.ts` e
`bozza.ts`. Su Android i fogli (`Foglio.tsx`) salgono e scendono insieme alla
tastiera con un `paddingBottom` animato (sull'iPhone il foglio di sistema lo
fa da sé): `KeyboardAvoidingView` con Fabric non anima,
salta.

### Ricette italiane (2026-09-29)

Il ricettario di Quanto Basta: 200 ricette, 10 per regione, scritte con parole
nostre (mai copiate: i termini di GialloZafferano vietano la riproduzione
commerciale). Stanno nell'app, senza foto, in una sezione a parte da cui si
aggiungono una alla volta (scelta di Paolo: importarle tutte seppellirebbe il
quaderno di chi ne ha già uno). Formato e regole in `src/catalogo/catalogo.ts`,
un file per regione in `src/catalogo/testi/`; un test pretende che ogni riga
sia capita dal lettore dell'incolla. Il «+» ora chiede da dove arriva la
ricetta: Scrivi, Dalle ricette italiane, Da un link (legge lo schema.org
Recipe della pagina, foto compresa, `src/io/pagina.ts` e `src/io/link.ts`),
Cerca sul web. Lo stesso lettore serve Condividi dal browser
(expo-share-intent, estensione iOS con App Group, patch in `patches/`).
**Da fare**: Paolo rilegge le ricette.

### Menù, icone e sezioni (2026-09-30)

Scelte di Paolo, dettagli in `docs/DESIGN.md`: segni e icone delle categorie
dal set Lucide (59 da scegliere, in otto gruppi senza titolo); il «+», i tre
puntini di una sezione e la foto aprono un menù nativo che nasce dal comando
(`MenuNativo.tsx` con @expo/ui: SwiftUI su iPhone, Material su Android); i
titoli delle sezioni in colore con una riga (`TitoloSezione.tsx`). Nella
1.0.2 build 10, inviata all'App Store il 30/09.

### iPhone tutto Liquid Glass (2026-10-01, ramo `liquid-glass`)

Su iPhone la barra in alto e i fogli dal basso sono quelli di sistema, di
vetro: `useIntestazione` (`componenti/Intestazione.tsx`, decisioni in
`logica-intestazione.ts`) e `FoglioDiSistema.tsx` (la sheet di SwiftUI di
@expo/ui). Categorie e Impostazioni stanno in una pila di una pagina, per
avere la barra. Android invariato. Il perché in `docs/DESIGN.md`. **Da
provare**: i comandi di vetro nel pannello (`ComandiDiVetro.tsx`), che oggi
non si vedono perché l'app non gira su iPad (col simbolo nel colore fisso del
testo, non ancora quello adattivo della barra). `@react-navigation/elements`
è fissato alla versione che usa native-stack: se un aggiornamento ne porta
due, `useAltezzaBarra` darebbe zero e la copertina non passerebbe più sotto
la barra.

## L'aspetto

Sta tutto in `docs/DESIGN.md`: la tavolozza e i suoi contrasti calcolati, le
otto tinte delle categorie, Caveat solo sul marchio, i segni e le icone,
l'intestazione di sistema su iPhone e nostra su Android, le due viste per ogni lista, i
menù e come si tratta una fotografia. Le pagine con cui si è scelto stanno in
`docs/design/campionari/`, con un indice.

## I difetti gravi trovati dalle revisioni

Nel primo piano, tutti nel codice che il piano stesso forniva: un ingrediente
senza nome marcato affidabile, una ricetta inglese letta come italiana, una
prova sui dati veri che non poteva fallire, un banco di prova più permissivo
del database vero, una validazione dei segnaposto sul testo sbagliato. Dicono
dove insistere: le revisioni devono eseguire e rompere il codice, non
rileggerlo.

## Questioni aperte

- Un identificativo fatto di soli spazi passa la validazione dell'import,
  perché il controllo è sull'uguaglianza con la stringa vuota e non su `trim()`.
  Non fa perdere dati, lascia un identificativo strano nel database.
- Togliendo l'indicazione della lingua dall'ordinamento nessun test cade, ma
  solo perché questa macchina ha già il locale italiano.
- Un incolla inglese in unità metriche senza intestazione viene etichettato
  italiano. Verificato che non fa danno: gli ingredienti escono corretti lo
  stesso e nessuno consuma quell'etichetta.
- Due commenti nel codice attribuiscono a una riga un effetto che non ha
  (l'ordinamento degli alias in `units.ts`, quello delle parole-numero in
  `numeri.ts`): togliendo quelle righe i test restano verdi.

Tutte valutate, nessuna bloccante, nessuna corretta: costano più del danno che
fanno.

Se ne sono aggiunte due, che sono decisioni di prodotto e aspettano Paolo — le
porzioni che diventano `31,98` riscalando per ingrediente, e se l'export debba
portarsi dietro le foto. Il dettaglio sta in fondo a `docs/DESIGN.md`.

## Sugli store

Account, firme, schede e trappole di Play Console e App Store Connect stanno in
`docs/BUILD.md`. L'informativa è su https://www.duebytes.it/quantobasta/privacy/,
il testo in `docs/store/privacy.md`: dal 29/09 dice che l'app va su internet
solo per leggere una ricetta da un sito scelto dall'utente («Da un link»,
Condividi). Le schede privacy degli store restano «nessun dato raccolto»:
scaricare la pagina che l'utente chiede non è una raccolta.
