Dati in tempo reale · servizio pubblico

Mappa degli avvisi — dati in tempo reale che altri siti incorporano

Una mappa di avvisi di attacco aereo dove la pagina è solo una parte del prodotto. Gli avvisi, i bersagli in movimento, la linea del fronte e i punti termici arrivano da cinque fonti indipendenti, si aggiornano con i propri orologi — 15, 10 e 20 secondi — e lasciano attraverso un'API JSON aperta e un widget che altri siti web inseriscono in un proprio frame.

Categoria
Dati in tempo reale · servizio pubblico
Costo stimato
da €20.000
Aggiorna
avvisi 15 s · bersagli 10 s · feed 20 s
Fonti
cinque, indipendenti l'uno dall'altro
Stack
PHP 8.3, lavoratori Python, SQLite, Leaflet
map.megainet.art
Mappa degli avvisi
Homepage del progetto — map.megainet.art

01Panoramica del progetto

Mappa degli avvisimostra dove si trova attualmente un allerta aereo: per oblast e per distretto, con obiettivi in movimento sulla mappa, la linea del fronte, punti termici dai satelliti e un feed di canali di monitoraggio sottostante. Viene letto da persone che hanno bisogno della risposta in pochi secondi, ed è letto su un telefono, di notte, con una connessione mobile scadente.

La pagina, però, è solo una parte del prodotto. Gli stessi dati escono attraverso un'API JSON aperta con chiavi e limiti di utilizzo, e attraverso un widget che altri siti web incorporano in un proprio frame. Abbiamo progettato e costruito tutto: i raccoglitori, lo storage, l'API, la mappa e il widget.

02Contesto e problema

I dati che rispondono a «c'è un allerta qui» non esistono in un solo posto. Gli avvisi ufficiali arrivano per oblast. Gli avvisi locali per le comunità provengono da un servizio diverso. Dove si trovano gli obiettivi è scritto, a parole, dai canali di monitoraggio. La linea del fronte è pubblicata da un progetto di mappatura. Gli incendi sono visti dai satelliti. Cinque fonti, cinque formati, cinque idee diverse di cosa significhi «ora».

Il secondo problema è il silenzio. Qualsiasi di quelle fonti può fermarsi: un canale tace, un'API inizia a scadere — e la modalità di errore onesta è dirlo, non continuare a disegnare l'immagine di ieri. Una mappa che appare calma perché la sua fonte è morta è peggiore di nessuna mappa.

03Obiettivi del progetto

  • un'immagine assemblata da cinque fonti indipendenti, ciascuna con il proprio orologio di aggiornamento;
  • una risposta in pochi secondi su un telefono, con una connessione debole, di notte;
  • dati che possono lasciare il sito: un'API aperta con chiavi, limiti e tariffe, e un widget incorporabile;
  • tre lingue, perché il pubblico non è solo locale;
  • una fonte che è caduta in silenzio deve essere visibile come silenziosa, non come calma;
  • l'indirizzo del server non deve mai raggiungere le fonti che legge.

04Cinque fonti, un'immagine

  • Avvisi ufficiali per oblast — la spina dorsale della mappa;
  • avvisi locali per comunità e distretti, da un servizio separato;
  • canali di monitoraggio in Telegram — leggi sia dalle anteprime pubbliche che, per i canali chiusi, attraverso il protocollo di messaggistica stesso;
  • la linea del fronte, da un progetto di mappatura che lo pubblica;
  • punti termici da satelliti NASA — incendi visti dall'orbita.

I collezionisti funzionano come due lavoratori a lungo termine sotto il supervisore di sistema, ciascuno riavviato autonomamente, e scrivono nello storage locale. Il sito web non comunica mai direttamente con una fonte: legge ciò che i collezionisti hanno già scritto, motivo per cui una fonte lenta rende la mappa più vecchia piuttosto che non disponibile.

05Quattro file invece di un database

I dati vivono in quattro file SQLite separati: il registro degli avvisi, le iscrizioni push e il loro stato per regione, gli eventi della mappa con il feed e le chiavi API con i loro contatori di frequenza. Non c'è un database condiviso di proposito — il fallimento di un file non deve compromettere gli altri. Se le iscrizioni push non sono disponibili, la mappa continua a disegnarsi; se il negozio di chiavi è occupato, la pagina continua a rispondere.

Gli stessi file sono scritti dal pannello di controllo dell'intero gruppo — emettendo una chiave, ripristinando uno stato di avviso — quindi ogni connessione si apre con un timeout di attesa. SQLite rinuncia istantaneamente a un database occupato per impostazione predefinita, e «istantaneamente» qui significherebbe una pagina di errore mentre un lavoratore stava semplicemente scrivendo una riga.

06Tre orologi su una pagina

Dati diversi invecchiano a velocità diverse, quindi si aggiornano a velocità diverse: avvisi ogni 15 secondi, obiettivi in movimento ogni 10, il feed ogni 20. Un intervallo comune sarebbe sbagliato in entrambe le direzioni contemporaneamente — troppo lento per gli obiettivi, dispendioso per il feed, e una richiesta inutile ogni pochi secondi per migliaia di schede aperte.

Ogni blocco porta anche il proprio «ultimo aggiornamento». Una pagina che si ridisegna silenziosamente ti insegna a fidarti di essa esattamente quando non dovrebbe essere fidata; un timestamp che smette di muoversi è il modo più veloce possibile per dire «questa parte è obsoleta».

07Un'API aperta con chiavi e tariffe

