Project Structure
Understand the Kotlin template folders, feature modules, and ownership boundaries.
The Android template is one Gradle app module with package code under
com.soarstarter.kotlin. The main split is core/ for reusable app services,
data/ for persistence and network boundaries, feature/ for screen families,
and nav/ for typed routes and graph composition.
The template's AGENTS.md / CLAUDE.md tree is slightly stale. Current code
has core/showcase/, no feature/test/, no AuthGate.kt, and no separate
MainNavGraph.kt; MainNavGraph is a private composable inside
AppNavGraph.kt.
Project map
local.properties is git-ignored and belongs at the repo root. Android Studio
also writes sdk.dir there. Firebase client configuration belongs at
app/google-services.json; the Gradle plugin is applied only when that file is
present.
App entry points
| File | Role |
|---|---|
SoarApp.kt | @HiltAndroidApp; starts Sentry, PostHog, and the update controller on process start |
MainActivity.kt | @AndroidEntryPoint; handles deep-link intents, edge-to-edge bars, theme, locale, gates, root nav, and ToastHost |
app/build.gradle.kts | Android SDK versions, BuildConfig fields, conditional Google Services plugin, signing config |
AndroidManifest.xml | Permissions, FCM service, launcher activity, custom scheme, App Links |
core/
core/ is reusable app infrastructure. Feature code can depend on it; core/
should not depend on feature screens.
| Folder | Owns |
|---|---|
analytics/ | AnalyticsController and typed AnalyticsEvent for PostHog |
auth/ | SessionController and Google Sign-In controller |
biometric/ | Biometric app-lock controller and gate |
deeplink/ | DeepLinkHandler, DeepLinkResolver, DeepLinkDestination |
di/ | Hilt modules for DataStore, repositories, session flow, coroutines, biometric binding |
error/ | AppErrorBus, ErrorBoundary, SentryReporter |
haptics/ | Android vibrator wrapper used by toast and demos |
legal/ | Legal document model, consent controller, LEGAL_VERSION |
locale/ | AppLanguage, LocaleController, LocalizedAppHost |
onboarding/ | Onboarding completion controller |
purchases/ | RevenueCat lifecycle, entitlement reader, PremiumGate |
rating/ | Play In-App Review controller |
result/ | AppResult, AppError, friendly error mapping |
showcase/ | Capability catalog models shared by the removable Showcase leaf |
ui/components/ | Reusable Compose controls and states |
ui/theme/ | Material 3 color schemes, typography, theme controller |
ui/toast/ | SharedFlow toast controller and root overlay |
update/ | Play In-App Updates controller and gate state |
data/
data/ is where platform and backend details are hidden from screens.
| Folder | Owns |
|---|---|
local/ | AppPreferences, the typed DataStore flows for theme, locale, gates, rating, and biometrics |
model/ | Serializable app models such as Todo, Profile, Subscription, and profile/user DTOs |
network/ | NetworkObserver, backed by ConnectivityManager.NetworkCallback |
notifications/ | FCM service, token table data source, in-memory inbox, test-push function client |
remote/ | SupabaseClientProvider and Supabase plugin setup |
repository/ | Auth, todos, profile, subscription, and upload repositories plus Supabase remote data sources |
When adding a backend-backed feature, follow the existing shape:
data/model/NewThing.kt
data/repository/NewThingRemoteDataSource.kt
data/repository/SupabaseNewThingRemoteDataSource.kt
data/repository/NewThingRepository.kt
core/di/RepositoryModule.kt binding
feature/newthing/NewThingViewModel.kt
feature/newthing/NewThingScreen.kt
nav/Routes.kt + graph mountfeature/
Each feature folder owns a screen family, its view models, and private UI.
| Folder | Role |
|---|---|
auth/ | Login, signup, verification, forgot/reset password, pure validators |
component/ | Data-driven UI component gallery and interactive demos |
guide/ | Purchase-gated developer-guide example content |
home/ | Home tab and entitlement-aware license card |
legal/ | Consent gate UI and legal document screens |
main/ | Main shell, bottom tabs, drawer, sign-out state |
notifications/ | Push setup, FCM token display, in-memory inbox, test push button |
onboarding/ | Four-page onboarding pager |
paywall/ | Paywall, subscription management, redeem-code screen |
permissions/ | Permission priming screen |
profile/ | Me tab, personal info, account security, biometric toggle |
refer/ | Android share-sheet referral example |
showcase/ | Removable demo catalog and capability demos |
todos/ | Example CRUD feature on the Home stack |
update/ | Update dialogs used by UpdateGate |
upload/ | Supabase Storage image upload sample |
There is no current feature/test/ folder. Use the Showcase demos or add your
own debug-only screen if you need manual observability triggers.
nav/
Current files:
| File | Role |
|---|---|
Routes.kt | Type-safe @Serializable app routes in object AppRoutes |
AppNavGraph.kt | Root gates, outer nav destinations, auth graph, and private MainNavGraph |
OnboardingGate.kt | Gate that shows onboarding before consent/main content |
The tab graph is mounted inside feature/main/MainShellScreen.kt, where each
tab gets a nested destination graph and tab navigation preserves back stacks.
Tests
Unit tests live in app/src/test. The current suite covers controllers,
repositories, validators, model rules, component catalogs, entitlement gates,
and view models using fakes and kotlinx-coroutines-test.
Instrumented tests live in app/src/androidTest. Current files include a smoke
instrumented test and nav/NavRouteTest.kt. Run them only with a connected
device or emulator:
./gradlew connectedDebugAndroidTest