Données en direct · service public

Carte des alertes — données en direct que d'autres sites intègrent

Une carte d'alerte de raid aérien où la page n'est qu'une partie du produit. Les alertes, les cibles mobiles, la ligne de front et les points thermiques proviennent de cinq sources indépendantes, se rafraîchissent selon leurs propres horloges — 15, 10 et 20 secondes — et sortent par une API JSON ouverte et un widget que d'autres sites web intègrent dans un cadre qui leur est propre.

Catégorie
Données en direct · service public
Coût estimé
à partir de 20 000 €
Rafraîchir
alertes 15 s · cibles 10 s · flux 20 s
Sources
cinq, indépendants les uns des autres
Pile
PHP 8.3, travailleurs Python, SQLite, Leaflet
map.megainet.art
Carte des alertes
Page d'accueil du projet — map.megainet.art

01Aperçu du projet

Carte des alertesmontre où une alerte aérienne est en ce moment : par oblast et par district, avec des cibles mobiles sur la carte, la ligne de front, des points thermiques provenant de satellites et un fil de canaux de surveillance en dessous. Il est consulté par des personnes qui ont besoin de la réponse en quelques secondes, et il est consulté sur un téléphone, la nuit, avec une mauvaise connexion mobile.

La page, cependant, n'est qu'une partie du produit. Les mêmes données sortent par une API JSON ouverte avec des clés et des limites de taux, et par un widget que d'autres sites web intègrent dans un cadre qui leur est propre. Nous avons conçu et construit tout cela : les collecteurs, le stockage, l'API, la carte et le widget.

02Contexte et le problème

Les données qui répondent à « y a-t-il une alerte ici » n'existent pas en un seul endroit. Les alertes officielles viennent par oblast. Les alertes locales pour les communautés proviennent d'un service différent. Où se trouvent les cibles est écrit, en mots, par des canaux de surveillance. La ligne de front est publiée par un projet de cartographie. Les incendies sont vus par des satellites. Cinq sources, cinq formats, cinq idées différentes de ce que signifie « maintenant ».

Le deuxième problème est le silence. Chacune de ces sources peut s'arrêter — un canal devient silencieux, une API commence à expirer — et le mode d'échec honnête est de le dire, pas de continuer à dessiner l'image d'hier. Une carte qui semble calme parce que sa source est morte est pire qu'aucune carte.

03Objectifs du projet

  • une image assemblée à partir de cinq sources indépendantes, chacune sur son propre cycle de rafraîchissement ;
  • une réponse en quelques secondes sur un téléphone, avec une connexion faible, la nuit ;
  • des données qui peuvent quitter le site : une API ouverte avec des clés, des limites et des tarifs, et un widget intégrable ;
  • trois langues, car le public n'est pas seulement local ;
  • une source qui est tombée silencieuse doit être visible comme silencieuse, pas comme calme;
  • l'adresse du serveur ne doit jamais atteindre les sources qu'il lit.

04Cinq sources, une image

  • Alertes officielles par oblast — l'épine dorsale de la carte;
  • alertes locales pour les communautés et les districts, d'un service séparé;
  • canaux de surveillance dans Telegram — lire à la fois à partir des aperçus publics et, pour les canaux fermés, via le protocole de messagerie lui-même;
  • la ligne de front, d'un projet de cartographie qui le publie ;
  • points thermiques provenant des satellites de la NASA — des incendies vus depuis l'orbite.

Les collecteurs fonctionnent comme deux travailleurs de longue durée sous le superviseur du système, chacun redémarré de manière autonome, et écrivent dans le stockage local. Le site web ne communique jamais directement avec une source : il lit ce que les collecteurs ont déjà écrit, c'est pourquoi une source lente rend la carte plus ancienne plutôt qu'inaccessible.

05Quatre fichiers au lieu d'une base de données

Les données résident dans quatre fichiers SQLite distincts : le journal des alertes, les abonnements push et leur état par région, les événements de la carte avec le flux, et les clés API avec leurs compteurs de taux. Il n'y a pas de base de données partagée intentionnellement — l'échec d'un fichier ne doit pas entraîner la chute des autres. Si les abonnements push ne sont pas disponibles, la carte se dessine toujours ; si le magasin de clés est occupé, la page répond toujours.

Les mêmes fichiers sont écrits par le panneau de contrôle de l'ensemble du groupe — émettant une clé, réinitialisant un état d'alerte — donc chaque connexion s'ouvre avec un délai d'attente. SQLite abandonne instantanément une base de données occupée par défaut, et «instantanément» ici signifierait une page d'erreur pendant qu'un travailleur écrivait simplement une ligne.

06Trois horloges sur une page

Différentes données vieillissent à des vitesses différentes, donc elles se rafraîchissent à des vitesses différentes : alertes toutes les 15 secondes, cibles mobiles toutes les 10, le flux toutes les 20. Un intervalle commun serait erroné dans les deux sens à la fois — trop lent pour les cibles, gaspilleur pour le flux, et une demande inutile toutes les quelques secondes pour des milliers d'onglets ouverts.

Chaque bloc porte également son propre «dernier mis à jour». Une page qui se redessine silencieusement vous apprend à lui faire confiance exactement quand elle ne devrait pas être digne de confiance ; un horodatage qui cesse de bouger est le moyen le plus rapide de dire «cette partie est obsolète».

07Une API ouverte avec des clés et des tarifs

