# QuantoBasta — stato dei lavori

Ultimo aggiornamento: 2026-08-19

## 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. Ramo di lavoro: `pezzo-a`.

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

- **Dosatore puro**, non ricettario. Niente procedimento, niente passi di
  preparazione, 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
```

## Dove si lavora

Il repository di Paolo sta sul NAS, in `Server/Siti Web/_private/dosatore-app`,
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

Xcode 26.6 con la runtime iOS 26.5. Il giro completo funziona:

```
xcrun simctl boot "iPhone 17"
cd /Users/paolo/dev/quantobasta && nohup npx expo start --port 8081 > /tmp/expo-server.log 2>&1 &
xcrun simctl openurl booted "exp://127.0.0.1:8081"
xcrun simctl io booted screenshot foto.png
xcrun simctl ui booted appearance dark      # per collaudare il tema scuro
```

`npx expo start --ios` **non funziona**: usa AppleScript per attivare la
finestra del simulatore e il sandbox lo blocca. Va avviato il server da solo e
aperto l'indirizzo con `simctl`.

Per toccare lo schermo serve `idb`, perché `simctl` non sa simulare i tocchi:

```
idb_companion --udid <UDID> &          # installato con brew, tap facebook/fb
uvx --from fb-idb idb ui tap --udid <UDID> X Y
```

Gli Apple Events nel sandbox **non** sono stati attivati e non servono.

## Dove siamo

**Tutti e 23 i task finiti, 395 test verdi, il redesign fatto e l'app compilata
per la prima volta su tutti e due i sistemi** (2026-08-31). Gira nel simulatore
iPhone e nell'emulatore Android, sia dentro Expo Go sia come app vera con dentro
il suo JavaScript.

Quello che resta prima di pubblicare sta in fondo a questo file.

| Task | Cosa | Stato |
|---|---|---|
| 1-4 | vocabolari, unità, formattazione, riscalo | fatto |
| 5 | categorie e catalogo delle trenta icone | fatto |
| 6-8 | parser: numeri, riga, blocco incollato | fatto |
| 9 | migrazione dalla vecchia webapp | fatto |
| 10-11 | schema SQLite, repository ricette | fatto |
| 12-13 | repository categorie, repository riscalo | fatto |
| 14-15 | file foto, export e import in zip | fatto |
| 16-17 | traduzioni, impalcatura e navigazione | fatto |
| 18 | schermata Categorie, la principale | fatto |
| 19 | elenco ricette, filtrato e con le miniature | fatto |
| 20 | dosatore, il cuore dell'app | fatto |
| 21 | gestione categorie e scelta icona | fatto |
| 22 | scrivi e modifica una ricetta | fatto |
| 23 | export e import nell'interfaccia | fatto |

Da qui in poi è tutta interfaccia, e qui c'è una regola che vale per tutte le
schermate che restano: **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 rete è il disegno vero e proprio, e quello si collauda
nel simulatore.

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

## Cosa servirà da Paolo, più avanti

Account Apple Developer (99 dollari l'anno) e Google Play (25 una tantum), una
chiave API Anthropic per l'estrazione da foto del pezzo C, e un posto dove
mettere il proxy. Il nome sugli store va riservato appena c'è l'account: le
ricerche non trovano altre app chiamate "Quanto Basta", ma non è una prova.


## Cosa manca per pubblicare

Il codice è finito, revisionato, e **compila su tutti e due i sistemi**: la
procedura sta in `docs/BUILD.md`. Quello che resta non è quasi più codice.

**Fatto, e non lo era fino al 2026-08-31.** L'app compilata gira sul simulatore
iPhone e sull'emulatore Android. Compilare ha dimostrato quattro cose che dentro
Expo Go non si potevano sapere: il database si apre, Caveat entra nel pacchetto,
l'icona «q.b.» è quella giusta sulla schermata del telefono, e sparisce il
pulsante flottante di Expo Go che copriva un comando in alto a destra. Su
Android, con l'emulatore in inglese, si è vista per la prima volta la traduzione
inglese a schermo.

**Provato su telefoni veri, dal 2026-09-23.** L'app firmata gira sull'iPhone
17 Pro Max di Paolo e su un Redmi Note 9 Pro in prestito. Fotocamera, galleria,
condivisione e importazione funzionano su tutti e due; il `.quantobasta` si apre
toccandolo in File (iOS) e nel gestore file di Xiaomi. Il lavoro di quei giorni
(backup e condivisione, anteprima dell'import, impostazioni) sta nella spec
`docs/superpowers/specs/2026-09-16-scambio-ricette-design.md` e nel piano
omonimo; i difetti che solo i telefoni veri hanno mostrato sono in `BUILD.md`.

**Serve Paolo, e blocca.** Gli account ci sono e sono verificati tutti e due
(dettagli in `BUILD.md`). Manca la scheda dell'app su Google Play. L'informativa
è online dal 2026-09-23 su https://www.duebytes.it/quantobasta/privacy/, in
italiano e inglese, ed è l'indirizzo da mettere in tutte e due le schede. Il
nome è riservato su Apple: «Quanto Basta: Dosaricette», perché «Quanto Basta»
da solo era già preso. Su Google Play, con l'account personale, prima della
produzione servono 12 tester per 14 giorni.

**Serve Paolo, e non blocca.** Le fotografie delle ricette — oggi nessuna delle
sue ne ha una — e le schermate per le schede degli store, che senza foto
mostrano l'app come sarà per chiunque la installi il primo giorno.

**Già a posto**, sistemato a suo tempo: i testi dei permessi esistono in italiano
e in inglese (Apple rifiuta le app che chiedono un permesso senza dire perché
nella lingua giusta); `supportsTablet` è a `false`, altrimenti servirebbero anche
le schermate per iPad; `usesNonExemptEncryption` è dichiarato, altrimenti ogni
caricamento si ferma sulla domanda sulla crittografia; e Caveat entra nel
pacchetto una volta sola invece di quattro.

**Sulla privacy**, per compilare le schede: l'app non fa nessuna chiamata di
rete, non raccoglie nessun identificativo e non manda niente da nessuna parte.
Tutto sta nel dispositivo, e l'unico modo per far uscire i dati è l'export, che
li mette in un file che decide l'utente dove mandare. Il testo pronto da
pubblicare è in `docs/store/privacy.md`.
