Живі дані · суспільний сервіс

Карта тривог — живі дані, які вбудовують до себе

Карта повітряних тривог, де сторінка — лише частина продукту. Тривоги, рухомі цілі, лінія фронту та термоточки надходять із п’яти незалежних джерел, оновлюються кожен за своїм годинником — 15, 10 і 20 секунд — і виходять назовні відкритим JSON-API та віджетом, який чужі сайти ставлять до себе в рамку.

Категорія
Живі дані · суспільний сервіс
Оцінка вартості
від €20 000
Оновлення
тривоги 15 с · цілі 10 с · стрічка 20 с
Джерела
п’ять, незалежних одне від одного
Стек
PHP 8.3, воркери на Python, SQLite, Leaflet
map.megainet.art
Alerts Map
Головна сторінка проєкту — map.megainet.art

01Про проєкт

Карта тривог показує, де зараз повітряна тривога: по областях і по громадах, з рухом цілей на карті, лінією фронту, термоточками із супутників і стрічкою моніторингових каналів унизу. Її читають ті, кому відповідь потрібна за секунди, і читають з телефона, вночі, на поганому мобільному інтернеті.

При цьому сторінка — лише частина продукту. Ті самі дані виходять назовні відкритим JSON-API з ключами та лімітами і віджетом, який інші сайти ставлять до себе в рамку. Ми спроєктували й зробили все: збирачі, зберігання, API, карту та віджет.

02Контекст і проблема

Даних, які відповідають на питання «чи є тривога тут», не існує в одному місці. Офіційні тривоги надходять по областях. Локальні тривоги громад — з іншого сервісу. Де цілі, словами пишуть моніторингові канали. Лінію фронту публікує картографічний проєкт. Пожежі бачать супутники. П’ять джерел, п’ять форматів, п’ять різних уявлень про те, що таке «зараз».

Друга проблема — мовчання. Будь-яке з джерел може стати: канал замовк, API почав відвалюватися за таймаутом, — і чесна поведінка тут сказати про це, а не продовжувати малювати вчорашню картину. Карта, що виглядає спокійною, бо в неї помер джерело, гірша за відсутність карти.

03Завдання проєкту

  • одна картина, зібрана з п’яти незалежних джерел, у кожного свій годинник оновлення;
  • відповідь за секунди з телефона, на слабкому зв’язку, вночі;
  • дані, які можуть виходити із сайту: відкритий API з ключами, лімітами й тарифами, і віджет для вбудовування;
  • три мови, бо аудиторія не лише місцева;
  • джерело, що замовкло, має бути видно як мовчання, а не як спокій;
  • адреса самого сервера не має доходити до джерел, які він читає.

04П’ять джерел — одна картина

  • Офіційні тривоги по областях — основа карти;
  • локальні тривоги громад і районів, з окремого сервісу;
  • моніторингові канали в Telegram — читаються і через публічні прев’ю, і, для закритих каналів, самим протоколом месенджера;
  • лінія фронту — від картографічного проєкту, який її публікує;
  • термоточки із супутників NASA — пожежі, видимі з орбіти.

Збирачі працюють двома довгоживучими воркерами під системним супервізором, кожен перезапускається сам по собі, і пишуть у локальне сховище. Сайт ніколи не ходить до джерела напряму: він читає те, що збирачі вже записали, — тому повільне джерело робить карту старішою, а не недоступною.

05Чотири файли замість однієї бази

Дані лежать у чотирьох окремих файлах SQLite: журнал тривог, підписки на пуші та їхній стан по регіонах, події карти зі стрічкою, ключі API з лічильниками лімітів. Спільної бази немає навмисно — відмова одного файлу не має забирати решту. Недоступні підписки — карта однаково малюється; зайнятий склад ключів — сторінка однаково відповідає.

У ті самі файли пише загальна панель керування групи проєктів — випуск ключа, скидання стану тривоги, — тому кожне з’єднання відкривається з очікуванням зайнятості. За замовчуванням SQLite на зайнятій базі здається миттєво, і це «миттєво» тут означало б сторінку з помилкою в момент, коли воркер лише дописував рядок.

06Троє годинників на одній сторінці

Різні дані старіють з різною швидкістю — і оновлюються з різною: тривоги раз на 15 секунд, рухомі цілі раз на 10, стрічка раз на 20. Один спільний інтервал був би неправильним одразу в обидва боки: надто повільним для цілей, марнотратним для стрічки й зайвим запитом кожні кілька секунд для тисяч відкритих вкладок.

У кожного блока є і своє «оновлено». Сторінка, що мовчки перемальовується, привчає довіряти їй саме тоді, коли довіряти не варто; зупинена позначка часу — найшвидший спосіб сказати «ця частина застаріла».

07Відкритий API з ключами й тарифами

Карта публікує те, що знає: поточні тривоги, події, аналітику з тепловою картою «область × кошик часу», ритм доби, типи цілей і напрямки. Анонім отримує скромний ліміт на хвилину; ключ піднімає його, а тарифи ростуть сходинками для тих, хто на цьому будує.

