Платформа кэшбэка и лояльности

Платформа кэшбэка и лояльности
FlutterDartTypeScriptVuePHPPostgreSQLRubyFastlane

Обзор проекта

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

Бизнес-модель требует не одного приложения, а целого семейства: флагманского потребительского приложения, где покупатели находят участвующие магазины и отслеживают кэшбэк, отдельного приложения для мерчантов, чтобы магазины подключались и запускали собственные вознаграждения, и растущего каталога white-label приложений — каждое из них полностью брендированное, независимо публикуемое приложение кэшбэка для партнёрского бренда или розничной сети, и все они работают на одном продукте.

К моменту зрелости проекта экосистема включала 15+ работающих мобильных приложений. Инженерная задача состояла не в том, чтобы хорошо построить одно приложение, — а в том, чтобы создать единую кодовую базу, которая может стать любым числом брендированных приложений кэшбэка без линейного роста затрат на поддержку с каждым новым партнёром.

Мы отвечали за всю систему целиком: общий потребительский клиент, приложение для мерчантов, парк white-label приложений, движок правил кэшбэка и бэкенд-сервисы, а также внутренние админ-инструменты, которые превратили «запуск нового брендированного приложения» из многодневной инженерной задачи в форму самообслуживания.

Главный экран приложения с балансом кэшбэка и бонусом за приглашение

Главный экран приложения с балансом кэшбэка и бонусом за приглашение

Страница магазина со ставкой кэшбэка за покупку

Страница магазина со ставкой кэшбэка за покупку

Лента ваучеров и новостей магазинов

Лента ваучеров и новостей магазинов

Настройка отдельного white-label приложения

Настройка отдельного white-label приложения

Список white-label приложений в админке

Список white-label приложений в админке

Одна кодовая база, много приложений

Флагманское потребительское приложение и каждый white-label вариант работают на единой кодовой базе. Нет форков, нет веток под отдельные бренды и нет скопированных проектов, которые нужно держать в синхронизации. То, что различается между приложениями — брендинг, тема, идентичность бренда, фиче-флаги, конфигурация вознаграждений и метаданные для сторов, — выражено целиком через конфигурацию, которая живёт вне кода.

Мы построили клиент вокруг системы flavor-ов и конфигураций: единый бинарный «чертёж», который определяет идентичность бренда на этапе сборки из конфигурационного бандла конкретного приложения. Цвета, типографика, логотипы, сплэш-экраны, иконки приложений, идентификаторы бандлов и наборы включённых функций инжектируются для каждого flavor-а. Ошибка, исправленная один раз, или функция, выпущенная один раз, попадает во все приложения парка в следующем релизе — нет расхождений между брендами, которые нужно поддерживать.

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

Это и есть ключевой экономический рычаг проекта: предельная стоимость шестнадцатого приложения близка к нулю, потому что это тот же код, что и у первого, только с другой конфигурацией.

Нативная конфигурация сборки на Dart

Жизнеспособность парка white-label приложений зависит от нативной конфигурации сборки — настроек Android и iOS, которые действительно важны для сторов. Идентификаторы приложений и бандлов, отображаемые названия приложений, номера версий и сборок, настройка подписи, ресурсы иконок и сплэш-экранов, а также записи по каждому flavor-у в build.gradle и в проекте Xcode — всё это должно быть корректным для каждого отдельного приложения и каждой отдельной сборки.

Вместо того чтобы поддерживать это вручную, мы написали собственный инструментарий на Dart, который программно управляет конфигурацией сборки для Android и iOS. Получив конфигурационный бандл бренда, инструмент перезаписывает соответствующие записи в Gradle, манифесте, Info.plist и каталоге ресурсов под нужный flavor перед запуском сборки. Хранение этой логики на Dart означает, что она использует тот же источник истины, что и Flutter-клиент, и выполняется как полноценный шаг нашего процесса сборки — поэтому нативная конфигурация бренда генерируется детерминированно из его конфигурации и никогда не правится вручную.

Приложение для мерчантов

Офлайн-магазинам нужен был собственный инструмент — не урезанная версия потребительского приложения, а специально созданное приложение для управления программой вознаграждений и понимания своих клиентов. Из приложения для мерчантов владелец магазина за считанные минуты подключается к платформе, задаёт свои правила кэшбэка и скидок, подтверждает покупки клиентов для начисления кэшбэка и наконец видит, кто его клиенты: новые против вернувшихся, как часто они заходят и как работает каждая акция. Для многих из этих бизнесов это первый структурированный взгляд на свою клиентскую базу за всё время. Мы построили его на том же фундаменте Flutter и общей библиотеке компонентов, что и потребительские приложения, поэтому обновления дизайн-системы и платформенные исправления распространяются на обе аудитории, а специфичные для мерчантов сценарии живут в собственных модулях.

Настраиваемые правила кэшбэка и скидок

Сердце платформы — гибкий движок правил, который позволяет каждому магазину проектировать собственные вознаграждения без нашей помощи. Через приложение для мерчантов магазин составляет правила, такие как:

  • Кэшбэк за покупку — процент или фиксированная сумма, возвращаемая на баланс клиента за каждую подходящую покупку.
  • Бонус на день рождения — вознаграждение, автоматически начисляемое около дня рождения клиента, чтобы вернуть его в магазин.
  • Бонус за приглашение — реферальное вознаграждение, которое выплачивается, когда существующий клиент приглашает друга, тот присоединяется и совершает первую покупку.

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

Админ-интерфейс и автоматизированный сборочный конвейер