La mappa pubblica ciò che sa: avvisi attuali, eventi, un endpoint analitico con una mappa di calore di «oblast × time bucket», il ritmo della giornata, tipi di obiettivi e direzioni. I chiamanti anonimi hanno un limite modesto al minuto; una chiave lo aumenta, e le tariffe salgono a scaglioni per coloro che costruiscono su di essa.

Le chiavi vengono emesse dal pannello di controllo condiviso, mai digitate a mano, e l'uso è conteggiato per chiave al giorno. Un endpoint è deliberatamente chiuso a tutti tranne che al proprietario della chiave — quello che comunica a una chiave la propria tariffa, limite e consumo. Tutto il resto è aperto, perché una mappa di servizio pubblico che nasconde i propri dati è solo metà di un servizio pubblico.

08Un widget che vive sui siti di altre persone

Il widget è la parte del prodotto che esce di casa. Due dimensioni fisse — una striscia di stato e un pannello quadrato — tre lingue, due temi e una politica di incorniciatura scritta specificamente in modo che l'incorporamento sia consentito qui e da nessun'altra parte del sito: la mappa e il widget possono essere incorniciati, l'account e le pagine di supporto non possono.

Poiché vive in un frame, il widget non ha cookie propri e non sceglie una generazione dell'interfaccia: appare uguale per tutti. Questa è una decisione, non una limitazione — un widget che si presenta in modo diverso a seconda delle scelte precedenti di un visitatore sarebbe impossibile da supportare sulla pagina di qualcun altro.

09Push che conosce la tua regione

Un abbonamento è legato a una regione, e lo stato di ogni regione è mantenuto accanto agli abbonamenti. È questo che fa arrivare una notifica al confine — quando l'avviso nel tuo oblast inizia o finisce — invece di su ogni aggiornamento della sorgente. La differenza è l'intero prodotto: uno è un segnale, l'altro è rumore che le persone spengono entro un giorno.

C'è un'applicazione nativa sopra gli stessi dati, e comunica con un'API dell'app invece che con le pagine web. Un endpoint di salute proprio risponde al registro della flotta, perché un controllo di vitalità non deve essere più costoso del lavoro che verifica.

10Tre lingue, incluso il widget

La mappa parla ucraino, inglese e russo, e così fanno il riferimento API, le pagine dell'account e il widget. Una nuova stringa dell'interfaccia viene aggiunta a tutte e tre contemporaneamente e un controllo conta quelle mancanti: il conteggio deve essere zero. Le interfacce tradotte a metà non si annunciano — mostrano silenziosamente una lingua dentro l'altra e sembrano a posto a chiunque le abbia scritte.

I nomi delle regioni sono un'altra storia: provengono dalle fonti con la loro ortografia, quindi la mappa mantiene un dizionario proprio piuttosto che fidarsi di ciò che è arrivato nel feed.

11Leggere fonti senza mostrare il tuo indirizzo

Tutto ciò che i raccoglitori ottengono passa attraverso un proxy SOCKS5, incluso il protocollo di messaggistica utilizzato per i canali chiusi — il proxying lì è fatto nel codice, senza una dipendenza extra. L'indirizzo del server non raggiunge mai una fonte, e una fonte che decide di bloccare qualcuno blocca il proxy, non la macchina che serve la mappa.

Il limitatore di velocità si trova davanti all'API per lo stesso motivo al contrario: un endpoint pubblico con dati in tempo reale attira scraper, e un limite per chiave al minuto è ciò che mantiene un servizio pubblico utilizzabile per le persone per cui è stato scritto.

12Stack tecnologico

  • PHP 8.3 senza un framework: un piccolo router, endpoint e renderer;
  • Lavoratori Python sotto il supervisore di sistema — uno solo con la libreria standard, uno che parla il protocollo di messaggistica;
  • SQLite, quattro file separati, ognuno con il proprio motivo di esistere;
  • Leafletper la mappa, risorse hashate, un widget con dimensioni fisse;
  • web push con stato per regione, un'app nativa sugli stessi dati;
  • uscita SOCKS5 per ogni richiesta in uscita, limiti di velocità per chiave davanti all'API.

13Il risultato

Una mappa che risponde in secondi e continua a rispondere quando una delle sue cinque fonti si ferma. Dati che altri siti possono utilizzare: un'API aperta con chiavi e tariffe, e un widget in tre lingue e due temi. Notifiche che si attivano al limite di un evento piuttosto che a ogni polling. Un'applicazione nativa sugli stessi dati, e un pannello di controllo dove vengono emesse le chiavi e ripristinati gli stati.

14Lezioni apprese

Tre cose che porteremmo in qualsiasi progetto con dati in tempo reale.Separare il raccoglitore dalla pagina: un sito web che recupera una fonte mentre un visitatore aspetta è un sito web che va giù ogni volta che la fonte non è disponibile.Dai a ogni blocco il proprio orologio e il proprio timestamp: un singolo intervallo è errato in entrambe le direzioni, e un ridisegno silenzioso nasconde la stagnazione.Dì quando non sai: un blocco vuoto che lo ammette vale di più di una mappa dall'aspetto tranquillo con i dati di ieri.

E una lezione di prodotto: nel momento in cui i dati possono essere incorporati altrove, il widget diventa il prodotto. Ha bisogno di dimensioni fisse, della propria politica di frame e traduzioni — la stessa cura della pagina principale, non un avanzo di essa.

Se hai dati in tempo reale e hai bisogno di una mappa, un'API e un widget che altri siti possono utilizzare, questo è il tipo di lavoro che facciamo dalla A alla Z.