javascript

История о том, как ТехВилл сделал первый в России offline‑first PWA для курьерской доставки

  • четверг, 4 декабря 2025 г. в 00:00:05
https://habr.com/ru/companies/vkusvill/articles/972846/

Я, Алексей Борискин из команды ТехВилла, рассказываю, как мы сделали первый в России offline-first PWA для курьеров-партнеров. Теперь никакой зависимости от интернета — ваши заказы закрываются своевременно, и сотни курьеров-партнёров работают спокойно даже при полном отсутствии связи.Подробнее об этом проекте и других технических деталях — в моём канале: https://t.me/dostavka_bagov.

Десятое сентября, 20:14. Нижегородская «Ласточка». Уже одетый, с рюкзаком, стою в проходе. Пытаюсь скинуть сестре мем — фото не отправляется. Сообщение тоже не отправляется. До меня начинает доходить.

Двенадцатое сентября, 15:05. Приехал на владимирский даркстор. Полюбовался бегающими курьерами-партнерами, попытался заговорить с кем-то в курилке. Затем вышел Денис, куратор. Спрашиваю у него, как живётся, как закрываются заказы, как ребята в дарке себя чувствуют, какие терминалы работают. Получается очень рваная беседа, так как Денису постоянно приходится отвлекаться на телефон: ему звонят курьеры-партнеры и просят закрыть заказ через 1С-админку. Их в смене двое кураторов, потому что одному с такой нагрузкой не справиться. Ночью заказов меньше — закрывать заказы помогает горячая линия.

Раньше тоже бывали проблемы с интернетом. Железобетонные конструкции в целом сильно против идеи пропускать сквозь себя электромагнитные волны. А если речь ещё и про лифт? А подъезды без окон? Вот и вот. Изредка случалось и так, что дом стоит за пригорком от вышки связи. Например, на улице Голубые Дали в Адлере никогда не работала связь у одного из операторов — я жил там четыре года и знаю, о чём говорю. Не могу же я рекомендовать курьеру купить сим-карту другого оператора.

А не так давно мы столкнулись с новым кейсом: сигнал стабильный, хороший, 4G LTE. Вот только доступа к серверам совсем нет. Наше мобильное приложение тоже считало, что интернет есть, и даже не выбрасывало курьеров-партнеров в «офлайн-режим». Для закрытия заказа неизбежно приходилось звонить на главную линию.

Шестнадцатого сентября я вернулся в рабочий ритм и создал новую задачу. Нам пришлось переписать систему определения сети таким образом, чтобы нативные данные о качестве покрытия никак не влияли на синхронизацию.

Впрочем, придётся вернуться во времена ещё более ранние. На проект я приходил, пленённый идеей сделать полностью независимое от интернета прогрессивное веб-приложение. Этакое детище Виктора Франкенштейна — мобильное приложение, которое на самом деле веб-страничка, но не просто веб-страничка, а с кешированием, локальным хранилищем, огромным по меркам вебки функционалом и вообще вот «почти-почти» настоящее приложение, но только с кроссплатформенностью.

Вообще, у нашего приложения был офлайн-режим и задолго до меня. Но зачем делать offline-first для приложения доставки? Курьеру-партнеру неизбежно будет нужен интернет, верно? Нужно же брать заказы, нужно отслеживать маршруты, нужно закрывать заказы, нужно принимать оплату по терминалу или QR-коду. Основная проблема офлайна была такова: «Я как курьер, закрывший заказ в подъезде без интернета, хочу, чтобы по выходе на улицу у меня отработала очередь закрытия заказов, чтобы сервер получил данные о закрытых заказах».

Под Новый год я спроектировал абсолютно бесполезную фичу — возможность закрывать заказы с оплатой по терминалу в офлайне. Казалось бы, зачем? Если на устройстве нет интернета, вряд ли интернет будет на терминале. После Нового года моя доработка нырнула в глубокий бэклог — не до неё было, и вообще особых поползновений по офлайну не виделось.

Позже стало ясно, что интернет будет временами отключаться — и не только в подъезде или лифте. И это никак не должно влиять на закрытие заказов. Количество просроченных заказов за три дня было таким, что меня достали из других задач, подробно расспросили, что я думаю на этот счёт, «и, кстати, что там у нас с терминалами». Важно отметить, что заказы привозились вовремя. Но из-за того, что отображение включало только серверное время, курьеры-партнеры сильно нервничали, кураторы ругались, бизнес видел очень сильно искажённые данные.

Generated image 1
Generated image 1

