feat(search-record): Phase C Wave 4 — Search Record end-to-end Store5 migration - #2689
Conversation
… migration
End-to-end migration of the Search Record feature to the kmp-project-template
Store5 architecture. This is Wave 4 of Phase C — the second read-only feature
wave (after Wave 3: search). Search Record is purely local (no network /
Ktorfit), querying ClientDaoHelper directly via SearchRecordLocalDataSource.
Data (core/data):
- Relocated SearchRecordRepository to com.mifos.core.data.searchrecord
- Relocated SearchRecordLocalDataSource(+Impl) to com.mifos.core.data.searchrecord.local
- Relocated SearchRecordRepositoryImpl to com.mifos.core.data.searchrecord.impl
- Repository now returns Flow<List<GenericSearchRecord>> — dropped the
Result<T> wrapper and its catch-map-failure scaffold; errors flow through
the standard Flow.catch in the VM
- RepositoryModule imports updated to new packages
Feature (feature/search-record):
- Restructured to {ui, di, navigation} subpackages
(VM + Screen + State moved under ui/)
- SearchRecordViewModel switched from com.mifos.core.ui.util.BaseViewModel
(legacy) to com.mifos.core.ui.store.BaseViewModel (typealias to
template.core.base.ui.viewmodel.BaseViewModel)
- SearchRecordState owns screenState: ScreenState<List<GenericSearchRecord>>
(replaces the bespoke DialogState.Loading/Error sealed type +
searchRecords + isNoResultsFound triple)
- displayTitle moved from hardcoded "Address"/"Identifiers" strings in
the VM to a StringResource derived from RecordType, rendered via
stringResource in the Screen
- SearchRecordScreen uses ScreenContent — Loading / Empty / Error / Content
rendered through framework slots; custom empty slot distinguishes
"initial blank query" from "no results for entered query"
- MifosAlertDialog raw-error-message rendering removed; ScreenState.Error
is rendered through ScreenContent's default error slot
- Navigation split: SearchRecordRoute.kt (@serializable) + Navigation builder
- @Preview functions (Content / Loading / NoResults / Error) via
PreviewParameterProvider
- gradle deps: projects.core.data + projects.core.ui only (dropped
projects.core.common + projects.core.domain + projects.core.model —
the chain is transitively available via core.data + core.ui api())
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|



Summary
End-to-end migration of the Search Record feature (
feature/search-record) to the kmp-project-template architecture. This is Wave 4 of Phase C — the second read-only feature wave (after Wave 3 search).Note on Store5: Search Record is purely local — it filters already-cached Room tables (
client_address,client_identifier) via fuzzyLIKE %query%. There is no remote fetch in this feature, so per the Store5-on-every-fetch HARD RULE it correctly bypasses Store5 and consumes the DAOFlowdirectly. The data is persisted byfeature/client(future Wave 5+). A retroactive Wave 4.5 PR will follow this one wrapping Wave 3'sSearchApiin a properSearchStore(Wave 3 was authored before that rule was pinned).Layers touched
Data (
core/data)SearchRecordRepository→com.mifos.core.data.searchrecord.*SearchRecordLocalDataSource(+ impl) →com.mifos.core.data.searchrecord.local.*SearchRecordRepositoryImpl→com.mifos.core.data.searchrecord.impl.*Result<T>wrapper — repository now returnsFlow<List<GenericSearchRecord>>directly. Errors propagate via standardFlow.catchin the VM, not encoded in the payload type.RepositoryModuleimports updated to the new packages.Feature (
feature/search-record){ui, di, navigation}subpackages (VM + Screen + State now underui/).SearchRecordViewModelswitched from the legacycom.mifos.core.ui.util.BaseViewModelto the newcom.mifos.core.ui.store.BaseViewModeltypealias overtemplate.core.base.ui.viewmodel.BaseViewModel.SearchRecordStatenow ownsscreenState: ScreenState<List<GenericSearchRecord>>— replaces the bespokeDialogState.{Loading, Error}sealed type +searchRecordslist +isNoResultsFoundflag triple.displayTitlemoved from hardcoded\"Address\"/\"Identifiers\"literals in the VM to aStringResourcederived fromRecordType, rendered viastringResource(state.displayTitle)in the Screen.SearchRecordScreenusesScreenContent— Loading / Empty / Error / Content rendered through framework slots; the customemptyslot distinguishes "initial blank query" from "no results for entered query".MifosAlertDialogthat renderederror.messageraw to the user (violated the no-hardcoded-user-facing-strings rule indirectly).ScreenState.Erroris now rendered throughScreenContent's default error slot, which uses framework-controlled copy.SearchRecordRoute.kt(@Serializable) +SearchRecordNavigation.kt(theNavGraphBuilderextension).@Previewfunctions viaPreviewParameterProvidercovering Content / Loading / NoResults / Error states.build.gradle.ktsdeps reduced toprojects.core.data+projects.core.uionly (droppedprojects.core.common,projects.core.domain,projects.core.model— all available transitively through theapi()chain).Plan rule pinned this wave
Added the Store5-mandatory-on-fetch HARD RULE to
plan-layer/.../store5-adoption/C-features.md(framework PR following this one):This rule surfaced when the user asked "why aren't we writing a Store5 store here" — search-record correctly stays outside Store5, but Wave 3 (search) should have been Store5-wrapped from the start. Wave 4.5 will retrofit search.
Acceptance (G-C wave 4)
SearchRecordRepositorylives incom.mifos.core.data.searchrecord.*SearchRecordLocalDataSourcelives incom.mifos.core.data.searchrecord.local.*Flow<List<GenericSearchRecord>>— noResult<T>wrappingSearchRecordViewModelextends the templateBaseViewModeltypealiasSearchRecordState.screenState: ScreenState<List<GenericSearchRecord>>SearchRecordScreenusesScreenContentfeature/search-record/build.gradle.ktshas zeroprojects.coreBase.*referencescomposeResourcesrunCatchingin production sourcef0dba387) — prior wave is contained@Previewcovers Content / Loading / Empty / Error statesTest plan
androidApp+iosAppScreenContentContent slot