Разработка мобильного приложения для аукциона

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Разработка мобильного приложения для аукциона
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Разработка мобильного приложения для аукциона

Аукционное приложение — один из самых технически требовательных продуктов в мобильной разработке. Причина: состояние лота меняется в реальном времени, каждые несколько секунд может появиться новая ставка, и пользователь на другом конце ждёт мгновенного результата. Задержка в 2 секунды при отображении чужой ставки — и пользователь делает ставку на уже проигранную позицию.

Реальное время: WebSocket как основа

Polling для аукциона — неприемлемо. WebSocket с переподключением — стандарт:

// iOS: WebSocket через URLSessionWebSocketTask
class AuctionWebSocket {
    private var webSocketTask: URLSessionWebSocketTask?
    private var reconnectTimer: Timer?

    func connect(auctionId: String) {
        let url = URL(string: "wss://api.yourauction.com/auctions/\(auctionId)/live")!
        webSocketTask = URLSession.shared.webSocketTask(with: url)
        webSocketTask?.resume()
        receive()
    }

    private func receive() {
        webSocketTask?.receive { [weak self] result in
            switch result {
            case .success(let message):
                if case .string(let text) = message {
                    self?.handleMessage(text)
                }
                self?.receive() // продолжаем слушать
            case .failure:
                self?.scheduleReconnect()
            }
        }
    }

    private func scheduleReconnect() {
        reconnectTimer?.invalidate()
        reconnectTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { [weak self] _ in
            self?.connect(auctionId: self?.currentAuctionId ?? "")
        }
    }
}
// Android: OkHttp WebSocket
class AuctionWebSocketManager(
    private val client: OkHttpClient,
    private val scope: CoroutineScope
) {
    private val _events = MutableSharedFlow<AuctionEvent>()
    val events: SharedFlow<AuctionEvent> = _events.asSharedFlow()

    fun connect(auctionId: String) {
        val request = Request.Builder()
            .url("wss://api.yourauction.com/auctions/$auctionId/live")
            .build()

        client.newWebSocket(request, object : WebSocketListener() {
            override fun onMessage(webSocket: WebSocket, text: String) {
                scope.launch {
                    val event = json.decodeFromString<AuctionEvent>(text)
                    _events.emit(event)
                }
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                scope.launch {
                    delay(3000)
                    connect(auctionId)
                }
            }
        })
    }
}

Типы событий от сервера: BID_PLACED (новая ставка), AUCTION_EXTENDED (время продлено), AUCTION_ENDED, YOU_WON, YOU_WERE_OUTBID.

Гонка условий при ставках

Самая сложная бизнес-логика: два пользователя делают ставку одновременно. Пример:

  1. Текущая ставка: 1000 ₽
  2. Пользователь A видит 1000 ₽, делает ставку 1100 ₽
  3. Пользователь B видит 1000 ₽, делает ставку 1050 ₽
  4. Обе ставки приходят на сервер в один момент

Правильное решение — оптимистическая блокировка с версией лота:

def place_bid(user_id: str, lot_id: str, amount: Decimal, expected_version: int) -> BidResult:
    with db.transaction():
        lot = db.select_for_update(f"SELECT * FROM lots WHERE id = %s", lot_id)

        if lot.version != expected_version:
            # За это время кто-то уже поднял ставку
            return BidResult(
                success=False,
                reason="LOT_UPDATED",
                current_bid=lot.current_bid,
                new_version=lot.version
            )

        if amount <= lot.current_bid:
            return BidResult(
                success=False,
                reason="BID_TOO_LOW",
                current_bid=lot.current_bid,
                new_version=lot.version
            )

        db.execute(
            "UPDATE lots SET current_bid=%s, current_bidder=%s, version=version+1 WHERE id=%s",
            (amount, user_id, lot_id)
        )
        db.execute(
            "INSERT INTO bids (lot_id, user_id, amount) VALUES (%s, %s, %s)",
            (lot_id, user_id, amount)
        )

        broadcast_to_websockets(lot_id, {
            "type": "BID_PLACED",
            "amount": str(amount),
            "bidder": mask_username(user_id),
            "version": lot.version + 1
        })

        return BidResult(success=True, new_version=lot.version + 1)

При LOT_UPDATED клиент получает актуальную ставку и может предложить пользователю сделать новую с учётом текущей цены.

Автоставка (proxy bidding)

Пользователь устанавливает максимальную сумму, которую готов заплатить. Система автоматически повышает его ставку в ответ на ставки конкурентов — до установленного максимума.

def process_autobid(lot_id: str, new_bid_amount: Decimal, new_bidder_id: str):
    """Проверяем автоставки после каждой новой ставки"""
    autobids = db.get_active_autobids(lot_id, exclude_user=new_bidder_id)

    for autobid in sorted(autobids, key=lambda x: x.max_amount, reverse=True):
        counter_amount = new_bid_amount + lot.bid_step

        if counter_amount <= autobid.max_amount:
            # Автоматически ставим от имени держателя автоставки
            place_bid(autobid.user_id, lot_id, counter_amount, lot.version)
            break

Автоставка — источник конфликтов с пользователями, поэтому важна детальная история: «Ваша ставка 1 200 ₽ была автоматически повышена в ответ на ставку 1 100 ₽».

Продление времени anti-sniping

Снайпинг — ставка в последние секунды. Чтобы его избежать, аукцион продлевается при ставке в конце:

ANTI_SNIPING_THRESHOLD = timedelta(minutes=2)
ANTI_SNIPING_EXTENSION = timedelta(minutes=2)

def after_bid_placed(lot_id: str):
    lot = db.get_lot(lot_id)
    time_remaining = lot.ends_at - datetime.utcnow()

    if time_remaining < ANTI_SNIPING_THRESHOLD:
        new_end_time = lot.ends_at + ANTI_SNIPING_EXTENSION
        db.update_lot_end_time(lot_id, new_end_time)
        broadcast_to_websockets(lot_id, {
            "type": "AUCTION_EXTENDED",
            "new_end_time": new_end_time.isoformat()
        })

Таймер на клиенте синхронизируется с серверным временем при получении AUCTION_EXTENDED.

Платёжная логика

Победитель получает push-уведомление и имеет ограниченное время (24–48 часов) для оплаты. Если не оплатил — лот переходит следующему по ставке или выставляется повторно.

Для ценных лотов — предоплата перед участием: депозит блокируется при регистрации на торги, возвращается проигравшим.

Комиссия с продажи (покупателя или продавца) удерживается при оплате. Payouts продавцу — через Stripe Connect или аналог.

Ориентиры по срокам

Scope Срок
Просмотр лотов, WebSocket, ставки, push-уведомления 6–8 недель
Автоставки, anti-sniping, история ставок +2 недели
Кабинет продавца, публикация лотов, payouts +3–4 недели
Депозиты и escrow +1–2 недели

Стоимость рассчитывается индивидуально после анализа требований.