Получив зелёный свет на исполнение мечты, я пошёл выносить мозг моим любимым фронтендерам. Называть их так уже, наверное, даже некорректно, ибо они по самые плечи в мобильной разработке, проблемы решают далёкие от тех, что мы можем увидеть в мемах про фронтенд. Мы плотно проанализировали, что у нас есть, наметили план: что мы можем сделать, а где физику не обмануть. Так у нас появилось более развитое локальное хранилище, мы добавили новые способы закрытия заказов (пока ещё бесполезные — дальше расскажу, как это зароляло). По сути, это уже стало напоминать offline-first: мы храним данные локально, синхронизируемся при возможности. Но исходили из того, что максимум минут через пять интернет у курьера-партнера появится.

Почти всё лето я занимался большим-пребольшим эпиком — как через всю систему, для всего бизнеса, протащить реальное время закрытия заказа. Чтобы и курьер-партнер, и куратор, и помощник доставки видели, когда именно закрылся заказ. Как сделать так, чтобы курьерские вознаграждения учитывали это время, пуши клиентские тоже приходили вовремя (а не вовремя не приходили), а курьерский рейтинг не страдал от ненастоящих просрочек?

К концу лета всё было в проде. В основном это бэкендерские штучки — здесь неинтересно. Кафка-шмафка, не мне вам рассказывать. И вот я приехал в родной город. И прямо на перроне, когда не смог сестре отправить сообщение, понял, что всё это я делал, по сути, зря. Как у курьера включится мой лакомый офлайн-режим, если iOS бодро мне рассказывает про LTE?

И, стоя рядом с Денисом, я слушал душераздирающую историю новой сложной работы, понимая, что столько моей работы никак, НИКАК, не помогло ни реальным курьерам-партнерам, ни реальному Денису. Двенадцатое сентября, день моего рождения, 15:45.

Второе ноября, 13:08. Приезжаю снова на владимирский даркстор. Мы сделали новое определение сети, переработали кучу багов, добавили Background Task (напомню, мы работаем с весьма спорным JS-фреймворком Ionic), приоритезацию запросов, нафеячили слоистую архитектуру, но по-прежнему не показываем курьерам-партнерам, что какие-то процессы происходят в фоне. Я даже раскатал новый функционал на владимирских пользователей, чтобы на месте спросить, как это работает.

На этот раз я уже куда смелее зашёл на дарк, представился, заговорил сам с куратором. Его зовут Александр, и с первых же секунд он врывается в беседу с железобетонным: «У вас ничего не работает». 10–12 заказов в день возвращаются на вкладку «МОИ», не закрываются как нужно. Сидим, разговариваем дальше, он накидывает очень крутых идей, что ещё можно сделать, в чём-то попадает на 100% в наши планы, а в чём-то открывает мне глаза на реальные проблемы. Но в какой-то момент разговора я понимаю, что он больше не на телефоне.

– Саш, а ты больше не закрываешь заказы сам через админку?
– О, это было худшее время в истории. Три месяца было тяжело,а потом заработал офлайн — и всё, теперь курьеры сами закрывают. Где-то с конца сентября живём спокойно.
– Сможешь после праздников мне написать, сколько заказов в «МОИ» вернулись у курьеров?
– Конечно, не вопрос.

Вы бы знали, какое это приятное ощущение, невзначай услышать, что твоя работа кого-то спасла. Что результат твоей работы — это переход из точки «все заказы через звонок» в точку «дюжина заказов через звонок». Что ты спас кому-то сотни часов работы и тысячи нервных клеток.

Шестое ноября, 15:18. Пишу Саше вопрос, о котором условились раньше: сколько заказов не удалось курьерам закрыть самим за ноябрьские праздники. В ответ: «Пока не было больше таких».

Видимо, у меня всё-таки получилось. Обстоятельства сложились так, что вместо бесполезной инженерной мульки мы сделали нечто поистине великое. Наша команда сделала единственное в России работающее offline-first PWA для курьерской службы.

Сейчас курьер-партнер ВкусВилла уверенно идёт к подъезду, у него куча информации на карточке заказа, он может до вас дозвониться. Но самое главное — ОН МОЖЕТ ЗАКРЫТЬ ЗАКАЗ.


Он может закрыть заказ, если вы хотите оплатить его наличными, терминалом, QR-кодом — любым удобным для вас способом. И, конечно, он может закрыть заказ, заранее вами предоплаченный. А куратор, бизнес и вы как покупатель получаете максимально прозрачную информацию об этом событии.