ComposeTemplate is a generator, not a single app. Changes can affect the source fixture, generated consumers, or both.
Open an issue before substantial work, especially for build-logic, navigation, data-strategy projection, secrets, module boundaries, or generated-project structure. Documentation lives in wiki/; behavior and docs must change together.
- Branch from
mainunless an active issue explicitly targets another branch. - Keep each PR focused on one logical outcome.
- Explain why the change is needed and which generated configurations it affects.
- Do not merge until required checks are green and review findings are resolved.
Run the source-template gates:
./gradlew ktlintCheck detekt testDebugUnitTest assembleDebug :app:assembleReleaseFor build-logic or generation changes, test the affected consumer strategies explicitly. Examples:
./gradlew create-new-app \
-Pargs='com.example.remote,RemoteApp' \
-PdataStrategy=remote \
-q --console=plain
./gradlew create-new-app \
-Pargs='com.example.minimal,MinimalApp' \
-PdataStrategy=minimal \
-q --console=plainIf secrets projection changed, also generate a network-backed secret-free consumer:
./gradlew create-new-app \
-Pargs='com.example.secretfree,SecretFreeApp' \
-PdataStrategy=remote \
-PwithSecrets=false \
-q --console=plainBuild every generated consumer you test:
./gradlew assembleDebug :app:assembleReleaseClean generated sibling projects before committing.
./gradlew scaffoldFeature -PfeatureName=smoke_test
./gradlew :feature:smoke_test:presentation:compileDebugKotlinFor Room scaffolding:
./gradlew scaffoldFeature \
-PfeatureName=database_smoke_test \
-PwithDatabase=true
./gradlew :feature:database_smoke_test:data:compileDebugKotlinRemove generated smoke-test feature folders before committing.
The full source template retains secrets. Copy secrets.properties.example, supply non-placeholder local values, and run ./gradlew validateSecrets. Never commit secrets.properties or a production keystore. NDK/XOR is hardening and obfuscation, not secure client-side secret storage.
- Every retained feature has
data,domain,navigation, andpresentationmodules. - Modules are discovered from folders; do not add manual
include(...)entries. :appmay import onlycore:common,core:navigation, andcore:ui.- Always-present core modules may name only one another.
- Optional core modules may depend on core, never on features.
- A feature may reference another feature only through its navigation contract.
- Use DI multibindings for optional integrations instead of importing removable implementations.
Boundary tasks run during normal build/test lifecycles. Narrow exceptions belong in the importing module's own moduleBoundary block.
Run ./gradlew ktlintCheck detekt; use ./gradlew ktlintFormat for Kotlin formatting. Update the relevant wiki page, root README, generated-consumer wording, and CI contract whenever behavior changes.
Use GitHub Issues for bugs/features. Report vulnerabilities through a private GitHub security advisory, not a public issue.