Разработка системы уведомлений через административную панель
Административная панель для рассылки 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'ов).







