Vai al contenuto

Compila RAS v2 - Gap analysis gestione foto

Data: 2026-07-31

Spec di riferimento: docs/operativo/ras_compila_v2_photo_spec_20260731.md

Sintesi

La gestione foto attuale funziona per casi semplici, ma non ha ancora un modello unico.

La stessa foto puo comparire in:

  • payload.images;
  • payload.detail.image;
  • payload.detail.images;
  • payload.detail.gallery.items;
  • payload.detail.libretto.images;
  • payload.interventi[].immagini;
  • PACK.photo_tray;
  • IndexedDB locale come local:<id>;
  • draft server legacy_dynamic_draft;
  • answer server legacy_dynamic_answer;
  • output stampa.

Questo rende instabili upload, cancellazione, refresh, duplicati e stampa, perche ogni funzione deve ricordarsi di aggiornare molte strutture.

Stato attuale rispetto alla spec

1. Foto subito visibili

Parzialmente presente.

Il client crea riferimenti local:<id> e usa IndexedDB/blob URL per mostrare subito le immagini. Questo e corretto come direzione.

Gap:

  • la visibilita dipende dal fatto che il blob locale sia ancora presente in IndexedDB;
  • non esiste un registro foto separato che dica "questa foto esiste, e locale/pending/server";
  • l'upload puo sostituire chiavi in molte strutture con replaceLocalKeyEverywhere(), ma il modello resta fragile.

2. Foto visibili dopo refresh

Parzialmente presente.

Esistono funzioni per:

  • recuperare local:<id> da IndexedDB;
  • diagnosticare foto locali/orfane;
  • mostrare stato foto locali.

Gap:

  • la fonte dati resta il payload domanda, non un ledger;
  • se un riferimento locale resta ma il blob manca, serve UI piu centrale e meno "debug";
  • la ricostruzione da draft/server puo sovrascrivere o fondere stati locali in modo difficile da prevedere.

3. Cancellazione

Non conforme alla spec.

Stato attuale:

  • savePhotoDeletionOnline() richiede online per cancellazioni server;
  • se la foto e local: la rimuove localmente e puo cancellare il blob IndexedDB;
  • non esiste un cestino RAS;
  • non esiste una coda delete_pending vera;
  • deleteImageKeyEverywhere() rimuove globalmente una chiave da tutte le risposte e dal parcheggio.

Gap critico:

  • cancellare non deve distruggere senza recupero;
  • offline delete deve essere registrato e sincronizzato dopo;
  • serve distinguere "rimuovi assegnazione dalla domanda" da "elimina asset".

4. Parcheggio

Presente e importante.

Stato attuale:

  • PACK.photo_tray esiste;
  • UI openTrayModal() esiste;
  • le foto possono essere aggiunte/rimosse dal parcheggio.

Gap:

  • parcheggio e solo lista chiavi, senza metadati;
  • manca origine domanda/sezione;
  • non e collegato a un ledger;
  • non e distinto formalmente dal futuro cestino.

5. Duplicati

Parzialmente corretto dopo fix recenti.

Stato attuale:

  • removeOneImageRefFromPayload() rimuove una singola occorrenza usando indice o galleryItemId;
  • questo migliora il caso "cancello una tessera e ne spariscono due".

Gap:

  • esistono ancora funzioni globali che rimuovono tutte le occorrenze della stessa chiave;
  • manca il concetto di assignment_id stabile per ogni tessera;
  • stessa foto in piu domande e duplicato nella stessa domanda non sono modellati esplicitamente.

6. Stampa/PDF

Non conforme alla spec.

Stato attuale:

  • _rasV2ImmediatePrintBlockReason() blocca stampa se ci sono foto locali o pending;
  • _rasEnsureV2ConsolidatedForPrint() prova a consolidare e poi blocca se restano local:;
  • i pulsanti stampa vengono disabilitati quando c'e blocco.

