Nel GLPI standard una notifica è una e-mail asincrona: finisce nello spam, il tecnico non vive nella webmail e il follow-up resta ore senza risposta. Smart Notify sostituisce questo modello con una campanella nella barra di navigazione di GLPI che interroga il database e aggrega più di una dozzina di eventi ITIL quasi in tempo reale. Gestire parchi GLPI di clienti in produzione ci ha insegnato che accendere la campanella è la parte facile; la difficile è calibrare ciò che mostra perché non diventi rumore. Questa guida spiega come funziona il poll sotto il cofano, un SQL di diagnostica, la matrice di quali eventi tenere attivi e le trappole sul campo che più spesso rompono l'installazione.
Perché l'e-mail nativa non risolve l'allerta operativa
Le notifiche native di GLPI dipendono dalla coda queuednotification e da modelli e-mail. È un modello asincrono e fuori dallo strumento: il tecnico deve alternare tra GLPI e la casella di posta, l'e-mail transazionale finisce nello spam aziendale e nessuno controlla la webmail in tempo reale. L'esito classico dell'operatività è un'approvazione ferma per ore e un'attività assegnata che nessuno ha visto.
La campanella risolve questo per chi è connesso a GLPI. Ma attenzione alla prima trappola: la campanella non sostituisce l'e-mail per il richiedente. Notifica il tecnico in sessione, non il cliente che ha aperto il ticket dal self-service. L'errore comune è disattivare le notifiche e-mail pensando che la campanella copra tutti, e il richiedente smette di essere avvisato. Campanella ed e-mail sono livelli complementari, non alternativi.
Come funziona la campanella sotto il cofano (polling + delta)
Il JavaScript della campanella esegue un poll ogni 30 secondi (refresh_interval predefinito) verso un endpoint AJAX. A ogni ciclo il backend scorre fino a sedici sorgenti di eventi, compone la lista, applica la ritenzione (retention_days, 90 giorni di default), taglia a max_notifications (50 di default) e ordina per data decrescente. Ogni notifica riceve un hash stabile (sha1(tipo_id_timestamp)): è ciò che segna l'elemento come letto senza aggiungere un campo al ticket.
Ciò che solo chi opera nota è il costo di quel poll ogni 30 s per tecnico connesso. Per questo l'endpoint usa la modalità delta: il client restituisce l'hash dell'ultimo stato (state=); se nulla è cambiato, la risposta scende da circa 18 KB a ~93 byte. E il read-check è diventato un unico SELECT in blocco: prima era un SELECT per notifica, arrivando a ~700 per poll negli utenti con grande backlog. Il GET chiama anche session_write_close() subito, per non trattenere il lock di sessione PHP mentre scorre il database.
# La campanella fa polling ogni 30s su questo endpoint (instradato da module_ajax):
GET /plugins/nextool/ajax/module_ajax.php?module=smartnotify&file=notifications.php&action=get&state=${HASH}
# Senza novita dall'ultimo poll, la risposta e un delta di ~93 byte:
{ "success": true, "unchanged": true, "state": "...md5...", "unread_count": 4 }
# Solo quando qualcosa cambia arriva il payload completo (~18KB) con l'array notifications[].
Le sorgenti di eventi e cosa lasciare attivo
La configurazione globale espone sedici trigger e ogni tecnico affina i propri nella finestra delle preferenze (raggiungibile direttamente dal menu a tendina della campanella). Contano due regole di targeting: il follow-up che tu hai scritto non ti notifica (la query filtra users_id != utente), e la notifica arriva per coinvolgimento diretto oppure per gruppo tecnico (notify_group_involvement), rispettando sempre le entità attive della sessione.
Nel mantenimento operativo tre trigger arrivano disattivati di default di proposito, e l'esperienza conferma la scelta: i documenti allegati sono rumore nei parchi con molti caricamenti; i nuovi problemi e i nuovi cambiamenti sono eventi meno frequenti che intasano la campanella di chi gestisce solo ticket. Accendere tutto è la via più rapida alla fatica da allerta: il tecnico inizia a ignorare la campanella, e allora non serve a nulla.
| Famiglia di evento | Trigger (config) | Default | Nota sul campo |
|---|---|---|---|
| Follow-up (ticket, problema, cambiamento) | notify_*_followup | Attivo | Ciò che muove di più il backlog; tienilo |
| Validazioni e risposte di validazione | notify_*_validation(_response) | Attivo | Un'approvazione ferma è un collo di bottiglia silenzioso |
| Attività assegnate | notify_*_task | Attivo | È la coda di lavoro del tecnico |
| Soluzioni registrate | notify_solution | Attivo | Chiude il cerchio per chi segue |
| Documenti allegati | notify_document | Inattivo | Rumoroso dove i caricamenti abbondano |
| Nuovi ticket | notify_new_ticket | Attivo | Segnale di ingresso in coda |
| Nuovi problemi / cambiamenti | notify_new_problem / _change | Inattivo | Meno comuni; attivali per profilo |
| Avvisi manuali (broadcast) | notify_manual | Attivo | Manutenzione, cambio di processo |
Diagnostica via SQL: chi ha silenziato cosa
Quando un cliente si lamenta che "la campanella non avvisa", il problema è quasi sempre una preferenza individuale o l'entità sbagliata, non un bug. Queste tre query risolvono il triage direttamente nel database (tabelle reali del modulo):
-- 1. Quanti tecnici hanno silenziato ogni tipo di evento (trova rumore/fatica):
SELECT
SUM(ticket_followups = 0) AS muto_followup_ticket,
SUM(solutions = 0) AS muto_soluzione,
SUM(documents = 0) AS muto_documento,
SUM(sound_enabled = 0) AS suono_off
FROM glpi_plugin_nextool_smartnotify_preferences;
-- 2. Record di lettura per utente (backlog e ultima attivita):
SELECT users_id, COUNT(*) AS letture_registrate, MAX(date_read) AS ultima_lettura
FROM glpi_plugin_nextool_smartnotify_read
GROUP BY users_id
ORDER BY ultima_lettura DESC;
-- 3. Broadcast manuali attivi e loro destinazione (all/user/group/entity):
SELECT id, title, priority, target_type, target_id, entities_id, date_creation
FROM glpi_plugin_nextool_smartnotify_manual
WHERE is_active = 1
ORDER BY date_creation DESC;
Suoni per priorità e la trappola dell'autoplay
Le notifiche emettono un suono tramite la Web Audio API, con quattro timbri mappati per priorità. Prima di guardare lo schermo, il tecnico sente se ciò che è arrivato è routine o urgenza:
| Priorità | Suono | Timbro (circa) |
|---|---|---|
| Bassa | subtle | Breve e grave (440 Hz) |
| Normale | default | Standard (523 Hz) |
| Alta | alert | Medio (659 Hz) |
| Urgente | alarm | Lungo e acuto (880 Hz) |
La trappola qui non è del modulo, è del browser: la politica di autoplay di Chrome consente di creare l'AudioContext solo dopo il primo gesto dell'utente. In pratica, il primo suono di una sessione esce solo dopo il primo clic sulla pagina. Ogni mese qualcuno apre un ticket dicendo "il suono non funziona": la risposta è fare un clic sulla pagina. Non è un bug, è la Web Audio API che rispetta il browser.
Broadcast manuali e pulizia automatica
Gli amministratori inviano avvisi manuali con targeting preciso: tutti, un utente, un gruppo o un'entità (la colonna target_type nella tabella _manual). È il canale giusto per una finestra di manutenzione o un cambio di processo senza inviare e-mail all'intera base. La ritenzione è gestita da una CronTask giornaliera (smartnotify_cleanup), registrata all'installazione come MODE_EXTERNAL. È importante: in MODE_INTERNAL l'attività gira via web-hit e può bloccarsi in state=2. Attiva il cron di GLPI dall'esterno (su GLPI 11, front/cron.php) e la pulizia avviene da sola secondo retention_days e logs_retention_days.
# CronTask registrata all'installazione (idempotente), 1x/giorno, MODE_EXTERNAL:
# Nome: smartnotify_cleanup Frequenza: DAY_TIMESTAMP (86400s)
# Attiva il cron di GLPI dall'esterno (non dipendere mai dal MODE_INTERNAL via web-hit):
* * * * * www-data /usr/bin/php /var/www/html/front/cron.php >/dev/null 2>&1
La trappola che rompe l'installazione: MySQL 8 vs MariaDB
Un caso reale di mantenimento (giugno 2026, cliente su MySQL 8.0.46): l'installazione del modulo diventava un HTTP 500 e il parco restava senza campanella. La causa radice non era in GLPI, era nel SQL: un blocco ALTER TABLE ... ADD COLUMN IF NOT EXISTS, sintassi esclusiva di MariaDB. Su MySQL 8 quell'IF NOT EXISTS a livello di colonna non esiste e lo statement fallisce con errore 1064, facendo cadere l'intera installazione. La lezione vale per qualsiasi plugin GLPI: il DDL condizionale non è portabile tra MariaDB e MySQL. La correzione (versione 2.2.1+) ha rimosso il DDL condizionale dal .sql e spostato le migrazioni in PHP con gli helper portabili del plugin base. Se usi MySQL 8, assicurati che il modulo sia alla 2.2.1 o superiore.
In NexTool implementiamo e manteniamo ambienti GLPI end to end. Se il tuo team convive con ticket dimenticati e notifiche e-mail che nessuno apre, Smart Notify è gratuito e si attiva in pochi minuti dal catalogo di moduli NexTool, e il nostro team di mantenimento aiuta a calibrare cosa riceve ogni profilo perché la campanella diventi segnale, non rumore.
Questo contenuto è stato prodotto con l'ausilio dell'intelligenza artificiale e revisionato dal team di Nextool Solutions.