# Changelog

## v0.3.4 — 2026-06-17 (Verifica aggiornamenti in-app)

### Note
- Rilascio di verifica del canale di aggiornamento in-app ripristinato in 0.3.3. Nessuna modifica funzionale all'app.

## v0.3.3 — 2026-06-17 (Aggiornamenti in-app ripristinati)

### Correzioni
- **Aggiornamenti in-app**: il controllo delle nuove versioni funziona di nuovo. Dopo che il repository è diventato privato, il canale di distribuzione non era più raggiungibile dall'app; ora feed e APK sono serviti via GitLab Pages (pubblico). Da questa versione in poi l'app rileva e scarica gli aggiornamenti.

## v0.3.2 — 2026-06-17 (Chiusura foglio tappa)

### Funzionalità / UX
- **Dettaglio tappa**: il foglio in basso ora si chiude trascinandolo verso il basso direttamente dal contenuto (non solo dalla maniglia). Lo scorrimento interno resta fluido: il foglio si chiude solo quando il contenuto è già in cima.

## v0.3.1 — 2026-06-17 (Fix dettaglio tappa)

### Correzioni
- **Mappa del dettaglio tappa**: non più ingrandita all'eccesso quando la tappa è una sola — ora inquadra il luogo a un livello di zoom leggibile.
- **Pulsanti del dettaglio tappa**: le icone (indietro, modifica) ora centrate nei rispettivi cerchi.
- **Foglio del dettaglio tappa**: ora si trascina e si espande correttamente — meteo, registro di bordo e foto di nuovo raggiungibili.

## v0.3.0 — 2026-06-15 (Mappa nativa: scorrimento fluido + hardening)

### Funzionalità / UX
- **Mappa nativa**: la cartografia passa da WebView a rendering nativo (MapLibre GL). Scorrimento, zoom e animazioni della mappa ora fluidi a 120 Hz; sparisce lo scatto percepito su home, dettaglio e vista tappa.
- **Liste e fogli più rapidi**: foglio trascinabile (taccuino, pianificazione) e lista tappe senza rimbalzo, con scorrimento a un dito reattivo.
- **Creazione/modifica tappa più pulita**: ricerca "Luogo" imposta solo le coordinate senza sovrascrivere il nome; rimosso un campo indirizzo che non veniva salvato.

### Accessibilità
- I pulsanti di chiusura "✕" (fogli azioni, modali) ora annunciati correttamente dallo screen reader (label + ruolo).

### Sicurezza / hardening
- **Aggiornamento APK**: l'app non scarica più l'APK automaticamente all'avvio — solo su tap del banner, con verifica MD5 e whitelist degli host (https + gitlab.com).
- **Chiavi AI**: l'endpoint personalizzato si applica solo ai provider custom/Ollama; Claude/OpenAI/Gemini/Mistral usano sempre l'endpoint ufficiale (nessuna key inviata a endpoint residui).
- Il logger sanitizza il contesto alla sorgente, indipendentemente dalla configurazione Sentry.

### Pulizie
- Selettori atomici nel wizard + ricalcolo km selettivo (meno re-render).
- Rimozione di codice morto (distanze, campi payload mappa, alias store, cover hero inutilizzate); enum tipi tappa unificato; rimossi `MediaTypeOptions` deprecati (SDK 55) e cast superflui.

## v0.2.0 — 2026-06-08 (Cartografo: vista tappa + creazione a schermo unico)