La carte publie ce qu'elle sait : alertes actuelles, événements, un point de terminaison analytique avec une carte thermique de « oblast × tranche horaire », le rythme de la journée, types de cibles et directions. Les appelants anonymes ont une limite modeste par minute ; une clé l'augmente, et les tarifs augmentent par paliers pour ceux qui s'appuient dessus.

Les clés sont délivrées depuis le panneau de contrôle partagé, jamais saisies à la main, et l'utilisation est comptabilisée par clé et par jour. Un point de terminaison est délibérément fermé à tous sauf au propriétaire de la clé — celui qui indique à une clé son propre tarif, sa limite et sa consommation. Tout le reste est ouvert, car une carte de service public qui cache ses données n'est qu'à moitié un service public.

08Un widget qui vit sur les sites des autres

Le widget est la partie du produit qui sort de chez elle. Deux tailles fixes — une barre d'état et un panneau carré — trois langues, deux thèmes, et une politique de cadre écrite spécifiquement pour que l'intégration soit autorisée ici et nulle part ailleurs sur le site : la carte et le widget peuvent être intégrés, le compte et les pages de support ne le peuvent pas.

Parce qu'il vit dans un cadre, le widget n'a pas de cookies propres et ne choisit pas de génération d'interface : il a le même aspect pour tout le monde. C'est une décision, pas une limitation — un widget qui se rendrait différemment selon les choix précédents d'un visiteur serait impossible à prendre en charge sur la page de quelqu'un d'autre.

09Push qui connaît votre région

Un abonnement est lié à une région, et l'état de chaque région est conservé à côté des abonnements. C'est ce qui fait qu'une notification arrive à la limite — lorsque l'alerte dans votre oblast commence ou se termine — au lieu d'à chaque actualisation de la source. La différence est tout le produit : l'un est un signal, l'autre est du bruit que les gens éteignent dans la journée.

Il existe une application native basée sur les mêmes données, et elle communique avec une API d'application plutôt qu'avec les pages web. Un point de terminaison de santé à part répond au registre de flotte, car un contrôle de vivacité ne doit pas être plus coûteux que le travail qu'il vérifie.

10Trois langues, y compris le widget

La carte parle ukrainien, anglais et russe, tout comme la référence API, les pages de compte et le widget. Une nouvelle chaîne d'interface est ajoutée aux trois en même temps et un contrôle compte les éléments manquants : le compte doit être zéro. Les interfaces à moitié traduites ne s'annoncent pas — elles montrent discrètement une langue à l'intérieur d'une autre et semblent correctes à ceux qui les ont écrites.

Les noms de région sont une autre histoire : ils proviennent des sources dans leur propre orthographe, donc la carte garde un dictionnaire à elle plutôt que de faire confiance à ce qui est arrivé dans le flux.

11Lire des sources sans montrer votre adresse

Tout ce que les collecteurs récupèrent passe par un proxy SOCKS5, y compris le protocole de messagerie utilisé pour les canaux fermés — le proxyage se fait là en code, sans dépendance supplémentaire. L'adresse du serveur n'atteint jamais une source, et une source qui décide de bloquer quelqu'un bloque le proxy, pas la machine qui sert la carte.

Le limiteur de taux se trouve devant l'API pour la même raison à l'envers : un point de terminaison public avec des données en direct attire les scrapers, et une limite par clé par minute est ce qui maintient un service public utilisable pour les personnes pour lesquelles il a été écrit.

12Pile technologique

  • PHP 8.3 sans cadre : un petit routeur, des points de terminaison et des rendus ;
  • Travailleurs Python sous le superviseur système — un sur la bibliothèque standard seule, un parlant le protocole de messagerie ;
  • SQLite, quatre fichiers séparés, chacun avec sa propre raison d'exister ;
  • Leafletpour la carte, des actifs hachés, un widget avec des tailles fixes ;
  • push web avec état par région, une application native sur les mêmes données ;
  • sortie SOCKS5 pour chaque demande sortante, limites de taux par clé devant l'API.

13Le résultat

Une carte qui répond en quelques secondes et continue de répondre lorsque l'une de ses cinq sources s'arrête. Des données que d'autres sites peuvent utiliser : une API ouverte avec des clés et des tarifs, et un widget en trois langues et deux thèmes. Des notifications qui se déclenchent à la limite d'un événement plutôt que sur chaque sondage. Une application native sur les mêmes données, et un panneau de contrôle où les clés sont émises et les états sont réinitialisés.

14Leçons à retenir

Trois choses que nous emporterions dans tout projet avec des données en direct.Séparez le collecteur de la page: un site web qui récupère une source pendant qu'un visiteur attend est un site qui tombe en panne chaque fois que la source est indisponible.Donnez à chaque bloc sa propre horloge et son propre horodatage: un seul intervalle est incorrect dans les deux sens, et un redessin silencieux cache l'obsolescence.Dites quand vous ne savez pas: un bloc vide qui l'admet vaut plus qu'une carte au look calme avec les données d'hier.

Et une leçon produit : au moment où les données peuvent être intégrées ailleurs, le widget devient le produit. Il a besoin de tailles fixes, de sa propre politique de cadre et de traductions — le même soin que la page principale, pas un reste de celle-ci.

Si vous avez des données en direct et avez besoin d'une carte, d'une API et d'un widget que d'autres sites peuvent utiliser, c'est le type de travail que nous faisons de bout en bout.