Skip to content

feat(search): Phase C Wave 3 — Search end-to-end Store5 migration - #2688

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

feat(search): Phase C Wave 3 — Search end-to-end Store5 migration#2688
therajanmaurya merged 1 commit into
openMF:store5Migrationfrom
therajanmaurya:feat/store5-w3-search-e2e

Conversation

@therajanmaurya

Copy link
Copy Markdown
Member

Summary

End-to-end migration of the Search feature to the kmp-project-template Store5 architecture. This is Wave 3 of Phase C (the per-feature wave) — the first read-only feature wave, following Wave 1 (activate, mutation) and Wave 2 (auth, mutation).

Layers touched

Network (core/network)

  • New SearchApi (Ktorfit, suspend) at com.mifos.core.network.search.api.SearchApi — returns List<SearchedEntity> directly, no Flow / no Call wrapper
  • Registered in NetworkModule (single { get<Ktorfit>().createSearchApi() })
  • @Deprecated on SearchService.searchResources and DataManagerSearch.searchResources — to be deleted in Phase D

Data (core/data)

  • New ScreenTypes.kt adds ScreenState<T> / DataFreshness / ScreenDataStream<T> typealiases over the template.core.base.store.screen.* originals
  • SearchRepository interface relocated com.mifos.core.data.repositorycom.mifos.core.data.search
  • Implementation rewritten as com.mifos.core.data.search.impl.SearchRepositoryImpl — uses SearchApi, suspend, no DataState/Flow
  • RepositoryModule updated to bind the new impl
  • RoomSubmitOutbox.toEntry refactored from runCatching { ... }.getOrNull() to explicit try/catch per project rule (no runCatching in production code — see plan rule update)

Feature (feature/search)

  • Restructured to {ui, di, navigation, components} subpackages
  • SearchViewModel extends BaseViewModel<SearchScreenState, Nothing, SearchAction> (MVI)
  • SearchScreenState owns resultState: ScreenState<List<SearchedEntity>>SearchResultState (legacy 4-state sealed) deleted
  • SearchScreen uses ScreenContent<List<SearchedEntity>> with custom empty slot that distinguishes "initial blank screen" from "no results for query"
  • Components renamed: SearchScreenEventSearchAction (UpdateSearchText / ClearSearchText / UpdateSelectedFilter / UpdateExactMatch / PerformSearch)
  • SearchNavigation.kt split into SearchRoute.kt (the @Serializable route) + SearchNavigation.kt (the NavGraphBuilder + navigateToSearchScreen extension)
  • Accessibility contentDescription strings moved from inline literals to composeResources (feature_search_a11y_*)
  • 5 @Preview functions on SearchScreen (Loading / InitialEmpty / NoResults / Content / Error)
  • build.gradle.kts deps: projects.core.data + projects.core.ui only — no projects.coreBase.* (per the hard rule pinned in the plan this wave)

Plan rules pinned this wave

Two HARD RULES added to plan-layer/.../store5-adoption/C-features.md:

  1. No runCatching in production code — it swallows CancellationException and breaks structured concurrency. Use explicit try/catch (re-throwing CancellationException) for read flows; SubmitHandler<R> handles mutation flows internally.
  2. Feature modules NEVER use projects.coreBase.* — only projects.core.*. The core.* modules are the project's facade over the framework; core-base/* deps flow transitively via api(). If a feature needs a template.core.base.* type, add a typealias / pass-through in core/<x>/ and re-run the wave.

Acceptance (G-C wave 3)

  • SearchApi exists in core.network.search.api.*, registered in NetworkModule
  • SearchRepository lives in core.data.search.*, no Flow<DataState<*>>
  • Legacy SearchService.searchResources + DataManagerSearch.searchResources are @Deprecated
  • SearchViewModel extends BaseViewModel<S, E, A> and owns ScreenState<List<SearchedEntity>>
  • SearchScreen uses ScreenContent and renders Loading / Empty / Error / Content
  • feature/search has 4 @Preview states covering Loading / InitialEmpty / NoResults / Content / Error
  • feature/search/build.gradle.kts has zero projects.coreBase.* references
  • No hardcoded user-facing strings (titles, hints, errors, contentDescriptions) — all from composeResources
  • Wave 3 commit base = Wave 2 merge commit (920c6810) ← prior wave is contained

Wave protocol

This branch was cut from upstream/store5Migration after Wave 2 (PR #2687) merged, per the HARD RULE in C-features.md ("ALWAYS sync store5Migration before starting a new wave").

Next

  • Wave 4 onward (release lock for client / loan / savings — see plan-layer/.../active/store5-adoption/PLAN.md for the registry).
  • Phase D will delete the @Deprecated SearchService.searchResources / DataManagerSearch.searchResources / the legacy SearchUiState (already deleted in this PR) once every wave has landed.

Test plan

  • App builds on androidApp + iosApp (smoke test)
  • Open SearchScreen from drawer → empty state (no input) renders nothing in the result area
  • Type query → tap Search → Loading → Content/Empty/Error per backend response
  • Clear button resets to empty state
  • Filter chip opens dialog → selecting a filter triggers a new search
  • Exact-match checkbox toggles and re-runs search
  • Tap a result row → navigates to client/center/group/loan/savings detail

End-to-end migration of the Search feature to the kmp-project-template
Store5 architecture, following the per-resource API + MVI ViewModel +
ScreenContent pattern.

Network (core/network):
- New SearchApi (Ktorfit, suspend) at core.network.search.api.SearchApi
- @deprecated SearchService.searchResources + DataManagerSearch.searchResources

Data (core/data):
- ScreenTypes typealiases for ScreenState / DataFreshness / ScreenDataStream
- Relocated SearchRepository to com.mifos.core.data.search; new impl uses
  SearchApi (suspend, returns List<SearchedEntity>) — no more Flow<DataState>
- RepositoryModule binds the new impl
- RoomSubmitOutbox.toEntry now uses try/catch instead of runCatching

Feature (feature/search):
- Restructured to {ui, di, navigation, components} subpackages
- SearchViewModel extends BaseViewModel<SearchScreenState, Nothing, SearchAction>
- SearchScreenState owns ScreenState<List<SearchedEntity>>
- SearchScreen uses ScreenContent (Loading / Empty / Error / Content slots)
- Search components use SearchAction (renamed from SearchScreenEvent)
- SearchNavigation split: SearchRoute.kt (@serializable) + nav builder
- Accessibility content descriptions moved into composeResources
- @Preview functions for Loading / InitialEmpty / NoResults / Content / Error
- gradle deps: projects.core.data + projects.core.ui (no projects.coreBase.*)
@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: 3636d30b-813c-4dfa-9f04-ee22298f7c13

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:27
@therajanmaurya
therajanmaurya requested a review from a team May 21, 2026 15:27
@therajanmaurya
therajanmaurya enabled auto-merge (squash) May 21, 2026 15:27
@therajanmaurya
therajanmaurya merged commit f0dba38 into openMF:store5Migration May 21, 2026
2 of 3 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