### Funzionalità / UX
- **Vista tappa "La Tavola della Tappa"**: registro cartografo map-first — mappa-tavola full-bleed col sigillo del luogo (non un pin GPS), marginalia (indice tappa, nome, coordinate) e foglio trascinabile con Naviga, annotazione e registro di bordo.
- **Creazione itinerario a schermo unico**: niente più wizard a 3 step. Essenziali (nome · date · veicolo) sempre visibili + "Dettagli (facoltativi)" collassati. Creare un viaggio = un nome e un tap.
- **Ricerca indirizzo a schermo intero**: l'input resta ancorato in alto, mai coperto da tastiera o lista (risolve il bug di creazione segnalato).
- **Categorie tappa con legenda**: ogni categoria è emoji + etichetta (corretta l'icona "bussola" che appariva per le Grotte).
- **Home costellazione**: inquadratura al primo render adattiva (mostra tutte le spedizioni se vicine, mette a fuoco l'attiva se sono lontane).

### Accessibilità
- "Riduci movimento" di sistema ora rispettato dalle animazioni.
- Conferma prima di eliminare un itinerario; aree di tocco e label migliorate.

### Theming / pulizie
- Colori spostati su token (chip timeline, ombre); rimossa la barra-accent laterale nei toast.
- Traduzioni completate (wizard, feedback) su tutte e 9 le lingue.

## v0.1.6 — 2026-06-01 (prima release pubblica — design fixes + pulizie pre-lancio)

### Funzionalità / UX
- Tab Mappa: ora mostra la mappa reale dell'itinerario attivo (non più placeholder)
- Home: coordinate di partenza reali da impostazioni (non più Milano hardcoded)
- Export itinerario: BottomSheet al posto di Modal
- FAB itinerari circolare; gradient card unificati (mono-brand ambra/teal/ink)
- Dark mode: contrasti banner/chip corretti (WCAG); onboarding rispetta la preferenza tema
- Donazioni "Supporta il progetto" → Ko-fi (importo libero)
- Impostazioni: nuovo toggle opt-in **Report di crash** (anonimi, default OFF)

### Rimozioni / pulizie
- Rimossa lista "file recenti" fittizia nella schermata Import
- Rimosso toggle "Avvisi meteo" non funzionante (nessun backend notifiche)
- Rimossi deep-link App Links verso dominio di terzi (resta scheme `ontheroad://`)
- Accessibilità tab e card migliorata (label/role)

### Infra
- Distribuzione consolidata sul repo principale pubblico (feed/APK/release unica fonte)
- Keystore di firma rigenerato (identità di produzione)

### Audit / hardening
- Bug confermati fase 1: `routeKm` cache key ora ordine-sensibile (A→B ≠ B→A su OSRM); `excelExporter` cost passa per `__safeCell`
- Import GPX/KML: cap dimensione input 25 MB pre-parse + scarto coordinate fuori range (DoS/malformati)
- HTTP: `AbortController` + timeout `API_TIMEOUTS.import` (15s) su fetch URL import; OSRM `drivingTime` con timeout + log su fallimento
- `STOP_ICONS` fonte unica (`constants/stopForm.ts`): fix icona benzina divergente tra new/edit
- Token `colors.onColor`/`colors.scrim` + de-hardcode hex in 12 file UI (nessun impatto visivo)
- Pexels: BYOK, nessuna key embeddata di default

## v0.1.5 — 2026-05-21 (CI fix audit path + exit code)

### Bug
- `scripts/i18n-audit-ast.mjs` aveva ROOT hardcoded a un path assoluto locale invece di derivare via `dirname(fileURLToPath(import.meta.url))`
- Inoltre mancava `process.exit(0)` esplicito + `STRICT` mode check finale (duplicato perso in edit)
- Fix: path computation dinamico + exit code 1 quando hit > 0 in --strict

## v0.1.4 — 2026-05-21 (CI fix babel parser)

### Bug
- v0.1.3 quality stage CI failed: `@babel/parser` non era transitive in node_modules dell'ambiente CI con `--legacy-peer-deps`
- Fix: aggiunto `@babel/parser` + `@babel/traverse` come `devDependencies` espliciti

## v0.1.3 — 2026-05-21 (i18n audit AST + fix completo)

### Bug critico
- Audit precedente (regex) mancava stringhe multi-line, template literal e ObjectProperty values. Risultato: dopo install in inglese restavano in italiano: profile "Ultimi viaggi", settings "MEMBRO DAL", tutta sezione "API KEY", AI assistant section header, varie etichette wizard, completione viaggio banner
- Nuovo `scripts/i18n-audit-ast.mjs`: AST-based con @babel/parser + traverse — visita StringLiteral / JSXText / TemplateLiteral con context-aware filtering
- Filter intelligente: skip ObjectProperty `defaultValue` dentro `t()`, enum values, icon names kebab-case, system AI prompts (file whitelist)
- Integrato in CI quality gate via `npm run i18n:audit:ast:strict`

### Fix esaustivi (≈30 stringhe addizionali)
- `profile.tsx`: "MEMBRO DAL", "ULTIMI VIAGGI", "VEDI TUTTI →"
- `settings.tsx`: "MEMBRO DAL", "MAPBOX — GEOCODING LUOGHI", "PEXELS — FOTO TAPPE E HOME", hint Mapbox/Pexels, hint API keys, hint Ollama, "AUTO (sistema)"
- `app/itinerary/[id].tsx`: "Hai completato il viaggio!", "Nessuna tappa geolocalizzata", giorno/giorni e tappa/tappe pluralization
- `app/itinerary/[id]/map.tsx`: TAPPE/TAPPA templates, "ATTIVA", "TAPPE ORDINATE"
- `app/itinerary/[id]/stop/[stopId]/index.tsx`: "TAPPA XX / YY" template
- `app/itinerary/[id]/stop/{new,edit}.tsx`: "COVER · TOCCA PER AGGIUNGERE/MODIFICARE"
- `app/import.tsx`: "FIG. 01 — IMPORTA", "FIG. 02 — RECENTI", "oppure tocca...", "tappe ·", "Importa file →", "Tappa N"
- `app/feedback.tsx`: rating "Voto N su 5" → "N {{starRatingOf}} 5", "Invia feedback"
- `app/(tabs)/itineraries.tsx`: "tappe" pluralization
- `components/UpdateBanner.tsx`: bannerText template "Nuova versione X disponibile" / "v X pronto" / "Download X — N%", "Errore installazione.", "Download fallito."
- `components/ai/AiCompletionPanel.tsx`: "Configura AI nelle impostazioni"
- `components/itinerary/wizard/StepBasics.tsx`: subtitle "Dai un nome..."
- `components/itinerary/wizard/StepSummary.tsx`: subtitle "Verifica i dettagli..."
- `components/itinerary/wizard/SuccessOverlay.tsx`: "Viaggio creato!"
- `components/itinerary/DayPanel.tsx`: "Nessuna tappa — tocca +"
- `components/itinerary/DayPanelPhotosRow.tsx`: "Foto dei luoghi"
- `components/itinerary/ItineraryCard.tsx`: " giorni · tappe" template
- `components/itinerary/StepTimelineItem.tsx`: "Da fare"
- `components/itinerary/DayPanelHeader.tsx`: "tappa/tappe" pluralization
- `components/itinerary/DayNavSheetRow.tsx`: MONTHS_IT hardcoded → toLocaleDateString + "tappa/tappe" pluralization
- `components/photos/PhotoGrid.tsx`: default title param via t()
- `components/ui/SplashView.tsx`: "IL TUO VIAGGIO, SU CARTA" eyebrow

### Locales
- 50+ nuove chiavi: `settings.memberSince/apiMapboxLabel/apiMapboxHint/apiPexelsLabel/apiPexelsHint/apiKeyHint/ollamaHint`, `wizard.basicsSubtitle/summarySubtitle/success/successSubtitle`, `itinerary.noStops/completed/noStopsGeocoded/photosOfPlaces/stopsOrdered/active/notDone`, `stop.tapToAddCover/tapToEditCover`, `splash.tagline`, `ai.configureKeyShort`, `feedback.starRatingOf/submitButton`, `import.figImport/figRecent/importHint/importFileBtn/stopsCount/stopsSingular`, `updateBanner.readyToInstall/downloading/available/installError/downloadError`

## v0.1.2 — 2026-05-20 (release signing fix)

### Bug critico
- v0.1.1 build_apk in CI usava `expo prebuild --clean` che rigenera `android/app/build.gradle` da template Expo, scartando le modifiche manuali a `signingConfigs.release`. APK firmato comunque con debug.keystore (verificato con `apksigner --print-certs`)
- Fix: plugin Expo `withReleaseKeystore` modifica `app/build.gradle` durante mod-phase (`withAppBuildGradle`), garantendo che ad ogni prebuild il signing release sia inserito correttamente

### Plugin idempotente
- `plugins/withReleaseKeystore.js`: brace-matching naive su `signingConfigs { }` + `buildTypes.release { }` blocks. Inietta block con `release.keystore` lookup + password da env/properties + `GradleException` se keystore manca
- Modifiche manuali precedenti a `android/app/build.gradle` rimosse (ora plugin è source-of-truth)

## v0.1.1 — 2026-05-20 (release signing keystore)

### Security
- **APK ora firmato con release keystore dedicato** (no più debug.keystore in produzione)
- Plugin gradle `signingConfigs.release` legge `ONTHEROAD_KEYSTORE_PASSWORD` da env/properties
- Build fallisce esplicito (`GradleException`) se `android/app/release.keystore` manca — niente fallback silenzioso su debug
- `.gitignore` esclude `release.keystore` + `keystore.properties` + `gradle.properties.local`
- CI `.gitlab-ci.yml`: passa password via `ORG_GRADLE_PROJECT_ONTHEROAD_KEYSTORE_PASSWORD` (CI variable masked + protected)
- Tag `v*` ora protetti GitLab (solo Maintainers possono crearli, condizione per accesso a signing secrets)
- `scripts/copy-release-keystore.sh`: orchestratore che decodifica keystore da `ONTHEROAD_RELEASE_KEYSTORE_B64` (CI) o copia da `~/.ontheroad/release.keystore` (locale)

### Docs
- `docs/dev/BUILD.md`: sezione setup release keystore + verifica signing + CI vars

## v0.1.0 — 2026-05-20 (pre-launch hardening, first public version)

### Security / Privacy
- Permission Android rimosse (non utilizzate): `RECORD_AUDIO`, `SYSTEM_ALERT_WINDOW`, `VIBRATE`
- Plugin Expo `withCleanPermissions` (idempotente): rigenera AndroidManifest pulito ad ogni `expo prebuild`
- `expo-updates` disabilitato: nessun bundle JS arbitrario può essere servito da `u.expo.dev`. Self-update via APK + MD5 verify resta unica via di update

### i18n
- 17 chiavi `t()` mancanti aggiunte a tutte le 9 locales: prima il fallback i18next mostrava la chiave raw all'utente (es. `itinerary.exportPdf` invece di "Esporta PDF"). Coperte ora: `export.failed/progress`, `eyebrow.daySingular/stopSingular`, `feedback.consentLabel`, `itinerary.deleteStop/exportPdf/exportExcel/exportGpx/tabInfo`, `profile.defaultName`, `settings.lastBackup/subscriptionStatus`, `stop.delete/deleteConfirm/deleteTitle`, `wizard.difficulty`

### Code quality
- `utils/routeKm.ts`: `console.warn` → `log.warn` (filtro Sentry centralizzato)

## v0.0.10 — 2026-05-20 (i18n audit fix)

### Bug critico
- `scripts/i18n-audit.ts` usava git glob `app/**/*.tsx` che NON matchava file diretti in `app/` (settings.tsx, feedback.tsx, import.tsx) — 98 stringhe hardcoded sfuggite ad audit v0.0.9. Fix: glob `*.tsx` + filter prefix

### i18n migration completata
- `app/settings.tsx`: 7 sezioni tradotte (ACCOUNT/PREFERENZE/MAPPE/NOTIFICHE/SUPPORTO/API/AI) + picker modali + modal modifica profilo + alert privacy/maps/sign-out
- `app/feedback.tsx`: title, chips categoria, label OGGETTO/MESSAGGIO, screenshot, diagnostica APP/BUILD
- `app/import.tsx`: title, errori parsing, dropzone, URL/Apri, preview
- `components/UpdateBanner.tsx`: alert install dialog completo
- `components/ErrorBoundary.tsx`: title, body, retry, send report
- 60 nuove chiavi: `settings.*`, `feedback.*`, `import.*`, `vehicleShort.*`, `mapStyleShort.*`, `mapStyleLong.*`, `navProvider.*`, `updateBanner.*`, `errorBoundary.*`, `common.never/open/confirm/exit/fromUrl/reorder`, `stop.openDetail/duplicateStop/noCoords`

### Audit script rinforzato
- Whitelist brand/format names (Bug/Feature/UX/Altro/Excel/GPX/PDF)
- Detect colon-based object props
- Skip JSX comments + t() positional defaults

## v0.0.9 — 2026-05-14 (i18n migration round 1)

### Bug critico
- `it.json` aveva chiavi duplicate (`map`, `stop`): JSON.parse perdeva entries delle prime occorrenze. Cambio lingua non si propagava su ~90% UI. Fix: dedup + 9 locales aggiornate

### i18n migration round 1
- Refactor tabs/_layout, home, itineraries, profile, onboarding, itinerary detail, stop detail/edit/new, ItineraryCard, StepTimelineItem (chip via stepTypeShort), StepItem, ItineraryBottomSheet, ToastStack, SnackbarView, SplashView, SpeedDialFAB, FAB, Lightbox, TipsList, TagChips, DateFieldRow, StepBasics, StepSummary, AiCompletionPanel
- 80+ nuove chiavi: `tabs.*`, `card.*`, `toast.*`, `splash.*`, `snackbar.*`, `errors.*`, `stepTypeShort.*`, `tag.*`, `stopType.*`
- `scripts/i18n-audit.ts`: broader regex (JSX text, prop strings, const, ternary, default `??`, object props)

## v0.0.8 — 2026-05-13 (regression recovery + plugin idempotente)

### Security
- Plugin Expo `withDebugCleartextHardening`: rigenera idempotentemente debug manifest + `network_security_config.xml` (cleartext solo localhost/LAN). Previene regressione H10 su `expo prebuild --clean`

### Build
- versionCode 7 → 8, versionName 0.0.7 → 0.0.8
- expo_runtime_version sync con appVersion

## v0.0.7 — 2026-05-13 (audit completo)

### Security
- Sentry `beforeSend` filtra `extra`/`breadcrumb.data` con whitelist; valori che assomigliano a token (`sk-`, `pk_`, `AIza`, `bearer`, `Authorization`) vengono scartati
- WebView MapLibre: `originWhitelist` ristretto da `['*']` a `['about:*', 'https://*']`; SRI hash su JS/CSS jsdelivr; `parseInboundMessage` valida con Zod
- Gemini API key spostata da query param a header `x-goog-api-key`
- Tokens `aiApiKey`/`mapboxToken`/`pexelsApiKey` ora SOLO in SecureStore (rimossi da `partialize` AsyncStorage); migration v5→v6 sposta plaintext esistenti
- XLSX export: nuovo `__safeCell` prefissa `'` su celle che iniziano con `=`/`+`/`-`/`@`/TAB/CR (formula injection)
- APK update: `downloadApk` verifica MD5 atteso dal feed `ontheroad-latest.json`; mismatch → file cancellato + errore
- xlsx pinnato a `0.18.5` esatto (no caret); xlsx + gpxParser lazy-importati
- AiError `safeBodyMessage` estrae solo campi error.message/detail (no echo raw body)
- backupImport schemi Zod con range coordinate + cutoff dimensione 10 MB
- Deep link host wildcard → host esatti `ontheroad.app` + `www.ontheroad.app`
- Plugin Expo `withHardenedAndroid` setta `android:allowBackup="false"`
- Debug manifest: `usesCleartextTraffic` rimosso, `networkSecurityConfig` permette cleartext solo verso localhost/LAN dev hosts
- Sentry `release`/`dist`/`environment` tagging per correlare crash a build

### Performance
- Zustand persist: nuovo `createDebouncedStorage(delayMs)` riduce write amplification (itinerary 1.5s, settings 1s)
- Wikipedia fetch lingue in `Promise.allSettled` parallelo (era waterfall N×3)
- `refreshRouteKm` ora `Promise.allSettled` (un day reject non blocca altri)
- `ItineraryCard` cover: rimosso `updateItinerary` storm; cache modulo serve session
- `coverImage.ts` cache con LRU bounded (max 100 entries)
- TripMapBase WebView: `injected` script + payload memoizzati per stabilità ref
- TripMapLayers: `JSON.stringify` payload memoizzato (pre-serializzato)
- FlatList itinerari + DraggableFlatList tappe: `initialNumToRender/maxToRenderPerBatch/windowSize`
- PhotoCard migrato a `expo-image` con `cachePolicy=memory-disk` + `recyclingKey`

### AI streaming
- `callAiProvider` supporta `signal: AbortSignal` + `onChunk: (delta) => void`
- Streaming SSE incrementale per Claude (`content_block_delta`), OpenAI + Mistral (`choices[0].delta.content`)
- Fallback non-streaming se body non leggibile
- `AiCompletionPanel`: bottone "Annulla" durante loading + contatore caratteri streamed

### Code quality
- Refactor componenti >400 LoC: DayPanel 507→315, AddressAutocomplete 460→246, DayNav 426→298, SplashView 386→244
- Estratti hook riutilizzabili: `useDayPhotos`, `useAddressSearch`, `useSplashAnimations`
- Estratti sub-component: `DayPanelHeader`, `DayPanelPhotosRow`, `AddressSuggestionRow`, `DayNavPill`, `DayNavSheetRow`
- Estratte utility pure: `cumulativeStopDistances`, `createId` (crypto.getRandomValues), `sentryFilter`
- Token semantici: `colors.bannerOfflineBg/Fg`, `onAccent`, `thumbGradients`
- Hex hardcoded migrati a token in 6+ componenti
- Pressable con flex layout corretti (View wrapper) in ItineraryBottomSheet, TypeChip, ActionRow, ExportMenu, StepTimelineItem, UpdateBanner
- `console.warn` → `log.warn` in wiki/osrm/openMeteo (filtro Sentry centralizzato)
- Timeout HTTP centralizzati in `utils/api/timeouts.ts`
- `Math.random` ID → `createId()` con crypto.getRandomValues in itineraryStore + toastStore

### A11y/i18n
- i18n: 42 → 29 stringhe hardcoded (action sheet, DayNav, StepActionSheet, SplashView)
- A11y: `accessibilityRole`/`accessibilityLabel` su CTAButton (usato 30+ volte) + ItineraryBottomSheet (8 button)
- WeatherBadge locale-aware (era `it-IT` hardcoded)
- PhotoCard segue `useSettingsStore().language` (era `'it'` hardcoded)

### Test coverage
- 12 suite/59 test → 23 suite/140 test
- Nuovi test: excelExporter (formula injection), aiProvider (sanitize+http error), webviewBridge (Zod), storage (debounce), backupImport (Zod schema), createId, aiProviderStream (SSE+abort), apkInstaller (MD5), settingsStoreMigration (SecureStore), sentryFilter (whitelist+sensitive detection), cumulativeDistance

## v0.0.6 — 2026-05-12

- Fix update checker: URL feed corretto (refpapps → refpapps1)
- Allinea version in package.json e app.json

## v0.0.5 — 2026-05-12

- Fix dark mode: testo CTA primario ora leggibile (era nero hardcoded su tutti i temi)
- Sostituito `#000000` con token `c.onPrimaryContainer` in EmptyState, CTAButton, FAB, SpeedDialFAB

## v0.0.4 — 2026-05-12

- Gradient fallback deterministico per cover ovunque (lista, home featured, hero detail)
- Cover deterministica per startCity: stessa città → stessa foto Picsum
- Fix wizard step-basics: bolla-in-bolla rimossa (AddressAutocomplete flat)
- DateTimePicker nativo Android per orario tappe (clock dialog)
- Decimal-pad per campi lat/lng GPS
- Verifica device end-to-end: 7/8 check PASS

## v0.0.3 — 2026-04-15

- Audit completo design/UX: 9 miglioramenti
- DayNav compatto + addStopBtn minimal
- DayNav lista verticale elegante + lingua italiana
- Polish round + bug fix critici
- Design v0.0.2: Design A Soft & Bold
