Реализация Real-Time трекинга курьера/заказа на сайте

Реализация Real-Time трекинга курьера/заказа на сайте

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Реализация Real-Time трекинга курьера/заказа на сайте
Средний
~5 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1422
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    984
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1250
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    986
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    1000

Реализация Real-Time трекинга курьера/заказа на сайте

Пользователь оформил заказ и ждёт курьера. Страница «Мои заказы» с полем «статус: в пути» — это уже прошлый век. Современный стандарт — карта с живым маркером курьера и счётчиком «прибудет через N минут». Технически это связка трёх компонентов: мобильное приложение/устройство курьера, бэкенд-приложение, клиентский браузер. Мы построили такие системы для 30+ проектов доставки — от локальных сервисов до федеральных сетей. Свяжитесь с нами для расчёта вашего проекта.

Почему polling базы — плохой выбор?

Казалось бы, можно опрашивать сервер каждые 5 секунд: GET /api/order/status. Но это создаёт лишнюю нагрузку на сервер, увеличивает TTFB для остальных запросов и не даёт мгновенного обновления. WebSocket в разы эффективнее: событие приходит сразу, без задержки опроса. Однако простая реализация WebSocket без авторизации открывает доступ к чужим заказам. Мы используем PrivateChannel Laravel Broadcasting с проверкой прав.

Архитектура потока данных

[Устройство курьера] GPS → POST /api/courier/location каждые 3–5с ↓ [Backend] Сохранить в Redis (TTL 60s) Publish в Redis Pub/Sub канал order:{id} ↓ [WebSocket сервер (Laravel Reverb / Pusher)] Broadcast event LocationUpdated ↓ [Браузер клиента] Обновить маркер на карте 

Геопозиции не хранятся в PostgreSQL при каждом обновлении — это 720 записей в час на одного курьера. В базу пишем только при смене статуса заказа и финальную позицию при завершении. Текущая позиция — в Redis с TTL.

Почему Redis — оптимальное хранилище для геоданных?

Redis обеспечивает низкую задержку записи и чтения (субмиллисекунды) и автоматическое удаление устаревших данных через TTL. Для трекинга это критично: позиция курьера актуальна лишь короткое время. Постоянная запись в PostgreSQL привела бы к 720 записям в час на одного курьера — неоправданная нагрузка на базу. С Redis мы экономим ресурсы и ускоряем чтение: получить текущую позицию можно за один запрос к in-memory хранилищу. Экономия на серверной инфраструктуре может достигать 40% за счёт отказа от постоянного polling.

Пример конфигурации WebSocket-сервера с Laravel Reverb Для продакшена рекомендуется использовать Reverb с горизонтальным масштабированием через Redis. Настройка сводится к установке пакета, публикации конфига и запуску воркера. Подробнее — в официальной документации Laravel.

Таблица заказов

CREATE TABLE delivery_orders ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL REFERENCES users(id), courier_id BIGINT REFERENCES couriers(id), status VARCHAR(50) NOT NULL DEFAULT 'pending', -- pending | assigned | picked_up | in_transit | delivered | failed address_lat DECIMAL(10, 8), address_lng DECIMAL(11, 8), address_text VARCHAR(500), estimated_at TIMESTAMP, delivered_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT NOW() ); CREATE TABLE delivery_status_log ( id BIGSERIAL PRIMARY KEY, order_id BIGINT NOT NULL REFERENCES delivery_orders(id), status VARCHAR(50) NOT NULL, lat DECIMAL(10, 8), lng DECIMAL(11, 8), note TEXT, created_at TIMESTAMP NOT NULL DEFAULT NOW() ); 

API курьера: обновление позиции и broadcast

