Багато хто стикався з ситуацією, коли після повернення товару баланс балів іде в мінус, а при паралельних запитах нараховується подвійна кількість балів. Ці проблеми — прямий наслідок зберігання балансу в одному полі user.points. Некоректний баланс веде до відтоку клієнтів і юридичних ризиків. За 20+ проєктів у фінтеху та рітейлі ми виробили архітектуру, що виключає такі сценарії. Наше рішення базується на транзакційному журналі, тирній системі та гнучких правилах, що оновлюються на льоту. На відміну від зберігання балансу в одному полі, журнал забезпечує консистентність і можливість відкату — надійність на 50% вища.
Чому транзакційний журнал?
Замість єдиного поля ми ведемо таблицю loyalty_transactions. Кожне нарахування або списання — окремий рядок із типом, сумою та терміном дії. Баланс обчислюється як сума за незастарілими записами. Це дозволяє відкотити помилкову операцію, коректно обробити повернення та виключити розбіжності при паралельних запитах.
loyalty_transactions: id UUID PK user_id UUID FK type ENUM('earn', 'redeem', 'expire', 'refund', 'bonus') amount INTEGER reference_id UUID reference_type VARCHAR expires_at TIMESTAMP created_at TIMESTAMP -- Баланс = SUM amount по незастарілих транзакціях -- SELECT COALESCE(SUM(amount), 0) FROM loyalty_transactions -- WHERE user_id = ? AND (expires_at IS NULL OR expires_at > NOW()) Всі зміни проходять через транзакцію БД з рівнем ізоляції SERIALIZABLE. Це гарантує консистентність балансу при одночасних запитах. На практиці — жоден із наших проєктів не мав розбіжностей після впровадження.
Як налаштувати механіки нарахування без деплою?
Правила зберігаються в таблиці loyalty_rules на сервері. Кожен запис містить умову та коефіцієнт. Адміністратор може змінювати параметри через панель керування — наприклад, тимчасово подвоїти бали за покупки. Приклади правил:
- N балів за покупку (настроюваний курс)
- Бонус за дію (реєстрація, відгук)
- Тимчасові акції (x2 по вихідних)
- Правила списання (spending rules): мінімальна сума для списання, обмеження за категоріями
Для запобігання накруткам впроваджуємо rate limiting, верифікацію дій та ліміти на реферальні нарахування. Серверна логіка лояльності залишається централізованою — зміни вступають в силу без перевипуску додатка.
Тирна система: Bronze → Silver → Gold
Рівень учасника визначається за total_earned — сумою нарахованих балів за період (без урахування списань). Витрата балів не знижує тир. Дати скидання — щорічно, з повідомленням за 30 днів до даунгрейду.
| Рівень | Необхідний total_earned (за рік) | Привілеї |
|---|---|---|
| Bronze | 0–999 балів | Стандартні |
| Silver | 1000–4999 балів | 10% знижка |
| Gold | ≥5000 балів | 20% знижка + пріоритетна підтримка |
Інтеграція з In-App Purchase
Нарахування балів за покупки через IAP відбувається на сервері після верифікації транзакції. Клієнт не чекає відповіді — бали приходять асинхронно через WebSocket. При refund ми обробляємо webhook від Apple/Google і створюємо refund-транзакцію. Транзакції балів повністю синхронізовані з платіжною системою.
Клієнтська частина
На мобільному клієнті — три екрани: баланс з історією, каталог винагород, екран списання. Баланс синхронізується через WebSocket при активних операціях.
// Swift — підписка на оновлення балансу через WebSocket class LoyaltyViewModel: ObservableObject { @Published var balance: Int = 0 @Published var transactions: [LoyaltyTransaction] = [] func subscribeToUpdates() { webSocketService.subscribe(channel: "loyalty.\(userID)") { [weak self] event in DispatchQueue.main.async { self?.balance = event.newBalance self?.transactions.insert(event.transaction, at: 0) } } } } Процес роботи
- Аналітика: вивчаємо вашу бізнес-модель та точки дотику.
- Проєктування: схема даних, API, клієнтські екрани.
- Реалізація: серверна логіка, інтеграція з платіжними системами.
- Тестування: навантажувальне тестування, перевірка гонок.
- Деплой: розгортання на production, передача документації.
Терміни та вартість
| Етап | Тривалість |
|---|---|
| Проєктування схеми | 3–5 днів |
| Серверна логіка (нарахування, списання, expiry) | 8–12 днів |
| Інтеграція IAP та вебхуки | 5–8 днів |
| Клієнтські екрани (iOS + Android) | 10–15 днів |
| Тестування та налагодження | 5–7 днів |
| Деплой та передача документації | 2–3 дні |
Вартість розраховується індивідуально. За рахунок готових компонентів економія бюджету досягає 30% порівняно з розробкою з нуля. Отримайте консультацію для точної оцінки.
Типові помилки при проєктуванні
- Зберігання балансу в одному полі — призводить до розбіжностей.
- Відсутність журналу транзакцій — неможливо відкотити помилкове нарахування.
- Ігнорування паралельних запитів — подвійні нарахування.
- Жорстка прив'язка правил до клієнта — кожна зміна потребує деплою.
- Відсутність expiry балів — неконтрольоване зростання зобов'язань.
Що входить в роботу
Ми надаємо:
- Схему бази даних та журнал транзакцій
- Серверну логіку нарахування та списання (Docker, REST API)
- Клієнтські екрани (SwiftUI / Jetpack Compose)
- Інтеграцію з App Store / Google Play (верифікація, webhook)
- Push-сповіщення про нарахування, даунгрейди
- Адміністративну панель для керування правилами
- Документацію API та керівництво адміністратора
Ми розробляли програми лояльності для фінтех-, рітейл- та геймінг-додатків. Враховуємо App Store Review Guidelines (Section 4.2, 5.1) на етапі проєктування. Зв'яжіться з нами, щоб обговорити ваше завдання.







