MyFamilyTracker
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
From zero to 22 live Play Store apps as a solo developer. The architecture decisions, tooling, and mental models that made it possible without burning out.
On this page
22 apps on Google Play. Solo. No team. No funding. No co-founder.
People ask how. The honest answer: systems, not hustle. I didn't work 18-hour days. I built infrastructure that compounds — so every new app is easier than the last.
Here's exactly how it works.
The biggest time-killer for any developer is decision fatigue. What folder structure? What DI framework? What state management approach?
I made those decisions once, then never made them again.
Every app I ship uses the same foundation:
app/
├── data/
│ ├── local/ # Room, DataStore
│ ├── remote/ # Retrofit, Firebase
│ └── repository/ # Repository implementations
├── domain/
│ ├── model/ # Pure Kotlin data classes
│ ├── repository/ # Repository interfaces
│ └── usecase/ # Business logic, one action each
└── presentation/
├── ui/
│ └── screen/ # Composables per screen
└── viewmodel/ # StateFlow-based ViewModelsMVVM + Clean Architecture + Hilt + Jetpack Compose. Same package structure. Same naming conventions. Same patterns for state, navigation, data flow.
When I start app #23, I'm not starting from zero. I'm copying a scaffold and filling in product logic.
Every ViewModel follows this exact shape:
@HiltViewModel
class HomeViewModel @Inject constructor(
private val getAppsUseCase: GetAppsUseCase
) : ViewModel() {
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
init {
loadApps()
}
private fun loadApps() {
viewModelScope.launch {
getAppsUseCase()
.onSuccess { apps ->
_uiState.value = HomeUiState.Success(apps)
}
.onFailure { error ->
_uiState.value = HomeUiState.Error(error.message ?: "Unknown error")
}
}
}
}
sealed interface HomeUiState {
data object Loading : HomeUiState
data class Success(val apps: List<App>) : HomeUiState
data class Error(val message: String) : HomeUiState
}No LiveData. No nullable state. No guessing what state the UI is in.
StateFlowEvery new screen, every new feature — I describe the pattern once. My custom skills encode my exact architecture conventions, so the generated code is immediately mergeable.
I built skills for:
The output isn't boilerplate I have to fix. It's production-ready code that matches my conventions exactly.
22 repos. Same version tracking system:
# config/version.properties
VERSION_MAJOR=1
VERSION_MINOR=3
VERSION_PATCH=2
VERSION_CODE=47One script bumps them all:
./version-bump.sh patch MyFamilyTracker
# → VERSION_PATCH=3, VERSION_CODE=48No manual version editing. No off-by-one mistakes. No forgetting to bump before release.
Every app is signed the same way. Keystore credentials live in
local.propertiesbuild.gradle.ktssigningConfigs {
create("play store") {
val props = Properties().apply {
load(rootProject.file("local.properties").inputStream())
}
storeFile = file(props["KEYSTORE_PATH"] as String)
storePassword = props["KEYSTORE_PASSWORD"] as String
keyAlias = props["KEY_ALIAS"] as String
keyPassword = props["KEY_PASSWORD"] as String
}
}No hardcoded credentials. No "which keystore did I use for this app?" panic.
13+ years in QA before I started building. People assume this was a liability — "you're not a real developer." It's the opposite.
QA engineers see what breaks. Developers who came up through QA ship things that don't.
What QA thinking gives you as a solo dev:
My apps don't have 5-star ratings because I'm a genius. They have good ratings because I think like a tester when I build.
Solo doesn't mean isolated. It means:
| Solo advantage | What it enables |
|---|---|
| No approval chains | Ship when it's ready, not when the process allows |
| No coordination overhead | Move at the speed of the idea |
| Full ownership | Every decision is yours — and so is every lesson |
| No meetings | That's just 8 hours back per week |
The 22 apps aren't 22 side projects. They're 22 bets. Some will grow. Some won't. The ones that do get depth — real features, real maintenance, real user relationships.
The goal isn't 50 apps. It's depth.
Pick the apps with real traction. Build them into something people rely on every day. Stop treating every app like a portfolio piece and start treating the best ones like products.
If you're thinking about building solo:
Everything else is learnable on the way.
Sudarshan Chaudhari
AI Systems Builder / Product Engineer
Bangkok, Thailand
Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.
Related Posts
Related Apps
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Building something? Available for Android dev and QA consulting.
Work with meComments — powered by Giscus
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
ReadPrivate dream journal — structured entry capture, pattern tagging, and optional Claude-powered insight generation. All data stays on-device by default.
ReadWorkout tracker — exercise logging with set/rep/weight history, goal progression, and local Room DB persistence. No account, no cloud sync required.
Read