Розробка мобільного додатку для краудфандингу
Кілька років тому одна з наших платформ для краудфандингу зіткнулася з проблемою: в останню годину кампанії кількість одночасних запитів на оформлення бекінгів зросла в 10 разів, і база даних не впоралася з транзакціями – частина платежів зависла в статусі pending, бекери отримали подвійні списання. Після аудиту ми переписали механізм авторизації та додали шардування по project_id. Ця помилка коштувала клієнту значних репутаційних втрат – і допомогла нам відточити архітектуру, яку тепер використовуємо в усіх проєктах. У статті розберемо ключові компоненти, що перетворюють MVP у production-grade платформу: від escrow-моделей до швидких виплат. Спираємося на досвід 50+ фінтех- та маркетплейс-рішень.
Як реалізувати надійне умовне списання коштів?
All-or-Nothing (AoN) – кошти списуються тільки при досягненні цілі. Якщо кампанія не зібрала потрібну суму – усі платежі повертаються. Реалізація: при бекінгу робимо authorization hold на картці (кошти заморожені, але не списані). При успіху кампанії – capture, при провалі – void.
# Stripe: створення PaymentIntent з capture_method=manual
import stripe
def back_project(user_id: str, project_id: str, amount: int, reward_tier_id: str) -> dict:
payment_intent = stripe.PaymentIntent.create(
amount=amount,
currency="usd",
capture_method="manual", # не списувати одразу
metadata={
"user_id": user_id,
"project_id": project_id,
"reward_tier_id": reward_tier_id
},
confirm=False # підтвердимо на клієнті
)
return {"client_secret": payment_intent.client_secret}
def capture_all_backers(project_id: str):
"""Викликається при успішному завершенні кампанії"""
backers = db.get_backers(project_id, status="authorized")
for backer in backers:
stripe.PaymentIntent.capture(backer.payment_intent_id)
db.update_backer_status(backer.id, "captured")
def refund_all_backers(project_id: str):
"""Викликається при провалі кампанії"""
backers = db.get_backers(project_id, status="authorized")
for backer in backers:
stripe.PaymentIntent.cancel(backer.payment_intent_id)
db.update_backer_status(backer.id, "cancelled")
Проблема: авторизація на картці діє обмежений термін – у Stripe це 7 днів для більшості карток, максимум 31 деньStripe Documentation: "Authorization holds". Кампанії довші за 30 днів – не можна утримувати авторизацію весь цей час. Рішення: списувати одразу (Keep-it-All модель) або виконувати повторну авторизацію незадовго до закінчення.
Keep-it-All (KiA) – кошти списуються одразу при бекінгу, незалежно від досягнення цілі. Технічно простіше, але менш приваблива для бекерів. Популярна для благодійних та творчих проєктів. За даними Statista, AoN-кампанії збирають в середньому на 40% більше коштів, ніж KiA, тому для комерційних проєктів ми рекомендуємо саме першу модель.
| Параметр | All-or-Nothing | Keep-it-All |
|---|---|---|
| Момент списання | При успіху кампанії | Одразу при бекінгу |
| Довіра бекерів | Висока | Середня |
| Складність реалізації | Висока (авторизація, таймаути) | Низька |
| Підходить для | Комерційні проєкти | Благодійність, творчість |
Чому AoN кращий для великих проєктів?
За даними Stripe, близько 70% успішних краудфандингових кампаній використовують AoN. Бекери почуваються впевненіше, знаючи, що їхні гроші не пропадуть, якщо ціль не буде досягнута.Рівні винагород (Reward Tiers)
Кожен проєкт пропонує кілька рівнів: «Підтримати» за $10, «Ранній доступ» за $50, «Ексклюзивний набір» за $200. У кожного рівня – кількість доступних слотів та поточна заповненість.
// iOS: екран вибору рівня винагороди
struct RewardTierView: View {
let tier: RewardTier
let onSelect: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("$\(tier.amount)")
.font(.title2.bold())
Spacer()
if let limit = tier.backerLimit {
Text("\(tier.backerCount)/\(limit) підтримали")
.font(.caption)
.foregroundColor(tier.isSoldOut ? .red : .secondary)
}
}
Text(tier.title).font(.headline)
Text(tier.description).font(.body).foregroundColor(.secondary)
if let estimatedDelivery = tier.estimatedDelivery {
Label("Доставка: \(estimatedDelivery)", systemImage: "shippingbox")
.font(.caption)
}
Button(tier.isSoldOut ? "Розібрано" : "Вибрати рівень") {
if !tier.isSoldOut { onSelect() }
}
.disabled(tier.isSoldOut)
}
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}
Обмежені слоти вимагають pessimistic locking на сервері: при оформленні бекінгу блокуємо рядок reward_tier для перевірки та декременту лічильника в одній транзакції.
Прогрес кампанії та соціальна механіка
Сторінка проєкту – центральний контент. Прогрес-бар зібраних коштів, зворотний відлік до кінця кампанії, стрічка оновлень від автора, коментарі бекерів.
Технічно найнавантаженіший момент: останній день кампанії. Усі бекери перевіряють прогрес одночасно. WebSocket для реального часу або aggressive polling (кожні 10 секунд в останні години) – з кешуванням на CDN.
// Android: WebSocket для живого оновлення прогресу
class CampaignProgressViewModel(
private val campaignId: String,
private val wsClient: WebSocketClient
) : ViewModel() {
val progress = MutableStateFlow<CampaignProgress?>(null)
init {
wsClient.connect("wss://api.yourplatform.com/campaigns/$campaignId/live")
viewModelScope.launch {
wsClient.messages.collect { message ->
val update = json.decodeFromString<CampaignProgressUpdate>(message)
progress.value = update.progress
}
}
}
override fun onCleared() {
wsClient.disconnect()
}
}
Оновлення проєкту та комунікація з бекерами
Автор публікує оновлення про хід робіт. Бекери отримують push-сповіщення про кожне нове оновлення. Сегментація: сповіщення тільки тим, хто підтримав саме цей проєкт.
FCM topic-based messaging для цього не підходить – потрібна таргетована розсилка через серверний список отримувачів. Для кожного проєкту зберігається список device_tokens бекерів.
Як проходить верифікація авторів (KYC) і чому це критично важливо?
Публічний збір коштів приваблює шахрайські проєкти. Базовий захист:
- Ручна модерація нових проєктів перед публікацією
- Верифікація особи автора через KYC (паспорт + селфі) – обов'язкова для виведення коштів
- Автоматичне обмеження на виведення до підтвердження KYC
Процес верифікації покроково:
- Автор заповнює профіль у додатку.
- Натискає «Пройти верифікацію» – система генерує accessToken для KYC-провайдера.
- Відкривається нативний SDK (Sumsub, Veriff або Onfido), де автор робить фото паспорта та селфі.
- SDK передає дані провайдеру, який перевіряє документи та повертає статус.
- Якщо статус
approved, автор може запросити виведення коштів. Якщоrejected– відправляється на повторну перевірку з коментарем.
Інтеграція з KYC-провайдерами: Sumsub, Veriff, Onfido. Мобільний додаток ініціює KYC через SDK провайдера – процес повністю в нативному UI. Гарантуємо безпеку даних – усі SDK сертифіковані.
// iOS: Sumsub KYC flow
import IdensicMobileSDK
let sdk = SNSMobileSDK.build(
accessToken: kycAccessToken
)
.withHandlers(
onStatusDidChange: { [weak self] sdk, prevStatus in
if sdk.mainState == .approved {
self?.onKYCApproved()
}
},
onEvent: { sdk, event in }
)
.assemble()
sdk.present(from: self)
Виведення коштів для авторів
Після успішного завершення кампанії автор хоче отримати гроші. Схема виведення:
- KYC пройдено → можна запросити виведення
- Платформа утримує комісію (зазвичай 5–10%)
- Залишок виводиться через Stripe Connect (payout на банківський рахунок) або міжнародним переказом
Stripe Connect – стандарт для маркетплейсів з виплатами. Кожен автор – окремий Connected Account.
Що входить в нашу роботу
- Аналітика вимог та проєктування архітектури
- Розробка під iOS (Swift 5.9+, SwiftUI) та Android (Kotlin, Jetpack Compose)
- Інтеграція платежів (Stripe, Braintree) та KYC-провайдерів
- Налаштування push-сповіщень (FCM/APNs), deep linking, App Tracking Transparency
- Модерація контенту та anti-fraud алгоритми
- Деплой в App Store та Google Play, тести та підтримка
Орієнтири за термінами
| Scope | Термін |
|---|---|
| Базова версія: перегляд та підтримка проєктів, оплата, історія | 6–8 тижнів |
| Кабінет автора: створення проєктів, оновлення, аналітика | +3–4 тижні |
| All-or-Nothing з escrow та автоматичним capture/refund | +2 тижні |
| KYC та виведення через Stripe Connect | +2–3 тижні |
Вартість розраховується індивідуально після аналізу вимог. Щоб обговорити деталі вашого проєкту, залиште заявку – ми зв'яжемося протягом дня. Отримайте консультацію з архітектури – наші інженери допоможуть обрати оптимальне рішення.







