Реализация системы достижений и бейджей для геймификации мобильного приложения
Система достижений влияет на retention не потому что пользователям нравятся иконки. Она работает через conpletion psychology: незаконченный прогрессбар вызывает желание его закрыть. Достижение, которое видно но недостижимо — раздражает. Видно и легко достижимо — вовлекает. Это инженерная задача с психологическим контекстом.
Модель данных
Три ключевые сущности:
Achievement — шаблон достижения: id, title, description, icon_url, criteria (тип события + порог), xp_reward, badge_type (bronze/silver/gold/platinum). Критерии храним как JSON: {"event":"workout_completed","count":10} или {"event":"streak_days","count":7}.
UserAchievement — факт получения: user_id, achievement_id, progress (текущее значение), unlocked_at (null если не разблокировано).
AchievementEvent — лог событий для пересчёта прогресса: user_id, event_type, value, occurred_at. Это важно — пересчёт прогресса должен быть идемпотентным и восстанавливаемым из лога.
Логика проверки и разблокировки
Два подхода: event-driven (на каждое событие проверяем все релевантные достижения) и batch (периодический пересчёт всех пользователей). Для большинства приложений — event-driven на бэкенде.
Клиент отправляет событие (например workout_completed) → бэкенд incrementы счётчик в UserAchievement.progress → если progress >= criteria.count и unlocked_at IS NULL → устанавливаем unlocked_at, записываем XP, отправляем push-уведомление через APNs/FCM.
Критично: операция должна быть атомарной. Конкурентные запросы от одного пользователя с двух устройств не должны дважды разблокировать достижение. Postgres: UPDATE с WHERE unlocked_at IS NULL RETURNING * в транзакции.
Отображение на клиенте
Три состояния бейджа: locked (с прогрессбаром), unlocked (полноцветный), newly unlocked (анимация разблокировки).
Анимация разблокировки — момент, который нельзя испортить. На iOS: UIViewPropertyAnimator + Lottie для сложных анимаций. На Flutter: AnimationController + Lottie widget. Файл анимации (.json Lottie) для каждого типа бейджа — bronze/silver/gold отдельно. Не делай это через GIF — качество хуже, контроля меньше.
Тост или full-screen moment? Зависит от веса достижения. Обычное достижение — bottom sheet или overlay на 2–3 секунды. Редкое (gold/platinum) — full-screen celebration с конфетти (Confetti package на Flutter, кастомный CAEmitterLayer на iOS).
Прогресс и витрина
Экран «Мои достижения»: группировка по категориям, locked достижения видны с прогрессбаром (motivational), unlocked — с датой. Не скрывай locked достижения — это убивает motivation loop.
Счётчик разблокированных достижений в профиле пользователя, total XP от достижений (если есть система уровней). Шейринг бейджа в соцсети — UIActivityViewController с кастомным превью (UIActivityItemProvider).
Ориентиры по срокам
Базовая система с 20–30 достижениями, event-driven бэкендом и анимацией разблокировки — 2–3 дня для клиентской части при готовом бэкенде, 1–2 недели с бэкендом. Расширенная система с кастомными Lottie-анимациями, категориями, шерингом и аналитикой разблокировок — 3–4 недели. Стоимость рассчитывается индивидуально.







