Modulo S-13
- Il PDF scrive sopra il modulo ufficiale (FPDI, matrice convertita in PDF 1.4)
invece di ricostruirlo in HTML: 20 righe per foglio come l'originale.
- Una riga per ogni territorio attivo; riporto dell'ultimo rientro prima
dell'anno; assegnazioni a cavallo d'anno su entrambi i fogli; scelta per
data e non per anno registrato; nomi come "Cognome I.".
- Logica spostata in App\Services\Registro\ModuloS13.
Integrità dei dati
- Export/import XML (e quindi backup/ripristino): le date non slittano più di
un giorno; i file vecchi in UTC tornano al giorno giusto.
- Import XML: rifiuta file estranei o incompleti senza toccare i dati, errore
con riga e motivo, territori senza zona importati con il loro storico,
caratteri di controllo rimossi in export, chi importa conserva password e
ruolo di amministratore.
- Assegnazioni: assegnazioneCorrente corretta (filtro dentro ofMany), periodi
sovrapposti rifiutati in Assegna e Registro sotto lock, anno di servizio
ricavato dalla data, niente date future nel Registro.
- Utenti: non si declassa sé stessi né l'ultimo amministratore.
- Entrypoint: non sovrascrive più la copia persistente di APP_KEY con un
valore diverso; serve APP_KEY_ROTATE=1 per un cambio voluto.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
I due piu' gravi potevano causare perdita di dati silenziosa.
AppServiceProvider chiamava key:generate --force a ogni richiesta quando
APP_KEY risultava vuota. Poiche' nome e cognome dei proclamatori sono
cifrati con quella chiave, ogni riga scritta sotto una chiave poi
sostituita diventava irrecuperabile. La chiave e' ora risolta una sola
volta all'avvio del container e il provider solleva un'eccezione se manca,
invece di rigenerarla.
importTerritoryPdfFolder() caricava i PDF, costruiva l'elenco dei file e
poi lo scartava senza mai accodare il job: nessun errore, nessun territorio
aggiornato, e i file restavano su disco a crescita illimitata perche' la
pulizia viveva solo nel finally del job mai eseguito.
Sicurezza:
- i permessi non venivano riapplicati alle richieste /livewire/update, per
cui un permesso revocato restava attivo fino al reload della pagina
- host header injection: nginx passava l'Host del client come
X-Forwarded-Host e Laravel si fidava di tutti i proxy, abbastanza per far
generare a route() link verso domini arbitrari, inclusi i PDF pubblici
che contengono un codice di accesso valido
- lo schema forwarded e' ora deciso dal server e non dall'header del client
- campagna_id in Rientra e' #[Locked]: era derivato lato server ma
manipolabile dal client, permettendo di conteggiare un rientro su una
campagna arbitraria
- sortField del registro passava non validato a orderBy(), con 500 su
colonna inesistente
- SESSION_SECURE_COOKIE ora vale true fuori da local
- limiti su dimensione e numero di voci negli import ZIP
Integrita' e prestazioni:
- il default di assignment_link_ttl_hours era rimasto 24 dopo la
conversione da ore a mesi: i link PDF pubblici duravano due anni invece
di uno mese
- il seeder usava syncPermissions(), che a un secondo giro azzerava i
permessi personalizzati dei ruoli; ora e' additivo
- pdftoppm senza timeout poteva bloccare il worker indefinitamente
- nomi file deterministici nell'import: "1 A" e "1-A" scrivevano sullo
stesso PDF, sovrascrivendosi
- Setting::flushCache() dopo le cancellazioni massive, che non emettono
eventi e lasciavano la cache puntata a una riga inesistente
- riga settings creata dal seeder, per evitare due singleton concorrenti
- rimosse due migrazioni ridondanti che rompevano migrate:rollback
- indici su assigned_at, (attivo, deleted_at) e deleted_at
- risolti gli N+1 negli elenchi territori e proclamatori
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>