Разработка мобильного приложения для вызова мастера на дом (сантехник, электрик)
Задача «соединить клиента с мастером за 3 минуты» на поверхности выглядит просто: форма заявки, список исполнителей, кнопка «вызвать». На практике — это геолокационный матчинг в реальном времени, очереди задач с приоритетами, двусторонние уведомления и проблема «холодного старта» с нулевым числом мастеров в базе.
Что реально ломается при разработке
Главная боль — живая карта с мастерами. Если каждый мастер шлёт location каждые 3 секунды через REST, при 50 одновременных исполнителях сервер получает 1000 запросов в минуту только на обновление позиции. Решение: WebSocket-канал (на Flutter — пакет web_socket_channel 2.x) плюс серверный throttle. Клиент получает дельта-обновления, а не полный список. На карте — flutter_map с TileLayer от OpenStreetMap или Google Maps SDK, в зависимости от бюджета лицензии.
Вторая проблема — статусная машина заявки. Типичный граф: created → assigned → accepted → in_progress → completed | cancelled. Если не зафиксировать переходы на уровне бэкенда и не синхронизировать их с локальным состоянием (Riverpod StateNotifier или BLoC), клиент видит «мастер едет» даже после отмены — потому что push-уведомление пришло позже, чем пользователь обновил экран вручную. Решаем через FCM data messages вместо notification messages: приложение само решает, что показать, исходя из текущего состояния.
Ещё момент: рейтинги и отзывы нельзя открывать до завершения заявки. Если не добавить серверную проверку статуса перед записью отзыва, мастера получают оценки за несостоявшиеся визиты — видел такое в трёх разных проектах.
Стек и архитектура
Flutter + Dart как основной выбор для cross-platform: один кодовой базой закрываем iOS и Android, при этом нативные вызовы через MethodChannel — для фоновой геолокации (background_locator_2) и обработки входящих звонков через VOIP (на iOS — CallKit, на Android — ConnectionService). Встроенный чат — через Firebase Realtime Database или собственный WebSocket, медиафайлы (фото неисправности) — через Firebase Storage или S3 с presigned URLs.
Архитектурно: Clean Architecture со слоями domain / data / presentation. Репозитории изолируют логику от источника данных — легко менять Firebase на собственный API без переписывания UI. GetIt как service locator для DI, Dio с interceptors для REST, hive для кэша заявок офлайн.
Ключевые интеграции:
- Google Maps SDK / Yandex MapKit — маршрут мастера до клиента
- Firebase Cloud Messaging — уведомления о смене статуса
- Stripe / CloudPayments / ЮKassa — оплата после выполнения
- Twilio или Vonage — маскировка номеров при звонке
- OneSignal — маркетинговые пуши и retention-кампании
Отдельно про онбординг мастеров
Верификация исполнителя — не просто форма с полями. Нужна загрузка документов (паспорт, лицензия), ручная модерация или интеграция с сервисом проверки (например, российский «Контур.Фокус» для ИП). На Flutter: image_picker + dio multipart upload, статус проверки через polling или WebSocket. Пока аккаунт не верифицирован — флаг is_verified: false блокирует приём заявок на уровне API middleware.
Процесс работы
- Аудит требований — выясняем: монетизация (комиссия с заявки или подписка мастера), geography (один город или федеральная сеть), нужен ли веб-кабинет диспетчера
- Проектирование — ERD, State Machine диаграмма заявки, API контракты (OpenAPI 3.0)
- UI/UX — Figma-прототип, отдельные флоу для клиента и мастера
- Разработка — спринты по 2 недели, CI/CD через Fastlane + GitHub Actions
-
Тестирование — интеграционные тесты на
flutter_test, ручное QA на реальных устройствах - Публикация — App Store + Google Play, настройка ASO, скриншоты и описания
Сроки
MVP (клиент + мастер, базовый матчинг, оплата, пуши): 10–16 недель. Полная платформа с кабинетом диспетчера, аналитикой и верификацией: 20–28 недель. Стоимость рассчитывается после анализа ТЗ — слишком многое зависит от количества категорий мастеров и географии охвата.
Типичные ошибки, которые стоят дорого
- Реализовать геолокацию без
background_locator— мастер «пропадает» с карты, когда сворачивает приложение на Android 12+ из-за Doze Mode - Хранить токены FCM в локальной БД без TTL — через 3 месяца 30% токенов протухают, пуши перестают доставляться
- Не разделять FCM-каналы для клиента и мастера в одном приложении — оба получают чужие уведомления при смене роли







