Skip to content

feat(search-record): Phase C Wave 4 — Search Record end-to-end Store5 migration - #2689

Merged
therajanmaurya merged 1 commit into
openMF:store5Migrationfrom
therajanmaurya:feat/store5-w4-search-record-e2e
May 21, 2026
Merged

feat(search-record): Phase C Wave 4 — Search Record end-to-end Store5 migration#2689
therajanmaurya merged 1 commit into
openMF:store5Migrationfrom
therajanmaurya:feat/store5-w4-search-record-e2e

Conversation

@therajanmaurya

Copy link
Copy Markdown
Member

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 fuzzy LIKE %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 DAO Flow directly. The data is persisted by feature/client (future Wave 5+). A retroactive Wave 4.5 PR will follow this one wrapping Wave 3's SearchApi in a proper SearchStore (Wave 3 was authored before that rule was pinned).

Layers touched

Data (core/data)

  • Relocated SearchRecordRepositorycom.mifos.core.data.searchrecord.*
  • Relocated SearchRecordLocalDataSource (+ impl) → com.mifos.core.data.searchrecord.local.*
  • Relocated SearchRecordRepositoryImplcom.mifos.core.data.searchrecord.impl.*
  • Dropped the Result<T> wrapper — repository now returns Flow<List<GenericSearchRecord>> directly. Errors propagate via standard Flow.catch in the VM, not encoded in the payload type.
  • RepositoryModule imports updated to the new packages.

Feature (feature/search-record)

  • Restructured to {ui, di, navigation} subpackages (VM + Screen + State now under ui/).
  • SearchRecordViewModel switched from the legacy com.mifos.core.ui.util.BaseViewModel to the new com.mifos.core.ui.store.BaseViewModel typealias over template.core.base.ui.viewmodel.BaseViewModel.
  • SearchRecordState now owns screenState: ScreenState<List<GenericSearchRecord>> — replaces the bespoke DialogState.{Loading, Error} sealed type + searchRecords list + isNoResultsFound flag triple.
  • displayTitle moved from hardcoded \"Address\" / \"Identifiers\" literals in the VM to a StringResource derived from RecordType, rendered via stringResource(state.displayTitle) in the Screen.
  • SearchRecordScreen uses ScreenContent — Loading / Empty / Error / Content rendered through framework slots; the custom empty slot distinguishes "initial blank query" from "no results for entered query".
  • Removed the MifosAlertDialog that rendered error.message raw to the user (violated the no-hardcoded-user-facing-strings rule indirectly). ScreenState.Error is now rendered through ScreenContent's default error slot, which uses framework-controlled copy.
  • Navigation split: SearchRecordRoute.kt (@Serializable) + SearchRecordNavigation.kt (the NavGraphBuilder extension).
  • @Preview functions via PreviewParameterProvider covering Content / Loading / NoResults / Error states.
  • build.gradle.kts deps reduced to projects.core.data + projects.core.ui only (dropped projects.core.common, projects.core.domain, projects.core.model — all available transitively through the api() 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):

Every read pipeline that calls a core/network/<feature>/api/XxxApi MUST be wrapped in a Store5 Store<K, V> in core/data/<feature>/store/. Pure local queries (search-record) and one-shot mutations (auth, activate) are explicit exceptions.

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)

  • SearchRecordRepository lives in com.mifos.core.data.searchrecord.*
  • SearchRecordLocalDataSource lives in com.mifos.core.data.searchrecord.local.*
  • Repository returns Flow<List<GenericSearchRecord>> — no Result<T> wrapping
  • SearchRecordViewModel extends the template BaseViewModel typealias
  • SearchRecordState.screenState: ScreenState<List<GenericSearchRecord>>
  • SearchRecordScreen uses ScreenContent
  • feature/search-record/build.gradle.kts has zero projects.coreBase.* references
  • No hardcoded user-facing strings (titles, hints, errors, contentDescriptions) — all from composeResources
  • No runCatching in production source
  • Wave 4 commit base = Wave 3 merge commit (f0dba387) — prior wave is contained
  • Compose Multiplatform @Preview covers Content / Loading / Empty / Error states

Test plan

  • App builds on androidApp + iosApp
  • Open client → Address tab → search field renders → initial blank-state message
  • Type a fragment → 300ms debounce → results render via ScreenContent Content slot
  • Clear button resets to initial blank state
  • Same flow on Identifier tab
  • No-results state renders the "No results found / Try a different search term for X" copy
  • (Offline) data was previously cached by Client wave → search still works offline (no fetch happens here)

… 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())
@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • development

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3802757c-009d-4e12-942f-378bd6e5cae9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud

Copy link
Copy Markdown

@therajanmaurya
therajanmaurya marked this pull request as ready for review May 21, 2026 15:46
@therajanmaurya
therajanmaurya requested a review from a team May 21, 2026 15:46
@therajanmaurya
therajanmaurya merged commit c89bed6 into openMF:store5Migration May 21, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant