feat(auth): Phase C Wave 2 — Login end-to-end Store5 migration - #2687
Conversation
Second end-to-end feature wave. Adds the auth resource API + relocates
the Login chain following the Wave 1 template.
core/network/auth/api/AuthApi.kt (NEW)
Suspend Ktorfit interface for Fineract authentication endpoints.
Future auth-wave additions (OTP, refresh, logout) extend this same file.
core/network/di/NetworkModule.kt
+ single { get<Ktorfit>().createAuthApi() }
Method-level @deprecated on legacy login paths:
- DataManagerAuth.login
- ClientService.authenticate
Both surfaces stay compileable for un-migrated callers; Phase D deletes
them once nothing references them.
core/data/auth/ (relocate + rewrite)
git mv core/data/repository/LoginRepository.kt
-> core/data/auth/LoginRepository.kt
git mv core/data/repositoryImp/LoginRepositoryImp.kt
-> core/data/auth/impl/LoginRepositoryImpl.kt (renamed)
Impl now consumes AuthApi directly; no DataManagerAuth dependency.
RepositoryModule import updated; binding remains in core/data.
core/domain (delete pure-delegator use case)
- useCases/LoginUseCase.kt (deleted)
- di/UseCaseModule.kt: factoryOf(::LoginUseCase) removed
Surviving use cases: UsernameValidationUseCase + PasswordValidationUseCase
(validators — kept per the core/domain rule).
feature/auth/{ui, di, navigation}/ (restructure with MVI triple)
ui/
LoginState.kt — validation-error state (pre-submit gate)
LoginAction.kt — sealed Submit / DismissError
LoginEvent.kt — sealed NavigateToPasscode / ShowError(StringResource)
LoginViewModel.kt — extends BaseViewModel<LoginState, LoginEvent, LoginAction>
with SubmitHandler<PostAuthenticationResponse>.
Submitted -> persist user via prefManager, emit
NavigateToPasscode event. authenticated != true also
routes to ShowError. Failed -> ShowError.
LoginScreen.kt — uses MifosProgressIndicatorOverlay during submit;
Snackbar for error events; passcode navigation on
success. Includes 3 @Preview functions (Idle,
Submitting, ValidationError) using
org.jetbrains.compose.ui.tooling.preview.* (KMP-aware).
di/AuthModule.kt — import updated to ui/ package; viewModelOf-only
(Repository binding lives in core/data
RepositoryModule per the Koin DI ownership boundary).
navigation/
LoginRoute.kt — @serializable object (split from AuthNavigation)
AuthNavigation.kt — NavGraphBuilder.authNavGraph + nav extensions
No hardcoded user-facing strings:
composeResources additions:
feature_auth_update_server_configuration
feature_auth_cd_arrow_forward
feature_auth_cd_error_icon
feature_auth_cd_password_visibility
All button labels, content descriptions consume stringResource(...).
feature/auth/build.gradle.kts
+ implementation(projects.core.ui)
Other deps unchanged (core.data + core.domain for validators).
Grep invariants pass: zero DataState, zero MifosProgressIndicator legacy
imports, zero user-facing string literals, file layout matches plan.
|
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 |
|
field-officer submodule HEAD: 920c6810 (Wave 2 — auth login E2E merged via openMF/mifos-x-field-officer-app#2687). Co-authored-by: Rajan Maurya <therajanmaurya@Rajans-MacBook-Pro.local>
…bilebytesensei#37) field-officer submodule HEAD: 920c6810 (Wave 2 — auth login E2E merged via openMF/mifos-x-field-officer-app#2687). Co-authored-by: Rajan Maurya <therajanmaurya@Rajans-MacBook-Pro.local>



Summary
Phase C Wave 2 — second end-to-end feature wave. Follows the Wave 1 template (merged via
#2686) and applies it to the login flow.The login flow is harder than activate because the VM has to:
SubmitHandlerSubmitted, persist the user viaprefManager.updateUser(side effect) BEFORE navigatingresponse.authenticated != true) by routing toShowErrorMVI's
LoginState+LoginEvent+LoginActiontriple handles this cleanly: state holds validation errors (replayable), events emitNavigateToPasscode/ShowError(StringResource)(one-shot), actions areSubmit(username, password)/DismissError.Changes (21 files; +280 / -310 net)
core/network/auth/core/network/auth/api/AuthApi.kt— suspend Ktorfit interface forPOST authenticationreturningPostAuthenticationResponse. Future OTP / refresh / logout endpoints land here.core/network/di/NetworkModule.kt:+ single { get<Ktorfit>().createAuthApi() }@DeprecatedonDataManagerAuth.login+ClientService.authenticate— both stay compileable for un-migrated callers.core/data/auth/git mv core/data/repository/LoginRepository.kt → core/data/auth/LoginRepository.ktgit mv core/data/repositoryImp/LoginRepositoryImp.kt → core/data/auth/impl/LoginRepositoryImpl.ktLoginRepositoryImplconstructor:(authApi: AuthApi)— noDataManagerAuth.RepositoryModule.kt: import update +singleOf(::LoginRepositoryImpl) bind LoginRepository::class. Repository binding stays incore/dataper the Koin DI ownership boundary.core/domainuseCases/LoginUseCase.kt(pure delegator)UseCaseModule.kt: removedfactoryOf(::LoginUseCase)+ import.UsernameValidationUseCase,PasswordValidationUseCase(validators).feature/auth/{ui, di, navigation}/restructureOld flat layout (
feature/auth/login/{LoginViewModel, LoginScreen, LoginUiState}.kt) eliminated. New:VM logic flow:
handleAction(Submit(u, p))→ validate inputs → if valid,submit.submit { repo.login(u, p) }submit.state.collect { ... }:Submitted→ checkresponse.authenticated == true; if yes, persist user + emitNavigateToPasscode; if no, emitShowErrorFailed→ emitShowError(feature_auth_error_login_failed)handleAction(DismissError)→submit.reset()after snackbar consumes the error eventScreen consumes
stateFlow(validation errors) +submitState(submitting overlay) +eventFlow(one-shot navigation/error).No hardcoded user-facing strings
New
composeResources/values/strings.xmlentries:feature_auth_update_server_configurationfeature_auth_cd_arrow_forwardfeature_auth_cd_error_iconfeature_auth_cd_password_visibilityAll button labels and content descriptions consume
stringResource(...). Log strings (Logger.d("Login", ...)) remain as literals — allowed per plan (log tags are not user-facing).feature/auth/build.gradle.kts+ implementation(projects.core.ui)(forBaseViewModel)core.data+core.domainkept (validators stay in domain)coreBase.*depsGrep invariants
grep -rn "DataState|asDataStateFlow" feature/auth/ core/data/.../auth/ core/domain/useCases/LoginUseCase*grep -rn "template\.core\.base" feature/auth/KptTheme— Theme, accessed via api chain)grep -rn "DataManagerAuth|ClientService\.authenticate" feature/auth/ core/data/.../auth/feature/auth/src/commonMain/kotlin/Logger.dtags remain)Test plan
./gradlew :feature:auth:buildcompiles cleanly./gradlew :cmp-android:assembleDebugsucceeds; Koin DI resolvesauthenticated: false): error snackbarPhase status
#2686)Mifos*composables