Самая заметная часть системы — внутренний админ-интерфейс. Подключение нового white-label бренда раньше было инженерной задачей: создать конфигурацию, зарегистрировать идентификаторы бандлов, сгенерировать ресурсы для подписи, настроить листинги в сторах и добавить новую цель в CI. Мы свели всё это в единое веб-приложение, которым менеджеры управляют без написания кода.

Менеджер заполняет форму — название бренда, тема, ресурсы, метаданные стора, набор функций — и система делает остальное:

Генерация конфигурации: Админ-интерфейс сохраняет конфигурацию и ресурсы нового бренда и формирует конфигурационный бандл для конкретного flavor-а, который потребляет Flutter-клиент.

Регистрация в конвейере: Цель нового приложения автоматически регистрируется в CI/CD конвейере. Сборочная система подхватывает новый flavor, запускает наш собственный инструментарий на Dart для применения нативной конфигурации Android и iOS и выпускает подписанные артефакты для обеих платформ.

Запуски в режиме самообслуживания: То, что раньше требовало участия разработчика для каждого нового бренда, стало повторяемым процессом на основе формы. Бизнес может масштабировать число опубликованных приложений, не масштабируя размер инженерной команды.

Автоматизация сборки и деплоя на Fastlane

Весь процесс сборки и релиза автоматизирован от начала до конца с помощью Fastlane — open-source инструментария для автоматизации сборки и развёртывания мобильных приложений. Мы используем его, чтобы стандартизировать каждый шаг, который иначе был бы ручным и подверженным ошибкам в масштабе 15+ приложений: управление подписью и provisioning-профилями, сборку и подпись бинарников iOS и Android, а также публикацию каждого приложения в App Store и Google Play вместе с метаданными и скриншотами.

Поскольку все приложения используют единую конфигурацию Fastlane, параметризованную по flavor-у, релиз всего парка — это единая повторяемая операция. Новый white-label бренд наследует ровно тот же проверенный путь деплоя, что и флагманское приложение, — без написания отдельных скриптов релиза.

Админ-интерфейс — это приложение на Vue, работающее поверх наших PHP-сервисов и хранилища данных PostgreSQL, с инструментами на Ruby и Fastlane, оркестрирующими автоматизацию сборки и релиза.

Бэкенд и сервисы

В основе каждого приложения лежит общий бэкенд, который ведёт реестр кэшбэка (ledger), движок правил, профили клиентов и конфигурацию по брендам. Единый набор сервисов обеспечивает работу всего парка приложений, а контекст бренда определяется для каждого запроса — поэтому клиент в любом white-label приложении, во флагманском приложении или магазин в приложении для мерчантов обращается к одному и тому же проверенному API, ограниченному его брендом. Реестр фиксирует каждое начисление и списание, поэтому балансы всегда поддаются аудиту, а профили клиентов дают каждому магазину то понимание своей аудитории, которого офлайн-рознице обычно не хватает.

Отложенный deep linking и бонус за приглашение

Фича, которую это разблокировало, — бонус за приглашение. Рефералы — это то, как растёт платформа: довольный клиент приглашает друга, тот нажимает на ссылку-приглашение, но почти никогда у него ещё не установлено приложение. С обычным deep link контекст приглашения терялся в момент, когда друг попадал в стор: он устанавливал приложение, открывал его, оказывался на обычном главном экране — и связь между пригласившим и приглашённым исчезала, а вместе с ней и бонус за приглашение, обещанный обеим сторонам. Самый вирусный момент в продукте был сломан на самом важном шаге. Мы починили его с помощью отложенного deep linking, чтобы приглашение переживало установку.

Поскольку весь парк использует одну кодовую базу, фича была построена один раз, и каждое брендированное приложение — флагман, приложение мерчанта и все white-label варианты — унаследовало её автоматически. Мы реализовали её первородными механизмами, а не сторонним сервисом: лёгкий iOS App Clip перехватывает ссылку-приглашение ещё до того, как существует полное приложение, и передаёт её через общий контейнер App Group, а Google Play Install Referrer API несёт полезную нагрузку на Android. Очередь отложенных ссылок удерживает приглашение до тех пор, пока приложение не готово, а новый клиент не зарегистрировался и не залогинился, — только тогда реферал атрибутируется и бонус за приглашение начисляется и пригласившему, и новому клиенту, поэтому вознаграждение корректно разрешается, даже несмотря на то, что проходит через установку и свежий логин при холодном старте.

Полный технический разбор подхода — включая то, почему перестало работать распространённое решение, — мы описали в статье Отложенный deep linking после Firebase Dynamic Links: App Clips + Play Install Referrer.

Результаты

Теперь клиент может запустить полностью брендированное, готовое к публикации приложение кэшбэка для нового партнёра за долю того времени, что требовалось раньше, — не отвлекая инженеров от продуктовой работы под каждый запуск. Архитектура с общей кодовой базой держит 15+ приложений в едином ритме: одно исправление, одна функция, один релиз достигают их всех. Админ-интерфейс превратил повторяющееся инженерное «узкое место» в возможность самообслуживания, а автоматизированный конвейер сделал каждый новый запуск предсказуемым и повторяемым событием, а не отдельным проектом. А офлайн-магазины, которые раньше работали вслепую, теперь сами проводят кампании кэшбэка и скидок и впервые знают, кто их клиенты.

Именно такие платформы мы создаём в рамках разработки white-label приложений — одна кодовая база на Flutter, на которой работает целый флот брендированных приложений.

Детали проекта

Клиент
Не разглашается (NDA)
Дата
1 августа 2025 г.
Продолжительность
8 Месяцев

Заинтересованы в похожем проекте?

Давайте обсудим, как мы можем помочь воплотить ваше видение в жизнь.

Связаться с нами