Client Personal Demo (Open Source)
Role Solo Creator / Architect
Period Aug 2026
Stack
Go chi pgx/v5 PostgreSQL PostGIS JWT Docker Compose
geopulse — бекенд GPS fleet-tracking preview

geopulse — бекенд GPS fleet-tracking

Огляд

Незалежний demo-проєкт: REST API на Go для GPS fleet-tracking — техніка, кругові геозони, прийом позицій та детекція enter/exit подій на PostGIS. Моделює патерн, що стоїть за telematics-інтеграціями автопарків: трекер (або платформа на кшталт Traccar, що ретранслює від нього) шле позиції пінгами, і бекенд має перетворити цей сирий потік на достовірні події “техніка увійшла/вийшла із зони X”.

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


Справжня складна задача

Наївна реакція на кожен пінг — “чи ми зараз всередині геозони X? запалити подію” — дає два реальні баги: ретрансльований пінг повторно запалює “enter” для техніки, яка вже годину припаркована всередині зони, а пінг не по порядку (затриманий мережевим ретраєм) може змусити техніку, що вже покинула зону, здаватись такою, що знову в неї увійшла — бо координати застарілого пінга так кажуть. Обидва — задокументовані, реальні режими відмов telematics-систем — другий саме те “хибне geofence-спрацювання через затриману геодату”, описане в кейсі ivr-elevenlabs, з іншого боку того самого класу багу.


Архітектура

Конвеєр geopulse: позиція → подія

Кожен пінг проходить одну транзакцію: advisory-lock техніки → вставка-або-ігнор позиції → відхилення, якщо не по порядку → перевірка containment ST_DWithin для кожної геозони → чиста функція рішення → коміт того, що вийшло.


Ключові інженерні рішення

Рішення Чому
positions.UNIQUE(vehicle_id, recorded_at) + ON CONFLICT DO NOTHING Точні ретрансляції поглинаються на рівні БД — жодного дубльованого рядка, жодного повторного оцінювання
Перевірка “не по порядку” всередині тієї самої транзакції, що й вставка Пінг старіший за поточну останню позицію техніки зберігається в історії, але ніколи не рухає стан геозони назад у часі
pg_advisory_xact_lock(vehicle_id), утримуваний на всю транзакцію прийому-й-оцінки, не лише вставку Два одночасні пінги для тієї самої техніки не можуть обидва прочитати той самий “поточний стан” і незалежно вирішити запалити перехід — пінги для різної техніки все ще йдуть повністю паралельно, бо ключ блокування — per-vehicle
NextEventType винесена як чиста функція “зараз всередині?” + “який був останній тип події?” Жодного I/O, повністю юніт-тестована — включно з тестом послідовності, що симулює техніку на межі геозони через кілька пінгів, точний сценарій, що спричиняє флепінг enter/exit без відстеження останнього відомого стану
Кругові геозони (центр + радіус), не полігони Покриває типовий реальний випадок — депо, радіус доставки — простішим PostGIS-запитом (ST_DWithin), ніж containment полігонів, не жертвуючи справжньою складною частиною (гарантіями конкурентності/порядку)

Результати

  • Повний REST API: JWT-авторизація, CRUD техніки/геозон, ендпоінт прийому позицій, захищений X-Webhook-Secret (machine-to-machine, не дія диспетчера)
  • Рішення enter/exit чисте й повністю юніт-тестоване — включно з тестом на відсутність флепінгу — без потреби в БД для go test ./...
  • Перевірено наскрізно через docker compose up (образ postgis/postgis): міграції застосовуються, повна послідовність enter → все ще всередині → exit дає рівно 2 події (не одну на пінг), точний дубль-пінг поглинається без нових подій, пінг не по порядку зберігається, але інертний
  • Гарантія конкурентності підтверджена проти прямого стану БД: сплеск конкурентних/швидких пінгів у вже “всередині”-стан техніки дав нуль зайвих подій — 5 рядків geofence_events за всю тестову сесію (enter/exit/enter/exit/enter), точно відповідаючи реальній історії in/out техніки, попри значно більше 5 надісланих пінгів позицій

Код: github.com/valpere/geopulse


Стек

Go · chi (router) · pgx/v5 (без ORM) · golang-jwt · bcrypt · PostgreSQL + PostGIS (geography, ST_DWithin, pg_advisory_xact_lock) · Docker Compose · testify