Разработка мобильного приложения для CRM
CRM-приложение — не CRUD-обёртка над базой данных. Реальная система управления клиентами на мобильном устройстве требует офлайн-синхронизации, сложной ролевой модели, push-уведомлений о событиях воронки, интеграций с телефонией и почтой — и всё это должно работать быстро даже на устаревшем Android-устройстве в зоне с нестабильным 3G.
Ключевые технические задачи
Офлайн-первый подход и синхронизация
Менеджер по продажам в полях не может ждать загрузки данных клиента, пока ищет Wi-Fi. CRM-приложение обязано работать офлайн по умолчанию. Стандартный подход — локальная база SQLite с синхронизацией через конфликт-резолюцию на сервере.
На Flutter используем drift (бывший moor) как типизированный ORM поверх SQLite, и connectivity_plus для отслеживания состояния сети:
// Сохраняем действие локально и ставим в очередь синхронизации
Future<void> updateDealStage(String dealId, DealStage stage) async {
await localDb.updateDeal(dealId, stage: stage, syncStatus: SyncStatus.pending);
await syncQueue.enqueue(
SyncOperation(
type: OperationType.updateDeal,
payload: {'id': dealId, 'stage': stage.name},
createdAt: DateTime.now(),
),
);
// Триггерим синхронизацию, если есть сеть
if (await connectivity.checkConnectivity() != ConnectivityResult.none) {
syncService.flush();
}
}
Конфликты возникают, когда один контакт редактируют с разных устройств. Стратегия «последняя запись побеждает» ломает данные. Правильно: Last-Write-Wins на уровне поля, а не записи — с updated_at на каждое изменяемое поле, и вектор версий для критичных данных.
Ролевая модель и права доступа
CRM без ролей не существует: менеджер видит только своих клиентов, руководитель — весь отдел, администратор — всё. Ролевая модель должна быть реализована и на сервере (Row Level Security в PostgreSQL или middleware), и на клиенте — не для безопасности, а для UX: скрывать недоступные действия.
На iOS используем Keychain для хранения токена с привязкой к kSecAttrAccessibleWhenUnlockedThisDeviceOnly — токен не переходит на другое устройство при восстановлении из бэкапа, что критично для корпоративного CRM.
Интеграция с телефонией
Функция звонка прямо из карточки контакта — стандарт для мобильного CRM. На iOS используем CallKit для нативной интеграции: звонок через VoIP-провайдера (Twilio, Vonage) отображается как обычный входящий звонок с именем из CRM, пишется в историю звонков устройства.
// iOS CallKit провайдер
class CRMCallProvider: NSObject, CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// Подключаем Twilio Voice SDK
TwilioVoice.connect(with: connectOptions) { [weak self] call, error in
guard let call = call else { return }
self?.activeCall = call
action.fulfill()
// Логируем начало звонка в CRM
self?.crmService.logCallStarted(contactId: action.callUUID.uuidString)
}
}
}
На Android аналог — ConnectionService через TelecomManager.
Архитектура и стек
Для кроссплатформенного CRM-приложения Flutter — оптимальный выбор: один кодовой базе покрывает iOS и Android, что важно при постоянно меняющихся требованиях бизнеса. Архитектура: BLoC + Clean Architecture, слой репозиториев изолирует локальную базу и API.
| Слой | Технологии |
|---|---|
| UI | Flutter + Material 3 / Cupertino-адаптации |
| State management | flutter_bloc (BLoC pattern) |
| Локальная БД | drift (SQLite), Hive для кэша |
| Сеть | Dio + Retrofit-генерация, Interceptor для refresh token |
| Sync | WorkManager (Android) / BGTaskScheduler (iOS) |
| Push | Firebase Cloud Messaging + background fetch |
| Аналитика | Firebase Analytics, Crashlytics |
Для нативной iOS- или Android-разработки — SwiftUI + Combine / Jetpack Compose + ViewModel соответственно.
Работа с push-уведомлениями
CRM-события — назначенная встреча, новый лид, просроченная задача — требуют доставки push в background. На iOS UNUserNotificationCenter с content-available: 1 запускает приложение в фоне для обновления данных. Критичный момент: iOS даёт фоновому процессу не более 30 секунд, и слишком частые background fetches приводят к throttling системой.
Стратегия: push — только для уведомления о событии, тяжёлые данные подгружаются лениво при открытии нотификации.
Этапы работы
Аудит требований и проектирование data model → дизайн (если нет готового) → разработка API и мобильного клиента параллельно → интеграционное тестирование синхронизации с edge cases → тестирование на реальных устройствах с симуляцией потери сети → публикация в App Store / Google Play → поддержка.
Обязательный этап — нагрузочное тестирование синхронизации при большой базе (10 000+ контактов). На слабых Android-устройствах SQLite-операции с большим dataset без правильной пагинации и индексов вызывают ANR.
Сроки
MVP с базовым функционалом (контакты, сделки, задачи, офлайн): 8–12 недель. Полноценное приложение с телефонией, интеграциями (почта, календарь), расширенной аналитикой: 4–6 месяцев. Стоимость рассчитывается индивидуально после анализа требований.