Ключі випускаються із загальної панелі керування й ніколи не набираються руками, а витрата рахується за ключем і за днями. Одна точка навмисно закрита для всіх, крім власника ключа, — та, що розповідає ключу його тариф, ліміт і витрату. Решта відкрита, бо суспільний сервіс, що ховає свої дані, — суспільний лише наполовину.

08Віджет, що живе на чужих сайтах

Віджет — та частина продукту, що йде з дому. Два фіксовані розміри — смуга стану і квадратна панель, три мови, дві теми й політика вкладення в рамку, написана спеціально так, щоб вбудовування було дозволено тут і ніде більше на сайті: карту й віджет у рамку брати можна, кабінет і сторінки підтримки — ні.

Раз він живе в рамці, у віджета немає власних кук і він не обирає покоління інтерфейсу: виглядає однаково в усіх. Це рішення, а не обмеження — віджет, що малюється по-різному залежно від колишніх виборів відвідувача, неможливо було б підтримувати на чужій сторінці.

09Пуші, що знають ваш регіон

Підписка прив’язана до регіону, а стан кожного регіону зберігається поряд із підписками. Саме це робить сповіщення подією на межі — коли тривога у вашій області почалася чи закінчилася, — а не на кожне оновлення джерела. У цій різниці весь продукт: одне — сигнал, інше — шум, який вимикають першого ж дня.

Поверх тих самих даних працює нативний застосунок, і ходить він у своє app-API, а не по сторінках сайту. Окрема адреса живості відповідає реєстру застосунків: перевірка живості не має коштувати дорожче за роботу, яку перевіряє.

10Три мови, включно з віджетом

Карта говорить українською, англійською та російською — і так само говорять довідник API, сторінки кабінету й віджет. Новий рядок інтерфейсу заводиться одразу трьома мовами, а перевірка рахує відсутні: їх має бути нуль. Наполовину перекладені інтерфейси не повідомляють про себе — вони тихо показують одну мову всередині іншої й виглядають нормально для того, хто їх писав.

Назви регіонів — окрема історія: вони надходять із джерел у власному написанні, тому карта тримає власний словник, а не довіряє тому, що приїхало в стрічці.

11Читати джерела, не показуючи свою адресу

Усе, що забирають збирачі, іде через SOCKS5-проксі — включно з протоколом месенджера для закритих каналів, де проксіювання зроблено кодом, без зайвої залежності. Адреса самого сервера не доходить до джерела, а джерело, яке вирішило когось заблокувати, блокує проксі, а не машину, що віддає карту.

Обмежувач частоти стоїть перед API з тієї самої причини, тільки навпаки: публічна точка з живими даними притягує скрейперів, і ліміт на ключ за хвилину — це те, що лишає суспільний сервіс придатним для тих, заради кого він написаний.

12Технології

  • PHP 8.3 без фреймворка: маленький роутер, точки API та рендери;
  • воркери на Python під системним супервізором — один лише на стандартній бібліотеці, другий говорить протоколом месенджера;
  • SQLite, чотири окремі файли, у кожного своя причина існувати;
  • Leaflet для карти, асети з хешем в імені, віджет фіксованих розмірів;
  • вебпуші зі станом по регіонах, нативний застосунок на тих самих даних;
  • SOCKS5 назовні для кожного вихідного запиту, ліміти на ключ перед API.

13Результат

Карта, що відповідає за секунди і продовжує відповідати, коли одне з п’яти джерел стало. Дані, які можна забрати до себе: відкритий API з ключами й тарифами та віджет трьома мовами у двох темах. Сповіщення, що спрацьовують на межі події, а не на кожне опитування. Нативний застосунок на тих самих даних і панель, з якої випускають ключі та скидають стани.

14Висновки

Три речі, які ми понесемо в будь-який проєкт із живими даними. Відокремлювати збирач від сторінки: сайт, що йде до джерела, поки відвідувач чекає, — це сайт, який падає разом із джерелом. Давати кожному блоку свій годинник і свою позначку часу: один інтервал неправильний одразу в обидва боки, а мовчазне перемальовування ховає застарівання. Казати, коли не знаєш: порожній блок, який у цьому зізнається, вартий більше за спокійну на вигляд карту з учорашніми даними.

І один продуктовий висновок: щойно дані можна вбудувати до себе, продуктом стає віджет. Йому потрібні фіксовані розміри, власна політика рамки та переклади — та сама турбота, що й головній сторінці, а не залишок від неї.

Якщо у вас є живі дані й потрібні карта, API та віджет, який зможуть узяти інші сайти, — це робота, яку ми робимо цілком.

На які запити відповідає ця сторінка

розробка карти повітряних тривог, розробка карти в реальному часі, дашборд живих даних розробка, віджет для вбудовування на чужі сайти, публічний json api з ключами, ліміти api тарифи, sqlite для живих даних, воркери на python systemd, парсер телеграм-каналів, термоточки nasa на карті, розробка застосунку на leaflet, вебпуші по регіонах, нативний застосунок для вебсервісу, віджет карти в iframe, як зробити сервіс живої карти, розробка відкритого api даних, map megainet, карта тривог, де зараз тривога.