11 KiB
🧠 MEMORY.md — Stato Progetto
Obiettivo
App gestionale Laravel 13 con AdminLTE 4 per gestione Persone e Gruppi.
Funzionalità Implementate
Page-length selector
- 4 pagine: Individui, Eventi, Email, Gruppi
- Valori: 10, 20, 25, 50, 100 (default 20)
- Dropdown nel card-footer con campi hidden per preservare query params
- GruppoController: usa
LengthAwarePaginatorper paginare la collezione ordinata gerarchicamente
CSV Import Gruppi
- Stesso pattern di
IndividuoController(import GET, importStore POST, downloadTemplate GET) - Colonne: nome, descrizione, parent_id, diocesi_id, indirizzo_incontro, cap_incontro, città_incontro, sigla_provincia_incontro
- Fault-tolerant: skip righe vuote, log errori, try/catch su ogni riga
ICS Import Eventi
- Usa
Sabre\VObject\Reader::read()già in vendor/ - Mapping: SUMMARY→nome_evento, DESCRIPTION→descrizione, DTSTART→data_specifica+ora_inizio, DTEND→durata_minuti, LOCATION→luogo_indirizzo, UID→uid_esterno
- Dedup via uid_esterno
- RRULE: import come evento singolo con prima occorrenza
build-dist.sh (script di distribuzione)
- Genera
glastree-YYYYMMDD_HHMM.tar.gz - Include: sorgenti, vendor (production)
- Esclude: .git, node_modules, tests, cache, storage content, vendor/docs/tests, Docker
- Istruzioni post-estrazione complete: mkdir, permessi, configurazione, cache clear
Bug Fix Recenti
2026-06-07 — Colonne mancanti in eventi e gruppo_individuo
descrizione_eventoeis_incontro_gruppomancanti in install.sql → creata migration + ALTER TABLEruolo_nel_gruppomancante in install.sql per pivotgruppo_individuoVistaReport.php: aggiuntois_defaulta$fillable
2026-06-08 — build-dist.sh: "provide valid cache path" su server remoto
Problema: Le esclusioni in build-dist.sh usavano --exclude='storage/framework/cache' (e simili per sessions, views, logs), che escludevano l'intera directory dall'archivio. Dopo l'estrazione, le directory necessarie a Laravel non esistevano.
Fix:
- Cambiati exclude patterns per contenuti soltanto (non la directory):
--exclude='storage/framework/cache/*'(non/cache)--exclude='storage/framework/sessions/*'--exclude='storage/framework/views/*'--exclude='storage/logs/*'--exclude='storage/debugbar/*'
- Aggiunte esclusioni per upload utente:
--exclude='storage/app/public'--exclude='storage/app/private'
- Creato
.gitignoreinstorage/framework/views/(mancante) - Istruzioni post-estrazione riscritte con:
mkdir -pper tutte le directory necessarie (cache, sessions, views, logs, public, backups, documenti, bootstrap/cache)chmod -R 775echown -R www-data:www-dataper permessiphp artisan config:clear,route:clear,view:clear
Problema 419 (Page Expired) su Produzione
Il codice NON ha errori di CSRF — tutte le form hanno @csrf. Il problema è configurazione sessione del server:
storage/framework/sessions/non scrivibile dal web serverAPP_URLin.envnon corrisponde all'URL realeSESSION_SECURE_COOKIE=truema sito in HTTP
Soluzione:
chmod -R 775 storage/framework/sessions
php artisan config:clear
2026-06-08 — build-dist.sh: impossibilità salvare logo su server remoto
Problema:
public/storageera un symlink assoluto (/var/www/html/glastree/storage/app/public) incluso nell'archivio → all'estrazione su altro server puntava a path inesistente.php artisan storage:linkfalliva perché il symlink rotto esisteva già.- Sottodirectory
logos/,documenti/eventi/,avatars/gruppi/non create dalmkdir -p.
Fix:
- Aggiunto
--exclude='public/storage'al tar — il symlink va ricreato sul target. - Aggiunto
rm -f public/storageprima diphp artisan storage:linkper evitare conflitto. - Usato
ln -sf ../storage/app/public public/storage(invece diphp artisan storage:link --relativeche richiedesymfony/filesystemnon sempre presente). - Aggiunte al
mkdir -ple sottodirectory mancanti:storage/app/public/logos(logo upload)storage/app/public/documenti/eventi(event documenti)storage/app/private/avatars/gruppi(avatar gruppi)
- Aggiunta creazione
.gitignoreinstorage/app/public/(placeholder Laravel).
Fix form annidato salvataggio email
2026-06-08 — Problema: Il form di DELETE era annidato dentro il form di SAVE in entrambe le pagine:
resources/views/impostazioni/index.blade.phpresources/views/admin/email-settings/index.blade.php- HTML invalido: il browser chiudeva implicitamente il form SAVE all'apertura del form DELETE, causando l'invio alla route sbagliata.
Fix: Spostato il form DELETE fuori dal form SAVE, separato in un div autonomo.
Fix campi mancanti in validazione EmailSettingsController@save
2026-06-08: signature, signature_enabled, smtp_username, smtp_password non erano nelle regole di validazione di save(). Laravel scarta i campi non validati, quindi non venivano mai scritti nel DB.
Fix: Aggiunte le regole mancanti a $request->validate().
DiagnoseEmail Command
php artisan diagnose:email— controlla APP_KEY, tabella email_settings, record, decrittazione password, sender_accounts, log errori, estensioni PHP.
2026-06-08 — Firma email ancora non salvata (secondo tentativo)
Problema: La firma (campo signature) non veniva salvata nonostante le regole di validazione fossero state aggiunte.
Root cause analysis:
- HTML checkbox
signature_enabledsenza hidden fallback: quando non spuntato, il campo non veniva inviato → non presente in$validated→updateOrCreatenon lo aggiornava mai afalse. - La vecchia pagina
/impostazioni/aveva l'handlershown.bs.tabper il tab Firma (#email-firma) in un solo punto su due, causando possibile mancata inizializzazione dell'editor Quill su alcuni flussi di navigazione. - La verifica nel controller controllava solo
imap_hosteemail_address— anche se signature/signature_enabled fallivano, l'utente vedeva "salvato con successo".
Fix:
resources/views/admin/email-settings/index.blade.php:268— Aggiunto<input type="hidden" name="signature_enabled" value="0">prima della checkboxresources/views/impostazioni/index.blade.php:603— Stesso hidden fallbackresources/views/impostazioni/index.blade.php:1633— Aggiunto#email-firmaal primo handlershown.bs.tab(il secondo handler esisteva già ma il primo no)app/Http/Controllers/Admin/EmailSettingsController.php:70-82— Aggiunto log di warning se signature o signature_enabled non corrispondono dopo il salvataggio
2026-06-08 — Sync email: "Nessuna configurazione email attiva" nonostante test IMAP funzioni
Problema: Cliccando "Sincronizza Ora" nelle impostazioni email o "Ricevi/Invia" nella pagina email, viene mostrato "Nessuna configurazione email attiva". Il test IMAP funziona correttamente.
Root cause: Stesso bug dei checkbox senza hidden fallback. Il campo is_active nel tab Sincronizzazione non veniva inviato quando non spuntato. Alla prima configurazione, se l'utente non visitava esplicitamente il tab Sync e attivava lo switch, is_active rimaneva false (default DB). Il test IMAP usa EmailSetting::first() (ignora is_active), mentre syncEmails() e syncNow() usano EmailSetting::getActive() che filtra per is_active = true.
Fix:
resources/views/admin/email-settings/index.blade.php:251— Aggiunto<input type="hidden" name="is_active" value="0">prima della checkboxresources/views/impostazioni/index.blade.php:586— Stesso hidden fallbackEmailSetting::getActive()ora riceve sempreis_activedal form (0 o 1) grazie all'hidden fallback
2026-06-08 — Help page: aggiunto tab "Calendario" con documentazione OAuth
resources/views/help/index.blade.php: Aggiunto tab "Calendario" nel menu laterale (dopo Google Drive) e relativo tab-pane content con:- Requisiti (account Google, API Calendar, OAuth credentials)
- Passo 1: Google Cloud Console — abilitare Google Calendar API, creare OAuth Client ID (Web Application), redirect URI
https://developers.google.com/oauthplayground - Passo 2: Ottenere Refresh Token via Google OAuth Playground (Use your own OAuth credentials, scope
calendar) - Passo 3: Configurazione nell'app (Impostazioni → Calendario, nuova connessione Google Calendar, inserire Client ID/Secret/Refresh Token)
- Test connessione e sincronizzazione
- Nota: refresh token permanente finché non revocato
resources/views/help/pdf.blade.php: Aggiunta sezione "3. Google Calendar" nel TOC e contenuto, rinumerazione da 4 a 8 per sezioni successive
Differenza chiave Google Calendar vs Google Drive
- Drive: endpoint server
/auth/google-drive/callbackche gestisce automaticamente il callback OAuth e salva refresh token instorage_repositories - Calendar: NON ha endpoint server dedicato. Refresh token ottenuto manualmente via Google OAuth Playground e incollato nel campo "Refresh Token" del form
2026-06-08 — Pulsante Sync nella pagina calendario eventi
app/Http/Controllers/CalendarioConnessioneController.php: Aggiunto metodosyncAll()che itera tutte le connessioni attive (is_active = true), eseguesyncEvents()per ognuna, e restituisce JSON con risultati aggregati.routes/web.php: Aggiunta routePOST /calendario-connessioni/sync-all→syncAll(name:calendario-connessioni.sync-all).resources/views/eventi/calendar.blade.php: Aggiunto pulsante "Sync" nel card-tools che:- Invia POST AJAX a
sync-all - Mostra spinner durante l'operazione
- Al completamento mostra alert con riepilogo (connessioni, importati, esportati)
- Richiama
window.calendar.refetchEvents()per aggiornare la vista FullCalendar
- Invia POST AJAX a
- Esposto
window.calendarglobalmente per accesso dall'handler sync
2026-06-08 — Fix logo non visibile su installazione remota
Problema: Il logo uploadato non veniva visualizzato su installazioni remote, pur salvandosi correttamente su disco.
Root cause: getLogoPath() e getLogoSmallPath() in AppSetting.php usavano file_exists(public_path('storage/' . $path)) per verificare l'esistenza del file prima di restituire l'URL. Questo controllo dipendeva dal symlink public/storage → storage/app/public. Su installazioni remote dove il symlink era assente o mal configurato, file_exists restituiva false → metodo restituiva null → logo non mostrato.
Fix:
app/Models/AppSetting.php: Sostituitofile_exists(public_path('storage/' . $path))conStorage::disk('public')->exists($path)easset('storage/' . $path)conStorage::disk('public')->url($path). Il controllo ora avviene direttamente sustorage/app/public/(disk root), bypassando il symlink.app/Http/Controllers/ImpostazioniController.php: InuploadLogo(), aggiunta creazione automatica del symlinkpublic/storage → storage/app/publicse mancante, per garantire che il browser possa servire l'immagine.
Prossimi Passi
- (nessuno — in attesa di nuove richieste)