Skip to content
All case studies

Case study · Logistics

Real-time delivery tracking for drivers

A mission-critical driver app that streams delivery updates in real time with Firestore, Coroutines and Flow, made testable with Koin.

Role
Android Engineer
Company
T10
Period
Aug 2022 – Feb 2023

Context

T10 works in logistics. From August 2022 to February 2023 I developed and maintained its delivery driver app, a mission-critical tool: when it stops working, deliveries stop too. The app is built with Kotlin, MVVM and Firebase Firestore.

Challenge

  • Real time, all the time. Delivery data changes constantly, and drivers need to see each update as soon as it happens.
  • No leaks, no frozen screens. Firestore listeners have to start and stop with the screen, and updates must reach the UI without blocking the main thread.
  • Confidence to change. A mission-critical app needs code that can be tested in isolation, which means dependencies that can be swapped.

Approach

Reactive streams with Coroutines and Flow. I wrapped Firestore snapshot listeners in callbackFlow, turning callbacks into cold flows. The listener is registered when the UI starts collecting and removed in awaitClose when it stops, so there is nothing to forget to unregister.

DeliveryRepository.kt
fun observeDelivery(id: String): Flow<Delivery> = callbackFlow {
    val registration = firestore
        .collection("deliveries")
        .document(id)
        .addSnapshotListener { snapshot, error ->
            if (error != null) {
                close(error)
                return@addSnapshotListener
            }
            snapshot?.toObject<Delivery>()?.let { trySend(it) }
        }

    awaitClose { registration.remove() }
}

State that outlives rotations. Repositories expose flows, and ViewModels turn them into StateFlow with stateIn. The UI always renders the latest known state, and a configuration change doesn’t restart the stream.

Dependency injection with Koin. I integrated Koin to declare dependencies in modules. Swapping Firestore-backed implementations for fakes in tests became trivial, and the modular architecture became more stable.

Architecture

Firestoredelivery documentscallbackFlowsnapshot listenerRepositoryFlow<Delivery>ViewModelStateFlowUIlive statusinjectinjectKoin dependency graphswappable with fakes in tests
Simplified. The listener lives only while the UI is collecting, so nothing leaks.

Results

  • Real-time delivery tracking powered by reactive streams with Coroutines, Flow and Firestore.
  • Listeners tied to the UI lifecycle, so updates stop as soon as nobody is watching.
  • Better testability and a more stable modular architecture with Koin.

Stack

The tools behind this work, all used in production:

  • Kotlin
  • MVVM
  • Firebase Firestore
  • Coroutines
  • Flow
  • Koin

Details are simplified and client names are omitted to respect confidentiality.

Next case study

Pix payments at superapp scale

Zup Innovation

Want to build something like this?

I’m open to senior Android roles at international companies.