Розробка системи сповіщень через адміністративну панель
Адміністративна панель для розсилки push-сповіщень — це не просто форма з полями "заголовок" та "текст". Це інструмент для маркетолога або менеджера продукту, який повинен розуміти аудиторію, планувати рассилки, тестувати варіанти та бачити результати. Розберемо, з чого це складається технічно.
Архітектура системи
Компоненти, які взаємодіють:
Admin Panel (мобільний додаток)
↓
Campaign API (бекенд)
↓
Queue (RabbitMQ / Redis)
↓
Push Worker (надсилання через FCM / APNs / OneSignal)
↓
Webhook Handler (статуси доставки)
↓
Analytics DB (клацання, відкриття, конверсії)
Мобільний додаток — лише управляючий інтерфейс. Всю важку роботу робить серверна сторона.
Створення кампанії
Форма створення кампанії на мобільному — покроковий wizard:
Крок 1: Аудиторія. Вибір сегменту з заздалегідь створених (за тегами, поведінкою, географією) або створення нового фільтра прямо тут.
Крок 2: Контент. Заголовок, текст, зображення (Rich Push), Deep Link, кнопки дій. Превю сповіщення — як воно виглядає на iOS та Android.
Крок 3: Розклад. Надіслати зараз, у конкретний час, або Intelligent Delivery (автоматично в оптимальний час для кожного користувача).
Крок 4: A/B тест (опціонально). Два або три варіанти тексту, розподіл трафіку.
Крок 5: Підтвердження. Екран підсумку: N користувачів в аудиторії, очікуваний охоп, фінальне превю.
// iOS — багатошаговий wizard через NavigationController
class CampaignWizardCoordinator {
private var campaign = DraftCampaign()
private let navigationController: UINavigationController
func start() {
showAudienceStep()
}
func showAudienceStep() {
let vc = AudienceSelectionVC(draft: campaign) { [weak self] audience in
self?.campaign.audience = audience
self?.showContentStep()
}
navigationController.pushViewController(vc, animated: true)
}
func showContentStep() {
let vc = NotificationContentVC(draft: campaign) { [weak self] content in
self?.campaign.content = content
self?.showScheduleStep()
}
navigationController.pushViewController(vc, animated: true)
}
}
Превю сповіщення
Превю — важливий UX-елемент. Рекрутери часто не знають, як виглядає сповіщення на конкретній платформі.
// Android — кастомний View для превю iOS/Android
@Composable
fun NotificationPreview(
title: String,
body: String,
imageUrl: String?,
platform: Platform
) {
when (platform) {
Platform.IOS -> IOSNotificationMockup(title, body, imageUrl)
Platform.ANDROID -> AndroidNotificationMockup(title, body, imageUrl)
}
}
@Composable
fun IOSNotificationMockup(title: String, body: String, imageUrl: String?) {
Card(modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(12.dp)) {
Row(modifier = Modifier.padding(12.dp)) {
// App icon
Box(modifier = Modifier.size(40.dp).background(Color.Blue, RoundedCornerShape(8.dp)))
Spacer(Modifier.width(8.dp))
Column {
Text(title, fontWeight = FontWeight.SemiBold, fontSize = 13.sp)
Text(body, fontSize = 13.sp, maxLines = 2)
}
imageUrl?.let { AsyncImage(model = it, modifier = Modifier.size(56.dp)) }
}
}
}
Управління шаблонами
Шаблони — попередньо збережені варіанти сповіщень для типових подій. В admin panel — список шаблонів, створення нового, редагування, дублювання.
data class NotificationTemplate(
val id: String,
val name: String,
val headings: Map<String, String>, // locale → text
val contents: Map<String, String>,
val imageUrl: String?,
val data: Map<String, String>, // deep link params
val buttons: List<NotificationButton>,
val category: TemplateCategory
)
Шаблони зберігаються на сервері. Клієнт отримує список через API, відображає в RecyclerView / LazyColumn, дозволяє вибрати шаблон при створенні кампанії.
Аналітика в реальному часі
Під час активної рассилки — real-time дашборд:
Надіслано: 15,234 / 18,500
Доставлено: 14,891 (97.7%)
Відкрито: 2,341 (15.7%)
Клацання кнопок: 891 (38.1% від відкритих)
Дані через WebSocket або Server-Sent Events:
class CampaignStatsStream {
func subscribe(campaignId: String) -> AsyncStream<CampaignStats> {
AsyncStream { continuation in
let eventSource = EventSource(url: URL(string: "/api/campaigns/\(campaignId)/stats/stream")!)
eventSource.onMessage = { _, _, data in
if let stats = try? JSONDecoder().decode(CampaignStats.self, from: data) {
continuation.yield(stats)
}
}
eventSource.connect()
}
}
}
Права доступу
Різні ролі в admin panel:
| Роль | Може створювати | Може надсилати | Бачить аналітику |
|---|---|---|---|
| Редактор | Так | Ні (лише чернетка) | Тільки своїх кампаній |
| Маркетолог | Так | Так | Всі кампанії |
| Адміністратор | Так | Так | Все + управління шаблонами |
На сервері права перевіряються через middleware. На клієнті — відключаємо/приховуємо кнопки по role з JWT, але це тільки UX, не безпека.
Графік
Мобільна admin panel з wizard створення кампанії, управлінням шаблонів, real-time аналітикою, історією рассилок та ролевими правами доступу — 10–16 робочих днів для мобільної частини (без врахування серверної інфраструктури черги та worker'ів).







