Revisione blocchi 2 e 3: file protetti, ripristino atomico, import sicuri
Blocco 2 - Esiti delle azioni Livewire come avvisi (trait Avvisa) invece di flash che comparivano alla pagina dopo. - PDF, miniature e versioni dei territori non più serviti da nginx su /storage: TerritorioFileController con login, permessi e cache privata. - Ripristino tutto o niente: verifica dell'archivio, una transazione con import, piantine, blocco account e scambio dei file annullabile. - Backup formato 2 con piantine, storico PDF e area KML. - Posto unico preso in un passo (Cache::lock) e rispettato anche da import XML e PDF. - Import PDF da cartella: abbinamento corretto (1-A, 12 B, ambigui), caricamento a lotti, file non PDF ignorati, PDF sostituito nello storico. - L'import XML elimina i file dei territori che non usa più; comando territori:file-orfani per quelli accumulati prima. Blocco 3 - Password attuale richiesta al cambio volontario; AuthenticateSession chiude le sessioni aperte altrove. - Niente nomi dei proclamatori in chiaro nel registro attività. - Export XML senza remember_token; chi riceve l'hash dal file deve cambiare password. - Campagne: ultimo giorno incluso, percentuale sui territori distinti. - Coda: retry_after 960 s, stop_grace_period 16m, Redis volatile-lru, impostazioni rilette a ogni job. - Azzeramento che cancella anche piantine, area KML e anteprime. - Pulsanti profilo e menu che non si nascondevano; icona del sito. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
141
HANDOFF.md
141
HANDOFF.md
@@ -77,69 +77,60 @@ e l'unica che richiede una decisione, non del lavoro.
|
||||
|
||||
## Lavori in corso — 12 ottobre 2026 (riprendere da qui)
|
||||
|
||||
### Già fatto e committato su `dev` (commit `d433c93`, NON ancora pushato)
|
||||
Commit su `dev`, **nessuno pubblicato** (il push fa partire il deploy sulla demo):
|
||||
- `d433c93` — Modulo S-13 sul modulo ufficiale (regole in
|
||||
`app/Services/Registro/ModuloS13.php`) e blocco 1 della revisione
|
||||
(integrità dati).
|
||||
- `056d95c` — Editor piantine: bozza automatica, un solo "Pubblica" con
|
||||
anteprima, stati Bozza / Pubblicata / Modifiche da pubblicare. Come funziona:
|
||||
[Le piantine sono una sotto-app](#le-piantine-sono-una-sotto-app-renderer-esterno-agganci-minimi).
|
||||
- Il commit successivo chiude i blocchi 2 e 3 della revisione (sotto).
|
||||
|
||||
- **Modulo S-13** riscritto su modulo ufficiale (FPDI), regole decise con l'utente:
|
||||
20 righe/foglio, tutti i territori attivi, ciclo da 4 con riporto, riporto
|
||||
iniziale = ultimo rientro prima dell'anno, assegnazioni a cavallo d'anno su
|
||||
entrambi i fogli (sul vecchio senza rientro), nomi "Cognome I.", scelta per
|
||||
data. Codice in `app/Services/Registro/ModuloS13.php`.
|
||||
- **Blocco 1 della revisione** (integrità dati): date export/import che
|
||||
slittavano di un giorno, import XML che accettava file estranei, caratteri di
|
||||
controllo, territori senza zona scartati, admin estromesso dall'import,
|
||||
doppia assegnazione (`Assegnazione::sovrappostaA()` + lock), ultimo admin,
|
||||
`APP_KEY` sovrascritta dall'entrypoint (`APP_KEY_ROTATE=1`). Vedi la tabella
|
||||
"Bug corretti". Suite: 328 test verdi.
|
||||
- Il push su `dev` fa partire il deploy su demo: va fatto quando si decide.
|
||||
Produzione: al 12/10/2026 non esiste ancora (il sito gira in Docker sul PC di
|
||||
sviluppo, più la demo da `dev`). Nessuna correzione una tantum da fare.
|
||||
|
||||
### Finito, NON ancora committato: riprogettazione dell'Editor Piantine
|
||||
### Revisione profonda: blocchi 2 e 3 chiusi
|
||||
|
||||
Decisioni dell'utente: due pagine separate (gestione / editor); **un solo
|
||||
pulsante "Pubblica"** (immagine + PDF) con **anteprima obbligatoria** da
|
||||
confermare, disponibile da editor e gestione; dall'editor **si modificano i
|
||||
dati del territorio** (salvati subito nel gestionale); uso soprattutto da PC ma
|
||||
anche **tablet**; **stato di bozza**: in bozza va solo il disegno, salvata
|
||||
**automaticamente**; stati Bozza / Pubblicata / Modifiche da pubblicare.
|
||||
Come funziona: sezione [Le piantine sono una sotto-app](#le-piantine-sono-una-sotto-app-renderer-esterno-agganci-minimi).
|
||||
| Problema | Correzione |
|
||||
|---|---|
|
||||
| Esiti delle azioni Livewire persi o mostrati alla pagina dopo (11 componenti) | trait `Avvisa` + `<x-avvisi>`; un test vieta `session()->flash()` senza redirect |
|
||||
| PDF, miniature e versioni scaricabili da `/storage/territori-*` senza login (nomi indovinabili, cache Cloudflare 7 giorni) | nginx risponde 404 su `/storage/territori-`; `TerritorioFileController` con permessi della pagina e cache privata; `Territorio::pdfUrl()` / `miniaturaUrl()` |
|
||||
| Ripristino non atomico | estrazione verificata (CRC, byte) → una transazione con import, piantine, blocco account e scambio file (`rename`, annullabile) → file vecchi cancellati solo dopo il commit |
|
||||
| Piantine, storico PDF, area KML fuori dal backup | formato archivio 2 (`piantine.json`, `piantine/…`, `PiantineBackup`); gli archivi di formato 1 si ripristinano lo stesso |
|
||||
| Blocco "una sola operazione" ignorato da import XML/PDF, e controllo+presa in due passi | `BackupOperationState::occupa()` sotto `Cache::lock`, usato da tutte le porte; rilascio anche su errore e in `failed()` |
|
||||
| Import PDF da cartella: `1-A` → territorio 1, `12 B` ambiguo, solo 20 file, `Thumbs.db` blocca tutto, `__MACOSX` | abbinamento "cifre + al massimo una lettera"; ambigui scartati; caricamento a lotti dal browser; file non PDF ignorati |
|
||||
| Import PDF e caricamento dalla scheda cancellavano il vecchio PDF prima di scrivere il nuovo | prima il nuovo, poi il vecchio nello storico (`PiantinaPdfService::archiviaCorrente`, origini `import` / `manuale`) |
|
||||
| L'import XML lasciava sul disco i file dei territori ricreati (nel PC: 549 file, 80 MB) | l'import elimina i file non più usati; per i vecchi c'è `php artisan territori:file-orfani` (elenca; `--elimina` cancella) — **da lanciare quando si decide** |
|
||||
| Azzeramento lasciava piantine orfane, area KML, anteprime | cancellate anche quelle |
|
||||
| `/cambia-password` senza password attuale | richiesta, tranne dopo un ripristino (cambio obbligatorio) |
|
||||
| Sessioni aperte altrove non chiuse al cambio password | `AuthenticateSession` nel gruppo web; il ripristino conserva l'hash di chi lo esegue, così non viene buttato fuori |
|
||||
| Nomi dei proclamatori in chiaro nel registro attività | si salva `proclamatore_id`, il registro mostra il nome attuale; migrazione `2026_10_12_000010` ripulisce le voci vecchie |
|
||||
| Export XML con `remember_token`; l'import XML non obbligava a cambiare password | token non esportato e azzerato all'import; chi riceve l'hash dal file deve cambiare password |
|
||||
| Campagne: sparivano l'ultimo giorno; percentuale oltre il 100% | confronto per data; si contano i territori attivi distinti |
|
||||
| `retry_after` 90 s con job fino a 900 s | `config/queue.php`: 960 s |
|
||||
| Worker ucciso dopo 10 s al riavvio | `stop_grace_period: 16m` |
|
||||
| Redis `allkeys-lru` poteva sfrattare i job in coda | `volatile-lru` |
|
||||
| Cache statica di `Setting` vecchia nel worker | svuotata a ogni job (`Queue::before`) |
|
||||
| Pulsanti profilo/menu che non si nascondevano (barra che trabocca su telefono) | `.tm-btn` sta fuori dai layer di Tailwind e vince su `hidden`: si nasconde il contenitore |
|
||||
|
||||
Stato al 12/10/2026:
|
||||
- Codice completo: modello, servizio di pubblicazione + job, finestra condivisa,
|
||||
editor e gestione riscritti, JS e CSS. Migrazione
|
||||
`2026_10_09_000010_bozza_e_pubblicazione_piantine`.
|
||||
- Test: `PiantineEditorTest` (22), `PiantineManagerTest`,
|
||||
`PubblicazionePiantinaTest` (nuovo). Suite intera: **360 test verdi**.
|
||||
- Provato in browser (Playwright + Edge, in locale) su PC 1440, iPad
|
||||
orizzontale e verticale, iPhone: disegno, modifica vertici (8 maniglie su
|
||||
poligono), collegamento, anteprima generata dal renderer vero, conferma,
|
||||
stato "Pubblicata", filtri della gestione. Corretti lì: tendina territori che
|
||||
segnava tutti "(disattivato)" (colonna `attivo` non caricata), zoom sopra la
|
||||
ricerca dell'elenco, barra strumenti sopra il pannello su tablet e fuori
|
||||
schermo su telefono, crediti mappa stampati sul foglio del pannello.
|
||||
- Aggiunto `.gitattributes` (`*.sh text eol=lf`): con `core.autocrlf=true`
|
||||
l'entrypoint usciva con CRLF e il container locale non partiva ("no such
|
||||
file or directory"). Nel repository era già LF: il deploy non era a rischio.
|
||||
- **Non provato:** modifica vertici al tocco su un tablet vero, MultiPolygon
|
||||
in modifica vertici (si modifica il primo poligono).
|
||||
- Visto e **non** corretto (fuori tema): su telefono la barra superiore
|
||||
dell'app trabocca con nome/email lunghi ("Esci" fuori schermo);
|
||||
`/favicon.ico` risponde 404.
|
||||
Non cambiato, di proposito: `trustProxies('*')` (commento in
|
||||
`bootstrap/app.php`: con `real_ip` di nginx, restringerlo romperebbe HTTPS).
|
||||
|
||||
### Revisione profonda: blocchi ancora aperti
|
||||
Suite: **427 test verdi**. Provati in browser in locale: file protetti (404
|
||||
senza login, PDF e miniature con login), caricamento a lotti (25 PDF in 2
|
||||
lotti, `Thumbs.db` ignorato, nessun territorio toccato, posto liberato).
|
||||
|
||||
- **Blocco 2:** avvisi in tutte le ~10 pagine che oggi li perdono (usare il
|
||||
trait `Avvisa`); PDF dei territori serviti da nginx su `/storage` senza
|
||||
autenticazione (spostare su disco privato); ripristino non atomico e blocco
|
||||
"una sola operazione" ignorato da import XML/PDF; piantine e storico PDF
|
||||
assenti dal backup; import PDF da cartella (`1-A` sovrascrive `1`, solo 20
|
||||
file per `max_file_uploads`, `Thumbs.db` blocca tutto, `12 B` ambiguo).
|
||||
- **Blocco 3:** `/cambia-password` senza password attuale, sessioni non
|
||||
invalidate, `trustProxies('*')`, nomi in chiaro nell'activity log, export XML
|
||||
con hash/token, campagne (ultimo giorno, percentuali), `retry_after` 90 s,
|
||||
`stop_grace_period` del worker, Redis `allkeys-lru`, cache statica di
|
||||
`Setting` nel worker, azzeramento che lascia piantine e KML.
|
||||
- Produzione: al 12/10/2026 non esiste ancora (il sito gira in Docker sul PC
|
||||
di sviluppo, più la demo da `dev`). Nessuna correzione una tantum delle date
|
||||
slittate da fare.
|
||||
**Non provato / aperto:**
|
||||
- chiusura delle sessioni con due browser veri; coda e worker con un riavvio
|
||||
reale; modifica vertici al tocco su tablet vero;
|
||||
- dopo un ripristino le piantine pubblicate risultano "Modifiche da pubblicare"
|
||||
(l'import ricrea i territori con id nuovi): verso sicuro, basta ripubblicare;
|
||||
- `corrente()` / `liberaCorrente()` di `BackupOperationState` fanno get+forget
|
||||
senza mutex (finestra di millisecondi);
|
||||
- l'upload Livewire ha `throttle:60,1`: oltre ~1200 file al minuto qualche
|
||||
lotto riceve 429 (il browser lo segnala);
|
||||
- numeri di territorio con lettere davanti ("A12") non si abbinano da nome
|
||||
file: il PDF si carica dalla scheda.
|
||||
|
||||
---
|
||||
|
||||
@@ -748,13 +739,16 @@ Scelte non ovvie:
|
||||
cancellazioni scrivono righe nuove — e subito dopo si scrive l'unica riga che
|
||||
sopravvive, quella dell'azzeramento stesso.
|
||||
|
||||
- **Ordine del restore: staging → database → file.** I file si estraggono
|
||||
prima in `storage/app/backup-restore/<uuid>`, così un archivio corrotto o
|
||||
fuori limite fallisce mentre i dati correnti sono ancora intatti; poi
|
||||
`importXmlFromContent()` in transazione; poi la sostituzione dei file. Il
|
||||
disco `public` viene **svuotato**, non fuso: i percorsi vivono nelle righe
|
||||
appena riscritte, e tenere i vecchi file lascerebbe PDF orfani che nessuna
|
||||
schermata mostra e nessuna cancellazione raggiunge.
|
||||
- **Ordine del restore: verifica → una transazione → pulizia.** Dal 12/10/2026
|
||||
(`RestoreBackupArchive`): si estrae e si verifica tutto (CRC, byte, il
|
||||
`piantine.json` del formato 2) prima di toccare qualcosa; poi una sola
|
||||
`DB::transaction` contiene import XML, tabelle delle piantine, blocco degli
|
||||
account e, per ultimo, lo scambio dei file (`BackupArchive::scambiaFile()`:
|
||||
solo `rename()` sullo stesso volume, annotati e annullabili). Se qualcosa
|
||||
fallisce si torna allo stato di prima; i file vecchi aspettano in
|
||||
`storage/app/backup-precedenti/<uuid>` e si cancellano solo dopo il commit.
|
||||
Il disco `public` viene sostituito, non fuso: i percorsi vivono nelle righe
|
||||
appena riscritte.
|
||||
|
||||
- **Limiti sull'archivio in ingresso.** Un `.zip` è compresso: senza tetti su
|
||||
numero di entry, dimensione della singola entry e totale decompresso, pochi
|
||||
@@ -1245,21 +1239,12 @@ pubblicate da Laravel sono state rimosse perche' i paginatori sono tutti dentro
|
||||
componenti Livewire, che risolvono la vista dal namespace `livewire::` e non da
|
||||
`pagination::`. L'esclusione resta a guardia di future viste di terze parti.
|
||||
|
||||
### 7. Il backup non contiene l'area KML delle piantine
|
||||
### 7. Area KML, piantine e storico nel backup — chiuso il 12/10/2026
|
||||
|
||||
`BackupArchive` impacchetta il solo disco `public` (`storage/app/public`), e
|
||||
`PiantineArea` scrive in `storage/app/piantine/` — una cartella **sorella**, non
|
||||
dentro. Verificato: dopo un ripristino su volumi vuoti l'area va ricaricata a
|
||||
mano dal KML originale, che quindi conviene conservare fuori di qui.
|
||||
|
||||
I disegni invece si salvano: stanno in `territorio_mappe`, e da quando la chiave
|
||||
esterna è `nullOnDelete` sopravvivono anche allo svuotamento di `territori` che
|
||||
fa ogni import XML — scollegati, ma recuperabili.
|
||||
|
||||
Sistemarlo vuol dire estendere `BackupArchive` a una seconda cartella, cosa che
|
||||
tocca anche il formato dell'archivio (`FORMAT_VERSION`) e il ripristino. Non è
|
||||
stato fatto perché il KML è un file che l'utente ha già sul suo computer: la
|
||||
perdita è un fastidio, non un dato irrecuperabile.
|
||||
Dal formato 2 l'archivio contiene `piantine.json` (righe di `territorio_mappe`
|
||||
e `territorio_pdf_versioni`, con il numero del territorio per ricollegarle) e
|
||||
la cartella `piantine/` dell'area KML. Un archivio di formato 1 si ripristina
|
||||
lo stesso: piantine e storico restano vuoti, l'area in uso non si tocca.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user