01 · Контекст и задача
Сеть «Бавария» — это семь магазинов разливного пива и закусок к нему в станицах Краснодарского края. До нашего проекта учёт клиентов, скидок и карт лояльности велся в 1С на стороне, продавцы держали бумажные тетради, а постоянные клиенты помнили свой % скидки наизусть.
Что просил клиент: приложение для покупателей с картой лояльности и каталогом, личный кабинет каждой точки для приёма заказов, и единая админка для владельца — чтобы видеть все магазины в одном месте. И чтобы карты лояльности и баланс баллов синхронизировались с 1С — это критично, иначе на кассе и в приложении будут разные цифры.




02 · Что было сложно
- Интеграция с 1С без прямого API. 1С у клиента — это рабочая система учёта на бумаге. Прямого HTTP-сервиса в ней нет, эндпоинтов нет, REST поднимать никто не будет. Надо синхронизироваться через файловый обмен, и так, чтобы расхождение между приложением и кассой не накапливалось.
- Три роли в одной системе. Покупатель видит каталог и свою карту. Продавец на точке — только заказы своей точки. Владелец — все магазины целиком, выручку, реестр согласий, акции. Одна СУБД, разные интерфейсы, разные права — и без права на ошибку в правах: продавец не должен случайно увидеть данные соседней точки.
- Юридическая часть. Приложение собирает персональные данные — телефоны, имена, историю покупок. Нужны согласия по 152-ФЗ, оферта, отдельное согласие на рассылки. Всё это должно фиксироваться с датой, IP-адресом и устройством — на случай претензий нужны доказательства.
- Один договор, две сторы. RuStore — обязательно, российский рынок. App Store — тоже хотели сразу. Это разные сборки, разные требования к скриншотам, разные правила к приложениям с алкоголем (по сути — пивом и сопутствующим товаром).
Главное было — не клонировать «Магнит» или «Перекрёсток», а сделать систему под локальную сеть, где каждый продавец знает в лицо своих постоянных покупателей.
03 · Решения
Обмен с 1С через файлы
Сделали отдельный сервис обмена внутри Docker. 1С выгружает три файла — barcodes.json (штрих-коды карт лояльности), bonus_points.json (бонусные баллы клиентов) и total_spent.json (накопленные суммы покупок). Наш бэк забирает их по расписанию, разносит по коллекциям MongoDB и обновляет статус каждой записи. В админке владелец видит, когда была последняя синхронизация, сколько записей по каждому типу прошло, и может запустить обмен вручную одной кнопкой.
Пять уровней карт лояльности — все настраиваются из админки
Бронзовая (1%, без порога), Серебряная (3%, от 30 000 ₽ покупок), Золотая (5%, от 80 000 ₽), Платиновая (7%, от 150 000 ₽), Премиум (10%). Карты, % скидки и порог апгрейда меняются из админки — без релизов и без обращения к разработке. Цвет карты и обложка тоже задаются админом, приложение подтягивает свежие данные при каждом входе.
Реестр согласий с IP и устройством
При входе в приложение клиент даёт три отдельных согласия — оферта, обработка персональных данных, акции и рассылки. Каждое фиксируется в реестре с датой/временем (с точностью до секунды), IP-адресом и моделью устройства. Владелец может выгрузить весь реестр в CSV для предъявления контрагенту или Роскомнадзору, не разбираясь в SQL.
Личный кабинет точки — отдельный URL и отдельные права
У каждой точки свой логин на /operator/login. Продавец входит только в свой кабинет, видит только заказы своей точки и помечает их «выдано» или «отказ». Админ видит всех централизованно и может зайти в любую точку как наблюдатель. На уровне API роль проверяется на каждом эндпоинте — не на фронте, не «и так не покажу», а отдельной middleware-проверкой.
Защита от брутфорса на логине
После нескольких неверных попыток входа аккаунт блокируется на 15 минут. Лимит считается по логину и IP отдельно — нельзя забрутфорсить ни конкретный аккаунт админа, ни перебрать все логины с одного IP. В коллекции operators пароли хранятся захешированные (bcrypt), а не в открытом виде, как часто делают в таких системах.
Одна Flutter-кодовая база — две сторы
Приложение собрано на Flutter — одной кодовой базой под Android для RuStore и под iOS для App Store. Разделили только то, что физически разное: иконку и сплэш-скрин по требованиям каждой платформы, push-уведомления (FCM на Android, APNs на iOS), да настройку подписи под каждый сторе. Логика, экраны, API — общие.




04 · Результат
Через месяц после публикации в RuStore и App Store сеть зарегистрировала более двухсот клиентов. Половина из них уже совершила несколько покупок и поднялась с Бронзовой карты на Серебряную. Владелец впервые видит выручку по всем семи точкам в одной таблице — раньше это было обзвоном продавцов в конце недели.
1С продолжает быть основной системой учёта на кассе. Приложение и админка не пытаются её заменить — они синхронизируются с ней и показывают клиенту его реальные баллы, которые насчитала касса. Расхождений нет.
05 · Что дальше
Проект сейчас на поддержке. Основные направления развития — увеличение трафика из приложения (push-кампании по акциям, баннеры в каталоге), доработка обмена с 1С под новые типы скидок и подключение онлайн-оплаты с СБП — сейчас оплата только наличными или картой на точке.
Бэкенд и админка разделены на сервисы в Docker Compose, MongoDB вынесена в отдельный том с пейроль-доступом, SSL обновляется автоматически через certbot. То есть когда сеть откроет восьмой и девятый магазин — добавление новой точки занимает минут пять и не требует ни релиза приложения, ни вмешательства разработчика.