An Android app for Catholic faith formation — Scripture, liturgy, prayer, community, and AI-assisted spiritual reflection.
Started by Bwire and open to creative collaboration.
- Bible — multilingual Scripture reading (English + Latin Vulgate), paged, local-first.
- Liturgy — daily Missal readings and liturgical calendar, works fully offline.
- Prayer — seeded prayer content, readily available without a network connection.
- Community + AI Verbum — social features and AI-assisted reflection, built on the same modular foundation.
- Kotlin + Jetpack Compose + Material 3
- Hilt for dependency injection
- Room for local persistence
- Retrofit + Moshi + OkHttp for networking
- Coroutines + Flow
app/ → application entry point, navigation graph, feature wiring
core/ → shared infrastructure (common, ui, network, database)
feature/ → self-contained feature modules
- English Bible source (
pg1581) packaged in app assets. - Latin Vulgate source (
vulsearch_vulgate) packaged in app assets. - Canonical mapping and book metadata for all supported books.
- Locale-aware language selection with user override support.
- On app bootstrap, Bible seeding runs from assets into Room.
- Language selection resolves in this order:
- explicit user selection
- compatible device locale
- English fallback
- Latin fallback (if English unavailable)
- Bible access is repository-driven, paged, and cache-assisted.
- Batch inserts are used during seeding.
- Room is indexed for verse lookups.
- Paging is used for chapter/verse retrieval.
- In-memory chapter caching is used to reduce repeated I/O.
- Missal readings and liturgical calendar assets under
app/src/main/assets/missal/. - Multi-year static JSON datasets (as available from the source repository).
- Calendar and season logic in
feature/missaldomain/data layers.
Liturgy follows a local-first model with layered fallback:
- Return cached database data when available.
- Fall back to bundled assets when cache is missing.
- Optionally refresh from network sources where supported.
- Persist refreshed data back to Room.
This keeps the liturgy experience usable offline while allowing refresh when connectivity is available.
- Bible assets:
app/src/main/assets/bible/source/ - Missal assets:
app/src/main/assets/missal/ - Prayer assets:
app/src/main/assets/prayers/
Seeding and warmup are orchestrated from app bootstrap coordination logic so initial data is available early in app lifecycle.
./gradlew :app:compileDebugKotlin
./gradlew build
./gradlew verifyVerbumGuidelines
On Windows PowerShell, use ./gradlew.bat ... if required by local shell configuration.
Contributors work on feature branches and open PRs to dev. Everything beyond that — promoting builds through SIT, UAT, and out to the Play Store — is handled by the maintainer. Think of it like a parish: the Priest (that's me) handles the liturgy of deployment, you just need to show up prepared. 😏
All PRs to dev must originate from a branch with one of these prefixes:
| Prefix | Example |
|---|---|
feature-<description> |
feature-bible-search |
ft-<description> |
ft-prayer-detail-screen |
PRs from branches that do not match this convention are automatically rejected by CI before any code review begins. To rename your branch:
git branch -m old-name feature-your-description
git push origin feature-your-description
git push origin --delete old-nameOnce you open a PR, this is what happens:
feature-* / ft-*
│
▼ Pull Request (you open this)
dev ◄── CI validates: branch name, guidelines, lint, tests, build
│
└── Admin reviews and merges if all checks pass
│
▼ Admin opens PR: dev → sit
sit ◄── CI validates again
│
└── Admin merges; auto-deploys to SIT testers
│
▼ QA/Admin opens PR: sit → uat
uat ◄── CI validates (release mode)
│
└── Manual approval → Firebase UAT testers
│
▼ QA/Admin opens PR: uat → main
main ◄── Manual approval
│
└── Signed AAB → Google Play Store
Your job ends at step one. Open a clean PR to dev with all local checks passing. Once it merges, Bwire takes it from there.
Run all three checks locally and ensure they pass with zero errors:
./gradlew verifyVerbumGuidelines
./gradlew :app:compileDebugKotlin
./gradlew :app:assembleDebugThis section is the contributor contract for this repository.
app: app bootstrap, navigation graph, feature orchestration only.core/common: shared primitives (extensions, result wrappers, dispatchers, utilities).core/ui: theme engine, design tokens, reusable UI components, preview utilities.core/database: Room entities, DAOs, migrations.core/network: Retrofit APIs, interceptors, DTO mapping helpers.feature/*: feature-specific UI, ViewModel, domain use-cases, repositories, DI.
Allowed dependency direction:
app->feature/*,core/*feature/*->core/*core/*-> nofeature/*
Forbidden:
feature/*->feature/*- UI/ViewModel layer -> direct DAO imports
- Feature UI/ViewModel -> direct network API calls
- Use this screen structure:
FeatureScreen(...)for wiring andFeatureContent(...)for pure UI rendering. - Hoist screen state from ViewModel (
StateFlow+collectAsStateWithLifecycle) intoContentcomposables. - Route data access through
UseCaseandRepositorylayers; keep DAOs inside data/repository boundaries. - Keep each ViewModel focused; split by use-case when a ViewModel starts owning unrelated flows.
- Use type-safe domain models (
data class,enum class, sealed UI state) instead of untyped maps. - Use
MaterialThemeand liturgical theme tokens for all colors/typography/spacing. - Add previews for every
*Screen.ktfile. - Use one of the approved preview matrix patterns:
VerbumScreenPreviews { ... }, or@PreviewParameter(VerbumPreviewVariantProvider::class) variant: VerbumPreviewVariant
- For
TopAppBarand other experimental Material 3 APIs, annotate with@OptIn(ExperimentalMaterial3Api::class)at the right scope. - Keep AI calls behind
feature/ai-verbumdata/domain layers. - Write/maintain unit tests for domain logic and repository boundaries.
- Validate input in use-cases before repository calls (search query length, IDs, language keys, etc.).
- Do not import
com.verbum.core.database.dao.*in/ui/or*ViewModel.ktfiles. - Do not use force unwrap (
!!); use safe fallbacks and explicit null handling. - Do not hardcode hex colors in feature/UI files (
Color(0x...)); use theme tokens. - Do not call
verbumApi.sendAiMessage(...)outsidefeature/ai-verbumdata layer. - Do not put business logic directly inside composable bodies.
- Do not create feature-to-feature compile-time dependencies.
- Do not introduce Material 2 components; stay on Material 3.
- Do not create omni ViewModels that coordinate unrelated responsibilities.
- Do not add hidden global state as a shortcut for navigation/data flow.
- Do not skip previews for new/changed screen-level composables.
- Do not ship code without running verification + compile checks.
- Screen file:
FeatureScreen.kt - ViewModel:
FeatureViewModel.kt - Use case:
ActionThingUseCase.kt - Repository pair:
ThingRepository.kt+ThingRepositoryImpl.kt - UI state: sealed type named
FeatureUiState
Run these from repository root:
./gradlew verifyVerbumGuidelines./gradlew :app:compileDebugKotlin./gradlew :app:assembleDebug
Recommended for broader validation:
./gradlew build./gradlew test
./gradlew verifyVerbumGuidelines enforces:
- No
!!force unwraps. - No hardcoded hex colors outside allowed theme packages.
- No DAO imports in UI/ViewModel layers.
- No direct AI endpoint calls outside approved AI data layer.
- Every
*Screen.ktincludes@Previewand a preview variant matrix pattern. - Unit tests exist in
src/test.
Violations are reported with exact file:line locations.