Building AppointaKit: A Modern Android Showcase

When I set out to build a showcase app for my portfolio, I wanted it to be more than a toy project. I wanted something that demonstrates how I architect, build, and ship Android software at scale.

The Challenge

Most portfolio projects are simple CRUD apps that don’t reflect the complexity of real-world development. I needed something that showcased:

  • Clean Architecture with proper separation of concerns
  • Modern Jetpack libraries working together harmoniously
  • Production patterns like process death survival, pagination, and background work

The Stack

AppointaKit uses a single-module architecture with clean package separation:

  • Jetpack Compose for all UI — zero XML layouts
  • Material 3 with Dynamic Color support
  • Hilt for dependency injection across all layers
  • Room with Paging 3 for local persistence
  • WorkManager for appointment reminders
  • Navigation Compose 2.8+ with type-safe routes
  • Kotlin Coroutines + Flow for reactive data streams

Architecture Decisions

MVVM + UiState

Every ViewModel exposes a single StateFlow<UiState> and accepts events through an onEvent() function. This unidirectional data flow makes state management predictable:

data class BookingUiState(
    val currentStep: BookingStep,
    val service: Service?,
    val isLoading: Boolean,
)

SavedStateHandle for Process Death

The booking wizard persists its state through SavedStateHandle, surviving process death without losing the user’s progress across 4 steps.

Mock API with Real Architecture

Even though the data is mocked, the entire network layer uses real Retrofit + OkHttp with a MockInterceptor. Swapping to a real API would require changing one Hilt module.

What I Learned

Building this reinforced that good architecture isn’t about following patterns blindly — it’s about making the right trade-offs for your context. A single module was the right call for a showcase app, but the clean package separation means it could be split into modules without architectural changes.

The app is live on my portfolio — you can interact with it directly in your browser through an embedded demo.