Gap critico:

  • la stampa tecnica deve essere sempre consentita;
  • foto locali/pending devono diventare immagini se disponibili nel browser, oppure placeholder;
  • non deve esserci blocco totale solo per pending/local.

7. Offline

Parzialmente presente ma non completo.

Stato attuale:

  • IndexedDB salva blob locali;
  • esistono queue/draft/sync state;
  • upload pending e retry sono parzialmente implementati;
  • ci sono diagnostiche locali.

Gap:

  • non esiste coda operazioni foto completa;
  • mancano delete_pending, restore_pending, move_pending, park_pending, trash_pending;
  • non esiste una tabella/struttura server di reconciliation per operazioni foto;
  • conflitti e cancellazioni offline non sono modellati come eventi.

Problema architetturale

Il codice attuale lavora per "chiave immagine" dentro payload domanda.

La spec richiede invece tre livelli:

  1. asset foto;
  2. assegnazione foto a domanda/parcheggio/cestino;
  3. operazione pending/offline.

Senza questa separazione, ogni fix tende a moltiplicare condizioni speciali.

Proposta di refactor

Fase 1 - Stabilizzazione modello client

Senza cambiare ancora DB:

  • introdurre una struttura PACK.photo_ledger;
  • ogni foto ha asset_id, key, local_id, status, created_at, origin;
  • ogni tessera ha assignment_id, asset_id, scope, question_id, section_code, state;
  • parcheggio e cestino diventano viste/assegnazioni del ledger;
  • mantenere compatibilita scrivendo ancora images e detail.gallery.items per stampa/export.

Obiettivo: togliere la logica foto dalle singole funzioni UI e centralizzarla.

Fase 2 - Coda operazioni offline

Introdurre nel client una photo_ops_queue persistita in IndexedDB/draft:

  • upload;
  • delete assignment;
  • restore assignment;
  • move assignment;
  • park;
  • trash.

Ogni operazione deve essere idempotente con un op_id.

Fase 3 - API server leggere

Possibile evoluzione server:

  • endpoint per applicare operazioni foto;
  • endpoint per leggere ledger/cestino;
  • tabella o JSON nel draft per ledger pilota;
  • solo dopo stabilita, eventuale normalizzazione DB.

Fase 4 - Stampa tecnica permissiva

Cambiare la logica stampa:

  • non bloccare con foto locali/pending;
  • generare sempre preview/PDF tecnico;
  • usare immagini disponibili;
  • usare placeholder per immagini non risolvibili;
  • lasciare warning in UI e nel PDF.

Ordine consigliato

  1. Introdurre photo_ledger client-only con compatibilita verso payload attuale.
  2. Migrare aggiunta/cancellazione/parcheggio a funzioni ledger.
  3. Aggiungere cestino RAS client/draft.
  4. Aggiungere coda operazioni offline per cancellazione/spostamento/ripristino.
  5. Rendere stampa v2 permissiva.
  6. Solo dopo, valutare endpoint/server ledger.

Rischi

  • Refactor troppo grande in un colpo solo rischia regressioni su upload e stampa.
  • Tenere doppio modello temporaneo, ledger + payload legacy, richiede test mirati.
  • La stampa server non puo vedere blob locali del browser: serve placeholder o un flusso preview locale se si vogliono includere immagini non uploadate.
  • Se si elimina fisicamente un blob server prima di verificare tutte le assegnazioni, si rischia perdita dati.

Test minimi da creare

  • creazione ledger da payload legacy;
  • aggiunta foto locale crea asset + assignment + payload compatibile;
  • upload riuscito aggiorna asset senza perdere assignment;
  • cancellazione sposta assignment a cestino;
  • cancellazione offline crea op pending;
  • ripristino da cestino torna alla domanda originale;
  • parcheggio mantiene asset e cambia assignment;
  • duplicato stessa domanda cancella una sola assignment;
  • stessa foto in due domande cancella una sola assignment;
  • stampa non bloccata con foto locali/pending.