class CourierLocationController extends Controller { public function update(Request $request, DeliveryOrder $order): JsonResponse { $data = $request->validate([ 'lat' => 'required|numeric|between:-90,90', 'lng' => 'required|numeric|between:-180,180', ]); $key = "courier_location:{$order->courier_id}"; Redis::setex($key, 60, json_encode([ 'lat' => $data['lat'], 'lng' => $data['lng'], 'order_id' => $order->id, 'ts' => now()->timestamp, ])); broadcast(new CourierLocationUpdated( orderId: $order->id, lat: $data['lat'], lng: $data['lng'], eta: $this->calculateEta($order, $data['lat'], $data['lng']), )); return response()->json(['ok' => true]); } private function calculateEta(DeliveryOrder $order, float $lat, float $lng): ?int { $distanceKm = $this->haversineKm($lat, $lng, $order->address_lat, $order->address_lng); return (int) round($distanceKm / 30 * 60); } } // CourierLocationUpdated event class CourierLocationUpdated implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct( public readonly int $orderId, public readonly float $lat, public readonly float $lng, public readonly ?int $eta, ) {} public function broadcastOn(): Channel { return new PrivateChannel("order.{$this->orderId}"); } public function broadcastWith(): array { return [ 'lat' => $this->lat, 'lng' => $this->lng, 'eta' => $this->eta, ]; } } 

Авторизация канала в routes/channels.php:

Broadcast::channel('order.{orderId}', function (User $user, int $orderId) { return $user->id === DeliveryOrder::find($orderId)?->user_id; }); 

Канал PrivateChannel гарантирует, что только владелец заказа получает координаты. Это обязательное требование безопасности.

Клиентская часть: карта и анимация маркера

Используем Mapbox для отображения карты. Альтернатива — Яндекс.Карты, предпочтительнее для СНГ.

import mapboxgl from 'mapbox-gl'; // ... инициализация карты Echo.private(`order.${orderId}`) .listen('CourierLocationUpdated', ({ lat, lng, eta }) => { animateMarker(courierMarker, courierMarker.getLngLat().toArray(), [lng, lat]); if (eta !== null) { document.getElementById('eta').textContent = eta < 2 ? 'Курьер уже рядом' : `Прибудет через ~${eta} мин`; } }); function animateMarker(marker, from, to, duration = 500) { const start = performance.now(); function step(now) { const t = Math.min((now - start) / duration, 1); const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; const lng = from[0] + (to[0] - from[0]) * ease; const lat = from[1] + (to[1] - from[1]) * ease; marker.setLngLat([lng, lat]); if (t < 1) requestAnimationFrame(step); } requestAnimationFrame(step); } 

Сравнение методов расчёта ETA

Метод Точность Время построения маршрута Зависимости
По прямой (Haversine) Низкая (игнорирует дороги) Мгновенно Нет
Routing API (OSRM) Высокая (учитывает дороги) 50–200 мс Внешний сервис
Google Directions API Очень высокая (трафик) 200–500 мс API-ключ

Сравнение подходов к real-time доставке

Подход Задержка обновлений Нагрузка на сервер Сложность реализации
Polling (HTTP каждые 5 с) 5 сек в среднем Высокая Низкая
WebSocket (постоянное соединение) Мгновенно Низкая Средняя
Server-Sent Events Мгновенно Низкая Средняя

Как настроить Private Channel за 5 шагов

  1. Установите Laravel Reverb или Pusher.
  2. Настройте broadcasting в config/broadcasting.php.
  3. Создайте Event, реализующий ShouldBroadcast.
  4. Определите PrivateChannel в routes/channels.php.
  5. Подпишитесь на канал на клиенте через Echo.

Что входит в результат

  • Аналитика: интеграция с мобильным приложением курьера, согласование протокола.
  • Проектирование: схема данных, WebSocket-архитектура, авторизация.
  • Реализация: бэкенд на Laravel с Redis, broadcast, карта на фронтенде.
  • Тестирование: нагрузочное тестирование WebSocket (1k+ одновременных подключений).
  • Документация: описание API, инструкция по деплою.
  • Поддержка: гарантия на код, обучение команды.

Сроки ориентировочно

  • Базовый трекинг (Redis + broadcast + карта): от 4 до 5 дней.
  • Авторизация Private Channel + логика доступа: от 1 дня.
  • ETA-расчёт по прямой (Haversine): от 0.5 дня.
  • ETA через Routing API: от 1 до 2 дней.
  • Анимация маркера + сглаживание пути: от 1 дня.
  • Push-уведомления при смене статуса: от 1 до 2 дней.
  • Административная панель диспетчера: от 3 до 4 дней.

Почему стоит заказать у нас

Мы реализовали real-time трекинг для 30+ проектов, включая крупные службы доставки. Гарантируем стабильную работу WebSocket-соединений при тысячах курьеров, соблюдение приватности каналов и плавную анимацию без рывков. Закажите оценку вашего проекта — предложим оптимальное решение.