# 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`. I fogli (`Foglio.tsx`) salgono e scendono insieme alla tastiera
con un `paddingBottom` animato: `KeyboardAvoidingView` con Fabric non anima,
salta. **Da provare**: il foglio dell'ingrediente con la tastiera su Android.

### 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, `src/io/pagina.ts`), Cerca sul web. **Da fare**: Paolo
rilegge le ricette; «Da un link» mai provato sul telefono; il lettore sbaglia
«4 uova sode» (unità «uova», nome «sode»).

## 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 dodici segni disegnati da
noi, l'intestazione che non è quella di sistema, le due viste per ogni lista e
come si tratta una fotografia.

Le sei pagine con cui si è scelto stanno in `docs/design/campionari/`.

## I difetti gravi trovati dalle revisioni

Tutti nel codice che il piano stesso forniva, nessuno per errore di chi
implementava. Sono qui perché dicono su cosa vale la pena insistere.

1. **Nome vuoto.** Una riga di ingrediente fatta di solo un numero produceva un
   ingrediente senza nome e marcato affidabile. Era lo scenario del burro
   sparito, in un file che a due righe di distanza dichiarava la regola opposta.
2. **Lingua sbagliata.** Una ricetta inglese incollata con l'app in italiano
   veniva riconosciuta come italiana: il vocabolario italiano non conosce
   "Directions", quindi non si fermava al procedimento e lo leggeva come
   ingredienti, e quelle righe finte gonfiavano il punteggio. Uscivano
   ingredienti tipo "Preheat the oven to degrees" con quantità 350.
3. **La prova sui dati veri non poteva fallire.** Confrontava il numero di
   ricette migrate con quello letto dallo stesso file: togliendone tre, il
   confronto faceva nove uguale nove e passava.
4. **Il banco di prova era più permissivo del database vero.** La libreria usata
   nei test accende le chiavi esterne di suo, SQLite no. Quindi la riga dello
   schema che le accende non era provata da niente, e ci si sarebbero appoggiati
   altri cinque task.
5. **La validazione dei segnaposto guardava il testo sbagliato.** Controllava la
   stringa già sostituita, quindi una ricetta intitolata `Torta {della nonna}`
   faceva crashare la conferma di cancellazione.

## 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.
